Repository: openlgtv/epk2extract Branch: master Commit: 22a910d5578d Files: 237 Total size: 1.5 MB Directory structure: gitextract_meo9h1xu/ ├── .cirrus.yml ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .sonarcloud_gen.sh ├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── README.md ├── build.sh ├── cmake-modules/ │ └── FindLZO.cmake ├── code_format.sh ├── include/ │ ├── common.h │ ├── config.h │ ├── cramfs/ │ │ ├── cramfs.h │ │ ├── cramfs_fs.h │ │ └── cramfsswap.h │ ├── crc.h │ ├── epk.h │ ├── epk1.h │ ├── epk2.h │ ├── epk3.h │ ├── jffs2/ │ │ ├── jffs2.h │ │ └── mini_inflate.h │ ├── log.h │ ├── lz4/ │ │ ├── bench.h │ │ ├── lz4.h │ │ └── lz4hc.h │ ├── lzhs/ │ │ ├── lzhs.h │ │ └── tables.h │ ├── lzma/ │ │ ├── LzFind.h │ │ ├── LzHash.h │ │ ├── LzmaDec.h │ │ ├── LzmaEnc.h │ │ └── Types.h │ ├── lzma.h │ ├── lzo/ │ │ ├── lzo.h │ │ ├── miniacc.h │ │ ├── portab.h │ │ └── portab_a.h │ ├── main.h │ ├── mediatek.h │ ├── mediatek_pkg.h │ ├── mfile.h │ ├── minigzip.h │ ├── os_byteswap.h │ ├── osx/ │ │ └── elf.h │ ├── philips.h │ ├── realtek/ │ │ └── rtsplit.h │ ├── realtek.h │ ├── sniptype.h │ ├── squashfs/ │ │ ├── action.h │ │ ├── caches-queues-lists.h │ │ ├── compressor.h │ │ ├── error.h │ │ ├── gzip_wrapper.h │ │ ├── info.h │ │ ├── lz4_wrapper.h │ │ ├── lzo_wrapper.h │ │ ├── mksquashfs.h │ │ ├── process_fragments.h │ │ ├── progressbar.h │ │ ├── pseudo.h │ │ ├── read_fs.h │ │ ├── restore.h │ │ ├── sort.h │ │ ├── squashfs_compat.h │ │ ├── squashfs_fs.h │ │ ├── squashfs_swap.h │ │ ├── unsquashfs.h │ │ ├── unsquashfs_info.h │ │ ├── xattr.h │ │ └── xz_wrapper.h │ ├── stream/ │ │ ├── crc32.h │ │ └── tsfile.h │ ├── symfile.h │ ├── thpool.h │ ├── u-boot/ │ │ ├── image.h │ │ ├── mtdinfo.h │ │ ├── partcommon.h │ │ ├── partinfo.h │ │ ├── partinfov1.h │ │ └── partinfov2.h │ ├── util.h │ └── util_crypto.h ├── keys/ │ ├── AES.key │ ├── MTK.key │ ├── README.md │ ├── e60.pem │ ├── e60n.pem │ ├── general_pub.pem │ ├── h15.pem │ ├── k24.pem │ ├── k24n.pem │ ├── k24t.pem │ ├── k25lp.pem │ ├── k2l.pem │ ├── k2lp.pem │ ├── k3lp.pem │ ├── k5lp.pem │ ├── k6hp.pem │ ├── k6lp.pem │ ├── k6lpfhd.pem │ ├── k6lpwee.pem │ ├── k7lp.pem │ ├── k8ap.pem │ ├── k8apwee.pem │ ├── k8hp-hotel.pem │ ├── k8hp.pem │ ├── k8hpp.pem │ ├── k8hpt.pem │ ├── k8hpwee.pem │ ├── k8lp-hotel.pem │ ├── k8lp.pem │ ├── k8lpn-hotel.pem │ ├── k8lpn.pem │ ├── k8lpn2.pem │ ├── k8lpwee.pem │ ├── kf23f-mnt.pem │ ├── kf23f.pem │ ├── kf23fwee.pem │ ├── kid23q.pem │ ├── lg1152.pem │ ├── lg1154_netcast.pem │ ├── lg1154_webos.pem │ ├── lm14.pem │ ├── lm15u.pem │ ├── lm18a.pem │ ├── lm21a.pem │ ├── lm21an.pem │ ├── lm21ann.pem │ ├── lm21u.pem │ ├── lm21ut.pem │ ├── m14.pem │ ├── m16.pem │ ├── m16p.pem │ ├── m16p3.pem │ ├── m16pp.pem │ ├── m23.pem │ ├── m2_sspm.pem │ ├── m3.pem │ ├── mtk5369.pem │ ├── mtk5398.pem │ ├── netflix_pub.pem │ ├── o18.pem │ ├── o18_2019.pem │ ├── o18k.pem │ ├── o20.pem │ ├── o208k.pem │ ├── o20n.pem │ ├── o22.pem │ ├── o22n.pem │ ├── o22n2.pem │ ├── o22n28k.pem │ ├── o22n3.pem │ ├── o24.pem │ └── o24n.pem ├── partinfo.py ├── sonar-project.properties └── src/ ├── CMakeLists.txt ├── cramfs/ │ ├── CMakeLists.txt │ ├── cramfsswap.c │ └── uncramfs.c ├── crc32.c ├── epk.c ├── epk1.c ├── epk2.c ├── epk3.c ├── jffs2/ │ ├── CMakeLists.txt │ ├── crc32.cpp │ ├── jffs2extract.cpp │ └── mini_inflate.cpp ├── lz4/ │ ├── CMakeLists.txt │ ├── bench.c │ ├── lz4.c │ ├── lz4_format_description.txt │ ├── lz4demo.c │ └── lz4hc.c ├── lzhs/ │ ├── CMakeLists.txt │ ├── lzhs.c │ └── lzhs_lib.c ├── lzma/ │ ├── CMakeLists.txt │ ├── LzFind.c │ ├── LzmaDec.c │ └── LzmaEnc.c ├── lzo-lg.c ├── main.c ├── mediatek.c ├── mediatek_pkg.c ├── mfile.c ├── minigzip.c ├── partinfo.c ├── philips.c ├── realtek.c ├── squashfs/ │ ├── CMakeLists.txt │ ├── action.c │ ├── caches-queues-lists.c │ ├── compressor.c │ ├── gzip_wrapper.c │ ├── info.c │ ├── lz4_wrapper.c │ ├── lzma_wrapper.c │ ├── lzma_xz_wrapper.c │ ├── lzo_wrapper.c │ ├── mksquashfs.c │ ├── process_fragments.c │ ├── progressbar.c │ ├── pseudo.c │ ├── read_file.c │ ├── read_fs.c │ ├── read_xattrs.c │ ├── restore.c │ ├── sort.c │ ├── swap.c │ ├── unsquash-1.c │ ├── unsquash-2.c │ ├── unsquash-3.c │ ├── unsquash-4.c │ ├── unsquashfs.c │ ├── unsquashfs_info.c │ ├── unsquashfs_xattr.c │ ├── xattr.c │ └── xz_wrapper.c ├── stream/ │ ├── CMakeLists.txt │ ├── crc32.c │ └── tsfile.c ├── symfile.c ├── thpool.c ├── tools/ │ ├── CMakeLists.txt │ ├── idb_extract.c │ ├── jffs2extract.c │ ├── lzhs_scanner.c │ ├── lzhsenc.c │ └── tsfile.c ├── util.c └── util_crypto.c ================================================ FILE CONTENTS ================================================ ================================================ FILE: .cirrus.yml ================================================ env: CIRRUS_CLONE_DEPTH: 1 linux_x64_task: container: cpu: 2 memory: 2G image: gcc:15.2.0 install_script: - apt-get update -qq - apt-get install -qq liblzo2-dev libssl-dev libc6-dev cmake build_script: - ./build.sh darwin_aarch64_task: macos_instance: image: ghcr.io/cirruslabs/macos-ventura-base:latest install_script: - brew install openssl@3 lzo - brew reinstall openssl@3 build_script: - ./build.sh ================================================ FILE: .editorconfig ================================================ root = true [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true ================================================ FILE: .gitattributes ================================================ # auto-detect text files; use LF * text=auto eol=lf # text extensions *.txt text *.md text *.c text *.h text *.cpp text *.yml text *.cmake text # important that these use LF *.sh text eol=lf *.py text eol=lf # specific text filenames .gitattributes text .gitignore text .editorconfig text AUTHORS text COPYING text ================================================ FILE: .github/workflows/build.yml ================================================ name: SonarQube on: push: branches: - master - develop pull_request: types: [opened, synchronize, reopened] jobs: build: name: Build and analyze runs-on: ubuntu-latest env: BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Install Dependencies run: | sudo apt-get install -y git build-essential cmake liblzo2-dev libssl-dev libc6-dev - name: Install Build Wrapper uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5 - name: Run Build Wrapper run: | build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} ./build.sh - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@v5 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: > --define sonar.cfamily.compile-commands="${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json" ================================================ FILE: .gitignore ================================================ ### CMake ### CMakeCache.txt CMakeFiles Makefile cmake_install.cmake install_manifest.txt ### C ### # Object files *.o # Libraries *.a *.la # Executables *.exe *.out ### Epk2Extract ### # build build_linux build_cygwin build_osx # Linux build artifacts src/epk2extract src/tools/idb_extract src/tools/jffs2extract src/tools/lzhs_scanner src/tools/lzhsenc ================================================ FILE: .sonarcloud_gen.sh ================================================ #!/bin/sh csv_prop(){ echo -ne "$1=" cat | paste -sd, } gen(){ cat <<-EOF ## THIS FILE IS AUTOGENERATED ## edit .sonarcloud_gen.sh instead sonar.projectKey=openlgtv_epk2extract sonar.organization=openlgtv EOF (cat <<-EOF r1 EOF ) | csv_prop "sonar.issue.ignore.multicriteria" echo "" cat <<-EOF # format string is not a string literal sonar.issue.ignore.multicriteria.r1.ruleKey=c:S5281 sonar.issue.ignore.multicriteria.r1.resourceKey=** EOF echo "" (cat <<-EOF src/*.c src/lzhs/*.c src/stream/*.c src/tools/*.c include/*.h include/lzhs/*.h include/realtek/*.h include/stream/*.h EOF ) | csv_prop "sonar.inclusions" } cd "$(dirname "$(readlink -f "$0")")" gen > sonar-project.properties ================================================ FILE: AUTHORS ================================================ This project is covered by the GPL licence. See COPYING for details. epk2extract contributors list: - Arno1 - cronix - jenya - lprot - rtokarev (sym handling) - Smx (smxdev4@gmail.com, current maintainer) - sirius (original author of epk2extract) - tbage - xeros Special thanks to: - All the testers - Authors of the original compression algorithms and libraries ================================================ FILE: CMakeLists.txt ================================================ set(CMAKE_LEGACY_CYGWIN_WIN32 0) cmake_minimum_required(VERSION 3.13) project(epk2extract) if( NOT CMAKE_BUILD_TYPE ) set(CMAKE_BUILD_TYPE Debug) endif() set(CMAKE_CXX_FLAGS_TEST "-Ofast") set(CMAKE_C_FLAGS_TEST "-Ofast -funroll-loops -fprefetch-loop-arrays -march=native") set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 11) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake-modules/") find_package(OpenSSL REQUIRED) find_package(LZO REQUIRED) find_package(Threads REQUIRED) find_package(ZLIB REQUIRED) find_library(M_LIB m REQUIRED) add_subdirectory(src) ================================================ FILE: COPYING ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. ================================================ FILE: README.md ================================================ [![Build Status](https://travis-ci.org/openlgtv/epk2extract.svg?branch=master)](https://travis-ci.org/openlgtv/epk2extract) epk2extract =========== [![Join the chat at https://gitter.im/openlgtv/epk2extract](https://badges.gitter.im/openlgtv/epk2extract.svg)](https://gitter.im/openlgtv/epk2extract?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Join on Discord: https://discord.gg/xWqRVEm epk2extract is a tool that can extract, decrypt, convert multiple file formats that can be found in LG TV sets and similar devices. Supported Formats: =========================================== **NOTE: To unpack epk v2 and v3 you need proper AES and RSA keys for decryption. To get them you will need to dump them from a running TV.** **NOTE: To decrypt PVR recordings you need a dump of the unique AES-128 key from your TV** | Format | Notes | :----- | :----- | epk v1 | First version of epk format, not encrypted and not signed | epk v2 | Introduces signing and encryption, keys needed | epk v3 | Introduced with WebOS. Keys needed | Mediatek pkg | UPG/PKG files used by Hisense/Sharp/Philips (missing Philips AES key) and possibly others | Philips "fusion" | Upgrade files used by some Philips TVs | squashfs | | cramfs | | lz4 | Slightly modified version with header magic | lzo | | gzip | | jffs2 | | lzhs | Special compression for MTK bootloaders (boot.pak, tzfw.pak), uses lzss + huffman | lzhs_fs | LZHS compressed filesystem used in MTK Upgrade files for the external writable partition (3rdw) | mtdinfo/partinfo | LG Partition table format (mtdi.pak, part.pak) | str/pif | PVR recording format that can be found in netcast models | sym | LG Debugging symbols. Can extract function names and addresses to an IDA script file (idc) Although epk2extract is only tested on LG firmware files, you may use it to extract other files like a general unpack tool, as long as they are supported according to the table above. **!!WARNING!!**
**epk2extract isn't designed to repack files**
**If you wish to repack modified files, follow the openlgtv wiki/forum, and do it in a Linux environment (no cygwin)**
**Don't repack files extracted in cygwin environment**
**In any case, you do so at your own risk**
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE* | Tools: | Description | :---- | :---- | lzhsenc | Compresses a given file with lzhs algorithm | lzhs_scanner | Scans a given file to find lzhs files, and extracts them | idb_extract | Extracts Image Database (IDB) files that can be found in LG firmwares | jffs2extract | Extracts JFFS2 images. Supports various compression algorithms To compile on Linux: =========================================== ### Install build dependencies: Ubuntu/Debian: ```shell apt-get install git build-essential cmake liblzo2-dev libssl-dev libc6-dev zlib1g-dev ``` Mandriva/Mageia: ```shell urpmi git task-c++-devel cmake liblzo-devel libopenssl-devel glibc-devel --auto ``` ### Build it ```shell ./build.sh ``` After building, epk2extract can be found in ./build_\/ To compile on Cygwin: ===================== ### Install Cygwin and during setup select following packages: Devel -> gcc-g++, git, cmake, make Libs -> liblzo2-devel, zlib-devel Net -> openssl-devel Utils -> ncurses ### Build it ```shell ./build.sh ``` The build script automatically copies required shared libraries to the ./build_cygwin/ folder, so you can use epk2extract standalone/portable without a full cygwin installation. ===================== ### How to speed up extraction process You can build the test build, which contains compiler optimizations, with this command ```shell CMAKE_FLAGS=-DCMAKE_BUILD_TYPE=Test ./build.sh ``` The Test build is orders of magnitude faster than the Debug build ### To use: Put *.pem and AES.key files in the same directory as the epk2extract binary. Run it via sudo/fakeroot to avoid warnings (while extracting device nodes from rootfs): fakeroot ./epk2extract file ## To get IDC from SYM run: ./epk2extract xxxxxxxx.sym ## To decode part.pak or mtdi.pak do: ./epk2extract part.pak Or use partinfo.py (**deprected**) python partinfo.py part.pak ================================================ FILE: build.sh ================================================ #!/bin/bash #epk2extract build script #Copyright 2016 Smx #All right reserved normal='tput sgr0' lred='printf \033[01;31m' lgreen='printf \033[01;32m' lyellow='printf \033[01;33m' lblue='printf \033[01;34m' white='printf \033[01;37m' cwd=$(pwd) srcdir=`cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd` exe=( "epk2extract" "tools/lzhsenc" "tools/lzhs_scanner" "tools/idb_extract" "tools/jffs2extract" "tools/tsfile" ) nproc_cmd="nproc" if [ "$OSTYPE" == "cygwin" ]; then rel=build_cygwin elif [[ "$OSTYPE" =~ "linux" ]]; then rel=build_linux elif [[ "$OSTYPE" =~ "darwin" ]]; then nproc_cmd="sysctl -n hw.logicalcpu" rel=build_osx CMAKE_FLAGS="-DOPENSSL_ROOT_DIR=$(brew --prefix)/opt/openssl ${CMAKE_FLAGS}" else $lred; "Can't build - unknown OS type. Aborting..."; $normal exit 1 fi installdir=$srcdir/$rel objdir=$installdir/obj cd $srcdir if [ "$1" == "clean" ]; then $lyellow; echo "Removing cmake cache and make files"; $normal rm -r $objdir if [ -d "$installdir" ]; then $lyellow; echo "Removing build dir"; $normal rm -r "$installdir" fi $lgreen; echo "Done!"; $normal exit 0 fi $lyellow; echo "Building epk2extract"; $normal if [ ! -e "$rel/obj" ]; then mkdir -p $objdir fi cd $objdir NUM_THREADS=$($nproc_cmd) case "$1" in "-v") MAKE_FLAGS="${MAKE_ARGS} VERBOSE=1 -j${NUM_THREADS}" ;; esac cmake $srcdir $CMAKE_FLAGS make $MAKE_FLAGS RESULT=$? cd src if [ ! $RESULT -eq 0 ]; then $lred; echo "Build Failed!"; $normal exit 1 fi if [ "$rel" == "build_cygwin" ]; then for exe in ${exe[@]}; do cp $exe.exe $installdir/ done if [ "$HOSTTYPE" == "i686" ]; then #cygwin32 sharedlibs=("cygz.dll" "cygwin1.dll" "cyglzo2-2.dll" "cyggcc_s-1.dll" "cygcrypto-1.1.dll" "cygstdc++-6.dll") elif [ "$HOSTTYPE" == "x86_64" ]; then #cygwin64 sharedlibs=("cygz.dll" "cygwin1.dll" "cyglzo2-2.dll" "cygcrypto-1.1.dll" "cyggcc_s-seh-1.dll" "cygstdc++-6.dll") fi for cyglib in ${sharedlibs[@]}; do $white; echo "Installing $cyglib"; $normal islibok=$(which "$cyglib" &>/dev/null; echo $?) if [ $islibok == 0 ]; then cp `which $cyglib` $installdir/ else $lred echo "Something wrong! $cyglib not found." echo "Verify your cygwin installation and try again." $normal exit 1 fi done else for exe in ${exe[@]}; do cp $exe $installdir/ done fi if [ -d "$srcdir/keys" ]; then for key in $(find ${srcdir}/keys -iname "*.pem" -or -iname "*.key" | sort); do $lblue; echo "Installing $(basename $key)"; $normal cp $key $installdir/ done fi $lgreen; echo "Build completed!"; $normal exit 0 ================================================ FILE: cmake-modules/FindLZO.cmake ================================================ # Find liblzo2 # LZO_FOUND - system has the LZO library # LZO_INCLUDE_DIR - the LZO include directory # LZO_LIBRARIES - The libraries needed to use LZO if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) # in cache already SET(LZO_FOUND TRUE) else (LZO_INCLUDE_DIR AND LZO_LIBRARIES) FIND_PATH(LZO_INCLUDE_DIR lzo/lzo1x.h ${LZO_ROOT}/include/ /usr/include/ /usr/local/include/ /sw/lib/ /sw/local/lib/ ) if(WIN32 AND MSVC) else(WIN32 AND MSVC) FIND_LIBRARY(LZO_LIBRARIES NAMES lzo2 PATHS ${LZO_ROOT}/lib /usr/lib /usr/local/lib /sw/lib /sw/local/lib ) endif(WIN32 AND MSVC) if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) set(LZO_FOUND TRUE) endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) if (LZO_FOUND) if (NOT LZO_FIND_QUIETLY) message(STATUS "Found LZO: ${LZO_LIBRARIES}") endif (NOT LZO_FIND_QUIETLY) else (LZO_FOUND) if (LZO_FIND_REQUIRED) message(FATAL_ERROR "Could NOT find LZO") endif (LZO_FIND_REQUIRED) endif (LZO_FOUND) MARK_AS_ADVANCED(LZO_INCLUDE_DIR LZO_LIBRARIES) endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) ================================================ FILE: code_format.sh ================================================ #!/bin/bash function my_indent() { file="$1" indent \ --linux-style \ --use-tabs \ --tab-size4 \ --indent-level4 \ --preprocessor-indentation4 \ --else-endif-column0 \ --braces-on-if-line \ --braces-on-func-def-line \ --braces-on-struct-decl-line \ --line-length0 \ "$file" } if [ -z "$1" ]; then dirs="src include" elif [ -d "$1" ]; then dirs="$1" elif [ -f "$1" ]; then echo "Reindenting ${1}..." my_indent "$1" exit 0 fi for file in `find src include -type f -name "*.c" -or -name "*.cpp" -or -name "*.h"`; do echo "Reindenting ${file}..." my_indent "$file" done exit 0 ================================================ FILE: include/common.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __COMMON_H #define __COMMON_H /* Branch Prediction Hints */ #ifdef __GNUC__ #define LIKELY(x) __builtin_expect (!!(x), 1) #define UNLIKELY(x) __builtin_expect (!!(x), 0) #else #define LIKELY(x) (x) #define UNLIKELY(x) (x) #endif #ifdef __GNUC__ #define UNUSED(x) UNUSED_ ## x __attribute__((__unused__)) #else #define UNUSED(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define UNUSED_FUNCTION(x) __attribute__((__unused__)) UNUSED_ ## x #else #define UNUSED_FUNCTION(x) UNUSED_ ## x #endif #ifdef __GNUC__ #define FORMAT_PRINTF(x, y) __attribute__((__format__(__printf__, (x), (y)))) #else #define FORMAT_PRINTF(x, y) #endif #define countof(x) (sizeof(x) / sizeof((x)[0])) #endif ================================================ FILE: include/config.h ================================================ /** * Copyright 20xx sirius * All right reserved */ #ifndef CONFIG_H_ # define CONFIG_H_ #include typedef struct { char *config_dir; char *dest_dir; int enableSignatureChecking; bool noAutoUnsquashfs; bool signatureOnly; } config_opts_t; extern config_opts_t config_opts; # define G_DIR_SEPARATOR_S "/" # if defined(__APPLE__) # include # elif defined(__CYGWIN__) # include # else # include # endif # ifndef PATH_MAX # define PATH_MAX 4096 /* # chars in a path name including nul */ # endif #endif /* CONFIG_H_ */ ================================================ FILE: include/cramfs/cramfs.h ================================================ #ifndef __CRAMFS_H #define __CRAMFS_H #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ #define CRAMFS_SIGNATURE "Compressed ROMFS" // Needed by cramfs typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; /* * Reasonably terse representation of the inode data. */ struct cramfs_inode { u32 mode:16, uid:16; /* SIZE for device files is i_rdev */ u32 size:24, gid:8; /* NAMELEN is the length of the file name, divided by 4 and rounded up. (cramfs doesn't support hard links.) */ /* OFFSET: For symlinks and non-empty regular files, this contains the offset (divided by 4) of the file data in compressed form (starting with an array of block pointers; see README). For non-empty directories it is the offset (divided by 4) of the inode of the first file in that directory. For anything else, offset is zero. */ u32 namelen:6, offset:26; }; /* * Superblock information at the beginning of the FS. */ struct cramfs_super { u32 magic; /* 0x28cd3d45 - random number */ u32 size; /* Not used. mkcramfs currently writes a constant 1<<16 here. */ u32 flags; /* 0 */ u32 future; /* 0 */ u8 signature[16]; /* "Compressed ROMFS" */ u8 fsid[16]; /* random number */ u8 name[16]; /* user-defined name */ struct cramfs_inode root; /* Root inode data */ }; /* * Valid values in super.flags. Currently we refuse to mount * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be * changed to test super.future instead. */ #define CRAMFS_SUPPORTED_FLAGS (0xff) /* Uncompression interfaces to the underlying zlib */ int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen); int cramfs_uncompress_init(void); int cramfs_uncompress_exit(void); int is_cramfs_image(char const *imagefile, char *endian); int uncramfs(char const *dirname, char const *imagefile); #endif ================================================ FILE: include/cramfs/cramfs_fs.h ================================================ #ifndef __CRAMFS_FS_H # define __CRAMFS_FS_H # include # define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ // Needed by cramfs typedef unsigned char u8; typedef unsigned short u16; typedef unsigned int u32; /* * Width of various bitfields in struct cramfs_inode. * Primarily used to generate warnings in mkcramfs. */ # define CRAMFS_MODE_WIDTH 16 # define CRAMFS_UID_WIDTH 16 # define CRAMFS_SIZE_WIDTH 24 # define CRAMFS_GID_WIDTH 8 # define CRAMFS_NAMELEN_WIDTH 6 # define CRAMFS_OFFSET_WIDTH 26 /* * Since inode.namelen is a unsigned 6-bit number, the maximum cramfs * path length is 63 << 2 = 252. */ # define CRAMFS_MAXPATHLEN (((1 << CRAMFS_NAMELEN_WIDTH) - 1) << 2) /* * Reasonably terse representation of the inode data. */ struct cramfs_inode { u32 mode:CRAMFS_MODE_WIDTH, uid:CRAMFS_UID_WIDTH; /* SIZE for device files is i_rdev */ u32 size:CRAMFS_SIZE_WIDTH, gid:CRAMFS_GID_WIDTH; /* NAMELEN is the length of the file name, divided by 4 and rounded up. (cramfs doesn't support hard links.) */ /* OFFSET: For symlinks and non-empty regular files, this contains the offset (divided by 4) of the file data in compressed form (starting with an array of block pointers; see README). For non-empty directories it is the offset (divided by 4) of the inode of the first file in that directory. For anything else, offset is zero. */ u32 namelen:CRAMFS_NAMELEN_WIDTH, offset:CRAMFS_OFFSET_WIDTH; }; struct cramfs_info { u32 crc; u32 edition; u32 blocks; u32 files; }; /* * Superblock information at the beginning of the FS. */ struct cramfs_super { u32 magic; /* 0x28cd3d45 - random number */ u32 size; /* length in bytes */ u32 flags; /* feature flags */ u32 future; /* reserved for future use */ u8 signature[16]; /* "Compressed ROMFS" */ struct cramfs_info fsid; /* unique filesystem info */ u8 name[16]; /* user-defined name */ struct cramfs_inode root; /* root inode data */ }; /* * Feature flags * * 0x00000000 - 0x000000ff: features that work for all past kernels * 0x00000100 - 0xffffffff: features that don't work for past kernels */ # define CRAMFS_FLAG_FSID_VERSION_2 0x00000001 /* fsid version #2 */ # define CRAMFS_FLAG_SORTED_DIRS 0x00000002 /* sorted dirs */ # define CRAMFS_FLAG_HOLES 0x00000100 /* support for holes */ # define CRAMFS_FLAG_WRONG_SIGNATURE 0x00000200 /* reserved */ # define CRAMFS_FLAG_SHIFTED_ROOT_OFFSET 0x00000400 /* shifted root fs */ /* * Valid values in super.flags. Currently we refuse to mount * if (flags & ~CRAMFS_SUPPORTED_FLAGS). Maybe that should be * changed to test super.future instead. */ # define CRAMFS_SUPPORTED_FLAGS ( 0x000000ff \ | CRAMFS_FLAG_HOLES \ | CRAMFS_FLAG_WRONG_SIGNATURE \ | CRAMFS_FLAG_SHIFTED_ROOT_OFFSET ) #endif /* __CRAMFS_FS_H */ ================================================ FILE: include/cramfs/cramfsswap.h ================================================ #ifndef __CRAMFSSWAP_H #define __CRAMFSSWAP_H int cramswap(char *sinfile, char *soutfile); #endif //__CRAMFSSWAP_H ================================================ FILE: include/crc.h ================================================ /* ** CRC.H - header file for SNIPPETS CRC and checksum functions */ #ifndef CRC__H # define CRC__H # include /* For size_t */ # include "sniptype.h" /* For BYTE, WORD, DWORD */ /* ** File: ARCCRC16.C */ void init_crc_table(void); WORD crc_calc(WORD crc, char *buf, unsigned nbytes); void do_file(char *fn); /* ** File: CRC-16.C */ WORD crc16(char *data_p, WORD length); /* ** File: CRC-16F.C */ WORD updcrc(WORD icrc, BYTE * icp, size_t icnt); /* ** File: CRC_32.C */ # define UPDC32(octet,crc) (crc_32_tab[((crc)\ ^ ((BYTE)octet)) & 0xff] ^ ((crc) >> 8)) DWORD updateCRC32(unsigned char ch, DWORD crc); Boolean_T crc32file(char *name, DWORD * crc, long *charcnt); DWORD crc32buf(char *buf, size_t len); /* ** File: CHECKSUM.C */ unsigned checksum(void *buffer, size_t len, unsigned int seed); /* ** File: CHECKEXE.C */ void checkexe(char *fname); #endif /* CRC__H */ ================================================ FILE: include/epk.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __EPK_H #define __EPK_H #include #include #include #define SIGNATURE_SIZE 0x80 //RSA-1024 #define SIGNATURE_SIZE_NEW 0x100 //RSA-2048 typedef unsigned char signature_t[SIGNATURE_SIZE]; typedef unsigned char signature_new_t[SIGNATURE_SIZE_NEW]; typedef enum { RELEASE = 0, DEBUG, TEST, UNKNOWN, } BUILD_TYPE_T; typedef enum { EPK, EPK_V2, EPK_V3, EPK_V3_NEW, PAK_V2, RAW } FILE_TYPE_T; typedef enum { SIG_SHA1, SIG_SHA256 } SIG_TYPE_T; #define EPK_VERSION_FORMAT "%02" PRIx8 ".%02" PRIx8 ".%02" PRIx8 ".%02" PRIx8 #define EPKV1_VERSION_FORMAT "%02" PRIx8 ".%02" PRIx8 ".%02" PRIx8 bool isEpkVersionString(const char *str); int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_dir, SIG_TYPE_T sigType); int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType); void extractEPKfile(const char *epk_file, config_opts_t *config_opts); #endif ================================================ FILE: include/epk1.h ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * Copyright 20?? sirius * All right reserved */ #ifndef EPK1_H_ # define EPK1_H_ # include # include # include # include # include # include struct pakRec_t { uint32_t offset; uint32_t size; }; struct epk1BEHeader_t { unsigned char epakMagic[4]; uint32_t fileSize; uint32_t pakCount; uint32_t offset; uint32_t size; }; struct epk1BEVersion_t { uint8_t pad; uint8_t major; uint8_t minor1; uint8_t minor2; }; struct epk1Header_t { unsigned char epakMagic[4]; uint32_t fileSize; uint32_t pakCount; struct pakRec_t pakRecs[20]; unsigned char fwVer[4]; unsigned char otaID[32]; }; struct epk1NewHeader_t { unsigned char epakMagic[4]; uint32_t fileSize; uint32_t pakCount; unsigned char fwVer[4]; unsigned char otaID[32]; struct pakRec_t pakRecs[26]; }; struct pakHeader_t { unsigned char pakName[4]; uint32_t pakSize; unsigned char platform[15]; unsigned char unknown[105]; }; void extract_epk1_file(const char *epk_file, config_opts_t *config_opts); bool isFileEPK1(const char *epk_file); #endif /* EPK1_H_ */ ================================================ FILE: include/epk2.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef _EPK2_H_ #define _EPK2_H_ #include #include "mfile.h" #include "epk.h" #define EPK2_MAGIC "EPK2" #define PAK_MAGIC "MPAK" int compare_pak2_header(uint8_t *header, size_t headerSize); int compare_epk2_header(uint8_t *header, size_t headerSize); MFILE *isFileEPK2(const char *epk_file); void extractEPK2(MFILE *epk, config_opts_t *config_opts); typedef struct { char imageType[4]; uint32_t imageSize; //excluded headers and signatures char modelName[64]; uint32_t swVersion; uint32_t swDate; BUILD_TYPE_T devMode; uint32_t segmentCount; uint32_t segmentSize; uint32_t segmentIndex; char pakMagic[4]; unsigned char reserved[24]; uint32_t segmentCrc32; } PAK_V2_HEADER_T; typedef struct { uint32_t imageOffset; uint32_t imageSize; //containing headers (excluded signatures) char imageType[4]; uint32_t imageVersion; uint32_t segmentSize; } PAK_V2_LOCATION_T; /** * NOTE: the number of partitions is hardcoded in the structure * 16 - GP2 * 32 - (not sure if some sets use 32) * 64 - NC4 **/ typedef struct { char fileType[4]; uint32_t fileSize; uint32_t fileNum; char epkMagic[4]; uint8_t epakVersion[4]; char otaId[32]; PAK_V2_LOCATION_T imageLocation[64]; } EPK_V2_HEADER_T; struct epk2_structure { signature_t signature; EPK_V2_HEADER_T epkHeader; uint32_t crc32Info[64]; uint32_t reserved; char platformVersion[16]; char sdkVersion[16]; }; struct pak2_structure { signature_t signature; PAK_V2_HEADER_T pakHeader; unsigned char pData[]; }; #endif ================================================ FILE: include/epk3.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __EPK3_H #define __EPK3_H #include "mfile.h" #include "epk.h" #define EPK3_MAGIC "EPK3" int compare_epk3_header(uint8_t *header, size_t headerSize); int compare_epk3_new_header(uint8_t *header, size_t headerSize); MFILE *isFileEPK3(const char *epk_file); void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts); typedef struct __attribute__((packed)) { char epkMagic[4]; uint8_t epkVersion[4]; char otaId[32]; uint32_t packageInfoSize; uint32_t bChunked; } EPK_V3_HEADER_T; typedef struct __attribute__((packed)) { char epkMagic[4]; char epkVersion[4]; char otaId[32]; uint32_t packageInfoSize; uint32_t bChunked; uint32_t pakInfoMagic; uint8_t encryptType[6]; uint8_t updateType[3]; uint8_t gap[3]; float updatePlatformVersion; float compatibleMinimumVersion; int needToCheckCompatibleVersion; uint8_t reserved[1384]; } EPK_V3_NEW_HEADER_T; typedef union __attribute__((packed)) { EPK_V3_HEADER_T old; EPK_V3_NEW_HEADER_T new; } EPK_V3_HEADER_UNION; typedef struct __attribute__((packed)) { // SegmentInfo uint32_t isSegmented; uint32_t segmentIndex; uint32_t segmentCount; uint32_t segmentSize; } PACKAGE_SEGMENT_INFO_T; typedef struct __attribute__((packed)) { // PackageData //void * pData; uint32_t reserved; } PACKAGE_INFO_DATA_T; typedef struct __attribute__((packed)) { // PackageInfo uint32_t packageType; uint32_t packageInfoSize; char packageName[128]; char packageVersion[96]; char packageArchitecture[32]; unsigned char checkSum[32]; uint32_t packageSize; uint32_t dipk; PACKAGE_SEGMENT_INFO_T segmentInfo; PACKAGE_INFO_DATA_T infoData; } PAK_V3_HEADER_T; typedef struct __attribute__((packed)) { // ListHeader uint32_t packageInfoListSize; uint32_t packageInfoCount; PAK_V3_HEADER_T packages[]; } PAK_V3_LISTHEADER_T; typedef struct __attribute__((packed)) { uint32_t packageInfoListSize; uint32_t packageInfoCount; uint32_t pakInfoMagic; PAK_V3_HEADER_T packages[]; } PAK_V3_NEW_LISTHEADER_T; typedef union __attribute__((packed)) { PAK_V3_LISTHEADER_T old; PAK_V3_NEW_LISTHEADER_T new; } PAK_V3_LISTHEADER_UNION; struct __attribute__((packed)) epk3_head_structure { signature_t signature; EPK_V3_HEADER_T epkHeader; uint32_t crc32Info[384]; uint32_t reserved; //or unknown char platformVersion[16]; char sdkVersion[16]; }; struct __attribute__((packed)) epk3_new_head_structure { signature_new_t signature; EPK_V3_NEW_HEADER_T epkHeader; char platformVersion[16]; char sdkVersion[16]; }; struct __attribute__((packed)) epk3_structure { struct epk3_head_structure head; signature_t packageInfo_signature; PAK_V3_LISTHEADER_T packageInfo; }; struct __attribute__((packed)) epk3_new_structure { struct epk3_new_head_structure head; signature_new_t packageInfo_signature; PAK_V3_NEW_LISTHEADER_T packageInfo; }; typedef union __attribute__((packed)) { struct epk3_structure old; struct epk3_new_structure new; } epk3_union; struct __attribute__((packed)) pak3_structure { signature_t signature; PAK_V3_HEADER_T header; }; #endif ================================================ FILE: include/jffs2/jffs2.h ================================================ /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright © 2001-2007 Red Hat, Inc. * Copyright © 2004-2010 David Woodhouse * * Created by David Woodhouse * * For licensing information, see the file 'LICENCE' in the * jffs2 directory. */ #ifndef __LINUX_JFFS2_H__ #define __LINUX_JFFS2_H__ #ifdef __APPLE__ typedef __signed__ char __s8; typedef unsigned char __u8; typedef __signed__ short __s16; typedef unsigned short __u16; typedef __signed__ int __s32; typedef unsigned int __u32; #ifdef __GNUC__ __extension__ typedef __signed__ long long __s64; __extension__ typedef unsigned long long __u64; #else typedef __signed__ long long __s64; typedef unsigned long long __u64; #endif #else #include #endif /* Values we may expect to find in the 'magic' field */ #define JFFS2_OLD_MAGIC_BITMASK 0x1984 #define JFFS2_MAGIC_BITMASK 0x1985 #define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000 /* Summary node MAGIC marker */ #define JFFS2_SUM_MAGIC 0x02851885 /* We only allow a single char for length, and 0xFF is empty flash so we don't want it confused with a real length. Hence max 254. */ #define JFFS2_MAX_NAME_LEN 254 /* How small can we sensibly write nodes? */ #define JFFS2_MIN_DATA_LEN 128 #define JFFS2_COMPR_NONE 0x00 #define JFFS2_COMPR_ZERO 0x01 #define JFFS2_COMPR_RTIME 0x02 #define JFFS2_COMPR_RUBINMIPS 0x03 #define JFFS2_COMPR_COPY 0x04 #define JFFS2_COMPR_DYNRUBIN 0x05 #define JFFS2_COMPR_ZLIB 0x06 #define JFFS2_COMPR_LZO 0x07 #define JFFS2_COMPR_LZMA 0x08 /* Compatibility flags. */ #define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ #define JFFS2_NODE_ACCURATE 0x2000 /* INCOMPAT: Fail to mount the filesystem */ #define JFFS2_FEATURE_INCOMPAT 0xc000 /* ROCOMPAT: Mount read-only */ #define JFFS2_FEATURE_ROCOMPAT 0x8000 /* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ #define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 /* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ #define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) #define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) #define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) #define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) #define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) /* XATTR Related */ #define JFFS2_XPREFIX_USER 1 /* for "user." */ #define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ #define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ #define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ #define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ #define JFFS2_ACL_VERSION 0x0001 // Maybe later... //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at mount time, don't wait for it to happen later */ #define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific compression type */ struct jffs2_unknown_node { /* All start like this */ __u16 magic; __u16 nodetype; __u32 totlen; /* So we can skip over nodes we don't grok */ __u32 hdr_crc; }; struct jffs2_raw_dirent { __u16 magic; __u16 nodetype; /* == JFFS2_NODETYPE_DIRENT */ __u32 totlen; __u32 hdr_crc; __u32 pino; __u32 version; __u32 ino; /* == zero for unlink */ __u32 mctime; __u8 nsize; __u8 type; __u8 unused[2]; __u32 node_crc; __u32 name_crc; __u8 name[0]; }; /* The JFFS2 raw inode structure: Used for storage on physical media. */ /* The uid, gid, atime, mtime and ctime members could be longer, but are left like this for space efficiency. If and when people decide they really need them extended, it's simple enough to add support for a new type of raw node. */ struct jffs2_raw_inode { __u16 magic; /* A constant magic number. */ __u16 nodetype; /* == JFFS2_NODETYPE_INODE */ __u32 totlen; /* Total length of this node (inc data, etc.) */ __u32 hdr_crc; __u32 ino; /* Inode number. */ __u32 version; /* Version number. */ __u32 mode; /* The file's type or mode. */ __u16 uid; /* The file's owner. */ __u16 gid; /* The file's group. */ __u32 isize; /* Total resultant size of this inode (used for truncations) */ __u32 atime; /* Last access time. */ __u32 mtime; /* Last modification time. */ __u32 ctime; /* Change time. */ __u32 offset; /* Where to begin to write. */ __u32 csize; /* (Compressed) data size */ __u32 dsize; /* Size of the node's data. (after decompression) */ __u8 compr; /* Compression algorithm used */ __u8 usercompr; /* Compression algorithm requested by the user */ __u16 flags; /* See JFFS2_INO_FLAG_* */ __u32 data_crc; /* CRC for the (compressed) data. */ __u32 node_crc; /* CRC for the raw inode (excluding data) */ __u8 data[0]; }; struct jffs2_raw_xattr { __u16 magic; __u16 nodetype; /* = JFFS2_NODETYPE_XATTR */ __u32 totlen; __u32 hdr_crc; __u32 xid; /* XATTR identifier number */ __u32 version; __u8 xprefix; __u8 name_len; __u16 value_len; __u32 data_crc; __u32 node_crc; __u8 data[0]; } __attribute__((packed)); struct jffs2_raw_xref { __u16 magic; __u16 nodetype; /* = JFFS2_NODETYPE_XREF */ __u32 totlen; __u32 hdr_crc; __u32 ino; /* inode number */ __u32 xid; /* XATTR identifier number */ __u32 xseqno; /* xref sequential number */ __u32 node_crc; } __attribute__((packed)); struct jffs2_raw_summary { __u16 magic; __u16 nodetype; /* = JFFS2_NODETYPE_SUMMARY */ __u32 totlen; __u32 hdr_crc; __u32 sum_num; /* number of sum entries*/ __u32 cln_mkr; /* clean marker size, 0 = no cleanmarker */ __u32 padded; /* sum of the size of padding nodes */ __u32 sum_crc; /* summary information crc */ __u32 node_crc; /* node crc */ __u32 sum[0]; /* inode summary info */ }; union jffs2_node_union { struct jffs2_raw_inode i; struct jffs2_raw_dirent d; struct jffs2_raw_xattr x; struct jffs2_raw_xref r; struct jffs2_raw_summary s; struct jffs2_unknown_node u; }; /* Data payload for device nodes. */ union jffs2_device_node { __u16 old_id; __u32 new_id; }; #ifdef __cplusplus extern "C" { #endif #include struct jffs2_main_args { int erase_size; int verbose; bool keep_unlinked; }; int jffs2extract(char *infile, char *outdir, struct jffs2_main_args); #ifdef __cplusplus } #endif #endif /* __LINUX_JFFS2_H__ */ ================================================ FILE: include/jffs2/mini_inflate.h ================================================ /*------------------------------------------------------------------------- * Filename: mini_inflate.h * Version: $Id: mini_inflate.h,v 1.2 2002/01/17 00:53:20 nyet Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill * Description: Mini deflate implementation *-----------------------------------------------------------------------*/ /* * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ typedef __SIZE_TYPE__ size; #define NO_ERROR 0 #define COMP_UNKNOWN 1 /* The specififed bytype is invalid */ #define CODE_NOT_FOUND 2 /* a huffman code in the stream could not be decoded */ #define TOO_MANY_BITS 3 /* pull_bits was passed an argument that is too * large */ /* This struct represents an entire huffman code set. It has various lookup * tables to speed decoding */ struct huffman_set { int bits; /* maximum bit length */ int num_symbols; /* Number of symbols this code can represent */ int *lengths; /* The bit length of symbols */ int *symbols; /* All of the symbols, sorted by the huffman code */ int *count; /* the number of codes of this bit length */ int *first; /* the first code of this bit length */ int *pos; /* the symbol that first represents (in the symbols * array) */ }; struct bitstream { unsigned char *data; /* increments as we move from byte to byte */ unsigned char bit; /* 0 to 7 */ void *(*memcpy) (void *, const void *, size); unsigned long decoded; /* The number of bytes decoded */ int error; int distance_count[16]; int distance_first[16]; int distance_pos[16]; int distance_lengths[32]; int distance_symbols[32]; int code_count[8]; int code_first[8]; int code_pos[8]; int code_lengths[19]; int code_symbols[19]; int length_count[16]; int length_first[16]; int length_pos[16]; int length_lengths[288]; int length_symbols[288]; struct huffman_set codes; struct huffman_set lengths; struct huffman_set distance; }; #define NO_COMP 0 #define FIXED_COMP 1 #define DYNAMIC_COMP 2 long decompress_block(unsigned char *dest, unsigned char *source, void *(*inflate_memcpy) (void *dest, const void *src, size n)); ================================================ FILE: include/log.h ================================================ #ifndef _LOG_H_ # define _LOG_H_ /* * Copyright (c) 2011 Roman Tokarev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # define error_level 0 # define info_level 1 # define debug_level 2 # define say_error(format, args...) say(error_level, "error: "format, ##args) # define say_info(format, args...) say(info_level, "info: "format, ##args) # define say_debug(format, args...) say(debug_level, "debug: "format, ##args) extern unsigned verbose; int create_log(const char *fname); void say(unsigned level, const char *format, ...); #endif ================================================ FILE: include/lz4/bench.h ================================================ /* bench.h - Demo program to benchmark open-source compression algorithm Copyright (C) Yann Collet 2012 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ #pragma once #if defined (__cplusplus) extern "C" { #endif int BMK_benchFile(char **fileNamesTable, int nbFiles, int cLevel); // Parameters void BMK_SetBlocksize(int bsize); void BMK_SetNbIterations(int nbLoops); #if defined (__cplusplus) } #endif ================================================ FILE: include/lz4/lz4.h ================================================ /* LZ4 - Fast LZ compression algorithm Header File Copyright (C) 2011-2012, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ #pragma once #if defined (__cplusplus) extern "C" { #endif //**************************** // Simple Functions //**************************** int LZ4_compress(const char *source, char *dest, int isize); int LZ4_uncompress(const char *source, char *dest, int osize); int LZ4_decode_file(const char *input_filename, const char *output_filename); /* LZ4_compress() : isize : is the input size. Max supported value is ~1.9GB return : the number of bytes written in buffer dest or 0 if the compression fails (if LZ4_COMPRESSMIN is set) note : destination buffer must be already allocated. destination buffer must be sized to handle worst cases situations (input data not compressible) worst case size evaluation is provided by function LZ4_compressBound() LZ4_uncompress() : osize : is the output size, therefore the original size return : the number of bytes read in the source buffer If the source stream is malformed, the function will stop decoding and return a negative result, indicating the byte position of the faulty instruction This function never writes beyond dest + osize, and is therefore protected against malicious data packets note : destination buffer must be already allocated */ //**************************** // Advanced Functions //**************************** int LZ4_compressBound(int isize); /* LZ4_compressBound() : Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible) primarily useful for memory allocation of output buffer. isize : is the input size. Max supported value is ~1.9GB return : maximum output size in a "worst case" scenario note : this function is limited by "int" range (2^31-1) */ int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize); /* LZ4_uncompress_unknownOutputSize() : isize : is the input size, therefore the compressed size maxOutputSize : is the size of the destination buffer (which must be already allocated) return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize) If the source stream is malformed, the function will stop decoding and return a negative result, indicating the byte position of the faulty instruction This function never writes beyond dest + maxOutputSize, and is therefore protected against malicious data packets note : Destination buffer must be already allocated. This version is slightly slower than LZ4_uncompress() */ int LZ4_compressCtx(void **ctx, const char *source, char *dest, int isize); int LZ4_compress64kCtx(void **ctx, const char *source, char *dest, int isize); /* LZ4_compressCtx() : This function explicitly handles the CTX memory structure. It avoids allocating/deallocating memory between each call, improving performance when malloc is heavily invoked. This function is only useful when memory is allocated into the heap (HASH_LOG value beyond STACK_LIMIT) Performance difference will be noticeable only when repetitively calling the compression function over many small segments. Note : by default, memory is allocated into the stack, therefore "malloc" is not invoked. LZ4_compress64kCtx() : Same as LZ4_compressCtx(), but specific to small inputs (<64KB). isize *Must* be <64KB, otherwise the output will be corrupted. On first call : provide a *ctx=NULL; It will be automatically allocated. On next calls : reuse the same ctx pointer. Use different pointers for different threads when doing multi-threading. */ #if defined (__cplusplus) } #endif ================================================ FILE: include/lz4/lz4hc.h ================================================ /* LZ4 HC - High Compression Mode of LZ4 Header File Copyright (C) 2011-2012, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ #pragma once #if defined (__cplusplus) extern "C" { #endif int LZ4_compressHC(const char *source, char *dest, int isize); /* LZ4_compressHC : return : the number of bytes in compressed buffer dest note : destination buffer must be already allocated. To avoid any problem, size it to handle worst cases situations (input data not compressible) Worst case size evaluation is provided by function LZ4_compressBound() (see "lz4.h") */ /* Note : Decompression functions are provided within regular LZ4 source code (see "lz4.h") (BSD license) */ #if defined (__cplusplus) } #endif ================================================ FILE: include/lzhs/lzhs.h ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #ifndef _LZHS_H #define _LZHS_H #include #include #include #include "mfile.h" struct lzhs_header { uint32_t uncompressedSize, compressedSize; uint16_t checksum; /* checksum is 1 byte, segment number is 2 bytes */ uint8_t spare[6]; }; /* for LZSS */ #define N 4096 #define F 34 #define THRESHOLD 2 struct lzhs_ctx { /* LZSS */ unsigned long int textsize, codesize; uint8_t text_buf[N + F - 1]; int32_t match_length, match_position, lson[N + 1], rson[N + 257], dad[N + 1]; /* Huffman */ int32_t i, j, k; uint32_t c, code, len, code_buf_ptr; uint8_t code_buf[32], mask, bitno; uint32_t preno, precode; }; /*for Huffman */ typedef struct __attribute__ ((__packed__)) { uint32_t code; uint32_t len; } t_code; struct lzhs_ctx *lzhs_ctx_new(); void lzhs_init_lookup(); void unlzss(struct lzhs_ctx *ctx, cursor_t *in, cursor_t *out); void unhuff(struct lzhs_ctx *ctx, cursor_t *in, cursor_t *out); MFILE *is_lzhs(const char *filename); bool _is_lzhs_mem(struct lzhs_header *header); bool is_lzhs_mem(MFILE *file, off_t offset); void lzss(struct lzhs_ctx *ctx, FILE * infile, FILE * outfile, unsigned long int *p_textsize, unsigned long int *p_codesize); void huff(struct lzhs_ctx *ctx, FILE * in, FILE * out, unsigned long int *p_textsize, unsigned long int *p_codesize); int process_lzhs_segment(MFILE *in_file, off_t offset, const char *name); int extract_lzhs(MFILE *in_file); cursor_t *lzhs_decode(MFILE *in_file, off_t offset, const char *out_path, uint8_t *out_checksum); void lzhs_encode(const char *infile, const char *outfile); void scan_lzhs(const char *filename, int extract); #endif ================================================ FILE: include/lzhs/tables.h ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #ifndef _LZHS_TAB_H # define _LZHS_TAB_H static uint8_t charlen_table[2304] = { //256 + 32 elements of t_code 0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x83, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x86, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x96, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x89, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9B, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8A, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8B, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x8C, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8D, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8E, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x8F, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9E, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x92, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x93, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x95, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x9F, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9A, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA2, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA3, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x9B, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9C, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9D, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9E, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x9F, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA1, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB0, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB1, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB2, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xA2, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA3, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB3, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xA5, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB4, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB5, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB6, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA5, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA6, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA7, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA6, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB7, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xA9, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xA7, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA8, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xA9, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xAA, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xAB, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xAC, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xAD, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xAA, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xAE, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xAF, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB0, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB8, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB9, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xB1, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB2, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB3, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBA, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xBB, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xBC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xBD, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xB4, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB5, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB6, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBE, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xBF, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAC, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xAD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xB7, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xB9, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC1, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC2, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC3, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xC4, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC5, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC6, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC7, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC8, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xB1, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xBA, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBB, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC9, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCA, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCB, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB2, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xB3, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xCD, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCE, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCF, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xD0, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xD1, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xDE, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xBC, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBD, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBE, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD2, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xD3, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xDF, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xB5, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xD4, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xD5, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE1, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xD6, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB6, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xD7, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE2, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xD8, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE3, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE4, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE5, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xD9, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xB7, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xE6, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE7, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xBF, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xDA, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xDB, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xDC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE8, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xE9, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xEA, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC1, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xDD, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xEB, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xDE, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xEC, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xED, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xEE, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xC2, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC3, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xDF, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC4, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xEF, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xC5, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC6, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE1, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xC7, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xE2, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xF1, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF2, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xC8, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xC9, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xE3, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE4, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xCA, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xCB, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xCC, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xCD, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xCE, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xE5, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE6, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE7, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE8, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xE9, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xB9, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xF3, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF4, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xEA, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xF5, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xCF, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD0, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBA, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xD1, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD2, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD3, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD4, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD5, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xBB, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0xBC, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xBD, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xBE, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xD6, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xD7, 0x01, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0xEB, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xEC, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xED, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xEE, 0x03, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0xF6, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF7, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF9, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xFA, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xFB, 0x07, 0x00, 0x00, 0x0B, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xF9, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFA, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFB, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xFC, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFD, 0x1F, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xFD, 0x0F, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xFF, 0x1F, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x00, 0xBF, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 }; static uint8_t pos_table[256] = { //32 elements of t_code 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x2F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3A, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3B, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3D, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00 }; #endif ================================================ FILE: include/lzma/LzFind.h ================================================ /* LzFind.h -- Match finder for LZ algorithms 2009-04-22 : Igor Pavlov : Public domain */ #ifndef __LZ_FIND_H #define __LZ_FIND_H #include "Types.h" #ifdef __cplusplus extern "C" { #endif typedef UInt32 CLzRef; typedef struct _CMatchFinder { Byte *buffer; UInt32 pos; UInt32 posLimit; UInt32 streamPos; UInt32 lenLimit; UInt32 cyclicBufferPos; UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ UInt32 matchMaxLen; CLzRef *hash; CLzRef *son; UInt32 hashMask; UInt32 cutValue; Byte *bufferBase; ISeqInStream *stream; int streamEndWasReached; UInt32 blockSize; UInt32 keepSizeBefore; UInt32 keepSizeAfter; UInt32 numHashBytes; int directInput; size_t directInputRem; int btMode; int bigHash; UInt32 historySize; UInt32 fixedHashSize; UInt32 hashSizeSum; UInt32 numSons; SRes result; UInt32 crc[256]; } CMatchFinder; #define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) #define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) #define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) int MatchFinder_NeedMove(CMatchFinder *p); Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); void MatchFinder_MoveBlock(CMatchFinder *p); void MatchFinder_ReadIfRequired(CMatchFinder *p); void MatchFinder_Construct(CMatchFinder *p); /* Conditions: historySize <= 3 GB keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB */ int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, UInt32 *distances, UInt32 maxLen); /* Conditions: Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. Mf_GetPointerToCurrentPos_Func's result must be used only before any other function */ typedef void (*Mf_Init_Func)(void *object); typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); typedef void (*Mf_Skip_Func)(void *object, UInt32); typedef struct _IMatchFinder { Mf_Init_Func Init; Mf_GetIndexByte_Func GetIndexByte; Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; Mf_GetMatches_Func GetMatches; Mf_Skip_Func Skip; } IMatchFinder; void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); void MatchFinder_Init(CMatchFinder *p); UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/lzma/LzHash.h ================================================ /* LzHash.h -- HASH functions for LZ algorithms 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __LZ_HASH_H #define __LZ_HASH_H #define kHash2Size (1 << 10) #define kHash3Size (1 << 16) #define kHash4Size (1 << 20) #define kFix3HashSize (kHash2Size) #define kFix4HashSize (kHash2Size + kHash3Size) #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) #define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); #define HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } #define HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } #define HASH5_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ hash4Value &= (kHash4Size - 1); } /* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ #define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; #define MT_HASH2_CALC \ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); #define MT_HASH3_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } #define MT_HASH4_CALC { \ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ hash2Value = temp & (kHash2Size - 1); \ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } #endif ================================================ FILE: include/lzma/LzmaDec.h ================================================ /* LzmaDec.h -- LZMA Decoder 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __LZMA_DEC_H #define __LZMA_DEC_H #include "Types.h" #ifdef __cplusplus extern "C" { #endif /* #define _LZMA_PROB32 */ /* _LZMA_PROB32 can increase the speed on some CPUs, but memory usage for CLzmaDec::probs will be doubled in that case */ #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif /* ---------- LZMA Properties ---------- */ #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaProps { unsigned lc, lp, pb; UInt32 dicSize; } CLzmaProps; /* LzmaProps_Decode - decodes properties Returns: SZ_OK SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); /* ---------- LZMA Decoder state ---------- */ /* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ #define LZMA_REQUIRED_INPUT_MAX 20 typedef struct { CLzmaProps prop; CLzmaProb *probs; Byte *dic; const Byte *buf; UInt32 range, code; SizeT dicPos; SizeT dicBufSize; UInt32 processedPos; UInt32 checkDicSize; unsigned state; UInt32 reps[4]; unsigned remainLen; int needFlush; int needInitState; UInt32 numProbs; unsigned tempBufSize; Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; } CLzmaDec; #define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } void LzmaDec_Init(CLzmaDec *p); /* There are two types of LZMA streams: 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ typedef enum { LZMA_FINISH_ANY, /* finish at any point */ LZMA_FINISH_END /* block must be finished at the end */ } ELzmaFinishMode; /* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! You must use LZMA_FINISH_END, when you know that current output buffer covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, and output value of destLen will be less than output buffer size limit. You can check status result also. You can use multiple checks to test data integrity after full decompression: 1) Check Result and "status" variable. 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. You must use correct finish mode in that case. */ typedef enum { LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ } ELzmaStatus; /* ELzmaStatus is used only as output value for function call */ /* ---------- Interfaces ---------- */ /* There are 3 levels of interfaces: 1) Dictionary Interface 2) Buffer Interface 3) One Call Interface You can select any of these interfaces, but don't mix functions from different groups for same object. */ /* There are two variants to allocate state for Dictionary Interface: 1) LzmaDec_Allocate / LzmaDec_Free 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs You can use variant 2, if you set dictionary buffer manually. For Buffer Interface you must always use variant 1. LzmaDec_Allocate* can return: SZ_OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties */ SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); /* ---------- Dictionary Interface ---------- */ /* You can use it, if you want to eliminate the overhead for data copying from dictionary to some other external buffer. You must work with CLzmaDec variables directly in this interface. STEPS: LzmaDec_Constr() LzmaDec_Allocate() for (each new stream) { LzmaDec_Init() while (it needs more decompression) { LzmaDec_DecodeToDic() use data from CLzmaDec::dic and update CLzmaDec::dicPos } } LzmaDec_Free() */ /* LzmaDec_DecodeToDic The decoding to internal dictionary buffer (CLzmaDec::dic). You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! finishMode: It has meaning only if the decoding reaches output limit (dicLimit). LZMA_FINISH_ANY - Decode just dicLimit bytes. LZMA_FINISH_END - Stream must be finished after dicLimit. Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_NEEDS_MORE_INPUT LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error */ SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- Buffer Interface ---------- */ /* It's zlib-like interface. See LzmaDec_DecodeToDic description for information about STEPS and return results, but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need to work with CLzmaDec variables manually. finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). */ SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); /* ---------- One Call Interface ---------- */ /* LzmaDecode finishMode: It has meaning only if the decoding reaches output limit (*destLen). LZMA_FINISH_ANY - Decode just destLen bytes. LZMA_FINISH_END - Stream must be finished after (*destLen). Returns: SZ_OK status: LZMA_STATUS_FINISHED_WITH_MARK LZMA_STATUS_NOT_FINISHED LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK SZ_ERROR_DATA - Data error SZ_ERROR_MEM - Memory allocation error SZ_ERROR_UNSUPPORTED - Unsupported properties SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). */ SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/lzma/LzmaEnc.h ================================================ /* LzmaEnc.h -- LZMA Encoder 2009-02-07 : Igor Pavlov : Public domain */ #ifndef __LZMA_ENC_H #define __LZMA_ENC_H #include "Types.h" #ifdef __cplusplus extern "C" { #endif #define LZMA_PROPS_SIZE 5 typedef struct _CLzmaEncProps { int level; /* 0 <= level <= 9 */ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version (1 << 12) <= dictSize <= (1 << 30) for 64-bit version default = (1 << 24) */ int lc; /* 0 <= lc <= 8, default = 3 */ int lp; /* 0 <= lp <= 4, default = 0 */ int pb; /* 0 <= pb <= 4, default = 2 */ int algo; /* 0 - fast, 1 - normal, default = 1 */ int fb; /* 5 <= fb <= 273, default = 32 */ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ int numHashBytes; /* 2, 3 or 4, default = 4 */ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ int numThreads; /* 1 or 2, default = 2 */ } CLzmaEncProps; void LzmaEncProps_Init(CLzmaEncProps *p); void LzmaEncProps_Normalize(CLzmaEncProps *p); UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); /* ---------- CLzmaEncHandle Interface ---------- */ /* LzmaEnc_* functions can return the following exit codes: Returns: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater in props SZ_ERROR_WRITE - Write callback error. SZ_ERROR_PROGRESS - some break from progress callback SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ typedef void * CLzmaEncHandle; CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); /* ---------- One Call Interface ---------- */ /* LzmaEncode Return code: SZ_OK - OK SZ_ERROR_MEM - Memory allocation error SZ_ERROR_PARAM - Incorrect paramater SZ_ERROR_OUTPUT_EOF - output buffer overflow SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) */ SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/lzma/Types.h ================================================ /* Types.h -- Basic types 2009-11-23 : Igor Pavlov : Public domain */ #ifndef __7Z_TYPES_H #define __7Z_TYPES_H #include #ifdef _WIN32 #include #endif #ifndef EXTERN_C_BEGIN #ifdef __cplusplus #define EXTERN_C_BEGIN extern "C" { #define EXTERN_C_END } #else #define EXTERN_C_BEGIN #define EXTERN_C_END #endif #endif EXTERN_C_BEGIN #define SZ_OK 0 #define SZ_ERROR_DATA 1 #define SZ_ERROR_MEM 2 #define SZ_ERROR_CRC 3 #define SZ_ERROR_UNSUPPORTED 4 #define SZ_ERROR_PARAM 5 #define SZ_ERROR_INPUT_EOF 6 #define SZ_ERROR_OUTPUT_EOF 7 #define SZ_ERROR_READ 8 #define SZ_ERROR_WRITE 9 #define SZ_ERROR_PROGRESS 10 #define SZ_ERROR_FAIL 11 #define SZ_ERROR_THREAD 12 #define SZ_ERROR_ARCHIVE 16 #define SZ_ERROR_NO_ARCHIVE 17 typedef int SRes; #ifdef _WIN32 typedef DWORD WRes; #else typedef int WRes; #endif #ifndef RINOK #define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } #endif typedef unsigned char Byte; typedef short Int16; typedef unsigned short UInt16; #ifdef _LZMA_UINT32_IS_ULONG typedef long Int32; typedef unsigned long UInt32; #else typedef int Int32; typedef unsigned int UInt32; #endif #ifdef _SZ_NO_INT_64 /* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. NOTES: Some code will work incorrectly in that case! */ typedef long Int64; typedef unsigned long UInt64; #else #if defined(_MSC_VER) || defined(__BORLANDC__) typedef __int64 Int64; typedef unsigned __int64 UInt64; #else typedef long long int Int64; typedef unsigned long long int UInt64; #endif #endif #ifdef _LZMA_NO_SYSTEM_SIZE_T typedef UInt32 SizeT; #else typedef size_t SizeT; #endif typedef int Bool; #define True 1 #define False 0 #ifdef _WIN32 #define MY_STD_CALL __stdcall #else #define MY_STD_CALL #endif #ifdef _MSC_VER #if _MSC_VER >= 1300 #define MY_NO_INLINE __declspec(noinline) #else #define MY_NO_INLINE #endif #define MY_CDECL __cdecl #define MY_FAST_CALL __fastcall #else #define MY_CDECL #define MY_FAST_CALL #endif /* The following interfaces use first parameter as pointer to structure */ typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) < input(*size)) is allowed */ } ISeqInStream; /* it can return SZ_ERROR_INPUT_EOF */ SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); typedef struct { size_t (*Write)(void *p, const void *buf, size_t size); /* Returns: result - the number of actually written bytes. (result < size) means error */ } ISeqOutStream; typedef enum { SZ_SEEK_SET = 0, SZ_SEEK_CUR = 1, SZ_SEEK_END = 2 } ESzSeek; typedef struct { SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ISeekInStream; typedef struct { SRes (*Look)(void *p, void **buf, size_t *size); /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. (output(*size) > input(*size)) is not allowed (output(*size) < input(*size)) is allowed */ SRes (*Skip)(void *p, size_t offset); /* offset must be <= output(*size) of Look */ SRes (*Read)(void *p, void *buf, size_t *size); /* reads directly (without buffer). It's same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); } ILookInStream; SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); /* reads via ILookInStream::Read */ SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); #define LookToRead_BUF_SIZE (1 << 14) typedef struct { ILookInStream s; ISeekInStream *realStream; size_t pos; size_t size; Byte buf[LookToRead_BUF_SIZE]; } CLookToRead; void LookToRead_CreateVTable(CLookToRead *p, int lookahead); void LookToRead_Init(CLookToRead *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToLook; void SecToLook_CreateVTable(CSecToLook *p); typedef struct { ISeqInStream s; ILookInStream *realStream; } CSecToRead; void SecToRead_CreateVTable(CSecToRead *p); typedef struct { SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); /* Returns: result. (result != SZ_OK) means break. Value (UInt64)(Int64)-1 for size means unknown value. */ } ICompressProgress; typedef struct { void *(*Alloc)(void *p, size_t size); void (*Free)(void *p, void *address); /* address can be 0 */ } ISzAlloc; #define IAlloc_Alloc(p, size) (p)->Alloc((p), size) #define IAlloc_Free(p, a) (p)->Free((p), a) EXTERN_C_END #endif ================================================ FILE: include/lzma.h ================================================ #pragma once #include #include #include #include #include #include #include "jffs2/jffs2.h" #ifndef PAGE_SIZE extern int page_size; #define PAGE_SIZE page_size #endif #define LZMA_MALLOC malloc #define LZMA_FREE free #define PRINT_ERROR(msg) fprintf(stderr, msg) #define INIT #define STATIC #ifndef __APPLE__ # include #endif #include "lzma/LzmaDec.h" #include "lzma/LzmaEnc.h" #define LZMA_BEST_LEVEL (9) #define LZMA_BEST_LC (0) #define LZMA_BEST_LP (0) #define LZMA_BEST_PB (0) #define LZMA_BEST_FB (273) #define LZMA_BEST_DICT(n) (((int)((n) / 2)) * 2) static void *p_lzma_malloc(void *p, size_t size) { if (size == 0) return NULL; return LZMA_MALLOC(size); } static void p_lzma_free(void *p, void *address) { if (address != NULL) LZMA_FREE(address); } static ISzAlloc lzma_alloc = {p_lzma_malloc, p_lzma_free}; ================================================ FILE: include/lzo/lzo.h ================================================ #ifndef __LZO_LG_H #define __LZO_LG_H int check_lzo_header(const char *name); int lzo_unpack(const char *in_name, const char *out_name); #endif //__LZO_LG_H ================================================ FILE: include/lzo/miniacc.h ================================================ /* ACC --- Automatic Compiler Configuration This file is part of the LZO real-time data compression library. Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library 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 2 of the License, or (at your option) any later version. The LZO library 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 the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer http://www.oberhumer.com/opensource/lzo/ */ #ifndef __ACC_H_INCLUDED # define __ACC_H_INCLUDED 1 # define ACC_VERSION 20080430L # if defined(__CYGWIN32__) && !defined(__CYGWIN__) # define __CYGWIN__ __CYGWIN32__ # endif # if defined(__IBMCPP__) && !defined(__IBMC__) # define __IBMC__ __IBMCPP__ # endif # if defined(__ICL) && defined(_WIN32) && !defined(__INTEL_COMPILER) # define __INTEL_COMPILER __ICL # endif # if 1 && defined(__INTERIX) && defined(__GNUC__) && !defined(_ALL_SOURCE) # define _ALL_SOURCE 1 # endif # if defined(__mips__) && defined(__R5900__) # if !defined(__LONG_MAX__) # define __LONG_MAX__ 9223372036854775807L # endif # endif # if defined(__INTEL_COMPILER) && defined(__linux__) # pragma warning(disable: 193) # endif # if defined(__KEIL__) && defined(__C166__) # pragma warning disable = 322 # elif 0 && defined(__C251__) # pragma warning disable = 322 # endif # if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__MWERKS__) # if (_MSC_VER >= 1300) # pragma warning(disable: 4668) # endif # endif # if defined(__POCC__) && defined(_WIN32) # if (__POCC__ >= 400) # pragma warn(disable: 2216) # endif # endif # if 0 && defined(__WATCOMC__) # if (__WATCOMC__ >= 1050) && (__WATCOMC__ < 1060) # pragma warning 203 9 # endif # endif # if defined(__BORLANDC__) && defined(__MSDOS__) && !defined(__FLAT__) # pragma option -h # endif # if defined(ACC_CFG_NO_CONFIG_HEADER) # elif defined(ACC_CFG_CONFIG_HEADER) # include ACC_CFG_CONFIG_HEADER # else # endif # if defined(ACC_CFG_NO_LIMITS_H) # elif defined(ACC_LIBC_NAKED) || defined(ACC_BROKEN_LIMITS_H) # ifndef __ACC_FALLBACK_LIMITS_H_INCLUDED # define __ACC_FALLBACK_LIMITS_H_INCLUDED # undef CHAR_BIT # define CHAR_BIT 8 # ifndef MB_LEN_MAX # define MB_LEN_MAX 1 # endif # ifndef __SCHAR_MAX__ # define __SCHAR_MAX__ 127 # endif # ifndef __SHRT_MAX__ # define __SHRT_MAX__ 32767 # endif # ifndef __INT_MAX__ # define __INT_MAX__ 2147483647 # endif # ifndef __LONG_MAX__ # if defined(__alpha__) || defined(_LP64) || defined(__MIPS_PSX2__) # define __LONG_MAX__ 9223372036854775807L # else # define __LONG_MAX__ 2147483647L # endif # endif # undef SCHAR_MIN # undef SCHAR_MAX # undef UCHAR_MAX # define SCHAR_MIN (-1 - SCHAR_MAX) # define SCHAR_MAX (__SCHAR_MAX__) # define UCHAR_MAX (SCHAR_MAX * 2 + 1) # undef SHRT_MIN # undef SHRT_MAX # undef USHRT_MAX # define SHRT_MIN (-1 - SHRT_MAX) # define SHRT_MAX (__SHRT_MAX__) # if ((__INT_MAX__) == (__SHRT_MAX__)) # define USHRT_MAX (SHRT_MAX * 2U + 1U) # else # define USHRT_MAX (SHRT_MAX * 2 + 1) # endif # undef INT_MIN # undef INT_MAX # undef UINT_MAX # define INT_MIN (-1 - INT_MAX) # define INT_MAX (__INT_MAX__) # define UINT_MAX (INT_MAX * 2U + 1U) # undef LONG_MIN # undef LONG_MAX # undef ULONG_MAX # define LONG_MIN (-1L - LONG_MAX) # define LONG_MAX ((__LONG_MAX__) + 0L) # define ULONG_MAX (LONG_MAX * 2UL + 1UL) # undef CHAR_MIN # undef CHAR_MAX # if defined(__CHAR_UNSIGNED__) || defined(_CHAR_UNSIGNED) # define CHAR_MIN 0 # define CHAR_MAX UCHAR_MAX # else # define CHAR_MIN SCHAR_MIN # define CHAR_MAX SCHAR_MAX # endif # endif # else # include # endif # if 0 # define ACC_0xffffL 0xfffful # define ACC_0xffffffffL 0xfffffffful # else # define ACC_0xffffL 65535ul # define ACC_0xffffffffL 4294967295ul # endif # if (ACC_0xffffL == ACC_0xffffffffL) # error "your preprocessor is broken 1" # endif # if (16ul * 16384ul != 262144ul) # error "your preprocessor is broken 2" # endif # if 0 # if (32767 >= 4294967295ul) # error "your preprocessor is broken 3" # endif # if (65535u >= 4294967295ul) # error "your preprocessor is broken 4" # endif # endif # if (UINT_MAX == ACC_0xffffL) # if defined(__ZTC__) && defined(__I86__) && !defined(__OS2__) # if !defined(MSDOS) # define MSDOS 1 # endif # if !defined(_MSDOS) # define _MSDOS 1 # endif # elif 0 && defined(__VERSION) && defined(MB_LEN_MAX) # if (__VERSION == 520) && (MB_LEN_MAX == 1) # if !defined(__AZTEC_C__) # define __AZTEC_C__ __VERSION # endif # if !defined(__DOS__) # define __DOS__ 1 # endif # endif # endif # endif # if defined(_MSC_VER) && defined(M_I86HM) && (UINT_MAX == ACC_0xffffL) # define ptrdiff_t long # define _PTRDIFF_T_DEFINED # endif # if (UINT_MAX == ACC_0xffffL) # undef __ACC_RENAME_A # undef __ACC_RENAME_B # if defined(__AZTEC_C__) && defined(__DOS__) # define __ACC_RENAME_A 1 # elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define __ACC_RENAME_A 1 # elif (_MSC_VER < 700) # define __ACC_RENAME_B 1 # endif # elif defined(__TSC__) && defined(__OS2__) # define __ACC_RENAME_A 1 # elif defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0410) # define __ACC_RENAME_A 1 # elif defined(__PACIFIC__) && defined(DOS) # if !defined(__far) # define __far far # endif # if !defined(__near) # define __near near # endif # endif # if defined(__ACC_RENAME_A) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__far) # define __far far # endif # if !defined(__huge) # define __huge huge # endif # if !defined(__near) # define __near near # endif # if !defined(__pascal) # define __pascal pascal # endif # if !defined(__huge) # define __huge huge # endif # elif defined(__ACC_RENAME_B) # if !defined(__cdecl) # define __cdecl _cdecl # endif # if !defined(__far) # define __far _far # endif # if !defined(__huge) # define __huge _huge # endif # if !defined(__near) # define __near _near # endif # if !defined(__pascal) # define __pascal _pascal # endif # elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # if !defined(__cdecl) # define __cdecl cdecl # endif # if !defined(__pascal) # define __pascal pascal # endif # endif # undef __ACC_RENAME_A # undef __ACC_RENAME_B # endif # if (UINT_MAX == ACC_0xffffL) # if defined(__AZTEC_C__) && defined(__DOS__) # define ACC_BROKEN_CDECL_ALT_SYNTAX 1 # elif defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER < 600) # define ACC_BROKEN_INTEGRAL_CONSTANTS 1 # endif # if (_MSC_VER < 700) # define ACC_BROKEN_INTEGRAL_PROMOTION 1 # define ACC_BROKEN_SIZEOF 1 # endif # elif defined(__PACIFIC__) && defined(DOS) # define ACC_BROKEN_INTEGRAL_CONSTANTS 1 # elif defined(__TURBOC__) && defined(__MSDOS__) # if (__TURBOC__ < 0x0150) # define ACC_BROKEN_CDECL_ALT_SYNTAX 1 # define ACC_BROKEN_INTEGRAL_CONSTANTS 1 # define ACC_BROKEN_INTEGRAL_PROMOTION 1 # endif # if (__TURBOC__ < 0x0200) # define ACC_BROKEN_SIZEOF 1 # endif # if (__TURBOC__ < 0x0400) && defined(__cplusplus) # define ACC_BROKEN_CDECL_ALT_SYNTAX 1 # endif # elif (defined(__PUREC__) || defined(__TURBOC__)) && defined(__TOS__) # define ACC_BROKEN_CDECL_ALT_SYNTAX 1 # define ACC_BROKEN_SIZEOF 1 # endif # endif # if defined(__WATCOMC__) && (__WATCOMC__ < 900) # define ACC_BROKEN_INTEGRAL_CONSTANTS 1 # endif # if defined(_CRAY) && defined(_CRAY1) # define ACC_BROKEN_SIGNED_RIGHT_SHIFT 1 # endif # define ACC_PP_STRINGIZE(x) #x # define ACC_PP_MACRO_EXPAND(x) ACC_PP_STRINGIZE(x) # define ACC_PP_CONCAT2(a,b) a ## b # define ACC_PP_CONCAT3(a,b,c) a ## b ## c # define ACC_PP_CONCAT4(a,b,c,d) a ## b ## c ## d # define ACC_PP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e # define ACC_PP_ECONCAT2(a,b) ACC_PP_CONCAT2(a,b) # define ACC_PP_ECONCAT3(a,b,c) ACC_PP_CONCAT3(a,b,c) # define ACC_PP_ECONCAT4(a,b,c,d) ACC_PP_CONCAT4(a,b,c,d) # define ACC_PP_ECONCAT5(a,b,c,d,e) ACC_PP_CONCAT5(a,b,c,d,e) # if 1 # define ACC_CPP_STRINGIZE(x) #x # define ACC_CPP_MACRO_EXPAND(x) ACC_CPP_STRINGIZE(x) # define ACC_CPP_CONCAT2(a,b) a ## b # define ACC_CPP_CONCAT3(a,b,c) a ## b ## c # define ACC_CPP_CONCAT4(a,b,c,d) a ## b ## c ## d # define ACC_CPP_CONCAT5(a,b,c,d,e) a ## b ## c ## d ## e # define ACC_CPP_ECONCAT2(a,b) ACC_CPP_CONCAT2(a,b) # define ACC_CPP_ECONCAT3(a,b,c) ACC_CPP_CONCAT3(a,b,c) # define ACC_CPP_ECONCAT4(a,b,c,d) ACC_CPP_CONCAT4(a,b,c,d) # define ACC_CPP_ECONCAT5(a,b,c,d,e) ACC_CPP_CONCAT5(a,b,c,d,e) # endif # define __ACC_MASK_GEN(o,b) (((((o) << ((b)-1)) - (o)) << 1) + (o)) # if 1 && defined(__cplusplus) # if !defined(__STDC_CONSTANT_MACROS) # define __STDC_CONSTANT_MACROS 1 # endif # if !defined(__STDC_LIMIT_MACROS) # define __STDC_LIMIT_MACROS 1 # endif # endif # if defined(__cplusplus) # define ACC_EXTERN_C extern "C" # else # define ACC_EXTERN_C extern # endif # if !defined(__ACC_OS_OVERRIDE) # if defined(ACC_OS_FREESTANDING) # define ACC_INFO_OS "freestanding" # elif defined(ACC_OS_EMBEDDED) # define ACC_INFO_OS "embedded" # elif 1 && defined(__IAR_SYSTEMS_ICC__) # define ACC_OS_EMBEDDED 1 # define ACC_INFO_OS "embedded" # elif defined(__CYGWIN__) && defined(__GNUC__) # define ACC_OS_CYGWIN 1 # define ACC_INFO_OS "cygwin" # elif defined(__EMX__) && defined(__GNUC__) # define ACC_OS_EMX 1 # define ACC_INFO_OS "emx" # elif defined(__BEOS__) # define ACC_OS_BEOS 1 # define ACC_INFO_OS "beos" # elif defined(__Lynx__) # define ACC_OS_LYNXOS 1 # define ACC_INFO_OS "lynxos" # elif defined(__OS400__) # define ACC_OS_OS400 1 # define ACC_INFO_OS "os400" # elif defined(__QNX__) # define ACC_OS_QNX 1 # define ACC_INFO_OS "qnx" # elif defined(__BORLANDC__) && defined(__DPMI32__) && (__BORLANDC__ >= 0x0460) # define ACC_OS_DOS32 1 # define ACC_INFO_OS "dos32" # elif defined(__BORLANDC__) && defined(__DPMI16__) # define ACC_OS_DOS16 1 # define ACC_INFO_OS "dos16" # elif defined(__ZTC__) && defined(DOS386) # define ACC_OS_DOS32 1 # define ACC_INFO_OS "dos32" # elif defined(__OS2__) || defined(__OS2V2__) # if (UINT_MAX == ACC_0xffffL) # define ACC_OS_OS216 1 # define ACC_INFO_OS "os216" # elif (UINT_MAX == ACC_0xffffffffL) # define ACC_OS_OS2 1 # define ACC_INFO_OS "os2" # else # error "check your limits.h header" # endif # elif defined(__WIN64__) || defined(_WIN64) || defined(WIN64) # define ACC_OS_WIN64 1 # define ACC_INFO_OS "win64" # elif defined(__WIN32__) || defined(_WIN32) || defined(WIN32) || defined(__WINDOWS_386__) # define ACC_OS_WIN32 1 # define ACC_INFO_OS "win32" # elif defined(__MWERKS__) && defined(__INTEL__) # define ACC_OS_WIN32 1 # define ACC_INFO_OS "win32" # elif defined(__WINDOWS__) || defined(_WINDOWS) || defined(_Windows) # if (UINT_MAX == ACC_0xffffL) # define ACC_OS_WIN16 1 # define ACC_INFO_OS "win16" # elif (UINT_MAX == ACC_0xffffffffL) # define ACC_OS_WIN32 1 # define ACC_INFO_OS "win32" # else # error "check your limits.h header" # endif # elif defined(__DOS__) || defined(__MSDOS__) || defined(_MSDOS) || defined(MSDOS) || (defined(__PACIFIC__) && defined(DOS)) # if (UINT_MAX == ACC_0xffffL) # define ACC_OS_DOS16 1 # define ACC_INFO_OS "dos16" # elif (UINT_MAX == ACC_0xffffffffL) # define ACC_OS_DOS32 1 # define ACC_INFO_OS "dos32" # else # error "check your limits.h header" # endif # elif defined(__WATCOMC__) # if defined(__NT__) && (UINT_MAX == ACC_0xffffL) # define ACC_OS_DOS16 1 # define ACC_INFO_OS "dos16" # elif defined(__NT__) && (__WATCOMC__ < 1100) # define ACC_OS_WIN32 1 # define ACC_INFO_OS "win32" # elif defined(__linux__) || defined(__LINUX__) # define ACC_OS_POSIX 1 # define ACC_INFO_OS "posix" # else # error "please specify a target using the -bt compiler option" # endif # elif defined(__palmos__) # define ACC_OS_PALMOS 1 # define ACC_INFO_OS "palmos" # elif defined(__TOS__) || defined(__atarist__) # define ACC_OS_TOS 1 # define ACC_INFO_OS "tos" # elif defined(macintosh) && !defined(__ppc__) # define ACC_OS_MACCLASSIC 1 # define ACC_INFO_OS "macclassic" # elif defined(__VMS) # define ACC_OS_VMS 1 # define ACC_INFO_OS "vms" # elif ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define ACC_OS_CONSOLE 1 # define ACC_OS_CONSOLE_PS2 1 # define ACC_INFO_OS "console" # define ACC_INFO_OS_CONSOLE "ps2" # elif (defined(__mips__) && defined(__psp__)) # define ACC_OS_CONSOLE 1 # define ACC_OS_CONSOLE_PSP 1 # define ACC_INFO_OS "console" # define ACC_INFO_OS_CONSOLE "psp" # else # define ACC_OS_POSIX 1 # define ACC_INFO_OS "posix" # endif # if (ACC_OS_POSIX) # if defined(_AIX) || defined(__AIX__) || defined(__aix__) # define ACC_OS_POSIX_AIX 1 # define ACC_INFO_OS_POSIX "aix" # elif defined(__FreeBSD__) # define ACC_OS_POSIX_FREEBSD 1 # define ACC_INFO_OS_POSIX "freebsd" # elif defined(__hpux__) || defined(__hpux) # define ACC_OS_POSIX_HPUX 1 # define ACC_INFO_OS_POSIX "hpux" # elif defined(__INTERIX) # define ACC_OS_POSIX_INTERIX 1 # define ACC_INFO_OS_POSIX "interix" # elif defined(__IRIX__) || defined(__irix__) # define ACC_OS_POSIX_IRIX 1 # define ACC_INFO_OS_POSIX "irix" # elif defined(__linux__) || defined(__linux) || defined(__LINUX__) # define ACC_OS_POSIX_LINUX 1 # define ACC_INFO_OS_POSIX "linux" # elif defined(__APPLE__) || defined(__MACOS__) # define ACC_OS_POSIX_MACOSX 1 # define ACC_INFO_OS_POSIX "macosx" # elif defined(__minix__) || defined(__minix) # define ACC_OS_POSIX_MINIX 1 # define ACC_INFO_OS_POSIX "minix" # elif defined(__NetBSD__) # define ACC_OS_POSIX_NETBSD 1 # define ACC_INFO_OS_POSIX "netbsd" # elif defined(__OpenBSD__) # define ACC_OS_POSIX_OPENBSD 1 # define ACC_INFO_OS_POSIX "openbsd" # elif defined(__osf__) # define ACC_OS_POSIX_OSF 1 # define ACC_INFO_OS_POSIX "osf" # elif defined(__solaris__) || defined(__sun) # if defined(__SVR4) || defined(__svr4__) # define ACC_OS_POSIX_SOLARIS 1 # define ACC_INFO_OS_POSIX "solaris" # else # define ACC_OS_POSIX_SUNOS 1 # define ACC_INFO_OS_POSIX "sunos" # endif # elif defined(__ultrix__) || defined(__ultrix) # define ACC_OS_POSIX_ULTRIX 1 # define ACC_INFO_OS_POSIX "ultrix" # elif defined(_UNICOS) # define ACC_OS_POSIX_UNICOS 1 # define ACC_INFO_OS_POSIX "unicos" # else # define ACC_OS_POSIX_UNKNOWN 1 # define ACC_INFO_OS_POSIX "unknown" # endif # endif # endif # if (ACC_OS_DOS16 || ACC_OS_OS216 || ACC_OS_WIN16) # if (UINT_MAX != ACC_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != ACC_0xffffffffL) # error "this should not happen" # endif # endif # if (ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_WIN32 || ACC_OS_WIN64) # if (UINT_MAX != ACC_0xffffffffL) # error "this should not happen" # endif # if (ULONG_MAX != ACC_0xffffffffL) # error "this should not happen" # endif # endif # if defined(CIL) && defined(_GNUCC) && defined(__GNUC__) # define ACC_CC_CILLY 1 # define ACC_INFO_CC "Cilly" # if defined(__CILLY__) # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__CILLY__) # else # define ACC_INFO_CCVER "unknown" # endif # elif 0 && defined(SDCC) && defined(__VERSION__) && !defined(__GNUC__) # define ACC_CC_SDCC 1 # define ACC_INFO_CC "sdcc" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(SDCC) # elif defined(__PATHSCALE__) && defined(__PATHCC_PATCHLEVEL__) # define ACC_CC_PATHSCALE (__PATHCC__ * 0x10000L + __PATHCC_MINOR__ * 0x100 + __PATHCC_PATCHLEVEL__) # define ACC_INFO_CC "Pathscale C" # define ACC_INFO_CCVER __PATHSCALE__ # elif defined(__INTEL_COMPILER) # define ACC_CC_INTELC 1 # define ACC_INFO_CC "Intel C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__INTEL_COMPILER) # if defined(_WIN32) || defined(_WIN64) # define ACC_CC_SYNTAX_MSC 1 # else # define ACC_CC_SYNTAX_GNUC 1 # endif # elif defined(__POCC__) && defined(_WIN32) # define ACC_CC_PELLESC 1 # define ACC_INFO_CC "Pelles C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__POCC__) # elif defined(__llvm__) && defined(__GNUC__) && defined(__VERSION__) # if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) # define ACC_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # else # define ACC_CC_LLVM (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # endif # define ACC_INFO_CC "llvm-gcc" # define ACC_INFO_CCVER __VERSION__ # elif defined(__GNUC__) && defined(__VERSION__) # if defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) # define ACC_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100 + __GNUC_PATCHLEVEL__) # elif defined(__GNUC_MINOR__) # define ACC_CC_GNUC (__GNUC__ * 0x10000L + __GNUC_MINOR__ * 0x100) # else # define ACC_CC_GNUC (__GNUC__ * 0x10000L) # endif # define ACC_INFO_CC "gcc" # define ACC_INFO_CCVER __VERSION__ # elif defined(__ACK__) && defined(_ACK) # define ACC_CC_ACK 1 # define ACC_INFO_CC "Amsterdam Compiler Kit C" # define ACC_INFO_CCVER "unknown" # elif defined(__AZTEC_C__) # define ACC_CC_AZTECC 1 # define ACC_INFO_CC "Aztec C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__AZTEC_C__) # elif defined(__BORLANDC__) # define ACC_CC_BORLANDC 1 # define ACC_INFO_CC "Borland C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__BORLANDC__) # elif defined(_CRAYC) && defined(_RELEASE) # define ACC_CC_CRAYC 1 # define ACC_INFO_CC "Cray C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(_RELEASE) # elif defined(__DMC__) && defined(__SC__) # define ACC_CC_DMC 1 # define ACC_INFO_CC "Digital Mars C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__DMC__) # elif defined(__DECC) # define ACC_CC_DECC 1 # define ACC_INFO_CC "DEC C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__DECC) # elif defined(__HIGHC__) # define ACC_CC_HIGHC 1 # define ACC_INFO_CC "MetaWare High C" # define ACC_INFO_CCVER "unknown" # elif defined(__IAR_SYSTEMS_ICC__) # define ACC_CC_IARC 1 # define ACC_INFO_CC "IAR C" # if defined(__VER__) # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__VER__) # else # define ACC_INFO_CCVER "unknown" # endif # elif defined(__IBMC__) # define ACC_CC_IBMC 1 # define ACC_INFO_CC "IBM C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__IBMC__) # elif defined(__KEIL__) && defined(__C166__) # define ACC_CC_KEILC 1 # define ACC_INFO_CC "Keil C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__C166__) # elif defined(__LCC__) && defined(_WIN32) && defined(__LCCOPTIMLEVEL) # define ACC_CC_LCCWIN32 1 # define ACC_INFO_CC "lcc-win32" # define ACC_INFO_CCVER "unknown" # elif defined(__LCC__) # define ACC_CC_LCC 1 # define ACC_INFO_CC "lcc" # if defined(__LCC_VERSION__) # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__LCC_VERSION__) # else # define ACC_INFO_CCVER "unknown" # endif # elif defined(_MSC_VER) # define ACC_CC_MSC 1 # define ACC_INFO_CC "Microsoft C" # if defined(_MSC_FULL_VER) # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(_MSC_VER) "." ACC_PP_MACRO_EXPAND(_MSC_FULL_VER) # else # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(_MSC_VER) # endif # elif defined(__MWERKS__) # define ACC_CC_MWERKS 1 # define ACC_INFO_CC "Metrowerks C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__MWERKS__) # elif (defined(__NDPC__) || defined(__NDPX__)) && defined(__i386) # define ACC_CC_NDPC 1 # define ACC_INFO_CC "Microway NDP C" # define ACC_INFO_CCVER "unknown" # elif defined(__PACIFIC__) # define ACC_CC_PACIFICC 1 # define ACC_INFO_CC "Pacific C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__PACIFIC__) # elif defined(__PGI) && (defined(__linux__) || defined(__WIN32__)) # define ACC_CC_PGI 1 # define ACC_INFO_CC "Portland Group PGI C" # define ACC_INFO_CCVER "unknown" # elif defined(__PUREC__) && defined(__TOS__) # define ACC_CC_PUREC 1 # define ACC_INFO_CC "Pure C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__PUREC__) # elif defined(__SC__) && defined(__ZTC__) # define ACC_CC_SYMANTECC 1 # define ACC_INFO_CC "Symantec C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__SC__) # elif defined(__SUNPRO_C) # define ACC_INFO_CC "SunPro C" # if ((__SUNPRO_C)+0 > 0) # define ACC_CC_SUNPROC __SUNPRO_C # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__SUNPRO_C) # else # define ACC_CC_SUNPROC 1 # define ACC_INFO_CCVER "unknown" # endif # elif defined(__SUNPRO_CC) # define ACC_INFO_CC "SunPro C" # if ((__SUNPRO_CC)+0 > 0) # define ACC_CC_SUNPROC __SUNPRO_CC # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__SUNPRO_CC) # else # define ACC_CC_SUNPROC 1 # define ACC_INFO_CCVER "unknown" # endif # elif defined(__TINYC__) # define ACC_CC_TINYC 1 # define ACC_INFO_CC "Tiny C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__TINYC__) # elif defined(__TSC__) # define ACC_CC_TOPSPEEDC 1 # define ACC_INFO_CC "TopSpeed C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__TSC__) # elif defined(__WATCOMC__) # define ACC_CC_WATCOMC 1 # define ACC_INFO_CC "Watcom C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__WATCOMC__) # elif defined(__TURBOC__) # define ACC_CC_TURBOC 1 # define ACC_INFO_CC "Turbo C" # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__TURBOC__) # elif defined(__ZTC__) # define ACC_CC_ZORTECHC 1 # define ACC_INFO_CC "Zortech C" # if (__ZTC__ == 0x310) # define ACC_INFO_CCVER "0x310" # else # define ACC_INFO_CCVER ACC_PP_MACRO_EXPAND(__ZTC__) # endif # else # define ACC_CC_UNKNOWN 1 # define ACC_INFO_CC "unknown" # define ACC_INFO_CCVER "unknown" # endif # if 0 && (ACC_CC_MSC && (_MSC_VER >= 1200)) && !defined(_MSC_FULL_VER) # error "ACC_CC_MSC: _MSC_FULL_VER is not defined" # endif # if !defined(__ACC_ARCH_OVERRIDE) && !defined(ACC_ARCH_GENERIC) && defined(_CRAY) # if (UINT_MAX > ACC_0xffffffffL) && defined(_CRAY) # if defined(_CRAYMPP) || defined(_CRAYT3D) || defined(_CRAYT3E) # define ACC_ARCH_CRAY_MPP 1 # elif defined(_CRAY1) # define ACC_ARCH_CRAY_PVP 1 # endif # endif # endif # if !defined(__ACC_ARCH_OVERRIDE) # if defined(ACC_ARCH_GENERIC) # define ACC_INFO_ARCH "generic" # elif (ACC_OS_DOS16 || ACC_OS_OS216 || ACC_OS_WIN16) # define ACC_ARCH_I086 1 # define ACC_ARCH_IA16 1 # define ACC_INFO_ARCH "i086" # elif defined(__alpha__) || defined(__alpha) || defined(_M_ALPHA) # define ACC_ARCH_ALPHA 1 # define ACC_INFO_ARCH "alpha" # elif (ACC_ARCH_CRAY_MPP) && (defined(_CRAYT3D) || defined(_CRAYT3E)) # define ACC_ARCH_ALPHA 1 # define ACC_INFO_ARCH "alpha" # elif defined(__amd64__) || defined(__x86_64__) || defined(_M_AMD64) # define ACC_ARCH_AMD64 1 # define ACC_INFO_ARCH "amd64" # elif defined(__thumb__) || (defined(_M_ARM) && defined(_M_THUMB)) # define ACC_ARCH_ARM 1 # define ACC_ARCH_ARM_THUMB 1 # define ACC_INFO_ARCH "arm_thumb" # elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCARM__) # define ACC_ARCH_ARM 1 # if defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 1) # define ACC_ARCH_ARM_THUMB 1 # define ACC_INFO_ARCH "arm_thumb" # elif defined(__CPU_MODE__) && ((__CPU_MODE__)+0 == 2) # define ACC_INFO_ARCH "arm" # else # define ACC_INFO_ARCH "arm" # endif # elif defined(__arm__) || defined(_M_ARM) # define ACC_ARCH_ARM 1 # define ACC_INFO_ARCH "arm" # elif (UINT_MAX <= ACC_0xffffL) && defined(__AVR__) # define ACC_ARCH_AVR 1 # define ACC_INFO_ARCH "avr" # elif defined(__bfin__) # define ACC_ARCH_BLACKFIN 1 # define ACC_INFO_ARCH "blackfin" # elif (UINT_MAX == ACC_0xffffL) && defined(__C166__) # define ACC_ARCH_C166 1 # define ACC_INFO_ARCH "c166" # elif defined(__cris__) # define ACC_ARCH_CRIS 1 # define ACC_INFO_ARCH "cris" # elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCEZ80__) # define ACC_ARCH_EZ80 1 # define ACC_INFO_ARCH "ez80" # elif defined(__H8300__) || defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define ACC_ARCH_H8300 1 # define ACC_INFO_ARCH "h8300" # elif defined(__hppa__) || defined(__hppa) # define ACC_ARCH_HPPA 1 # define ACC_INFO_ARCH "hppa" # elif defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386) # define ACC_ARCH_I386 1 # define ACC_ARCH_IA32 1 # define ACC_INFO_ARCH "i386" # elif (ACC_CC_ZORTECHC && defined(__I86__)) # define ACC_ARCH_I386 1 # define ACC_ARCH_IA32 1 # define ACC_INFO_ARCH "i386" # elif (ACC_OS_DOS32 && ACC_CC_HIGHC) && defined(_I386) # define ACC_ARCH_I386 1 # define ACC_ARCH_IA32 1 # define ACC_INFO_ARCH "i386" # elif defined(__ia64__) || defined(__ia64) || defined(_M_IA64) # define ACC_ARCH_IA64 1 # define ACC_INFO_ARCH "ia64" # elif (UINT_MAX == ACC_0xffffL) && defined(__m32c__) # define ACC_ARCH_M16C 1 # define ACC_INFO_ARCH "m16c" # elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICCM16C__) # define ACC_ARCH_M16C 1 # define ACC_INFO_ARCH "m16c" # elif defined(__m32r__) # define ACC_ARCH_M32R 1 # define ACC_INFO_ARCH "m32r" # elif (ACC_OS_TOS) || defined(__m68k__) || defined(__m68000__) || defined(__mc68000__) || defined(__mc68020__) || defined(_M_M68K) # define ACC_ARCH_M68K 1 # define ACC_INFO_ARCH "m68k" # elif (UINT_MAX == ACC_0xffffL) && defined(__C251__) # define ACC_ARCH_MCS251 1 # define ACC_INFO_ARCH "mcs251" # elif (UINT_MAX == ACC_0xffffL) && defined(__C51__) # define ACC_ARCH_MCS51 1 # define ACC_INFO_ARCH "mcs51" # elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC8051__) # define ACC_ARCH_MCS51 1 # define ACC_INFO_ARCH "mcs51" # elif defined(__mips__) || defined(__mips) || defined(_MIPS_ARCH) || defined(_M_MRX000) # define ACC_ARCH_MIPS 1 # define ACC_INFO_ARCH "mips" # elif (UINT_MAX == ACC_0xffffL) && defined(__MSP430__) # define ACC_ARCH_MSP430 1 # define ACC_INFO_ARCH "msp430" # elif defined(__IAR_SYSTEMS_ICC__) && defined(__ICC430__) # define ACC_ARCH_MSP430 1 # define ACC_INFO_ARCH "msp430" # elif defined(__powerpc__) || defined(__powerpc) || defined(__ppc__) || defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || defined(_ARCH_PWR) # define ACC_ARCH_POWERPC 1 # define ACC_INFO_ARCH "powerpc" # elif defined(__s390__) || defined(__s390) || defined(__s390x__) || defined(__s390x) # define ACC_ARCH_S390 1 # define ACC_INFO_ARCH "s390" # elif defined(__sh__) || defined(_M_SH) # define ACC_ARCH_SH 1 # define ACC_INFO_ARCH "sh" # elif defined(__sparc__) || defined(__sparc) || defined(__sparcv8) # define ACC_ARCH_SPARC 1 # define ACC_INFO_ARCH "sparc" # elif defined(__SPU__) # define ACC_ARCH_SPU 1 # define ACC_INFO_ARCH "spu" # elif (UINT_MAX == ACC_0xffffL) && defined(__z80) # define ACC_ARCH_Z80 1 # define ACC_INFO_ARCH "z80" # elif (ACC_ARCH_CRAY_PVP) # if defined(_CRAYSV1) # define ACC_ARCH_CRAY_SV1 1 # define ACC_INFO_ARCH "cray_sv1" # elif (_ADDR64) # define ACC_ARCH_CRAY_T90 1 # define ACC_INFO_ARCH "cray_t90" # elif (_ADDR32) # define ACC_ARCH_CRAY_YMP 1 # define ACC_INFO_ARCH "cray_ymp" # else # define ACC_ARCH_CRAY_XMP 1 # define ACC_INFO_ARCH "cray_xmp" # endif # else # define ACC_ARCH_UNKNOWN 1 # define ACC_INFO_ARCH "unknown" # endif # endif # if 1 && (ACC_ARCH_UNKNOWN) && (ACC_OS_DOS32 || ACC_OS_OS2) # error "FIXME - missing define for CPU architecture" # endif # if 1 && (ACC_ARCH_UNKNOWN) && (ACC_OS_WIN32) # error "FIXME - missing WIN32 define for CPU architecture" # endif # if 1 && (ACC_ARCH_UNKNOWN) && (ACC_OS_WIN64) # error "FIXME - missing WIN64 define for CPU architecture" # endif # if (ACC_OS_OS216 || ACC_OS_WIN16) # define ACC_ARCH_I086PM 1 # define ACC_ARCH_IA16PM 1 # elif 1 && (ACC_OS_DOS16 && defined(BLX286)) # define ACC_ARCH_I086PM 1 # define ACC_ARCH_IA16PM 1 # elif 1 && (ACC_OS_DOS16 && defined(DOSX286)) # define ACC_ARCH_I086PM 1 # define ACC_ARCH_IA16PM 1 # elif 1 && (ACC_OS_DOS16 && ACC_CC_BORLANDC && defined(__DPMI16__)) # define ACC_ARCH_I086PM 1 # define ACC_ARCH_IA16PM 1 # endif # if defined(ACC_ARCH_ARM_THUMB) && !defined(ACC_ARCH_ARM) # error "this should not happen" # endif # if defined(ACC_ARCH_I086PM) && !defined(ACC_ARCH_I086) # error "this should not happen" # endif # if (ACC_ARCH_I086) # if (UINT_MAX != ACC_0xffffL) # error "this should not happen" # endif # if (ULONG_MAX != ACC_0xffffffffL) # error "this should not happen" # endif # endif # if (ACC_ARCH_I386) # if (UINT_MAX != ACC_0xffffL) && defined(__i386_int16__) # error "this should not happen" # endif # if (UINT_MAX != ACC_0xffffffffL) && !defined(__i386_int16__) # error "this should not happen" # endif # if (ULONG_MAX != ACC_0xffffffffL) # error "this should not happen" # endif # endif # if !defined(__ACC_MM_OVERRIDE) # if (ACC_ARCH_I086) # if (UINT_MAX != ACC_0xffffL) # error "this should not happen" # endif # if defined(__TINY__) || defined(M_I86TM) || defined(_M_I86TM) # define ACC_MM_TINY 1 # elif defined(__HUGE__) || defined(_HUGE_) || defined(M_I86HM) || defined(_M_I86HM) # define ACC_MM_HUGE 1 # elif defined(__SMALL__) || defined(M_I86SM) || defined(_M_I86SM) || defined(SMALL_MODEL) # define ACC_MM_SMALL 1 # elif defined(__MEDIUM__) || defined(M_I86MM) || defined(_M_I86MM) # define ACC_MM_MEDIUM 1 # elif defined(__COMPACT__) || defined(M_I86CM) || defined(_M_I86CM) # define ACC_MM_COMPACT 1 # elif defined(__LARGE__) || defined(M_I86LM) || defined(_M_I86LM) || defined(LARGE_MODEL) # define ACC_MM_LARGE 1 # elif (ACC_CC_AZTECC) # if defined(_LARGE_CODE) && defined(_LARGE_DATA) # define ACC_MM_LARGE 1 # elif defined(_LARGE_CODE) # define ACC_MM_MEDIUM 1 # elif defined(_LARGE_DATA) # define ACC_MM_COMPACT 1 # else # define ACC_MM_SMALL 1 # endif # elif (ACC_CC_ZORTECHC && defined(__VCM__)) # define ACC_MM_LARGE 1 # else # error "unknown memory model" # endif # if (ACC_OS_DOS16 || ACC_OS_OS216 || ACC_OS_WIN16) # define ACC_HAVE_MM_HUGE_PTR 1 # define ACC_HAVE_MM_HUGE_ARRAY 1 # if (ACC_MM_TINY) # undef ACC_HAVE_MM_HUGE_ARRAY # endif # if (ACC_CC_AZTECC || ACC_CC_PACIFICC || ACC_CC_ZORTECHC) # undef ACC_HAVE_MM_HUGE_PTR # undef ACC_HAVE_MM_HUGE_ARRAY # elif (ACC_CC_DMC || ACC_CC_SYMANTECC) # undef ACC_HAVE_MM_HUGE_ARRAY # elif (ACC_CC_MSC && defined(_QC)) # undef ACC_HAVE_MM_HUGE_ARRAY # if (_MSC_VER < 600) # undef ACC_HAVE_MM_HUGE_PTR # endif # elif (ACC_CC_TURBOC && (__TURBOC__ < 0x0295)) # undef ACC_HAVE_MM_HUGE_ARRAY # endif # if (ACC_ARCH_I086PM) && !defined(ACC_HAVE_MM_HUGE_PTR) # if (ACC_OS_DOS16) # error "this should not happen" # elif (ACC_CC_ZORTECHC) # else # error "this should not happen" # endif # endif # ifdef __cplusplus extern "C" { # endif # if (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0200)) extern void __near __cdecl _AHSHIFT(void); # define ACC_MM_AHSHIFT ((unsigned) _AHSHIFT) # elif (ACC_CC_DMC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) extern void __near __cdecl _AHSHIFT(void); # define ACC_MM_AHSHIFT ((unsigned) _AHSHIFT) # elif (ACC_CC_MSC || ACC_CC_TOPSPEEDC) extern void __near __cdecl _AHSHIFT(void); # define ACC_MM_AHSHIFT ((unsigned) _AHSHIFT) # elif (ACC_CC_TURBOC && (__TURBOC__ >= 0x0295)) extern void __near __cdecl _AHSHIFT(void); # define ACC_MM_AHSHIFT ((unsigned) _AHSHIFT) # elif ((ACC_CC_AZTECC || ACC_CC_PACIFICC || ACC_CC_TURBOC) && ACC_OS_DOS16) # define ACC_MM_AHSHIFT 12 # elif (ACC_CC_WATCOMC) extern unsigned char _HShift; # define ACC_MM_AHSHIFT ((unsigned) _HShift) # else # error "FIXME - implement ACC_MM_AHSHIFT" # endif # ifdef __cplusplus } # endif # endif # elif (ACC_ARCH_C166) # if !defined(__MODEL__) # error "FIXME - C166 __MODEL__" # elif ((__MODEL__) == 0) # define ACC_MM_SMALL 1 # elif ((__MODEL__) == 1) # define ACC_MM_SMALL 1 # elif ((__MODEL__) == 2) # define ACC_MM_LARGE 1 # elif ((__MODEL__) == 3) # define ACC_MM_TINY 1 # elif ((__MODEL__) == 4) # define ACC_MM_XTINY 1 # elif ((__MODEL__) == 5) # define ACC_MM_XSMALL 1 # else # error "FIXME - C166 __MODEL__" # endif # elif (ACC_ARCH_MCS251) # if !defined(__MODEL__) # error "FIXME - MCS251 __MODEL__" # elif ((__MODEL__) == 0) # define ACC_MM_SMALL 1 # elif ((__MODEL__) == 2) # define ACC_MM_LARGE 1 # elif ((__MODEL__) == 3) # define ACC_MM_TINY 1 # elif ((__MODEL__) == 4) # define ACC_MM_XTINY 1 # elif ((__MODEL__) == 5) # define ACC_MM_XSMALL 1 # else # error "FIXME - MCS251 __MODEL__" # endif # elif (ACC_ARCH_MCS51) # if !defined(__MODEL__) # error "FIXME - MCS51 __MODEL__" # elif ((__MODEL__) == 1) # define ACC_MM_SMALL 1 # elif ((__MODEL__) == 2) # define ACC_MM_LARGE 1 # elif ((__MODEL__) == 3) # define ACC_MM_TINY 1 # elif ((__MODEL__) == 4) # define ACC_MM_XTINY 1 # elif ((__MODEL__) == 5) # define ACC_MM_XSMALL 1 # else # error "FIXME - MCS51 __MODEL__" # endif # elif (ACC_ARCH_CRAY_PVP) # define ACC_MM_PVP 1 # else # define ACC_MM_FLAT 1 # endif # if (ACC_MM_COMPACT) # define ACC_INFO_MM "compact" # elif (ACC_MM_FLAT) # define ACC_INFO_MM "flat" # elif (ACC_MM_HUGE) # define ACC_INFO_MM "huge" # elif (ACC_MM_LARGE) # define ACC_INFO_MM "large" # elif (ACC_MM_MEDIUM) # define ACC_INFO_MM "medium" # elif (ACC_MM_PVP) # define ACC_INFO_MM "pvp" # elif (ACC_MM_SMALL) # define ACC_INFO_MM "small" # elif (ACC_MM_TINY) # define ACC_INFO_MM "tiny" # else # error "unknown memory model" # endif # endif # if defined(SIZEOF_SHORT) # define ACC_SIZEOF_SHORT (SIZEOF_SHORT) # endif # if defined(SIZEOF_INT) # define ACC_SIZEOF_INT (SIZEOF_INT) # endif # if defined(SIZEOF_LONG) # define ACC_SIZEOF_LONG (SIZEOF_LONG) # endif # if defined(SIZEOF_LONG_LONG) # define ACC_SIZEOF_LONG_LONG (SIZEOF_LONG_LONG) # endif # if defined(SIZEOF___INT16) # define ACC_SIZEOF___INT16 (SIZEOF___INT16) # endif # if defined(SIZEOF___INT32) # define ACC_SIZEOF___INT32 (SIZEOF___INT32) # endif # if defined(SIZEOF___INT64) # define ACC_SIZEOF___INT64 (SIZEOF___INT64) # endif # if defined(SIZEOF_VOID_P) # define ACC_SIZEOF_VOID_P (SIZEOF_VOID_P) # endif # if defined(SIZEOF_SIZE_T) # define ACC_SIZEOF_SIZE_T (SIZEOF_SIZE_T) # endif # if defined(SIZEOF_PTRDIFF_T) # define ACC_SIZEOF_PTRDIFF_T (SIZEOF_PTRDIFF_T) # endif # define __ACC_LSR(x,b) (((x)+0ul) >> (b)) # if !defined(ACC_SIZEOF_SHORT) # if (ACC_ARCH_CRAY_PVP) # define ACC_SIZEOF_SHORT 8 # elif (USHRT_MAX == ACC_0xffffL) # define ACC_SIZEOF_SHORT 2 # elif (__ACC_LSR(USHRT_MAX,7) == 1) # define ACC_SIZEOF_SHORT 1 # elif (__ACC_LSR(USHRT_MAX,15) == 1) # define ACC_SIZEOF_SHORT 2 # elif (__ACC_LSR(USHRT_MAX,31) == 1) # define ACC_SIZEOF_SHORT 4 # elif (__ACC_LSR(USHRT_MAX,63) == 1) # define ACC_SIZEOF_SHORT 8 # elif (__ACC_LSR(USHRT_MAX,127) == 1) # define ACC_SIZEOF_SHORT 16 # else # error "ACC_SIZEOF_SHORT" # endif # endif # if !defined(ACC_SIZEOF_INT) # if (ACC_ARCH_CRAY_PVP) # define ACC_SIZEOF_INT 8 # elif (UINT_MAX == ACC_0xffffL) # define ACC_SIZEOF_INT 2 # elif (UINT_MAX == ACC_0xffffffffL) # define ACC_SIZEOF_INT 4 # elif (__ACC_LSR(UINT_MAX,7) == 1) # define ACC_SIZEOF_INT 1 # elif (__ACC_LSR(UINT_MAX,15) == 1) # define ACC_SIZEOF_INT 2 # elif (__ACC_LSR(UINT_MAX,31) == 1) # define ACC_SIZEOF_INT 4 # elif (__ACC_LSR(UINT_MAX,63) == 1) # define ACC_SIZEOF_INT 8 # elif (__ACC_LSR(UINT_MAX,127) == 1) # define ACC_SIZEOF_INT 16 # else # error "ACC_SIZEOF_INT" # endif # endif # if !defined(ACC_SIZEOF_LONG) # if (ULONG_MAX == ACC_0xffffffffL) # define ACC_SIZEOF_LONG 4 # elif (__ACC_LSR(ULONG_MAX,7) == 1) # define ACC_SIZEOF_LONG 1 # elif (__ACC_LSR(ULONG_MAX,15) == 1) # define ACC_SIZEOF_LONG 2 # elif (__ACC_LSR(ULONG_MAX,31) == 1) # define ACC_SIZEOF_LONG 4 # elif (__ACC_LSR(ULONG_MAX,63) == 1) # define ACC_SIZEOF_LONG 8 # elif (__ACC_LSR(ULONG_MAX,127) == 1) # define ACC_SIZEOF_LONG 16 # else # error "ACC_SIZEOF_LONG" # endif # endif # if !defined(ACC_SIZEOF_LONG_LONG) && !defined(ACC_SIZEOF___INT64) # if (ACC_SIZEOF_LONG > 0 && ACC_SIZEOF_LONG < 8) # if defined(__LONG_MAX__) && defined(__LONG_LONG_MAX__) # if (ACC_CC_GNUC >= 0x030300ul) # if ((__LONG_MAX__)+0 == (__LONG_LONG_MAX__)+0) # define ACC_SIZEOF_LONG_LONG ACC_SIZEOF_LONG # elif (__ACC_LSR(__LONG_LONG_MAX__,30) == 1) # define ACC_SIZEOF_LONG_LONG 4 # endif # endif # endif # endif # endif # if !defined(ACC_SIZEOF_LONG_LONG) && !defined(ACC_SIZEOF___INT64) # if (ACC_SIZEOF_LONG > 0 && ACC_SIZEOF_LONG < 8) # if (ACC_ARCH_I086 && ACC_CC_DMC) # elif (ACC_CC_CILLY) && defined(__GNUC__) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE) # define ACC_SIZEOF_LONG_LONG 8 # elif ((ACC_OS_WIN32 || ACC_OS_WIN64 || defined(_WIN32)) && ACC_CC_MSC && (_MSC_VER >= 1400)) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_OS_WIN64 || defined(_WIN64)) # define ACC_SIZEOF___INT64 8 # elif (ACC_ARCH_I386 && (ACC_CC_DMC)) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_ARCH_I386 && (ACC_CC_SYMANTECC && (__SC__ >= 0x700))) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_ARCH_I386 && (ACC_CC_INTELC && defined(__linux__))) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_ARCH_I386 && (ACC_CC_MWERKS || ACC_CC_PELLESC || ACC_CC_PGI || ACC_CC_SUNPROC)) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_ARCH_I386 && (ACC_CC_INTELC || ACC_CC_MSC)) # define ACC_SIZEOF___INT64 8 # elif ((ACC_OS_WIN32 || defined(_WIN32)) && (ACC_CC_MSC)) # define ACC_SIZEOF___INT64 8 # elif (ACC_ARCH_I386 && (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0520))) # define ACC_SIZEOF___INT64 8 # elif (ACC_ARCH_I386 && (ACC_CC_WATCOMC && (__WATCOMC__ >= 1100))) # define ACC_SIZEOF___INT64 8 # elif (ACC_CC_WATCOMC && defined(_INTEGRAL_MAX_BITS) && (_INTEGRAL_MAX_BITS == 64)) # define ACC_SIZEOF___INT64 8 # elif (ACC_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define ACC_SIZEOF_LONG_LONG 8 # elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define ACC_SIZEOF_LONG_LONG 8 # elif (ACC_CC_SDCC) && (ACC_SIZEOF_INT == 2) # elif 1 && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define ACC_SIZEOF_LONG_LONG 8 # endif # endif # endif # if defined(__cplusplus) && defined(ACC_CC_GNUC) # if (ACC_CC_GNUC < 0x020800ul) # undef ACC_SIZEOF_LONG_LONG # endif # endif # if defined(ACC_CFG_NO_LONG_LONG) || defined(__NO_LONG_LONG) # undef ACC_SIZEOF_LONG_LONG # endif # if !defined(ACC_SIZEOF_VOID_P) # if (ACC_ARCH_I086) # define __ACC_WORDSIZE 2 # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM) # define ACC_SIZEOF_VOID_P 2 # elif (ACC_MM_COMPACT || ACC_MM_LARGE || ACC_MM_HUGE) # define ACC_SIZEOF_VOID_P 4 # else # error "ACC_MM" # endif # elif (ACC_ARCH_AVR || ACC_ARCH_Z80) # define __ACC_WORDSIZE 1 # define ACC_SIZEOF_VOID_P 2 # elif (ACC_ARCH_C166 || ACC_ARCH_MCS51 || ACC_ARCH_MCS251 || ACC_ARCH_MSP430) # define ACC_SIZEOF_VOID_P 2 # elif (ACC_ARCH_H8300) # if defined(__NORMAL_MODE__) # define __ACC_WORDSIZE 4 # define ACC_SIZEOF_VOID_P 2 # elif defined(__H8300H__) || defined(__H8300S__) || defined(__H8300SX__) # define __ACC_WORDSIZE 4 # define ACC_SIZEOF_VOID_P 4 # else # define __ACC_WORDSIZE 2 # define ACC_SIZEOF_VOID_P 2 # endif # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x040000ul)) && (ACC_SIZEOF_INT == 4) # define ACC_SIZEOF_SIZE_T ACC_SIZEOF_INT # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_INT # endif # elif (ACC_ARCH_M16C) # define __ACC_WORDSIZE 2 # if defined(__m32c_cpu__) || defined(__m32cm_cpu__) # define ACC_SIZEOF_VOID_P 4 # else # define ACC_SIZEOF_VOID_P 2 # endif # elif (ACC_SIZEOF_LONG == 8) && ((defined(__mips__) && defined(__R5900__)) || defined(__MIPS_PSX2__)) # define __ACC_WORDSIZE 8 # define ACC_SIZEOF_VOID_P 4 # elif defined(__LLP64__) || defined(__LLP64) || defined(_LLP64) || defined(_WIN64) # define __ACC_WORDSIZE 8 # define ACC_SIZEOF_VOID_P 8 # elif (ACC_OS_OS400 || defined(__OS400__)) && defined(__LLP64_IFC__) # define ACC_SIZEOF_VOID_P ACC_SIZEOF_LONG # define ACC_SIZEOF_SIZE_T ACC_SIZEOF_LONG # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_LONG # elif (ACC_OS_OS400 || defined(__OS400__)) # define __ACC_WORDSIZE ACC_SIZEOF_LONG # define ACC_SIZEOF_VOID_P 16 # define ACC_SIZEOF_SIZE_T ACC_SIZEOF_LONG # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_LONG # elif (defined(__vms) || defined(__VMS)) && (__INITIAL_POINTER_SIZE+0 == 64) # define ACC_SIZEOF_VOID_P 8 # define ACC_SIZEOF_SIZE_T ACC_SIZEOF_LONG # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_LONG # elif (ACC_ARCH_SPU) # if 0 # define __ACC_WORDSIZE 16 # endif # define ACC_SIZEOF_VOID_P 4 # else # define ACC_SIZEOF_VOID_P ACC_SIZEOF_LONG # endif # endif # if !defined(ACC_WORDSIZE) # if defined(__ACC_WORDSIZE) # define ACC_WORDSIZE __ACC_WORDSIZE # else # define ACC_WORDSIZE ACC_SIZEOF_VOID_P # endif # endif # if !defined(ACC_SIZEOF_SIZE_T) # if (ACC_ARCH_I086 || ACC_ARCH_M16C) # define ACC_SIZEOF_SIZE_T 2 # else # define ACC_SIZEOF_SIZE_T ACC_SIZEOF_VOID_P # endif # endif # if !defined(ACC_SIZEOF_PTRDIFF_T) # if (ACC_ARCH_I086) # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM || ACC_MM_HUGE) # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_VOID_P # elif (ACC_MM_COMPACT || ACC_MM_LARGE) # if (ACC_CC_BORLANDC || ACC_CC_TURBOC) # define ACC_SIZEOF_PTRDIFF_T 4 # else # define ACC_SIZEOF_PTRDIFF_T 2 # endif # else # error "ACC_MM" # endif # else # define ACC_SIZEOF_PTRDIFF_T ACC_SIZEOF_SIZE_T # endif # endif # if defined(ACC_ABI_NEUTRAL_ENDIAN) # undef ACC_ABI_BIG_ENDIAN # undef ACC_ABI_LITTLE_ENDIAN # elif !defined(ACC_ABI_BIG_ENDIAN) && !defined(ACC_ABI_LITTLE_ENDIAN) # if (ACC_ARCH_ALPHA) && (ACC_ARCH_CRAY_MPP) # define ACC_ABI_BIG_ENDIAN 1 # elif (ACC_ARCH_ALPHA || ACC_ARCH_AMD64 || ACC_ARCH_BLACKFIN || ACC_ARCH_CRIS || ACC_ARCH_I086 || ACC_ARCH_I386 || ACC_ARCH_MSP430) # define ACC_ABI_LITTLE_ENDIAN 1 # elif (ACC_ARCH_M68K || ACC_ARCH_S390) # define ACC_ABI_BIG_ENDIAN 1 # elif 1 && defined(__IAR_SYSTEMS_ICC__) && defined(__LITTLE_ENDIAN__) # if (__LITTLE_ENDIAN__ == 1) # define ACC_ABI_LITTLE_ENDIAN 1 # else # define ACC_ABI_BIG_ENDIAN 1 # endif # elif 1 && defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) # define ACC_ABI_BIG_ENDIAN 1 # elif 1 && defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) # define ACC_ABI_LITTLE_ENDIAN 1 # elif 1 && (ACC_ARCH_ARM) && defined(__ARMEB__) && !defined(__ARMEL__) # define ACC_ABI_BIG_ENDIAN 1 # elif 1 && (ACC_ARCH_ARM) && defined(__ARMEL__) && !defined(__ARMEB__) # define ACC_ABI_LITTLE_ENDIAN 1 # elif 1 && (ACC_ARCH_MIPS) && defined(__MIPSEB__) && !defined(__MIPSEL__) # define ACC_ABI_BIG_ENDIAN 1 # elif 1 && (ACC_ARCH_MIPS) && defined(__MIPSEL__) && !defined(__MIPSEB__) # define ACC_ABI_LITTLE_ENDIAN 1 # endif # endif # if defined(ACC_ABI_BIG_ENDIAN) && defined(ACC_ABI_LITTLE_ENDIAN) # error "this should not happen" # endif # if defined(ACC_ABI_BIG_ENDIAN) # define ACC_INFO_ABI_ENDIAN "be" # elif defined(ACC_ABI_LITTLE_ENDIAN) # define ACC_INFO_ABI_ENDIAN "le" # elif defined(ACC_ABI_NEUTRAL_ENDIAN) # define ACC_INFO_ABI_ENDIAN "neutral" # endif # if (ACC_SIZEOF_INT == 1 && ACC_SIZEOF_LONG == 2 && ACC_SIZEOF_VOID_P == 2) # define ACC_ABI_I8LP16 1 # define ACC_INFO_ABI_PM "i8lp16" # elif (ACC_SIZEOF_INT == 2 && ACC_SIZEOF_LONG == 2 && ACC_SIZEOF_VOID_P == 2) # define ACC_ABI_ILP16 1 # define ACC_INFO_ABI_PM "ilp16" # elif (ACC_SIZEOF_INT == 4 && ACC_SIZEOF_LONG == 4 && ACC_SIZEOF_VOID_P == 4) # define ACC_ABI_ILP32 1 # define ACC_INFO_ABI_PM "ilp32" # elif (ACC_SIZEOF_INT == 4 && ACC_SIZEOF_LONG == 4 && ACC_SIZEOF_VOID_P == 8 && ACC_SIZEOF_SIZE_T == 8) # define ACC_ABI_LLP64 1 # define ACC_INFO_ABI_PM "llp64" # elif (ACC_SIZEOF_INT == 4 && ACC_SIZEOF_LONG == 8 && ACC_SIZEOF_VOID_P == 8) # define ACC_ABI_LP64 1 # define ACC_INFO_ABI_PM "lp64" # elif (ACC_SIZEOF_INT == 8 && ACC_SIZEOF_LONG == 8 && ACC_SIZEOF_VOID_P == 8) # define ACC_ABI_ILP64 1 # define ACC_INFO_ABI_PM "ilp64" # elif (ACC_SIZEOF_INT == 4 && ACC_SIZEOF_LONG == 8 && ACC_SIZEOF_VOID_P == 4) # define ACC_ABI_IP32L64 1 # define ACC_INFO_ABI_PM "ip32l64" # endif # if !defined(__ACC_LIBC_OVERRIDE) # if defined(ACC_LIBC_NAKED) # define ACC_INFO_LIBC "naked" # elif defined(ACC_LIBC_FREESTANDING) # define ACC_INFO_LIBC "freestanding" # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # define ACC_INFO_LIBC "mfreestanding" # elif defined(ACC_LIBC_ISOC90) # define ACC_INFO_LIBC "isoc90" # elif defined(ACC_LIBC_ISOC99) # define ACC_INFO_LIBC "isoc99" # elif defined(__dietlibc__) # define ACC_LIBC_DIETLIBC 1 # define ACC_INFO_LIBC "dietlibc" # elif defined(_NEWLIB_VERSION) # define ACC_LIBC_NEWLIB 1 # define ACC_INFO_LIBC "newlib" # elif defined(__UCLIBC__) && defined(__UCLIBC_MAJOR__) && defined(__UCLIBC_MINOR__) # if defined(__UCLIBC_SUBLEVEL__) # define ACC_LIBC_UCLIBC (__UCLIBC_MAJOR__ * 0x10000L + __UCLIBC_MINOR__ * 0x100 + __UCLIBC_SUBLEVEL__) # else # define ACC_LIBC_UCLIBC 0x00090bL # endif # define ACC_INFO_LIBC "uclibc" # elif defined(__GLIBC__) && defined(__GLIBC_MINOR__) # define ACC_LIBC_GLIBC (__GLIBC__ * 0x10000L + __GLIBC_MINOR__ * 0x100) # define ACC_INFO_LIBC "glibc" # elif (ACC_CC_MWERKS) && defined(__MSL__) # define ACC_LIBC_MSL __MSL__ # define ACC_INFO_LIBC "msl" # elif 1 && defined(__IAR_SYSTEMS_ICC__) # define ACC_LIBC_ISOC90 1 # define ACC_INFO_LIBC "isoc90" # else # define ACC_LIBC_DEFAULT 1 # define ACC_INFO_LIBC "default" # endif # endif # if !defined(__acc_gnuc_extension__) # if (ACC_CC_GNUC >= 0x020800ul) # define __acc_gnuc_extension__ __extension__ # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_gnuc_extension__ __extension__ # else # define __acc_gnuc_extension__ # endif # endif # if !defined(__acc_ua_volatile) # define __acc_ua_volatile volatile # endif # if !defined(__acc_alignof) # if (ACC_CC_CILLY || ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE || ACC_CC_PGI) # define __acc_alignof(e) __alignof__(e) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 700)) # define __acc_alignof(e) __alignof__(e) # elif (ACC_CC_MSC && (_MSC_VER >= 1300)) # define __acc_alignof(e) __alignof(e) # endif # endif # if defined(__acc_alignof) # define __acc_HAVE_alignof 1 # endif # if !defined(__acc_constructor) # if (ACC_CC_GNUC >= 0x030400ul) # define __acc_constructor __attribute__((__constructor__,__used__)) # elif (ACC_CC_GNUC >= 0x020700ul) # define __acc_constructor __attribute__((__constructor__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_constructor __attribute__((__constructor__)) # endif # endif # if defined(__acc_constructor) # define __acc_HAVE_constructor 1 # endif # if !defined(__acc_destructor) # if (ACC_CC_GNUC >= 0x030400ul) # define __acc_destructor __attribute__((__destructor__,__used__)) # elif (ACC_CC_GNUC >= 0x020700ul) # define __acc_destructor __attribute__((__destructor__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_destructor __attribute__((__destructor__)) # endif # endif # if defined(__acc_destructor) # define __acc_HAVE_destructor 1 # endif # if defined(__acc_HAVE_destructor) && !defined(__acc_HAVE_constructor) # error "this should not happen" # endif # if !defined(__acc_inline) # if (ACC_CC_TURBOC && (__TURBOC__ <= 0x0295)) # elif defined(__cplusplus) # define __acc_inline inline # elif (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0550)) # define __acc_inline __inline # elif (ACC_CC_CILLY || ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE || ACC_CC_PGI) # define __acc_inline __inline__ # elif (ACC_CC_DMC) # define __acc_inline __inline # elif (ACC_CC_INTELC) # define __acc_inline __inline # elif (ACC_CC_MWERKS && (__MWERKS__ >= 0x2405)) # define __acc_inline __inline # elif (ACC_CC_MSC && (_MSC_VER >= 900)) # define __acc_inline __inline # elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) # define __acc_inline inline # endif # endif # if defined(__acc_inline) # define __acc_HAVE_inline 1 # else # define __acc_inline # endif # if !defined(__acc_forceinline) # if (ACC_CC_GNUC >= 0x030200ul) # define __acc_forceinline __inline__ __attribute__((__always_inline__)) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 450) && ACC_CC_SYNTAX_MSC) # define __acc_forceinline __forceinline # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 800) && ACC_CC_SYNTAX_GNUC) # define __acc_forceinline __inline__ __attribute__((__always_inline__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_forceinline __inline__ __attribute__((__always_inline__)) # elif (ACC_CC_MSC && (_MSC_VER >= 1200)) # define __acc_forceinline __forceinline # endif # endif # if defined(__acc_forceinline) # define __acc_HAVE_forceinline 1 # else # define __acc_forceinline # endif # if !defined(__acc_noinline) # if 1 && (ACC_ARCH_I386) && (ACC_CC_GNUC >= 0x040000ul) && (ACC_CC_GNUC < 0x040003ul) # define __acc_noinline __attribute__((__noinline__,__used__)) # elif (ACC_CC_GNUC >= 0x030200ul) # define __acc_noinline __attribute__((__noinline__)) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 600) && ACC_CC_SYNTAX_MSC) # define __acc_noinline __declspec(noinline) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 800) && ACC_CC_SYNTAX_GNUC) # define __acc_noinline __attribute__((__noinline__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_noinline __attribute__((__noinline__)) # elif (ACC_CC_MSC && (_MSC_VER >= 1300)) # define __acc_noinline __declspec(noinline) # elif (ACC_CC_MWERKS && (__MWERKS__ >= 0x3200) && (ACC_OS_WIN32 || ACC_OS_WIN64)) # if defined(__cplusplus) # else # define __acc_noinline __declspec(noinline) # endif # endif # endif # if defined(__acc_noinline) # define __acc_HAVE_noinline 1 # else # define __acc_noinline # endif # if (defined(__acc_HAVE_forceinline) || defined(__acc_HAVE_noinline)) && !defined(__acc_HAVE_inline) # error "this should not happen" # endif # if !defined(__acc_noreturn) # if (ACC_CC_GNUC >= 0x020700ul) # define __acc_noreturn __attribute__((__noreturn__)) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 450) && ACC_CC_SYNTAX_MSC) # define __acc_noreturn __declspec(noreturn) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 600) && ACC_CC_SYNTAX_GNUC) # define __acc_noreturn __attribute__((__noreturn__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_noreturn __attribute__((__noreturn__)) # elif (ACC_CC_MSC && (_MSC_VER >= 1200)) # define __acc_noreturn __declspec(noreturn) # endif # endif # if defined(__acc_noreturn) # define __acc_HAVE_noreturn 1 # else # define __acc_noreturn # endif # if !defined(__acc_nothrow) # if (ACC_CC_GNUC >= 0x030300ul) # define __acc_nothrow __attribute__((__nothrow__)) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 450) && ACC_CC_SYNTAX_MSC) && defined(__cplusplus) # define __acc_nothrow __declspec(nothrow) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 800) && ACC_CC_SYNTAX_GNUC) # define __acc_nothrow __attribute__((__nothrow__)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_nothrow __attribute__((__nothrow__)) # elif (ACC_CC_MSC && (_MSC_VER >= 1200)) && defined(__cplusplus) # define __acc_nothrow __declspec(nothrow) # endif # endif # if defined(__acc_nothrow) # define __acc_HAVE_nothrow 1 # else # define __acc_nothrow # endif # if !defined(__acc_restrict) # if (ACC_CC_GNUC >= 0x030400ul) # define __acc_restrict __restrict__ # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 600) && ACC_CC_SYNTAX_GNUC) # define __acc_restrict __restrict__ # elif (ACC_CC_LLVM) # define __acc_restrict __restrict__ # elif (ACC_CC_MSC && (_MSC_VER >= 1400)) # define __acc_restrict __restrict # endif # endif # if defined(__acc_restrict) # define __acc_HAVE_restrict 1 # else # define __acc_restrict # endif # if !defined(__acc_likely) && !defined(__acc_unlikely) # if (ACC_CC_GNUC >= 0x030200ul) # define __acc_likely(e) (__builtin_expect(!!(e),1)) # define __acc_unlikely(e) (__builtin_expect(!!(e),0)) # elif (ACC_CC_INTELC && (__INTEL_COMPILER >= 800)) # define __acc_likely(e) (__builtin_expect(!!(e),1)) # define __acc_unlikely(e) (__builtin_expect(!!(e),0)) # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __acc_likely(e) (__builtin_expect(!!(e),1)) # define __acc_unlikely(e) (__builtin_expect(!!(e),0)) # endif # endif # if defined(__acc_likely) # define __acc_HAVE_likely 1 # else # define __acc_likely(e) (e) # endif # if defined(__acc_unlikely) # define __acc_HAVE_unlikely 1 # else # define __acc_unlikely(e) (e) # endif # if !defined(ACC_UNUSED) # if (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define ACC_UNUSED(var) ((void) &var) # elif (ACC_CC_BORLANDC || ACC_CC_HIGHC || ACC_CC_NDPC || ACC_CC_PELLESC || ACC_CC_TURBOC) # define ACC_UNUSED(var) if (&var) ; else # elif (ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE) # define ACC_UNUSED(var) ((void) var) # elif (ACC_CC_MSC && (_MSC_VER < 900)) # define ACC_UNUSED(var) if (&var) ; else # elif (ACC_CC_KEILC) # define ACC_UNUSED(var) {extern int __acc_unused[1-2*!(sizeof(var)>0)];} # elif (ACC_CC_PACIFICC) # define ACC_UNUSED(var) ((void) sizeof(var)) # elif (ACC_CC_WATCOMC) && defined(__cplusplus) # define ACC_UNUSED(var) ((void) var) # else # define ACC_UNUSED(var) ((void) &var) # endif # endif # if !defined(ACC_UNUSED_FUNC) # if (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0600)) # define ACC_UNUSED_FUNC(func) ((void) func) # elif (ACC_CC_BORLANDC || ACC_CC_NDPC || ACC_CC_TURBOC) # define ACC_UNUSED_FUNC(func) if (func) ; else # elif (ACC_CC_LLVM) # define ACC_UNUSED_FUNC(func) ((void) &func) # elif (ACC_CC_MSC && (_MSC_VER < 900)) # define ACC_UNUSED_FUNC(func) if (func) ; else # elif (ACC_CC_MSC) # define ACC_UNUSED_FUNC(func) ((void) &func) # elif (ACC_CC_KEILC || ACC_CC_PELLESC) # define ACC_UNUSED_FUNC(func) {extern int __acc_unused[1-2*!(sizeof((int)func)>0)];} # else # define ACC_UNUSED_FUNC(func) ((void) func) # endif # endif # if !defined(ACC_UNUSED_LABEL) # if (ACC_CC_WATCOMC) && defined(__cplusplus) # define ACC_UNUSED_LABEL(l) switch(0) case 1:goto l # elif (ACC_CC_INTELC || ACC_CC_WATCOMC) # define ACC_UNUSED_LABEL(l) if (0) goto l # else # define ACC_UNUSED_LABEL(l) switch(0) case 1:goto l # endif # endif # if !defined(ACC_DEFINE_UNINITIALIZED_VAR) # if 0 # define ACC_DEFINE_UNINITIALIZED_VAR(type,var,init) type var # elif 0 && (ACC_CC_GNUC) # define ACC_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = var # else # define ACC_DEFINE_UNINITIALIZED_VAR(type,var,init) type var = init # endif # endif # if !defined(ACC_COMPILE_TIME_ASSERT_HEADER) # if (ACC_CC_AZTECC || ACC_CC_ZORTECHC) # define ACC_COMPILE_TIME_ASSERT_HEADER(e) extern int __acc_cta[1-!(e)]; # elif (ACC_CC_DMC || ACC_CC_SYMANTECC) # define ACC_COMPILE_TIME_ASSERT_HEADER(e) extern int __acc_cta[1u-2*!(e)]; # elif (ACC_CC_TURBOC && (__TURBOC__ == 0x0295)) # define ACC_COMPILE_TIME_ASSERT_HEADER(e) extern int __acc_cta[1-!(e)]; # else # define ACC_COMPILE_TIME_ASSERT_HEADER(e) extern int __acc_cta[1-2*!(e)]; # endif # endif # if !defined(ACC_COMPILE_TIME_ASSERT) # if (ACC_CC_AZTECC) # define ACC_COMPILE_TIME_ASSERT(e) {typedef int __acc_cta_t[1-!(e)];} # elif (ACC_CC_DMC || ACC_CC_PACIFICC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) # define ACC_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (ACC_CC_MSC && (_MSC_VER < 900)) # define ACC_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # elif (ACC_CC_TURBOC && (__TURBOC__ == 0x0295)) # define ACC_COMPILE_TIME_ASSERT(e) switch(0) case 1:case !(e):break; # else # define ACC_COMPILE_TIME_ASSERT(e) {typedef int __acc_cta_t[1-2*!(e)];} # endif # endif # if (ACC_ARCH_I086 || ACC_ARCH_I386) && (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) # if (ACC_CC_GNUC || ACC_CC_HIGHC || ACC_CC_NDPC || ACC_CC_PACIFICC) # elif (ACC_CC_DMC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) # define __acc_cdecl __cdecl # define __acc_cdecl_atexit # define __acc_cdecl_main __cdecl # if (ACC_OS_OS2 && (ACC_CC_DMC || ACC_CC_SYMANTECC)) # define __acc_cdecl_qsort __pascal # elif (ACC_OS_OS2 && (ACC_CC_ZORTECHC)) # define __acc_cdecl_qsort _stdcall # else # define __acc_cdecl_qsort __cdecl # endif # elif (ACC_CC_WATCOMC) # define __acc_cdecl __cdecl # else # define __acc_cdecl __cdecl # define __acc_cdecl_atexit __cdecl # define __acc_cdecl_main __cdecl # define __acc_cdecl_qsort __cdecl # endif # if (ACC_CC_GNUC || ACC_CC_HIGHC || ACC_CC_NDPC || ACC_CC_PACIFICC || ACC_CC_WATCOMC) # elif (ACC_OS_OS2 && (ACC_CC_DMC || ACC_CC_SYMANTECC)) # define __acc_cdecl_sighandler __pascal # elif (ACC_OS_OS2 && (ACC_CC_ZORTECHC)) # define __acc_cdecl_sighandler _stdcall # elif (ACC_CC_MSC && (_MSC_VER >= 1400)) && defined(_M_CEE_PURE) # define __acc_cdecl_sighandler __clrcall # elif (ACC_CC_MSC && (_MSC_VER >= 600 && _MSC_VER < 700)) # if defined(_DLL) # define __acc_cdecl_sighandler _far _cdecl _loadds # elif defined(_MT) # define __acc_cdecl_sighandler _far _cdecl # else # define __acc_cdecl_sighandler _cdecl # endif # else # define __acc_cdecl_sighandler __cdecl # endif # elif (ACC_ARCH_I386) && (ACC_CC_WATCOMC) # define __acc_cdecl __cdecl # elif (ACC_ARCH_M68K && ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) # define __acc_cdecl cdecl # endif # if !defined(__acc_cdecl) # define __acc_cdecl # endif # if !defined(__acc_cdecl_atexit) # define __acc_cdecl_atexit # endif # if !defined(__acc_cdecl_main) # define __acc_cdecl_main # endif # if !defined(__acc_cdecl_qsort) # define __acc_cdecl_qsort # endif # if !defined(__acc_cdecl_sighandler) # define __acc_cdecl_sighandler # endif # if !defined(__acc_cdecl_va) # define __acc_cdecl_va __acc_cdecl # endif # if !defined(ACC_CFG_NO_WINDOWS_H) # if (ACC_OS_CYGWIN || (ACC_OS_EMX && defined(__RSXNT__)) || ACC_OS_WIN32 || ACC_OS_WIN64) # if (ACC_CC_WATCOMC && (__WATCOMC__ < 1000)) # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) # elif ((ACC_OS_CYGWIN || defined(__MINGW32__)) && (ACC_CC_GNUC && (ACC_CC_GNUC < 0x025f00ul))) # else # define ACC_HAVE_WINDOWS_H 1 # endif # endif # endif # if (ACC_ARCH_ALPHA) # define ACC_OPT_AVOID_UINT_INDEX 1 # define ACC_OPT_AVOID_SHORT 1 # define ACC_OPT_AVOID_USHORT 1 # elif (ACC_ARCH_AMD64) # define ACC_OPT_AVOID_INT_INDEX 1 # define ACC_OPT_AVOID_UINT_INDEX 1 # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # define ACC_OPT_UNALIGNED64 1 # elif (ACC_ARCH_ARM && ACC_ARCH_ARM_THUMB) # elif (ACC_ARCH_ARM) # define ACC_OPT_AVOID_SHORT 1 # define ACC_OPT_AVOID_USHORT 1 # elif (ACC_ARCH_CRIS) # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # elif (ACC_ARCH_I386) # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # elif (ACC_ARCH_IA64) # define ACC_OPT_AVOID_INT_INDEX 1 # define ACC_OPT_AVOID_UINT_INDEX 1 # define ACC_OPT_PREFER_POSTINC 1 # elif (ACC_ARCH_M68K) # define ACC_OPT_PREFER_POSTINC 1 # define ACC_OPT_PREFER_PREDEC 1 # if defined(__mc68020__) && !defined(__mcoldfire__) # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # endif # elif (ACC_ARCH_MIPS) # define ACC_OPT_AVOID_UINT_INDEX 1 # elif (ACC_ARCH_POWERPC) # define ACC_OPT_PREFER_PREINC 1 # define ACC_OPT_PREFER_PREDEC 1 # if defined(ACC_ABI_BIG_ENDIAN) # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # endif # elif (ACC_ARCH_S390) # define ACC_OPT_UNALIGNED16 1 # define ACC_OPT_UNALIGNED32 1 # if (ACC_SIZEOF_SIZE_T == 8) # define ACC_OPT_UNALIGNED64 1 # endif # elif (ACC_ARCH_SH) # define ACC_OPT_PREFER_POSTINC 1 # define ACC_OPT_PREFER_PREDEC 1 # endif # if !defined(ACC_CFG_NO_INLINE_ASM) # if defined(ACC_CC_LLVM) # define ACC_CFG_NO_INLINE_ASM 1 # endif # endif # if !defined(ACC_CFG_NO_UNALIGNED) # if defined(ACC_ABI_NEUTRAL_ENDIAN) || defined(ACC_ARCH_GENERIC) # define ACC_CFG_NO_UNALIGNED 1 # endif # endif # if defined(ACC_CFG_NO_UNALIGNED) # undef ACC_OPT_UNALIGNED16 # undef ACC_OPT_UNALIGNED32 # undef ACC_OPT_UNALIGNED64 # endif # if defined(ACC_CFG_NO_INLINE_ASM) # elif (ACC_ARCH_I386 && (ACC_OS_DOS32 || ACC_OS_WIN32) && (ACC_CC_DMC || ACC_CC_INTELC || ACC_CC_MSC || ACC_CC_PELLESC)) # define ACC_ASM_SYNTAX_MSC 1 # elif (ACC_OS_WIN64 && (ACC_CC_DMC || ACC_CC_INTELC || ACC_CC_MSC || ACC_CC_PELLESC)) # elif (ACC_ARCH_I386 && (ACC_CC_GNUC || ACC_CC_INTELC || ACC_CC_PATHSCALE)) # define ACC_ASM_SYNTAX_GNUC 1 # elif (ACC_ARCH_AMD64 && (ACC_CC_GNUC || ACC_CC_INTELC || ACC_CC_PATHSCALE)) # define ACC_ASM_SYNTAX_GNUC 1 # endif # if (ACC_ASM_SYNTAX_GNUC) # if (ACC_ARCH_I386 && ACC_CC_GNUC && (ACC_CC_GNUC < 0x020000ul)) # define __ACC_ASM_CLOBBER "ax" # elif (ACC_CC_INTELC) # define __ACC_ASM_CLOBBER "memory" # else # define __ACC_ASM_CLOBBER "cc", "memory" # endif # endif # if defined(__ACC_INFOSTR_MM) # elif (ACC_MM_FLAT) && (defined(__ACC_INFOSTR_PM) || defined(ACC_INFO_ABI_PM)) # define __ACC_INFOSTR_MM "" # elif defined(ACC_INFO_MM) # define __ACC_INFOSTR_MM "." ACC_INFO_MM # else # define __ACC_INFOSTR_MM "" # endif # if defined(__ACC_INFOSTR_PM) # elif defined(ACC_INFO_ABI_PM) # define __ACC_INFOSTR_PM "." ACC_INFO_ABI_PM # else # define __ACC_INFOSTR_PM "" # endif # if defined(__ACC_INFOSTR_ENDIAN) # elif defined(ACC_INFO_ABI_ENDIAN) # define __ACC_INFOSTR_ENDIAN "." ACC_INFO_ABI_ENDIAN # else # define __ACC_INFOSTR_ENDIAN "" # endif # if defined(__ACC_INFOSTR_OSNAME) # elif defined(ACC_INFO_OS_CONSOLE) # define __ACC_INFOSTR_OSNAME ACC_INFO_OS "." ACC_INFO_OS_CONSOLE # elif defined(ACC_INFO_OS_POSIX) # define __ACC_INFOSTR_OSNAME ACC_INFO_OS "." ACC_INFO_OS_POSIX # else # define __ACC_INFOSTR_OSNAME ACC_INFO_OS # endif # if defined(__ACC_INFOSTR_LIBC) # elif defined(ACC_INFO_LIBC) # define __ACC_INFOSTR_LIBC "." ACC_INFO_LIBC # else # define __ACC_INFOSTR_LIBC "" # endif # if defined(__ACC_INFOSTR_CCVER) # elif defined(ACC_INFO_CCVER) # define __ACC_INFOSTR_CCVER " " ACC_INFO_CCVER # else # define __ACC_INFOSTR_CCVER "" # endif # define ACC_INFO_STRING \ ACC_INFO_ARCH __ACC_INFOSTR_MM __ACC_INFOSTR_PM __ACC_INFOSTR_ENDIAN \ " " __ACC_INFOSTR_OSNAME __ACC_INFOSTR_LIBC " " ACC_INFO_CC __ACC_INFOSTR_CCVER # if defined(ACC_CFG_NO_CONFIG_HEADER) # elif defined(ACC_CFG_CONFIG_HEADER) # else # if !defined(ACC_CFG_AUTO_NO_HEADERS) # if defined(ACC_LIBC_NAKED) # elif defined(ACC_LIBC_FREESTANDING) # define HAVE_LIMITS_H 1 # define HAVE_STDARG_H 1 # define HAVE_STDDEF_H 1 # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # define HAVE_LIMITS_H 1 # define HAVE_SETJMP_H 1 # define HAVE_STDARG_H 1 # define HAVE_STDDEF_H 1 # define HAVE_STDIO_H 1 # define HAVE_STRING_H 1 # else # define STDC_HEADERS 1 # define HAVE_ASSERT_H 1 # define HAVE_CTYPE_H 1 # define HAVE_DIRENT_H 1 # define HAVE_ERRNO_H 1 # define HAVE_FCNTL_H 1 # define HAVE_FLOAT_H 1 # define HAVE_LIMITS_H 1 # define HAVE_MALLOC_H 1 # define HAVE_MEMORY_H 1 # define HAVE_SETJMP_H 1 # define HAVE_SIGNAL_H 1 # define HAVE_STDARG_H 1 # define HAVE_STDDEF_H 1 # define HAVE_STDIO_H 1 # define HAVE_STDLIB_H 1 # define HAVE_STRING_H 1 # define HAVE_TIME_H 1 # define HAVE_UNISTD_H 1 # define HAVE_UTIME_H 1 # define HAVE_SYS_STAT_H 1 # define HAVE_SYS_TIME_H 1 # define HAVE_SYS_TYPES_H 1 # if (ACC_OS_POSIX) # if (ACC_OS_POSIX_AIX) # define HAVE_SYS_RESOURCE_H 1 # elif (ACC_OS_POSIX_FREEBSD || ACC_OS_POSIX_MACOSX || ACC_OS_POSIX_NETBSD || ACC_OS_POSIX_OPENBSD) # define HAVE_STRINGS_H 1 # undef HAVE_MALLOC_H # elif (ACC_OS_POSIX_HPUX || ACC_OS_POSIX_INTERIX) # define HAVE_ALLOCA_H 1 # elif (ACC_OS_POSIX_MACOSX && ACC_LIBC_MSL) # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # elif (ACC_OS_POSIX_SOLARIS || ACC_OS_POSIX_SUNOS) # define HAVE_ALLOCA_H 1 # endif # if (ACC_LIBC_DIETLIBC || ACC_LIBC_GLIBC || ACC_LIBC_UCLIBC) # define HAVE_STRINGS_H 1 # define HAVE_SYS_MMAN_H 1 # define HAVE_SYS_RESOURCE_H 1 # define HAVE_SYS_WAIT_H 1 # endif # if (ACC_LIBC_NEWLIB) # undef HAVE_STRINGS_H # endif # elif (ACC_OS_CYGWIN) # define HAVE_IO_H 1 # elif (ACC_OS_EMX) # define HAVE_ALLOCA_H 1 # define HAVE_IO_H 1 # elif (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) # if !defined(__MINT__) # undef HAVE_MALLOC_H # endif # elif (ACC_ARCH_M68K && ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) # undef HAVE_DIRENT_H # undef HAVE_FCNTL_H # undef HAVE_MALLOC_H # undef HAVE_MEMORY_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # endif # if (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) # define HAVE_CONIO_H 1 # define HAVE_DIRECT_H 1 # define HAVE_DOS_H 1 # define HAVE_IO_H 1 # define HAVE_SHARE_H 1 # if (ACC_CC_AZTECC) # undef HAVE_CONIO_H # undef HAVE_DIRECT_H # undef HAVE_DIRENT_H # undef HAVE_MALLOC_H # undef HAVE_SHARE_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # elif (ACC_CC_BORLANDC) # undef HAVE_UNISTD_H # undef HAVE_SYS_TIME_H # if (ACC_OS_WIN32 || ACC_OS_WIN64) # undef HAVE_DIRENT_H # endif # if (__BORLANDC__ < 0x0400) # undef HAVE_DIRENT_H # undef HAVE_UTIME_H # endif # elif (ACC_CC_DMC) # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # define HAVE_SYS_DIRENT_H 1 # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # elif (ACC_OS_DOS32 && ACC_CC_HIGHC) # define HAVE_ALLOCA_H 1 # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # elif (ACC_CC_IBMC && ACC_OS_OS2) # undef HAVE_DOS_H # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # define HAVE_SYS_UTIME_H 1 # elif (ACC_CC_INTELC || ACC_CC_MSC) # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # define HAVE_SYS_UTIME_H 1 # elif (ACC_CC_LCCWIN32) # undef HAVE_DIRENT_H # undef HAVE_DOS_H # undef HAVE_UNISTD_H # undef HAVE_SYS_TIME_H # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__MINGW32__) # undef HAVE_UTIME_H # define HAVE_SYS_UTIME_H 1 # elif (ACC_OS_WIN32 && ACC_LIBC_MSL) # define HAVE_ALLOCA_H 1 # undef HAVE_DOS_H # undef HAVE_SHARE_H # undef HAVE_SYS_TIME_H # elif (ACC_CC_NDPC) # undef HAVE_DIRENT_H # undef HAVE_DOS_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # elif (ACC_CC_PACIFICC) # undef HAVE_DIRECT_H # undef HAVE_DIRENT_H # undef HAVE_FCNTL_H # undef HAVE_IO_H # undef HAVE_MALLOC_H # undef HAVE_MEMORY_H # undef HAVE_SHARE_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # elif (ACC_OS_WIN32 && ACC_CC_PELLESC) # undef HAVE_DIRENT_H # undef HAVE_DOS_H # undef HAVE_MALLOC_H # undef HAVE_SHARE_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # if (__POCC__ < 280) # else # define HAVE_SYS_UTIME_H 1 # endif # elif (ACC_OS_WIN32 && ACC_CC_PGI) && defined(__MINGW32__) # undef HAVE_UTIME_H # define HAVE_SYS_UTIME_H 1 # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) # elif (ACC_CC_SYMANTECC) # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # if (__SC__ < 0x700) # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # endif # elif (ACC_CC_TOPSPEEDC) # undef HAVE_DIRENT_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # elif (ACC_CC_TURBOC) # undef HAVE_UNISTD_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # if (ACC_OS_WIN32 || ACC_OS_WIN64) # undef HAVE_DIRENT_H # endif # if (__TURBOC__ < 0x0200) # undef HAVE_SIGNAL_H # endif # if (__TURBOC__ < 0x0400) # undef HAVE_DIRECT_H # undef HAVE_DIRENT_H # undef HAVE_MALLOC_H # undef HAVE_MEMORY_H # undef HAVE_UTIME_H # endif # elif (ACC_CC_WATCOMC) # undef HAVE_DIRENT_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # define HAVE_SYS_UTIME_H 1 # if (__WATCOMC__ < 950) # undef HAVE_UNISTD_H # endif # elif (ACC_CC_ZORTECHC) # undef HAVE_DIRENT_H # undef HAVE_MEMORY_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_TIME_H # endif # endif # if (ACC_OS_CONSOLE) # undef HAVE_DIRENT_H # endif # if (ACC_OS_EMBEDDED) # undef HAVE_DIRENT_H # endif # if (ACC_LIBC_ISOC90 || ACC_LIBC_ISOC99) # undef HAVE_DIRENT_H # undef HAVE_FCNTL_H # undef HAVE_MALLOC_H # undef HAVE_UNISTD_H # undef HAVE_UTIME_H # undef HAVE_SYS_STAT_H # undef HAVE_SYS_TIME_H # undef HAVE_SYS_TYPES_H # endif # if (ACC_LIBC_GLIBC >= 0x020100ul) # define HAVE_STDINT_H 1 # elif (ACC_LIBC_DIETLIBC) # undef HAVE_STDINT_H # elif (ACC_LIBC_UCLIBC) # define HAVE_STDINT_H 1 # elif (ACC_CC_BORLANDC) && (__BORLANDC__ >= 0x560) # undef HAVE_STDINT_H # elif (ACC_CC_DMC) && (__DMC__ >= 0x825) # define HAVE_STDINT_H 1 # endif # if (HAVE_SYS_TIME_H && HAVE_TIME_H) # define TIME_WITH_SYS_TIME 1 # endif # endif # endif # if !defined(ACC_CFG_AUTO_NO_FUNCTIONS) # if defined(ACC_LIBC_NAKED) # elif defined(ACC_LIBC_FREESTANDING) # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # define HAVE_LONGJMP 1 # define HAVE_MEMCMP 1 # define HAVE_MEMCPY 1 # define HAVE_MEMMOVE 1 # define HAVE_MEMSET 1 # define HAVE_SETJMP 1 # else # define HAVE_ACCESS 1 # define HAVE_ALLOCA 1 # define HAVE_ATEXIT 1 # define HAVE_ATOI 1 # define HAVE_ATOL 1 # define HAVE_CHMOD 1 # define HAVE_CHOWN 1 # define HAVE_CTIME 1 # define HAVE_DIFFTIME 1 # define HAVE_FILENO 1 # define HAVE_FSTAT 1 # define HAVE_GETENV 1 # define HAVE_GETTIMEOFDAY 1 # define HAVE_GMTIME 1 # define HAVE_ISATTY 1 # define HAVE_LOCALTIME 1 # define HAVE_LONGJMP 1 # define HAVE_LSTAT 1 # define HAVE_MEMCMP 1 # define HAVE_MEMCPY 1 # define HAVE_MEMMOVE 1 # define HAVE_MEMSET 1 # define HAVE_MKDIR 1 # define HAVE_MKTIME 1 # define HAVE_QSORT 1 # define HAVE_RAISE 1 # define HAVE_RMDIR 1 # define HAVE_SETJMP 1 # define HAVE_SIGNAL 1 # define HAVE_SNPRINTF 1 # define HAVE_STAT 1 # define HAVE_STRCHR 1 # define HAVE_STRDUP 1 # define HAVE_STRERROR 1 # define HAVE_STRFTIME 1 # define HAVE_STRRCHR 1 # define HAVE_STRSTR 1 # define HAVE_TIME 1 # define HAVE_UMASK 1 # define HAVE_UTIME 1 # define HAVE_VSNPRINTF 1 # if (ACC_OS_BEOS || ACC_OS_CYGWIN || ACC_OS_POSIX || ACC_OS_QNX || ACC_OS_VMS) # define HAVE_STRCASECMP 1 # define HAVE_STRNCASECMP 1 # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) # define HAVE_STRCASECMP 1 # define HAVE_STRNCASECMP 1 # else # define HAVE_STRICMP 1 # define HAVE_STRNICMP 1 # endif # if (ACC_OS_POSIX) # if (ACC_OS_POSIX_AIX) # define HAVE_GETRUSAGE 1 # elif (ACC_OS_POSIX_MACOSX && ACC_LIBC_MSL) # undef HAVE_CHOWN # undef HAVE_LSTAT # elif (ACC_OS_POSIX_UNICOS) # undef HAVE_ALLOCA # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # endif # if (ACC_CC_TINYC) # undef HAVE_ALLOCA # endif # if (ACC_LIBC_DIETLIBC || ACC_LIBC_GLIBC || ACC_LIBC_UCLIBC) # define HAVE_GETRUSAGE 1 # define HAVE_GETPAGESIZE 1 # define HAVE_MMAP 1 # define HAVE_MPROTECT 1 # define HAVE_MUNMAP 1 # endif # elif (ACC_OS_CYGWIN) # if (ACC_CC_GNUC < 0x025a00ul) # undef HAVE_GETTIMEOFDAY # undef HAVE_LSTAT # endif # if (ACC_CC_GNUC < 0x025f00ul) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # endif # elif (ACC_OS_EMX) # undef HAVE_CHOWN # undef HAVE_LSTAT # elif (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) # if !defined(__MINT__) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # endif # elif (ACC_ARCH_M68K && ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) # undef HAVE_ALLOCA # undef HAVE_ACCESS # undef HAVE_CHMOD # undef HAVE_CHOWN # undef HAVE_FSTAT # undef HAVE_GETTIMEOFDAY # undef HAVE_LSTAT # undef HAVE_SNPRINTF # undef HAVE_UMASK # undef HAVE_UTIME # undef HAVE_VSNPRINTF # endif # if (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) # undef HAVE_CHOWN # undef HAVE_GETTIMEOFDAY # undef HAVE_LSTAT # undef HAVE_UMASK # if (ACC_CC_AZTECC) # undef HAVE_ALLOCA # undef HAVE_DIFFTIME # undef HAVE_FSTAT # undef HAVE_STRDUP # undef HAVE_SNPRINTF # undef HAVE_UTIME # undef HAVE_VSNPRINTF # elif (ACC_CC_BORLANDC) # if (__BORLANDC__ < 0x0400) # undef HAVE_ALLOCA # undef HAVE_UTIME # endif # if ((__BORLANDC__ < 0x0410) && ACC_OS_WIN16) # undef HAVE_ALLOCA # endif # if (__BORLANDC__ < 0x0550) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # endif # elif (ACC_CC_DMC) # if (ACC_OS_WIN16) # undef HAVE_ALLOCA # endif # define snprintf _snprintf # define vsnprintf _vsnprintf # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (ACC_OS_DOS32 && ACC_CC_HIGHC) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (ACC_CC_IBMC) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (ACC_CC_INTELC) # define snprintf _snprintf # define vsnprintf _vsnprintf # elif (ACC_CC_LCCWIN32) # define utime _utime # elif (ACC_CC_MSC) # if (_MSC_VER < 600) # undef HAVE_STRFTIME # endif # if (_MSC_VER < 700) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (_MSC_VER < 1500) # define snprintf _snprintf # define vsnprintf _vsnprintf # endif # if ((_MSC_VER < 800) && ACC_OS_WIN16) # undef HAVE_ALLOCA # endif # if (ACC_ARCH_I086) && defined(__cplusplus) # undef HAVE_LONGJMP # undef HAVE_SETJMP # endif # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__MINGW32__) # if (ACC_CC_GNUC < 0x025f00ul) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # else # define snprintf _snprintf # define vsnprintf _vsnprintf # endif # elif (ACC_OS_WIN32 && ACC_LIBC_MSL) # if (__MSL__ < 0x8000ul) # undef HAVE_CHMOD # endif # elif (ACC_CC_NDPC) # undef HAVE_ALLOCA # undef HAVE_SNPRINTF # undef HAVE_STRNICMP # undef HAVE_UTIME # undef HAVE_VSNPRINTF # if defined(__cplusplus) # undef HAVE_STAT # endif # elif (ACC_CC_PACIFICC) # undef HAVE_ACCESS # undef HAVE_ALLOCA # undef HAVE_CHMOD # undef HAVE_DIFFTIME # undef HAVE_FSTAT # undef HAVE_MKTIME # undef HAVE_RAISE # undef HAVE_SNPRINTF # undef HAVE_STRFTIME # undef HAVE_UTIME # undef HAVE_VSNPRINTF # elif (ACC_OS_WIN32 && ACC_CC_PELLESC) # if (__POCC__ < 280) # define alloca _alloca # undef HAVE_UTIME # endif # elif (ACC_OS_WIN32 && ACC_CC_PGI) && defined(__MINGW32__) # define snprintf _snprintf # define vsnprintf _vsnprintf # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (ACC_CC_SYMANTECC) # if (ACC_OS_WIN16 && (ACC_MM_MEDIUM || ACC_MM_LARGE || ACC_MM_HUGE)) # undef HAVE_ALLOCA # endif # if (__SC__ < 0x600) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # else # define snprintf _snprintf # define vsnprintf _vsnprintf # endif # if (__SC__ < 0x700) # undef HAVE_DIFFTIME # undef HAVE_UTIME # endif # elif (ACC_CC_TOPSPEEDC) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (ACC_CC_TURBOC) # undef HAVE_ALLOCA # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # if (__TURBOC__ < 0x0200) # undef HAVE_RAISE # undef HAVE_SIGNAL # endif # if (__TURBOC__ < 0x0295) # undef HAVE_MKTIME # undef HAVE_STRFTIME # endif # if (__TURBOC__ < 0x0400) # undef HAVE_UTIME # endif # elif (ACC_CC_WATCOMC) # if (__WATCOMC__ < 1100) # undef HAVE_SNPRINTF # undef HAVE_VSNPRINTF # elif (__WATCOMC__ < 1200) # define snprintf _snprintf # define vsnprintf _vsnprintf # endif # elif (ACC_CC_ZORTECHC) # if (ACC_OS_WIN16 && (ACC_MM_MEDIUM || ACC_MM_LARGE || ACC_MM_HUGE)) # undef HAVE_ALLOCA # endif # undef HAVE_DIFFTIME # undef HAVE_SNPRINTF # undef HAVE_UTIME # undef HAVE_VSNPRINTF # endif # endif # if (ACC_OS_CONSOLE) # undef HAVE_ACCESS # undef HAVE_CHMOD # undef HAVE_CHOWN # undef HAVE_GETTIMEOFDAY # undef HAVE_LSTAT # undef HAVE_TIME # undef HAVE_UMASK # undef HAVE_UTIME # endif # if (ACC_LIBC_ISOC90 || ACC_LIBC_ISOC99) # undef HAVE_ACCESS # undef HAVE_CHMOD # undef HAVE_CHOWN # undef HAVE_FSTAT # undef HAVE_GETTIMEOFDAY # undef HAVE_LSTAT # undef HAVE_STAT # undef HAVE_UMASK # undef HAVE_UTIME # if 1 # undef HAVE_ALLOCA # undef HAVE_ISATTY # undef HAVE_MKDIR # undef HAVE_RMDIR # undef HAVE_STRDUP # undef HAVE_STRICMP # undef HAVE_STRNICMP # endif # endif # endif # endif # if !defined(ACC_CFG_AUTO_NO_SIZES) # if !defined(SIZEOF_SHORT) && defined(ACC_SIZEOF_SHORT) # define SIZEOF_SHORT ACC_SIZEOF_SHORT # endif # if !defined(SIZEOF_INT) && defined(ACC_SIZEOF_INT) # define SIZEOF_INT ACC_SIZEOF_INT # endif # if !defined(SIZEOF_LONG) && defined(ACC_SIZEOF_LONG) # define SIZEOF_LONG ACC_SIZEOF_LONG # endif # if !defined(SIZEOF_LONG_LONG) && defined(ACC_SIZEOF_LONG_LONG) # define SIZEOF_LONG_LONG ACC_SIZEOF_LONG_LONG # endif # if !defined(SIZEOF___INT32) && defined(ACC_SIZEOF___INT32) # define SIZEOF___INT32 ACC_SIZEOF___INT32 # endif # if !defined(SIZEOF___INT64) && defined(ACC_SIZEOF___INT64) # define SIZEOF___INT64 ACC_SIZEOF___INT64 # endif # if !defined(SIZEOF_VOID_P) && defined(ACC_SIZEOF_VOID_P) # define SIZEOF_VOID_P ACC_SIZEOF_VOID_P # endif # if !defined(SIZEOF_SIZE_T) && defined(ACC_SIZEOF_SIZE_T) # define SIZEOF_SIZE_T ACC_SIZEOF_SIZE_T # endif # if !defined(SIZEOF_PTRDIFF_T) && defined(ACC_SIZEOF_PTRDIFF_T) # define SIZEOF_PTRDIFF_T ACC_SIZEOF_PTRDIFF_T # endif # endif # if defined(HAVE_SIGNAL) && !defined(RETSIGTYPE) # define RETSIGTYPE void # endif # endif # if defined(ACC_CFG_NO_ACC_TYPE_H) # else # if (ACC_SIZEOF_LONG_LONG+0 > 0) __acc_gnuc_extension__ typedef long long acc_llong_t; __acc_gnuc_extension__ typedef unsigned long long acc_ullong_t; # endif # if (!(ACC_SIZEOF_SHORT+0 > 0 && ACC_SIZEOF_INT+0 > 0 && ACC_SIZEOF_LONG+0 > 0)) # error "missing defines for sizes" # endif # if (!(ACC_SIZEOF_PTRDIFF_T+0 > 0 && ACC_SIZEOF_SIZE_T+0 > 0 && ACC_SIZEOF_VOID_P+0 > 0)) # error "missing defines for sizes" # endif # if !defined(acc_int16e_t) # if (ACC_SIZEOF_LONG == 2) # define acc_int16e_t long # define acc_uint16e_t unsigned long # elif (ACC_SIZEOF_INT == 2) # define acc_int16e_t int # define acc_uint16e_t unsigned int # elif (ACC_SIZEOF_SHORT == 2) # define acc_int16e_t short int # define acc_uint16e_t unsigned short int # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_HI) && (ACC_CC_GNUC >= 0x025f00ul || ACC_CC_LLVM) typedef int __acc_int16e_hi_t __attribute__ ((__mode__(__HI__))); typedef unsigned int __acc_uint16e_hi_t __attribute__ ((__mode__(__HI__))); # define acc_int16e_t __acc_int16e_hi_t # define acc_uint16e_t __acc_uint16e_hi_t # elif (ACC_SIZEOF___INT16 == 2) # define acc_int16e_t __int16 # define acc_uint16e_t unsigned __int16 # else # endif # endif # if defined(acc_int16e_t) # define ACC_SIZEOF_ACC_INT16E_T 2 # endif # if !defined(acc_int32e_t) # if (ACC_SIZEOF_LONG == 4) # define acc_int32e_t long int # define acc_uint32e_t unsigned long int # elif (ACC_SIZEOF_INT == 4) # define acc_int32e_t int # define acc_uint32e_t unsigned int # elif (ACC_SIZEOF_SHORT == 4) # define acc_int32e_t short int # define acc_uint32e_t unsigned short int # elif (ACC_SIZEOF_LONG_LONG == 4) # define acc_int32e_t acc_llong_t # define acc_uint32e_t acc_ullong_t # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_SI) && (ACC_CC_GNUC >= 0x025f00ul || ACC_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) typedef int __acc_int32e_si_t __attribute__ ((__mode__(__SI__))); typedef unsigned int __acc_uint32e_si_t __attribute__ ((__mode__(__SI__))); # define acc_int32e_t __acc_int32e_si_t # define acc_uint32e_t __acc_uint32e_si_t # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_SI) && (ACC_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) typedef int __acc_int32e_si_t __attribute__ ((__mode__(__SI__))); typedef unsigned int __acc_uint32e_si_t __attribute__ ((__mode__(__SI__))); # define acc_int32e_t __acc_int32e_si_t # define acc_uint32e_t __acc_uint32e_si_t # define ACC_INT32_C(c) c##LL # define ACC_UINT32_C(c) c##ULL # elif (ACC_SIZEOF___INT32 == 4) # define acc_int32e_t __int32 # define acc_uint32e_t unsigned __int32 # else # endif # endif # if defined(acc_int32e_t) # define ACC_SIZEOF_ACC_INT32E_T 4 # endif # if !defined(acc_int64e_t) # if (ACC_SIZEOF___INT64 == 8) # if (ACC_CC_BORLANDC) && !defined(ACC_CFG_TYPE_PREFER___INT64) # define ACC_CFG_TYPE_PREFER___INT64 1 # endif # endif # if (ACC_SIZEOF_INT == 8) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_int64e_t int # define acc_uint64e_t unsigned int # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG == 8) # define acc_int64e_t long int # define acc_uint64e_t unsigned long int # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_LONG # elif (ACC_SIZEOF_LONG_LONG == 8) && !defined(ACC_CFG_TYPE_PREFER___INT64) # define acc_int64e_t acc_llong_t # define acc_uint64e_t acc_ullong_t # if (ACC_CC_BORLANDC) # define ACC_INT64_C(c) ((c) + 0ll) # define ACC_UINT64_C(c) ((c) + 0ull) # else # define ACC_INT64_C(c) c##LL # define ACC_UINT64_C(c) c##ULL # endif # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_LONG_LONG # elif (ACC_SIZEOF___INT64 == 8) # define acc_int64e_t __int64 # define acc_uint64e_t unsigned __int64 # if (ACC_CC_BORLANDC) # define ACC_INT64_C(c) ((c) + 0i64) # define ACC_UINT64_C(c) ((c) + 0ui64) # else # define ACC_INT64_C(c) c##i64 # define ACC_UINT64_C(c) c##ui64 # endif # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF___INT64 # else # endif # endif # if !defined(acc_int32l_t) # if defined(acc_int32e_t) # define acc_int32l_t acc_int32e_t # define acc_uint32l_t acc_uint32e_t # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_ACC_INT32E_T # elif (ACC_SIZEOF_INT >= 4) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_int32l_t int # define acc_uint32l_t unsigned int # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG >= 4) # define acc_int32l_t long int # define acc_uint32l_t unsigned long int # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_LONG # else # error "acc_int32l_t" # endif # endif # if !defined(acc_int64l_t) # if defined(acc_int64e_t) # define acc_int64l_t acc_int64e_t # define acc_uint64l_t acc_uint64e_t # define ACC_SIZEOF_ACC_INT64L_T ACC_SIZEOF_ACC_INT64E_T # else # endif # endif # if !defined(acc_int32f_t) # if (ACC_SIZEOF_SIZE_T >= 8) # define acc_int32f_t acc_int64l_t # define acc_uint32f_t acc_uint64l_t # define ACC_SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT64L_T # else # define acc_int32f_t acc_int32l_t # define acc_uint32f_t acc_uint32l_t # define ACC_SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT32L_T # endif # endif # if !defined(acc_intptr_t) # if 1 && (ACC_OS_OS400 && (ACC_SIZEOF_VOID_P == 16)) # define __ACC_INTPTR_T_IS_POINTER 1 typedef char *acc_intptr_t; typedef char *acc_uintptr_t; # define acc_intptr_t acc_intptr_t # define acc_uintptr_t acc_uintptr_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_VOID_P # elif (ACC_CC_MSC && (_MSC_VER >= 1300) && (ACC_SIZEOF_VOID_P == 4) && (ACC_SIZEOF_INT == 4)) typedef __w64 int acc_intptr_t; typedef __w64 unsigned int acc_uintptr_t; # define acc_intptr_t acc_intptr_t # define acc_uintptr_t acc_uintptr_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_SHORT == ACC_SIZEOF_VOID_P) && (ACC_SIZEOF_INT > ACC_SIZEOF_VOID_P) # define acc_intptr_t short # define acc_uintptr_t unsigned short # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_SHORT # elif (ACC_SIZEOF_INT >= ACC_SIZEOF_VOID_P) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_intptr_t int # define acc_uintptr_t unsigned int # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG >= ACC_SIZEOF_VOID_P) # define acc_intptr_t long # define acc_uintptr_t unsigned long # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_LONG # elif (ACC_SIZEOF_ACC_INT64L_T >= ACC_SIZEOF_VOID_P) # define acc_intptr_t acc_int64l_t # define acc_uintptr_t acc_uint64l_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_ACC_INT64L_T # else # error "acc_intptr_t" # endif # endif # if !defined(acc_word_t) # if defined(ACC_WORDSIZE) && (ACC_WORDSIZE > 0) # if (ACC_WORDSIZE == ACC_SIZEOF_ACC_INTPTR_T) && !defined(__ACC_INTPTR_T_IS_POINTER) # define acc_word_t acc_uintptr_t # define acc_sword_t acc_intptr_t # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_INTPTR_T # elif (ACC_WORDSIZE == ACC_SIZEOF_LONG) # define acc_word_t unsigned long # define acc_sword_t long # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_LONG # elif (ACC_WORDSIZE == ACC_SIZEOF_INT) # define acc_word_t unsigned int # define acc_sword_t int # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_INT # elif (ACC_WORDSIZE == ACC_SIZEOF_SHORT) # define acc_word_t unsigned short # define acc_sword_t short # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_SHORT # elif (ACC_WORDSIZE == 1) # define acc_word_t unsigned char # define acc_sword_t signed char # define ACC_SIZEOF_ACC_WORD_T 1 # elif (ACC_WORDSIZE == ACC_SIZEOF_ACC_INT64L_T) # define acc_word_t acc_uint64l_t # define acc_sword_t acc_int64l_t # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_INT64L_T # elif (ACC_ARCH_SPU) && (ACC_CC_GNUC) # if 0 typedef unsigned acc_word_t __attribute__ ((__mode__(__V16QI__))); typedef int acc_sword_t __attribute__ ((__mode__(__V16QI__))); # define acc_word_t acc_word_t # define acc_sword_t acc_sword_t # define ACC_SIZEOF_ACC_WORD_T 16 # endif # else # error "acc_word_t" # endif # endif # endif # if !defined(ACC_INT16_C) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 2) # define ACC_INT16_C(c) ((c) + 0) # define ACC_UINT16_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 2) # define ACC_INT16_C(c) ((c) + 0L) # define ACC_UINT16_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 2) # define ACC_INT16_C(c) c # define ACC_UINT16_C(c) c##U # elif (ACC_SIZEOF_LONG >= 2) # define ACC_INT16_C(c) c##L # define ACC_UINT16_C(c) c##UL # else # error "ACC_INT16_C" # endif # endif # if !defined(ACC_INT32_C) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 4) # define ACC_INT32_C(c) ((c) + 0) # define ACC_UINT32_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 4) # define ACC_INT32_C(c) ((c) + 0L) # define ACC_UINT32_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 4) # define ACC_INT32_C(c) c # define ACC_UINT32_C(c) c##U # elif (ACC_SIZEOF_LONG >= 4) # define ACC_INT32_C(c) c##L # define ACC_UINT32_C(c) c##UL # elif (ACC_SIZEOF_LONG_LONG >= 4) # define ACC_INT32_C(c) c##LL # define ACC_UINT32_C(c) c##ULL # else # error "ACC_INT32_C" # endif # endif # if !defined(ACC_INT64_C) && defined(acc_int64l_t) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 8) # define ACC_INT64_C(c) ((c) + 0) # define ACC_UINT64_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 8) # define ACC_INT64_C(c) ((c) + 0L) # define ACC_UINT64_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 8) # define ACC_INT64_C(c) c # define ACC_UINT64_C(c) c##U # elif (ACC_SIZEOF_LONG >= 8) # define ACC_INT64_C(c) c##L # define ACC_UINT64_C(c) c##UL # else # error "ACC_INT64_C" # endif # endif # if !defined(SIZEOF_ACC_INT16E_T) && defined(ACC_SIZEOF_ACC_INT16E_T) # define SIZEOF_ACC_INT16E_T ACC_SIZEOF_ACC_INT16E_T # endif # if !defined(SIZEOF_ACC_INT32E_T) && defined(ACC_SIZEOF_ACC_INT32E_T) # define SIZEOF_ACC_INT32E_T ACC_SIZEOF_ACC_INT32E_T # endif # if !defined(SIZEOF_ACC_INT64E_T) && defined(ACC_SIZEOF_ACC_INT64E_T) # define SIZEOF_ACC_INT64E_T ACC_SIZEOF_ACC_INT64E_T # endif # if !defined(SIZEOF_ACC_INT32L_T) && defined(ACC_SIZEOF_ACC_INT32L_T) # define SIZEOF_ACC_INT32L_T ACC_SIZEOF_ACC_INT32L_T # endif # if !defined(SIZEOF_ACC_INT64L_T) && defined(ACC_SIZEOF_ACC_INT64L_T) # define SIZEOF_ACC_INT64L_T ACC_SIZEOF_ACC_INT64L_T # endif # if !defined(SIZEOF_ACC_INT32F_T) && defined(ACC_SIZEOF_ACC_INT32F_T) # define SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT32F_T # endif # if !defined(SIZEOF_ACC_INTPTR_T) && defined(ACC_SIZEOF_ACC_INTPTR_T) # define SIZEOF_ACC_INTPTR_T ACC_SIZEOF_ACC_INTPTR_T # endif # if !defined(SIZEOF_ACC_WORD_T) && defined(ACC_SIZEOF_ACC_WORD_T) # define SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_WORD_T # endif # if 1 && !defined(acc_signo_t) && defined(__linux__) && defined(__dietlibc__) && (ACC_SIZEOF_INT != 4) # define acc_signo_t acc_int32e_t # endif # if !defined(acc_signo_t) # define acc_signo_t int # endif # if defined(__cplusplus) extern "C" { # endif # if (ACC_BROKEN_CDECL_ALT_SYNTAX) typedef void __acc_cdecl_sighandler(*acc_sighandler_t) (acc_signo_t); # elif defined(RETSIGTYPE) typedef RETSIGTYPE(__acc_cdecl_sighandler * acc_sighandler_t) (acc_signo_t); # else typedef void (__acc_cdecl_sighandler * acc_sighandler_t) (acc_signo_t); # endif # if defined(__cplusplus) } # endif # if defined(ACC_CFG_NO_ACC_UA_H) # else # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020700ul)) # elif (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020800ul)) && defined(__cplusplus) # elif (ACC_CC_INTELC) && defined(_WIN32) # elif (ACC_CC_INTELC && (__INTEL_COMPILER < 700)) # elif (ACC_CC_LLVM) # elif (ACC_CC_GNUC || ACC_CC_INTELC || ACC_CC_PATHSCALE) # if !defined(__acc_ua16_t) && (ACC_OPT_UNALIGNED16) && defined(acc_int16e_t) typedef struct { __acc_ua_volatile acc_uint16e_t v __attribute__ ((__packed__)); } __acc_ua16_t; # define __acc_ua16_t __acc_ua16_t # endif # if !defined(__acc_ua32_t) && (ACC_OPT_UNALIGNED32) && defined(acc_int32e_t) typedef struct { __acc_ua_volatile acc_uint32e_t v __attribute__ ((__packed__)); } __acc_ua32_t; # define __acc_ua32_t __acc_ua32_t # endif # if !defined(__acc_ua64_t) && (ACC_OPT_UNALIGNED64) && defined(acc_int64l_t) typedef struct { __acc_ua_volatile acc_uint64l_t v __attribute__ ((__packed__)); } __acc_ua64_t; # define __acc_ua64_t __acc_ua64_t # endif # endif # if (ACC_OPT_UNALIGNED16) && defined(acc_int16e_t) # define ACC_UA_GET16(p) (* (__acc_ua_volatile const acc_uint16e_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET16(p,v) (* (__acc_ua_volatile acc_uint16e_t*) (__acc_ua_volatile void*) (p) = (acc_uint16e_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE16(p) ACC_UA_GET16(p) # define ACC_UA_SET_BE16(p,v) ACC_UA_SET16(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE16(p) ACC_UA_GET16(p) # define ACC_UA_SET_LE16(p,v) ACC_UA_SET16(p,v) # endif # if !defined(ACC_CFG_NO_INLINE_ASM) && defined(__acc_HAVE_forceinline) # if (ACC_ARCH_POWERPC && ACC_ABI_BIG_ENDIAN) && (ACC_CC_GNUC) # if !defined(ACC_UA_GET_LE16) extern __acc_forceinline unsigned long __ACC_UA_GET_LE16(__acc_ua_volatile const void *pp); extern __acc_forceinline unsigned long __ACC_UA_GET_LE16(__acc_ua_volatile const void *pp) { __acc_ua_volatile const acc_uint16e_t *p = (__acc_ua_volatile const acc_uint16e_t *)pp; unsigned long v; __asm__ __volatile__("lhbrx %0,0,%1":"=r"(v):"r"(p), "m"(*p)); return v; } # define ACC_UA_GET_LE16(p) __ACC_UA_GET_LE16(p) # endif # if !defined(ACC_UA_SET_LE16) extern __acc_forceinline void __ACC_UA_SET_LE16(__acc_ua_volatile void *pp, unsigned long v); extern __acc_forceinline void __ACC_UA_SET_LE16(__acc_ua_volatile void *pp, unsigned long v) { __acc_ua_volatile acc_uint16e_t *p = (__acc_ua_volatile acc_uint16e_t *) pp; __asm__ __volatile__("sthbrx %2,0,%1":"=m"(*p):"r"(p), "r"(v)); } # define ACC_UA_SET_LE16(p,v) __ACC_UA_SET_LE16(p,v) # endif # endif # endif # if !defined(ACC_UA_COPY16) # define ACC_UA_COPY16(d,s) ACC_UA_SET16(d, ACC_UA_GET16(s)) # endif # endif # if (ACC_OPT_UNALIGNED32) && defined(acc_int32e_t) # define ACC_UA_GET32(p) (* (__acc_ua_volatile const acc_uint32e_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET32(p,v) (* (__acc_ua_volatile acc_uint32e_t*) (__acc_ua_volatile void*) (p) = (acc_uint32e_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE32(p) ACC_UA_GET32(p) # define ACC_UA_SET_BE32(p,v) ACC_UA_SET32(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE32(p) ACC_UA_GET32(p) # define ACC_UA_SET_LE32(p,v) ACC_UA_SET32(p,v) # endif # if !defined(ACC_CFG_NO_INLINE_ASM) && defined(__acc_HAVE_forceinline) # if (ACC_ARCH_POWERPC && ACC_ABI_BIG_ENDIAN) && (ACC_CC_GNUC) # if !defined(ACC_UA_GET_LE32) extern __acc_forceinline unsigned long __ACC_UA_GET_LE32(__acc_ua_volatile const void *pp); extern __acc_forceinline unsigned long __ACC_UA_GET_LE32(__acc_ua_volatile const void *pp) { __acc_ua_volatile const acc_uint32e_t *p = (__acc_ua_volatile const acc_uint32e_t *)pp; unsigned long v; __asm__ __volatile__("lwbrx %0,0,%1":"=r"(v):"r"(p), "m"(*p)); return v; } # define ACC_UA_GET_LE32(p) __ACC_UA_GET_LE32(p) # endif # if !defined(ACC_UA_SET_LE32) extern __acc_forceinline void __ACC_UA_SET_LE32(__acc_ua_volatile void *pp, unsigned long v); extern __acc_forceinline void __ACC_UA_SET_LE32(__acc_ua_volatile void *pp, unsigned long v) { __acc_ua_volatile acc_uint32e_t *p = (__acc_ua_volatile acc_uint32e_t *) pp; __asm__ __volatile__("stwbrx %2,0,%1":"=m"(*p):"r"(p), "r"(v)); } # define ACC_UA_SET_LE32(p,v) __ACC_UA_SET_LE32(p,v) # endif # endif # endif # if !defined(ACC_UA_COPY32) # define ACC_UA_COPY32(d,s) ACC_UA_SET32(d, ACC_UA_GET32(s)) # endif # endif # if (ACC_OPT_UNALIGNED64) && defined(acc_int64l_t) # define ACC_UA_GET64(p) (* (__acc_ua_volatile const acc_uint64l_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET64(p,v) (* (__acc_ua_volatile acc_uint64l_t*) (__acc_ua_volatile void*) (p) = (acc_uint64l_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE64(p) ACC_UA_GET64(p) # define ACC_UA_SET_BE64(p,v) ACC_UA_SET64(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE64(p) ACC_UA_GET64(p) # define ACC_UA_SET_LE64(p,v) ACC_UA_SET64(p,v) # endif # if !defined(ACC_UA_COPY64) # define ACC_UA_COPY64(d,s) ACC_UA_SET64(d, ACC_UA_GET64(s)) # endif # endif # endif # endif #endif #if defined(ACC_WANT_ACC_TYPE_H) # undef ACC_WANT_ACC_TYPE_H # if defined(ACC_CFG_NO_ACC_TYPE_H) # error "ACC_WANT_ACC_TYPE_H with ACC_CFG_NO_ACC_TYPE_H" # endif # if (ACC_SIZEOF_LONG_LONG+0 > 0) __acc_gnuc_extension__ typedef long long acc_llong_t; __acc_gnuc_extension__ typedef unsigned long long acc_ullong_t; # endif # if (!(ACC_SIZEOF_SHORT+0 > 0 && ACC_SIZEOF_INT+0 > 0 && ACC_SIZEOF_LONG+0 > 0)) # error "missing defines for sizes" # endif # if (!(ACC_SIZEOF_PTRDIFF_T+0 > 0 && ACC_SIZEOF_SIZE_T+0 > 0 && ACC_SIZEOF_VOID_P+0 > 0)) # error "missing defines for sizes" # endif # if !defined(acc_int16e_t) # if (ACC_SIZEOF_LONG == 2) # define acc_int16e_t long # define acc_uint16e_t unsigned long # elif (ACC_SIZEOF_INT == 2) # define acc_int16e_t int # define acc_uint16e_t unsigned int # elif (ACC_SIZEOF_SHORT == 2) # define acc_int16e_t short int # define acc_uint16e_t unsigned short int # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_HI) && (ACC_CC_GNUC >= 0x025f00ul || ACC_CC_LLVM) typedef int __acc_int16e_hi_t __attribute__ ((__mode__(__HI__))); typedef unsigned int __acc_uint16e_hi_t __attribute__ ((__mode__(__HI__))); # define acc_int16e_t __acc_int16e_hi_t # define acc_uint16e_t __acc_uint16e_hi_t # elif (ACC_SIZEOF___INT16 == 2) # define acc_int16e_t __int16 # define acc_uint16e_t unsigned __int16 # else # endif # endif # if defined(acc_int16e_t) # define ACC_SIZEOF_ACC_INT16E_T 2 # endif # if !defined(acc_int32e_t) # if (ACC_SIZEOF_LONG == 4) # define acc_int32e_t long int # define acc_uint32e_t unsigned long int # elif (ACC_SIZEOF_INT == 4) # define acc_int32e_t int # define acc_uint32e_t unsigned int # elif (ACC_SIZEOF_SHORT == 4) # define acc_int32e_t short int # define acc_uint32e_t unsigned short int # elif (ACC_SIZEOF_LONG_LONG == 4) # define acc_int32e_t acc_llong_t # define acc_uint32e_t acc_ullong_t # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_SI) && (ACC_CC_GNUC >= 0x025f00ul || ACC_CC_LLVM) && (__INT_MAX__+0 > 2147483647L) typedef int __acc_int32e_si_t __attribute__ ((__mode__(__SI__))); typedef unsigned int __acc_uint32e_si_t __attribute__ ((__mode__(__SI__))); # define acc_int32e_t __acc_int32e_si_t # define acc_uint32e_t __acc_uint32e_si_t # elif 1 && !defined(ACC_CFG_TYPE_NO_MODE_SI) && (ACC_CC_GNUC >= 0x025f00ul) && defined(__AVR__) && (__LONG_MAX__+0 == 32767L) typedef int __acc_int32e_si_t __attribute__ ((__mode__(__SI__))); typedef unsigned int __acc_uint32e_si_t __attribute__ ((__mode__(__SI__))); # define acc_int32e_t __acc_int32e_si_t # define acc_uint32e_t __acc_uint32e_si_t # define ACC_INT32_C(c) c##LL # define ACC_UINT32_C(c) c##ULL # elif (ACC_SIZEOF___INT32 == 4) # define acc_int32e_t __int32 # define acc_uint32e_t unsigned __int32 # else # endif # endif # if defined(acc_int32e_t) # define ACC_SIZEOF_ACC_INT32E_T 4 # endif # if !defined(acc_int64e_t) # if (ACC_SIZEOF___INT64 == 8) # if (ACC_CC_BORLANDC) && !defined(ACC_CFG_TYPE_PREFER___INT64) # define ACC_CFG_TYPE_PREFER___INT64 1 # endif # endif # if (ACC_SIZEOF_INT == 8) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_int64e_t int # define acc_uint64e_t unsigned int # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG == 8) # define acc_int64e_t long int # define acc_uint64e_t unsigned long int # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_LONG # elif (ACC_SIZEOF_LONG_LONG == 8) && !defined(ACC_CFG_TYPE_PREFER___INT64) # define acc_int64e_t acc_llong_t # define acc_uint64e_t acc_ullong_t # if (ACC_CC_BORLANDC) # define ACC_INT64_C(c) ((c) + 0ll) # define ACC_UINT64_C(c) ((c) + 0ull) # else # define ACC_INT64_C(c) c##LL # define ACC_UINT64_C(c) c##ULL # endif # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF_LONG_LONG # elif (ACC_SIZEOF___INT64 == 8) # define acc_int64e_t __int64 # define acc_uint64e_t unsigned __int64 # if (ACC_CC_BORLANDC) # define ACC_INT64_C(c) ((c) + 0i64) # define ACC_UINT64_C(c) ((c) + 0ui64) # else # define ACC_INT64_C(c) c##i64 # define ACC_UINT64_C(c) c##ui64 # endif # define ACC_SIZEOF_ACC_INT64E_T ACC_SIZEOF___INT64 # else # endif # endif # if !defined(acc_int32l_t) # if defined(acc_int32e_t) # define acc_int32l_t acc_int32e_t # define acc_uint32l_t acc_uint32e_t # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_ACC_INT32E_T # elif (ACC_SIZEOF_INT >= 4) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_int32l_t int # define acc_uint32l_t unsigned int # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG >= 4) # define acc_int32l_t long int # define acc_uint32l_t unsigned long int # define ACC_SIZEOF_ACC_INT32L_T ACC_SIZEOF_LONG # else # error "acc_int32l_t" # endif # endif # if !defined(acc_int64l_t) # if defined(acc_int64e_t) # define acc_int64l_t acc_int64e_t # define acc_uint64l_t acc_uint64e_t # define ACC_SIZEOF_ACC_INT64L_T ACC_SIZEOF_ACC_INT64E_T # else # endif # endif # if !defined(acc_int32f_t) # if (ACC_SIZEOF_SIZE_T >= 8) # define acc_int32f_t acc_int64l_t # define acc_uint32f_t acc_uint64l_t # define ACC_SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT64L_T # else # define acc_int32f_t acc_int32l_t # define acc_uint32f_t acc_uint32l_t # define ACC_SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT32L_T # endif # endif # if !defined(acc_intptr_t) # if 1 && (ACC_OS_OS400 && (ACC_SIZEOF_VOID_P == 16)) # define __ACC_INTPTR_T_IS_POINTER 1 typedef char *acc_intptr_t; typedef char *acc_uintptr_t; # define acc_intptr_t acc_intptr_t # define acc_uintptr_t acc_uintptr_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_VOID_P # elif (ACC_CC_MSC && (_MSC_VER >= 1300) && (ACC_SIZEOF_VOID_P == 4) && (ACC_SIZEOF_INT == 4)) typedef __w64 int acc_intptr_t; typedef __w64 unsigned int acc_uintptr_t; # define acc_intptr_t acc_intptr_t # define acc_uintptr_t acc_uintptr_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_SHORT == ACC_SIZEOF_VOID_P) && (ACC_SIZEOF_INT > ACC_SIZEOF_VOID_P) # define acc_intptr_t short # define acc_uintptr_t unsigned short # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_SHORT # elif (ACC_SIZEOF_INT >= ACC_SIZEOF_VOID_P) && (ACC_SIZEOF_INT < ACC_SIZEOF_LONG) # define acc_intptr_t int # define acc_uintptr_t unsigned int # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_INT # elif (ACC_SIZEOF_LONG >= ACC_SIZEOF_VOID_P) # define acc_intptr_t long # define acc_uintptr_t unsigned long # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_LONG # elif (ACC_SIZEOF_ACC_INT64L_T >= ACC_SIZEOF_VOID_P) # define acc_intptr_t acc_int64l_t # define acc_uintptr_t acc_uint64l_t # define ACC_SIZEOF_ACC_INTPTR_T ACC_SIZEOF_ACC_INT64L_T # else # error "acc_intptr_t" # endif # endif # if !defined(acc_word_t) # if defined(ACC_WORDSIZE) && (ACC_WORDSIZE > 0) # if (ACC_WORDSIZE == ACC_SIZEOF_ACC_INTPTR_T) && !defined(__ACC_INTPTR_T_IS_POINTER) # define acc_word_t acc_uintptr_t # define acc_sword_t acc_intptr_t # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_INTPTR_T # elif (ACC_WORDSIZE == ACC_SIZEOF_LONG) # define acc_word_t unsigned long # define acc_sword_t long # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_LONG # elif (ACC_WORDSIZE == ACC_SIZEOF_INT) # define acc_word_t unsigned int # define acc_sword_t int # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_INT # elif (ACC_WORDSIZE == ACC_SIZEOF_SHORT) # define acc_word_t unsigned short # define acc_sword_t short # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_SHORT # elif (ACC_WORDSIZE == 1) # define acc_word_t unsigned char # define acc_sword_t signed char # define ACC_SIZEOF_ACC_WORD_T 1 # elif (ACC_WORDSIZE == ACC_SIZEOF_ACC_INT64L_T) # define acc_word_t acc_uint64l_t # define acc_sword_t acc_int64l_t # define ACC_SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_INT64L_T # elif (ACC_ARCH_SPU) && (ACC_CC_GNUC) # if 0 typedef unsigned acc_word_t __attribute__ ((__mode__(__V16QI__))); typedef int acc_sword_t __attribute__ ((__mode__(__V16QI__))); # define acc_word_t acc_word_t # define acc_sword_t acc_sword_t # define ACC_SIZEOF_ACC_WORD_T 16 # endif # else # error "acc_word_t" # endif # endif # endif # if !defined(ACC_INT16_C) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 2) # define ACC_INT16_C(c) ((c) + 0) # define ACC_UINT16_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 2) # define ACC_INT16_C(c) ((c) + 0L) # define ACC_UINT16_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 2) # define ACC_INT16_C(c) c # define ACC_UINT16_C(c) c##U # elif (ACC_SIZEOF_LONG >= 2) # define ACC_INT16_C(c) c##L # define ACC_UINT16_C(c) c##UL # else # error "ACC_INT16_C" # endif # endif # if !defined(ACC_INT32_C) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 4) # define ACC_INT32_C(c) ((c) + 0) # define ACC_UINT32_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 4) # define ACC_INT32_C(c) ((c) + 0L) # define ACC_UINT32_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 4) # define ACC_INT32_C(c) c # define ACC_UINT32_C(c) c##U # elif (ACC_SIZEOF_LONG >= 4) # define ACC_INT32_C(c) c##L # define ACC_UINT32_C(c) c##UL # elif (ACC_SIZEOF_LONG_LONG >= 4) # define ACC_INT32_C(c) c##LL # define ACC_UINT32_C(c) c##ULL # else # error "ACC_INT32_C" # endif # endif # if !defined(ACC_INT64_C) && defined(acc_int64l_t) # if (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_INT >= 8) # define ACC_INT64_C(c) ((c) + 0) # define ACC_UINT64_C(c) ((c) + 0U) # elif (ACC_BROKEN_INTEGRAL_CONSTANTS) && (ACC_SIZEOF_LONG >= 8) # define ACC_INT64_C(c) ((c) + 0L) # define ACC_UINT64_C(c) ((c) + 0UL) # elif (ACC_SIZEOF_INT >= 8) # define ACC_INT64_C(c) c # define ACC_UINT64_C(c) c##U # elif (ACC_SIZEOF_LONG >= 8) # define ACC_INT64_C(c) c##L # define ACC_UINT64_C(c) c##UL # else # error "ACC_INT64_C" # endif # endif # if !defined(SIZEOF_ACC_INT16E_T) && defined(ACC_SIZEOF_ACC_INT16E_T) # define SIZEOF_ACC_INT16E_T ACC_SIZEOF_ACC_INT16E_T # endif # if !defined(SIZEOF_ACC_INT32E_T) && defined(ACC_SIZEOF_ACC_INT32E_T) # define SIZEOF_ACC_INT32E_T ACC_SIZEOF_ACC_INT32E_T # endif # if !defined(SIZEOF_ACC_INT64E_T) && defined(ACC_SIZEOF_ACC_INT64E_T) # define SIZEOF_ACC_INT64E_T ACC_SIZEOF_ACC_INT64E_T # endif # if !defined(SIZEOF_ACC_INT32L_T) && defined(ACC_SIZEOF_ACC_INT32L_T) # define SIZEOF_ACC_INT32L_T ACC_SIZEOF_ACC_INT32L_T # endif # if !defined(SIZEOF_ACC_INT64L_T) && defined(ACC_SIZEOF_ACC_INT64L_T) # define SIZEOF_ACC_INT64L_T ACC_SIZEOF_ACC_INT64L_T # endif # if !defined(SIZEOF_ACC_INT32F_T) && defined(ACC_SIZEOF_ACC_INT32F_T) # define SIZEOF_ACC_INT32F_T ACC_SIZEOF_ACC_INT32F_T # endif # if !defined(SIZEOF_ACC_INTPTR_T) && defined(ACC_SIZEOF_ACC_INTPTR_T) # define SIZEOF_ACC_INTPTR_T ACC_SIZEOF_ACC_INTPTR_T # endif # if !defined(SIZEOF_ACC_WORD_T) && defined(ACC_SIZEOF_ACC_WORD_T) # define SIZEOF_ACC_WORD_T ACC_SIZEOF_ACC_WORD_T # endif # if 1 && !defined(acc_signo_t) && defined(__linux__) && defined(__dietlibc__) && (ACC_SIZEOF_INT != 4) # define acc_signo_t acc_int32e_t # endif # if !defined(acc_signo_t) # define acc_signo_t int # endif # if defined(__cplusplus) extern "C" { # endif # if (ACC_BROKEN_CDECL_ALT_SYNTAX) typedef void __acc_cdecl_sighandler(*acc_sighandler_t) (acc_signo_t); # elif defined(RETSIGTYPE) typedef RETSIGTYPE(__acc_cdecl_sighandler * acc_sighandler_t) (acc_signo_t); # else typedef void (__acc_cdecl_sighandler * acc_sighandler_t) (acc_signo_t); # endif # if defined(__cplusplus) } # endif # if !defined(ACC_CFG_NO_ACC_UA_H) # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020700ul)) # elif (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020800ul)) && defined(__cplusplus) # elif (ACC_CC_INTELC) && defined(_WIN32) # elif (ACC_CC_INTELC && (__INTEL_COMPILER < 700)) # elif (ACC_CC_LLVM) # elif (ACC_CC_GNUC || ACC_CC_INTELC || ACC_CC_PATHSCALE) # if !defined(__acc_ua16_t) && (ACC_OPT_UNALIGNED16) && defined(acc_int16e_t) typedef struct { __acc_ua_volatile acc_uint16e_t v __attribute__ ((__packed__)); } __acc_ua16_t; # define __acc_ua16_t __acc_ua16_t # endif # if !defined(__acc_ua32_t) && (ACC_OPT_UNALIGNED32) && defined(acc_int32e_t) typedef struct { __acc_ua_volatile acc_uint32e_t v __attribute__ ((__packed__)); } __acc_ua32_t; # define __acc_ua32_t __acc_ua32_t # endif # if !defined(__acc_ua64_t) && (ACC_OPT_UNALIGNED64) && defined(acc_int64l_t) typedef struct { __acc_ua_volatile acc_uint64l_t v __attribute__ ((__packed__)); } __acc_ua64_t; # define __acc_ua64_t __acc_ua64_t # endif # endif # if (ACC_OPT_UNALIGNED16) && defined(acc_int16e_t) # define ACC_UA_GET16(p) (* (__acc_ua_volatile const acc_uint16e_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET16(p,v) (* (__acc_ua_volatile acc_uint16e_t*) (__acc_ua_volatile void*) (p) = (acc_uint16e_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE16(p) ACC_UA_GET16(p) # define ACC_UA_SET_BE16(p,v) ACC_UA_SET16(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE16(p) ACC_UA_GET16(p) # define ACC_UA_SET_LE16(p,v) ACC_UA_SET16(p,v) # endif # if !defined(ACC_CFG_NO_INLINE_ASM) && defined(__acc_HAVE_forceinline) # if (ACC_ARCH_POWERPC && ACC_ABI_BIG_ENDIAN) && (ACC_CC_GNUC) # if !defined(ACC_UA_GET_LE16) extern __acc_forceinline unsigned long __ACC_UA_GET_LE16(__acc_ua_volatile const void *pp); extern __acc_forceinline unsigned long __ACC_UA_GET_LE16(__acc_ua_volatile const void *pp) { __acc_ua_volatile const acc_uint16e_t *p = (__acc_ua_volatile const acc_uint16e_t *)pp; unsigned long v; __asm__ __volatile__("lhbrx %0,0,%1":"=r"(v):"r"(p), "m"(*p)); return v; } # define ACC_UA_GET_LE16(p) __ACC_UA_GET_LE16(p) # endif # if !defined(ACC_UA_SET_LE16) extern __acc_forceinline void __ACC_UA_SET_LE16(__acc_ua_volatile void *pp, unsigned long v); extern __acc_forceinline void __ACC_UA_SET_LE16(__acc_ua_volatile void *pp, unsigned long v) { __acc_ua_volatile acc_uint16e_t *p = (__acc_ua_volatile acc_uint16e_t *) pp; __asm__ __volatile__("sthbrx %2,0,%1":"=m"(*p):"r"(p), "r"(v)); } # define ACC_UA_SET_LE16(p,v) __ACC_UA_SET_LE16(p,v) # endif # endif # endif # if !defined(ACC_UA_COPY16) # define ACC_UA_COPY16(d,s) ACC_UA_SET16(d, ACC_UA_GET16(s)) # endif # endif # if (ACC_OPT_UNALIGNED32) && defined(acc_int32e_t) # define ACC_UA_GET32(p) (* (__acc_ua_volatile const acc_uint32e_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET32(p,v) (* (__acc_ua_volatile acc_uint32e_t*) (__acc_ua_volatile void*) (p) = (acc_uint32e_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE32(p) ACC_UA_GET32(p) # define ACC_UA_SET_BE32(p,v) ACC_UA_SET32(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE32(p) ACC_UA_GET32(p) # define ACC_UA_SET_LE32(p,v) ACC_UA_SET32(p,v) # endif # if !defined(ACC_CFG_NO_INLINE_ASM) && defined(__acc_HAVE_forceinline) # if (ACC_ARCH_POWERPC && ACC_ABI_BIG_ENDIAN) && (ACC_CC_GNUC) # if !defined(ACC_UA_GET_LE32) extern __acc_forceinline unsigned long __ACC_UA_GET_LE32(__acc_ua_volatile const void *pp); extern __acc_forceinline unsigned long __ACC_UA_GET_LE32(__acc_ua_volatile const void *pp) { __acc_ua_volatile const acc_uint32e_t *p = (__acc_ua_volatile const acc_uint32e_t *)pp; unsigned long v; __asm__ __volatile__("lwbrx %0,0,%1":"=r"(v):"r"(p), "m"(*p)); return v; } # define ACC_UA_GET_LE32(p) __ACC_UA_GET_LE32(p) # endif # if !defined(ACC_UA_SET_LE32) extern __acc_forceinline void __ACC_UA_SET_LE32(__acc_ua_volatile void *pp, unsigned long v); extern __acc_forceinline void __ACC_UA_SET_LE32(__acc_ua_volatile void *pp, unsigned long v) { __acc_ua_volatile acc_uint32e_t *p = (__acc_ua_volatile acc_uint32e_t *) pp; __asm__ __volatile__("stwbrx %2,0,%1":"=m"(*p):"r"(p), "r"(v)); } # define ACC_UA_SET_LE32(p,v) __ACC_UA_SET_LE32(p,v) # endif # endif # endif # if !defined(ACC_UA_COPY32) # define ACC_UA_COPY32(d,s) ACC_UA_SET32(d, ACC_UA_GET32(s)) # endif # endif # if (ACC_OPT_UNALIGNED64) && defined(acc_int64l_t) # define ACC_UA_GET64(p) (* (__acc_ua_volatile const acc_uint64l_t*) (__acc_ua_volatile const void*) (p)) # define ACC_UA_SET64(p,v) (* (__acc_ua_volatile acc_uint64l_t*) (__acc_ua_volatile void*) (p) = (acc_uint64l_t) (v)) # if (ACC_ABI_BIG_ENDIAN) # define ACC_UA_GET_BE64(p) ACC_UA_GET64(p) # define ACC_UA_SET_BE64(p,v) ACC_UA_SET64(p,v) # elif (ACC_ABI_LITTLE_ENDIAN) # define ACC_UA_GET_LE64(p) ACC_UA_GET64(p) # define ACC_UA_SET_LE64(p,v) ACC_UA_SET64(p,v) # endif # if !defined(ACC_UA_COPY64) # define ACC_UA_COPY64(d,s) ACC_UA_SET64(d, ACC_UA_GET64(s)) # endif # endif # endif #endif #if defined(ACC_WANT_ACC_INCD_H) # undef ACC_WANT_ACC_INCD_H # ifndef __ACC_INCD_H_INCLUDED # define __ACC_INCD_H_INCLUDED 1 # if defined(ACC_LIBC_NAKED) # ifndef __ACC_FALLBACK_STDDEF_H_INCLUDED # define __ACC_FALLBACK_STDDEF_H_INCLUDED # if defined(__PTRDIFF_TYPE__) typedef __PTRDIFF_TYPE__ acc_fallback_ptrdiff_t; # elif defined(__MIPS_PSX2__) typedef int acc_fallback_ptrdiff_t; # else typedef long acc_fallback_ptrdiff_t; # endif # if defined(__SIZE_TYPE__) typedef __SIZE_TYPE__ acc_fallback_size_t; # elif defined(__MIPS_PSX2__) typedef unsigned int acc_fallback_size_t; # else typedef unsigned long acc_fallback_size_t; # endif # if !defined(ptrdiff_t) typedef acc_fallback_ptrdiff_t ptrdiff_t; # ifndef _PTRDIFF_T_DEFINED # define _PTRDIFF_T_DEFINED 1 # endif # endif # if !defined(size_t) typedef acc_fallback_size_t size_t; # ifndef _SIZE_T_DEFINED # define _SIZE_T_DEFINED 1 # endif # endif # if !defined(__cplusplus) && !defined(wchar_t) typedef unsigned short wchar_t; # ifndef _WCHAR_T_DEFINED # define _WCHAR_T_DEFINED 1 # endif # endif # ifndef NULL # if defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ >= 4) # define NULL __null # elif defined(__cplusplus) # define NULL 0 # else # define NULL ((void*)0) # endif # endif # ifndef offsetof # define offsetof(s,m) ((size_t)((ptrdiff_t)&(((s*)0)->m))) # endif # endif # elif defined(ACC_LIBC_FREESTANDING) # if HAVE_STDDEF_H # include # endif # if HAVE_STDINT_H # include # endif # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # if HAVE_STDIO_H # include # endif # if HAVE_STDDEF_H # include # endif # if HAVE_STDINT_H # include # endif # else # include # if defined(HAVE_TIME_H) && defined(__MSL__) && defined(__cplusplus) # include # endif # if HAVE_SYS_TYPES_H # include # endif # if HAVE_SYS_STAT_H # include # endif # if STDC_HEADERS # include # include # else # if HAVE_STDLIB_H # include # endif # endif # if HAVE_STRING_H # if !STDC_HEADERS && HAVE_MEMORY_H # include # endif # include # endif # if HAVE_STRINGS_H # include # endif # if HAVE_INTTYPES_H # include # else # if HAVE_STDINT_H # include # endif # endif # if HAVE_UNISTD_H # include # endif # endif # endif #endif #if defined(ACC_WANT_ACC_INCE_H) # undef ACC_WANT_ACC_INCE_H # ifndef __ACC_INCE_H_INCLUDED # define __ACC_INCE_H_INCLUDED 1 # if defined(ACC_LIBC_NAKED) # elif defined(ACC_LIBC_FREESTANDING) # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # if defined(HAVE_SETJMP_H) # include # endif # else # if defined(HAVE_STDARG_H) # include # endif # if defined(HAVE_CTYPE_H) # include # endif # if defined(HAVE_ERRNO_H) # include # endif # if defined(HAVE_MALLOC_H) # include # endif # if defined(HAVE_ALLOCA_H) # include # endif # if defined(HAVE_FCNTL_H) # include # endif # if defined(HAVE_DIRENT_H) # include # endif # if defined(HAVE_SETJMP_H) # include # endif # if defined(HAVE_SIGNAL_H) # include # endif # if defined(TIME_WITH_SYS_TIME) # include # include # elif defined(HAVE_TIME_H) # include # endif # if defined(HAVE_UTIME_H) # include # elif defined(HAVE_SYS_UTIME_H) # include # endif # if defined(HAVE_IO_H) # include # endif # if defined(HAVE_DOS_H) # include # endif # if defined(HAVE_DIRECT_H) # include # endif # if defined(HAVE_SHARE_H) # include # endif # if defined(ACC_CC_NDPC) # include # endif # if defined(__TOS__) && (defined(__PUREC__) || defined(__TURBOC__)) # include # endif # endif # endif #endif #if defined(ACC_WANT_ACC_INCI_H) # undef ACC_WANT_ACC_INCI_H # ifndef __ACC_INCI_H_INCLUDED # define __ACC_INCI_H_INCLUDED 1 # if defined(ACC_LIBC_NAKED) # elif defined(ACC_LIBC_FREESTANDING) # elif defined(ACC_LIBC_MOSTLY_FREESTANDING) # else # if (ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) # include # elif (ACC_HAVE_WINDOWS_H) # if 1 && !defined(WIN32_LEAN_AND_MEAN) # define WIN32_LEAN_AND_MEAN 1 # endif # if 1 && !defined(_WIN32_WINNT) # define _WIN32_WINNT 0x0400 # endif # include # if (ACC_CC_BORLANDC || ACC_CC_TURBOC) # include # endif # elif (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_WIN16) # if (ACC_CC_AZTECC) # include # include # elif (ACC_CC_BORLANDC || ACC_CC_TURBOC) # include # include # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # include # elif (ACC_CC_PACIFICC) # include # include # include # elif (ACC_CC_WATCOMC) # include # endif # elif (ACC_OS_OS216) # if (ACC_CC_WATCOMC) # include # endif # endif # if defined(HAVE_SYS_MMAN_H) # include # endif # if defined(HAVE_SYS_RESOURCE_H) # include # endif # if (ACC_OS_DOS16 || ACC_OS_OS216 || ACC_OS_WIN16) # if defined(FP_OFF) # define ACC_PTR_FP_OFF(x) FP_OFF(x) # elif defined(_FP_OFF) # define ACC_PTR_FP_OFF(x) _FP_OFF(x) # else # define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) # endif # if defined(FP_SEG) # define ACC_PTR_FP_SEG(x) FP_SEG(x) # elif defined(_FP_SEG) # define ACC_PTR_FP_SEG(x) _FP_SEG(x) # else # define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) # endif # if defined(MK_FP) # define ACC_PTR_MK_FP(s,o) MK_FP(s,o) # elif defined(_MK_FP) # define ACC_PTR_MK_FP(s,o) _MK_FP(s,o) # else # define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) # endif # if 0 # undef ACC_PTR_FP_OFF # undef ACC_PTR_FP_SEG # undef ACC_PTR_MK_FP # define ACC_PTR_FP_OFF(x) (((const unsigned __far*)&(x))[0]) # define ACC_PTR_FP_SEG(x) (((const unsigned __far*)&(x))[1]) # define ACC_PTR_MK_FP(s,o) ((void __far*)(((unsigned long)(s)<<16)+(unsigned)(o))) # endif # endif # endif # endif #endif #if defined(ACC_WANT_ACC_LIB_H) # undef ACC_WANT_ACC_LIB_H # ifndef __ACC_LIB_H_INCLUDED # define __ACC_LIB_H_INCLUDED 1 # if !defined(__ACCLIB_FUNCNAME) # define __ACCLIB_FUNCNAME(f) f # endif # if !defined(ACCLIB_EXTERN) # define ACCLIB_EXTERN(r,f) extern r __ACCLIB_FUNCNAME(f) # endif # if !defined(ACCLIB_EXTERN_NOINLINE) # if defined(__acc_noinline) # define ACCLIB_EXTERN_NOINLINE(r,f) extern __acc_noinline r __ACCLIB_FUNCNAME(f) # else # define ACCLIB_EXTERN_NOINLINE(r,f) extern r __ACCLIB_FUNCNAME(f) # endif # endif # if !defined(__ACCLIB_CONST_CAST_RETURN) # if 1 && (ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __ACCLIB_CONST_CAST_RETURN(type,var) return (type) (acc_uintptr_t) (var); # elif (ACC_CC_GNUC || ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __ACCLIB_CONST_CAST_RETURN(type,var) \ { union { type a; const type b; } u; u.b = (var); return u.a; } # else # define __ACCLIB_CONST_CAST_RETURN(type,var) return (type) (var); # endif # endif # if (ACC_OS_WIN64) # define acclib_handle_t acc_int64l_t # define acclib_uhandle_t acc_uint64l_t # elif (ACC_ARCH_I386 && ACC_CC_MSC && (_MSC_VER >= 1300)) typedef __w64 long acclib_handle_t; typedef __w64 unsigned long acclib_uhandle_t; # define acclib_handle_t acclib_handle_t # define acclib_uhandle_t acclib_uhandle_t # else # define acclib_handle_t long # define acclib_uhandle_t unsigned long # endif # if 0 ACCLIB_EXTERN(int, acc_ascii_digit) (int); ACCLIB_EXTERN(int, acc_ascii_islower) (int); ACCLIB_EXTERN(int, acc_ascii_isupper) (int); ACCLIB_EXTERN(int, acc_ascii_tolower) (int); ACCLIB_EXTERN(int, acc_ascii_toupper) (int); ACCLIB_EXTERN(int, acc_ascii_utolower) (int); ACCLIB_EXTERN(int, acc_ascii_utoupper) (int); # endif # define acc_ascii_isdigit(c) (((unsigned)(c) - 48) < 10) # define acc_ascii_islower(c) (((unsigned)(c) - 97) < 26) # define acc_ascii_isupper(c) (((unsigned)(c) - 65) < 26) # define acc_ascii_tolower(c) ((int)(c) + (acc_ascii_isupper(c) << 5)) # define acc_ascii_toupper(c) ((int)(c) - (acc_ascii_islower(c) << 5)) # define acc_ascii_utolower(c) acc_ascii_tolower((unsigned char)(c)) # define acc_ascii_utoupper(c) acc_ascii_toupper((unsigned char)(c)) # ifndef acc_hsize_t # if (ACC_HAVE_MM_HUGE_PTR) # define acc_hsize_t unsigned long # define acc_hvoid_p void __huge * # define acc_hchar_p char __huge * # define acc_hchar_pp char __huge * __huge * # define acc_hbyte_p unsigned char __huge * # else # define acc_hsize_t size_t # define acc_hvoid_p void * # define acc_hchar_p char * # define acc_hchar_pp char ** # define acc_hbyte_p unsigned char * # endif # endif ACCLIB_EXTERN(acc_hvoid_p, acc_halloc) (acc_hsize_t); ACCLIB_EXTERN(void, acc_hfree) (acc_hvoid_p); # if (ACC_OS_DOS16 || ACC_OS_OS216) ACCLIB_EXTERN(void __far *, acc_dos_alloc) (unsigned long); ACCLIB_EXTERN(int, acc_dos_free) (void __far *); # endif ACCLIB_EXTERN(int, acc_hmemcmp) (const acc_hvoid_p, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemcpy) (acc_hvoid_p, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemmove) (acc_hvoid_p, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemset) (acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hsize_t, acc_hstrlen) (const acc_hchar_p); ACCLIB_EXTERN(int, acc_hstrcmp) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(int, acc_hstrncmp) (const acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(int, acc_ascii_hstricmp) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(int, acc_ascii_hstrnicmp) (const acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(int, acc_ascii_hmemicmp) (const acc_hvoid_p, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hchar_p, acc_hstrstr) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_ascii_hstristr) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemmem) (const acc_hvoid_p, acc_hsize_t, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_ascii_hmemimem) (const acc_hvoid_p, acc_hsize_t, const acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hchar_p, acc_hstrcpy) (acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_hstrcat) (acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hsize_t, acc_hstrlcpy) (acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(acc_hsize_t, acc_hstrlcat) (acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(int, acc_hstrscpy) (acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(int, acc_hstrscat) (acc_hchar_p, const acc_hchar_p, acc_hsize_t); ACCLIB_EXTERN(acc_hchar_p, acc_hstrccpy) (acc_hchar_p, const acc_hchar_p, int); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemccpy) (acc_hvoid_p, const acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hchar_p, acc_hstrchr) (const acc_hchar_p, int); ACCLIB_EXTERN(acc_hchar_p, acc_hstrrchr) (const acc_hchar_p, int); ACCLIB_EXTERN(acc_hchar_p, acc_ascii_hstrichr) (const acc_hchar_p, int); ACCLIB_EXTERN(acc_hchar_p, acc_ascii_hstrrichr) (const acc_hchar_p, int); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemchr) (const acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_hmemrchr) (const acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_ascii_hmemichr) (const acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_ascii_hmemrichr) (const acc_hvoid_p, int, acc_hsize_t); ACCLIB_EXTERN(acc_hsize_t, acc_hstrspn) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hsize_t, acc_hstrrspn) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hsize_t, acc_hstrcspn) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hsize_t, acc_hstrrcspn) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_hstrpbrk) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_hstrrpbrk) (const acc_hchar_p, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_hstrsep) (acc_hchar_pp, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_hstrrsep) (acc_hchar_pp, const acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_ascii_hstrlwr) (acc_hchar_p); ACCLIB_EXTERN(acc_hchar_p, acc_ascii_hstrupr) (acc_hchar_p); ACCLIB_EXTERN(acc_hvoid_p, acc_ascii_hmemlwr) (acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hvoid_p, acc_ascii_hmemupr) (acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hsize_t, acc_hfread) (void *, acc_hvoid_p, acc_hsize_t); ACCLIB_EXTERN(acc_hsize_t, acc_hfwrite) (void *, const acc_hvoid_p, acc_hsize_t); # if (ACC_HAVE_MM_HUGE_PTR) ACCLIB_EXTERN(long, acc_hread) (int, acc_hvoid_p, long); ACCLIB_EXTERN(long, acc_hwrite) (int, const acc_hvoid_p, long); # endif ACCLIB_EXTERN(long, acc_safe_hread) (int, acc_hvoid_p, long); ACCLIB_EXTERN(long, acc_safe_hwrite) (int, const acc_hvoid_p, long); ACCLIB_EXTERN(unsigned, acc_ua_get_be16) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_be24) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_be32) (const acc_hvoid_p); ACCLIB_EXTERN(void, acc_ua_set_be16) (acc_hvoid_p, unsigned); ACCLIB_EXTERN(void, acc_ua_set_be24) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(void, acc_ua_set_be32) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(unsigned, acc_ua_get_le16) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p); ACCLIB_EXTERN(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p); ACCLIB_EXTERN(void, acc_ua_set_le16) (acc_hvoid_p, unsigned); ACCLIB_EXTERN(void, acc_ua_set_le24) (acc_hvoid_p, acc_uint32l_t); ACCLIB_EXTERN(void, acc_ua_set_le32) (acc_hvoid_p, acc_uint32l_t); # if defined(acc_int64l_t) ACCLIB_EXTERN(acc_uint64l_t, acc_ua_get_be64) (const acc_hvoid_p); ACCLIB_EXTERN(void, acc_ua_set_be64) (acc_hvoid_p, acc_uint64l_t); ACCLIB_EXTERN(acc_uint64l_t, acc_ua_get_le64) (const acc_hvoid_p); ACCLIB_EXTERN(void, acc_ua_set_le64) (acc_hvoid_p, acc_uint64l_t); # endif ACCLIB_EXTERN_NOINLINE(short, acc_vget_short) (short, int); ACCLIB_EXTERN_NOINLINE(int, acc_vget_int) (int, int); ACCLIB_EXTERN_NOINLINE(long, acc_vget_long) (long, int); # if defined(acc_int64l_t) ACCLIB_EXTERN_NOINLINE(acc_int64l_t, acc_vget_acc_int64l_t) (acc_int64l_t, int); # endif ACCLIB_EXTERN_NOINLINE(acc_hsize_t, acc_vget_acc_hsize_t) (acc_hsize_t, int); # if !defined(ACC_CFG_NO_FLOAT) ACCLIB_EXTERN_NOINLINE(float, acc_vget_float) (float, int); # endif # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_EXTERN_NOINLINE(double, acc_vget_double) (double, int); # endif ACCLIB_EXTERN_NOINLINE(acc_hvoid_p, acc_vget_acc_hvoid_p) (acc_hvoid_p, int); ACCLIB_EXTERN_NOINLINE(const acc_hvoid_p, acc_vget_acc_hvoid_cp) (const acc_hvoid_p, int); # if !defined(ACC_FN_PATH_MAX) # if (ACC_OS_DOS16 || ACC_OS_WIN16) # define ACC_FN_PATH_MAX 143 # elif (ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN32 || ACC_OS_WIN64) # define ACC_FN_PATH_MAX 259 # elif (ACC_OS_TOS) # define ACC_FN_PATH_MAX 259 # endif # endif # if !defined(ACC_FN_PATH_MAX) # define ACC_FN_PATH_MAX 1023 # endif # if !defined(ACC_FN_NAME_MAX) # if (ACC_OS_DOS16 || ACC_OS_WIN16) # define ACC_FN_NAME_MAX 12 # elif (ACC_ARCH_M68K && ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) # define ACC_FN_NAME_MAX 12 # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # elif (ACC_OS_DOS32) # define ACC_FN_NAME_MAX 12 # endif # endif # if !defined(ACC_FN_NAME_MAX) # define ACC_FN_NAME_MAX ACC_FN_PATH_MAX # endif # define ACC_FNMATCH_NOESCAPE 1 # define ACC_FNMATCH_PATHNAME 2 # define ACC_FNMATCH_PATHSTAR 4 # define ACC_FNMATCH_PERIOD 8 # define ACC_FNMATCH_ASCII_CASEFOLD 16 ACCLIB_EXTERN(int, acc_fnmatch) (const acc_hchar_p, const acc_hchar_p, int); # undef __ACCLIB_USE_OPENDIR # if (HAVE_DIRENT_H || ACC_CC_WATCOMC) # define __ACCLIB_USE_OPENDIR 1 # if (ACC_OS_DOS32 && defined(__BORLANDC__)) # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # elif (ACC_OS_OS2 || ACC_OS_OS216) # elif (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) # elif (ACC_OS_WIN32 && !defined(ACC_HAVE_WINDOWS_H)) # elif (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_TOS || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) # undef __ACCLIB_USE_OPENDIR # endif # endif typedef struct { # if defined(__ACCLIB_USE_OPENDIR) void *u_dirp; # if (ACC_CC_WATCOMC) unsigned short f_time; unsigned short f_date; unsigned long f_size; # endif char f_name[ACC_FN_NAME_MAX + 1]; # elif (ACC_OS_WIN32 || ACC_OS_WIN64) acclib_handle_t u_handle; unsigned f_attr; unsigned f_size_low; unsigned f_size_high; char f_name[ACC_FN_NAME_MAX + 1]; # elif (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_TOS || ACC_OS_WIN16) char u_dta[21]; unsigned char f_attr; unsigned short f_time; unsigned short f_date; unsigned short f_size_low; unsigned short f_size_high; char f_name[ACC_FN_NAME_MAX + 1]; char u_dirp; # else void *u_dirp; char f_name[ACC_FN_NAME_MAX + 1]; # endif } acc_dir_t; # ifndef acc_dir_p # define acc_dir_p acc_dir_t * # endif ACCLIB_EXTERN(int, acc_opendir) (acc_dir_p, const char *); ACCLIB_EXTERN(int, acc_readdir) (acc_dir_p); ACCLIB_EXTERN(int, acc_closedir) (acc_dir_p); # if (ACC_CC_GNUC) && (defined(__CYGWIN__) || defined(__MINGW32__)) # define acc_alloca(x) __builtin_alloca((x)) # elif (ACC_CC_GNUC) && (ACC_OS_CONSOLE_PS2) # define acc_alloca(x) __builtin_alloca((x)) # elif (ACC_CC_BORLANDC || ACC_CC_LCC) && defined(__linux__) # elif (HAVE_ALLOCA) # define acc_alloca(x) ((void *) (alloca((x)))) # endif # if (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # define acc_stackavail() stackavail() # elif (ACC_ARCH_I086 && ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0410)) # define acc_stackavail() stackavail() # elif (ACC_ARCH_I086 && ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0400)) # if (ACC_OS_WIN16) && (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM) # else # define acc_stackavail() stackavail() # endif # elif ((ACC_ARCH_I086 || ACC_ARCH_I386) && (ACC_CC_DMC || ACC_CC_SYMANTECC)) # define acc_stackavail() stackavail() # elif ((ACC_ARCH_I086) && ACC_CC_MSC && (_MSC_VER >= 700)) # define acc_stackavail() _stackavail() # elif ((ACC_ARCH_I086) && ACC_CC_MSC) # define acc_stackavail() stackavail() # elif ((ACC_ARCH_I086 || ACC_ARCH_I386) && ACC_CC_TURBOC && (__TURBOC__ >= 0x0450)) # define acc_stackavail() stackavail() # elif (ACC_ARCH_I086 && ACC_CC_TURBOC && (__TURBOC__ >= 0x0400)) ACC_EXTERN_C size_t __cdecl stackavail(void); # define acc_stackavail() stackavail() # elif ((ACC_ARCH_I086 || ACC_ARCH_I386) && (ACC_CC_WATCOMC)) # define acc_stackavail() stackavail() # elif (ACC_ARCH_I086 && ACC_CC_ZORTECHC) # define acc_stackavail() _chkstack() # endif ACCLIB_EXTERN(acclib_handle_t, acc_get_osfhandle) (int); ACCLIB_EXTERN(const char *, acc_getenv) (const char *); ACCLIB_EXTERN(int, acc_isatty) (int); ACCLIB_EXTERN(int, acc_mkdir) (const char *, unsigned); ACCLIB_EXTERN(int, acc_rmdir) (const char *); ACCLIB_EXTERN(int, acc_response) (int *, char ***); ACCLIB_EXTERN(int, acc_set_binmode) (int, int); # if defined(acc_int32e_t) ACCLIB_EXTERN(acc_int32e_t, acc_muldiv32s) (acc_int32e_t, acc_int32e_t, acc_int32e_t); ACCLIB_EXTERN(acc_uint32e_t, acc_muldiv32u) (acc_uint32e_t, acc_uint32e_t, acc_uint32e_t); # endif ACCLIB_EXTERN(void, acc_wildargv) (int *, char ***); ACCLIB_EXTERN_NOINLINE(void, acc_debug_break) (void); ACCLIB_EXTERN_NOINLINE(void, acc_debug_nop) (void); ACCLIB_EXTERN_NOINLINE(int, acc_debug_align_check_query) (void); ACCLIB_EXTERN_NOINLINE(int, acc_debug_align_check_enable) (int); ACCLIB_EXTERN_NOINLINE(unsigned, acc_debug_running_on_qemu) (void); ACCLIB_EXTERN_NOINLINE(unsigned, acc_debug_running_on_valgrind) (void); # if !defined(acc_int64l_t) || defined(ACC_CFG_NO_DOUBLE) # undef __ACCLIB_PCLOCK_USE_RDTSC # undef __ACCLIB_PCLOCK_USE_PERFCTR # undef __ACCLIB_UCLOCK_USE_RDTSC # undef __ACCLIB_UCLOCK_USE_PERFCTR # else typedef struct { void *h; int mode; double tsc_to_seconds; unsigned cpu_type, cpu_features, cpu_khz, cpu_nrctrs; const char *cpu_name; } acc_perfctr_handle_t; typedef struct { acc_uint64l_t tsc; # if (ACC_OS_POSIX_LINUX) acc_uint64l_t pmc[18]; # else acc_uint64l_t pmc[1]; # endif } acc_perfctr_clock_t; # ifndef acc_perfctr_handle_p # define acc_perfctr_handle_p acc_perfctr_handle_t * # endif # ifndef acc_perfctr_clock_p # define acc_perfctr_clock_p acc_perfctr_clock_t * # endif ACCLIB_EXTERN(int, acc_perfctr_open) (acc_perfctr_handle_p); ACCLIB_EXTERN(int, acc_perfctr_close) (acc_perfctr_handle_p); ACCLIB_EXTERN(void, acc_perfctr_read) (acc_perfctr_handle_p, acc_perfctr_clock_p); # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_EXTERN(double, acc_perfctr_get_elapsed) (acc_perfctr_handle_p, const acc_perfctr_clock_p, const acc_perfctr_clock_p); ACCLIB_EXTERN(double, acc_perfctr_get_elapsed_tsc) (acc_perfctr_handle_p, acc_uint64l_t); # endif ACCLIB_EXTERN(int, acc_perfctr_flush_cpu_cache) (acc_perfctr_handle_p, unsigned); # endif # if defined(acc_int32e_t) ACCLIB_EXTERN(int, acc_tsc_read) (acc_uint32e_t *); # else # undef __ACCLIB_PCLOCK_USE_RDTSC # undef __ACCLIB_UCLOCK_USE_RDTSC # endif struct acc_pclock_handle_t; struct acc_pclock_t; typedef struct acc_pclock_handle_t acc_pclock_handle_t; typedef struct acc_pclock_t acc_pclock_t; # ifndef acc_pclock_handle_p # define acc_pclock_handle_p acc_pclock_handle_t * # endif # ifndef acc_pclock_p # define acc_pclock_p acc_pclock_t * # endif # define ACC_PCLOCK_REALTIME 0 # define ACC_PCLOCK_MONOTONIC 1 # define ACC_PCLOCK_PROCESS_CPUTIME_ID 2 # define ACC_PCLOCK_THREAD_CPUTIME_ID 3 # define ACC_PCLOCK_REALTIME_HR 4 # define ACC_PCLOCK_MONOTONIC_HR 5 struct acc_pclock_handle_t { acclib_handle_t h; int mode; const char *name; int (*gettime) (acc_pclock_handle_p, acc_pclock_p); # if defined(acc_int64l_t) acc_uint64l_t ticks_base; # endif # if defined(__ACCLIB_PCLOCK_USE_PERFCTR) acc_perfctr_handle_t pch; # endif }; struct acc_pclock_t { # if defined(acc_int64l_t) acc_int64l_t tv_sec; # else acc_int32l_t tv_sec_high; acc_uint32l_t tv_sec_low; # endif acc_uint32l_t tv_nsec; }; ACCLIB_EXTERN(int, acc_pclock_open) (acc_pclock_handle_p, int); ACCLIB_EXTERN(int, acc_pclock_open_default) (acc_pclock_handle_p); ACCLIB_EXTERN(int, acc_pclock_close) (acc_pclock_handle_p); ACCLIB_EXTERN(void, acc_pclock_read) (acc_pclock_handle_p, acc_pclock_p); # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_EXTERN(double, acc_pclock_get_elapsed) (acc_pclock_handle_p, const acc_pclock_p, const acc_pclock_p); # endif ACCLIB_EXTERN(int, acc_pclock_flush_cpu_cache) (acc_pclock_handle_p, unsigned); # if !defined(acc_int64l_t) || defined(ACC_CFG_NO_DOUBLE) # undef __ACCLIB_UCLOCK_USE_QPC # elif (ACC_OS_CYGWIN || ACC_OS_EMX || ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_HAVE_WINDOWS_H) # define __ACCLIB_UCLOCK_USE_QPC 1 # else # undef __ACCLIB_UCLOCK_USE_QPC # endif typedef struct { acclib_handle_t h; int mode; const char *name; # if defined(__ACCLIB_UCLOCK_USE_PERFCTR) acc_perfctr_handle_t pch; # endif # if defined(__ACCLIB_UCLOCK_USE_QPC) double qpf; # endif } acc_uclock_handle_t; typedef struct { union { acc_uint32l_t t32; # if !(ACC_OS_DOS16 || ACC_OS_WIN16) # if !defined(ACC_CFG_NO_DOUBLE) double td; # endif # if defined(acc_int64l_t) acc_int64l_t t64; # endif # endif } ticks; # if defined(__ACCLIB_UCLOCK_USE_RDTSC) acc_uint64l_t tsc; # endif # if defined(__ACCLIB_UCLOCK_USE_PERFCTR) acc_perfctr_clock_t pcc; # endif # if defined(__ACCLIB_UCLOCK_USE_QPC) acc_int64l_t qpc; # endif } acc_uclock_t; # ifndef acc_uclock_handle_p # define acc_uclock_handle_p acc_uclock_handle_t * # endif # ifndef acc_uclock_p # define acc_uclock_p acc_uclock_t * # endif ACCLIB_EXTERN(int, acc_uclock_open) (acc_uclock_handle_p); ACCLIB_EXTERN(int, acc_uclock_close) (acc_uclock_handle_p); ACCLIB_EXTERN(void, acc_uclock_read) (acc_uclock_handle_p, acc_uclock_p); # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_EXTERN(double, acc_uclock_get_elapsed) (acc_uclock_handle_p, const acc_uclock_p, const acc_uclock_p); # endif ACCLIB_EXTERN(int, acc_uclock_flush_cpu_cache) (acc_uclock_handle_p, unsigned); struct acc_getopt_t; typedef struct acc_getopt_t acc_getopt_t; # ifndef acc_getopt_p # define acc_getopt_p acc_getopt_t * # endif struct acc_getopt_longopt_t; typedef struct acc_getopt_longopt_t acc_getopt_longopt_t; # ifndef acc_getopt_longopt_p # define acc_getopt_longopt_p acc_getopt_longopt_t * # endif struct acc_getopt_longopt_t { const char *name; int has_arg; int *flag; int val; }; struct acc_getopt_t { void *user; char *optarg; void (*opterr) (acc_getopt_p, const char *, void *); int optind; int optopt; int errcount; const char *progname; int argc; char **argv; int eof; int shortpos; int pending_rotate_first, pending_rotate_middle; }; enum { ACC_GETOPT_NO_ARG, ACC_GETOPT_REQUIRED_ARG, ACC_GETOPT_OPTIONAL_ARG, ACC_GETOPT_EXACT_ARG = 0x10 }; enum { ACC_GETOPT_PERMUTE, ACC_GETOPT_RETURN_IN_ORDER, ACC_GETOPT_REQUIRE_ORDER }; ACCLIB_EXTERN(void, acc_getopt_init) (acc_getopt_p g, int start_argc, int argc, char **argv); ACCLIB_EXTERN(int, acc_getopt) (acc_getopt_p g, const char *shortopts, const acc_getopt_longopt_p longopts, int *longind); typedef struct { acc_uint32l_t seed; } acc_rand31_t; # ifndef acc_rand31_p # define acc_rand31_p acc_rand31_t * # endif ACCLIB_EXTERN(void, acc_srand31) (acc_rand31_p, acc_uint32l_t); ACCLIB_EXTERN(acc_uint32l_t, acc_rand31) (acc_rand31_p); # if defined(acc_int64l_t) typedef struct { acc_uint64l_t seed; } acc_rand48_t; # ifndef acc_rand48_p # define acc_rand48_p acc_rand48_t * # endif ACCLIB_EXTERN(void, acc_srand48) (acc_rand48_p, acc_uint32l_t); ACCLIB_EXTERN(acc_uint32l_t, acc_rand48) (acc_rand48_p); ACCLIB_EXTERN(acc_uint32l_t, acc_rand48_r32) (acc_rand48_p); # endif # if defined(acc_int64l_t) typedef struct { acc_uint64l_t seed; } acc_rand64_t; # ifndef acc_rand64_p # define acc_rand64_p acc_rand64_t * # endif ACCLIB_EXTERN(void, acc_srand64) (acc_rand64_p, acc_uint64l_t); ACCLIB_EXTERN(acc_uint32l_t, acc_rand64) (acc_rand64_p); ACCLIB_EXTERN(acc_uint32l_t, acc_rand64_r32) (acc_rand64_p); # endif typedef struct { unsigned n; acc_uint32l_t s[624]; } acc_randmt_t; # ifndef acc_randmt_p # define acc_randmt_p acc_randmt_t * # endif ACCLIB_EXTERN(void, acc_srandmt) (acc_randmt_p, acc_uint32l_t); ACCLIB_EXTERN(acc_uint32l_t, acc_randmt) (acc_randmt_p); ACCLIB_EXTERN(acc_uint32l_t, acc_randmt_r32) (acc_randmt_p); # if defined(acc_int64l_t) typedef struct { unsigned n; acc_uint64l_t s[312]; } acc_randmt64_t; # ifndef acc_randmt64_p # define acc_randmt64_p acc_randmt64_t * # endif ACCLIB_EXTERN(void, acc_srandmt64) (acc_randmt64_p, acc_uint64l_t); ACCLIB_EXTERN(acc_uint64l_t, acc_randmt64_r64) (acc_randmt64_p); # endif # define ACC_SPAWN_P_WAIT 0 # define ACC_SPAWN_P_NOWAIT 1 ACCLIB_EXTERN(int, acc_spawnv) (int mode, const char *fn, const char *const *argv); ACCLIB_EXTERN(int, acc_spawnvp) (int mode, const char *fn, const char *const *argv); ACCLIB_EXTERN(int, acc_spawnve) (int mode, const char *fn, const char *const *argv, const char *const envp); # endif #endif #if defined(ACC_WANT_ACC_CXX_H) # undef ACC_WANT_ACC_CXX_H # ifndef __ACC_CXX_H_INCLUDED # define __ACC_CXX_H_INCLUDED 1 # if defined(__cplusplus) # if defined(ACC_CXX_NOTHROW) # elif (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020800ul)) # elif (ACC_CC_BORLANDC && (__BORLANDC__ < 0x0450)) # elif (ACC_CC_HIGHC) # elif (ACC_CC_MSC && (_MSC_VER < 1100)) # elif (ACC_CC_NDPC) # elif (ACC_CC_TURBOC) # elif (ACC_CC_WATCOMC && !defined(_CPPUNWIND)) # elif (ACC_CC_ZORTECHC) # else # define ACC_CXX_NOTHROW throw() # endif # if !defined(ACC_CXX_NOTHROW) # define ACC_CXX_NOTHROW # endif # if defined(__ACC_CXX_DO_NEW) # elif (ACC_CC_NDPC || ACC_CC_PGI) # define __ACC_CXX_DO_NEW { return 0; } # elif ((ACC_CC_BORLANDC || ACC_CC_TURBOC) && ACC_ARCH_I086) # define __ACC_CXX_DO_NEW { return 0; } # else # define __ACC_CXX_DO_NEW ; # endif # if defined(__ACC_CXX_DO_DELETE) # elif (ACC_CC_BORLANDC || ACC_CC_TURBOC) # define __ACC_CXX_DO_DELETE { } # else # define __ACC_CXX_DO_DELETE ACC_CXX_NOTHROW { } # endif # if (ACC_CC_BORLANDC && (__BORLANDC__ < 0x0450)) # elif (ACC_CC_MSC && ACC_MM_HUGE) # define ACC_CXX_DISABLE_NEW_DELETE private: # elif (ACC_CC_MSC && (_MSC_VER < 1100)) # elif (ACC_CC_NDPC) # elif (ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) # elif (ACC_CC_TURBOC) # elif (ACC_CC_WATCOMC && (__WATCOMC__ < 1100)) # else # define __ACC_CXX_HAVE_ARRAY_NEW 1 # endif # if (__ACC_CXX_HAVE_ARRAY_NEW) # define __ACC_CXX_HAVE_PLACEMENT_NEW 1 # endif # if (__ACC_CXX_HAVE_PLACEMENT_NEW) # if (ACC_CC_GNUC >= 0x030000ul) # define __ACC_CXX_HAVE_PLACEMENT_DELETE 1 # elif (ACC_CC_INTELC) # define __ACC_CXX_HAVE_PLACEMENT_DELETE 1 # elif (ACC_CC_MSC && (_MSC_VER >= 1200)) # define __ACC_CXX_HAVE_PLACEMENT_DELETE 1 # elif (ACC_CC_LLVM || ACC_CC_PATHSCALE) # define __ACC_CXX_HAVE_PLACEMENT_DELETE 1 # elif (ACC_CC_PGI) # define __ACC_CXX_HAVE_PLACEMENT_DELETE 1 # endif # endif # if defined(ACC_CXX_DISABLE_NEW_DELETE) # elif defined(new) || defined(delete) # define ACC_CXX_DISABLE_NEW_DELETE private: # elif (ACC_CC_GNUC && (ACC_CC_GNUC < 0x025b00ul)) # define ACC_CXX_DISABLE_NEW_DELETE private: # elif (ACC_CC_HIGHC) # define ACC_CXX_DISABLE_NEW_DELETE private: # elif !defined(__ACC_CXX_HAVE_ARRAY_NEW) # define ACC_CXX_DISABLE_NEW_DELETE \ protected: static void operator delete(void*) __ACC_CXX_DO_DELETE \ protected: static void* operator new(size_t) __ACC_CXX_DO_NEW \ private: # else # define ACC_CXX_DISABLE_NEW_DELETE \ protected: static void operator delete(void*) __ACC_CXX_DO_DELETE \ static void operator delete[](void*) __ACC_CXX_DO_DELETE \ private: static void* operator new(size_t) __ACC_CXX_DO_NEW \ static void* operator new[](size_t) __ACC_CXX_DO_NEW # endif # if defined(ACC_CXX_TRIGGER_FUNCTION) # else # define ACC_CXX_TRIGGER_FUNCTION \ protected: virtual const void* acc_cxx_trigger_function() const; \ private: # endif # if defined(ACC_CXX_TRIGGER_FUNCTION_IMPL) # else # define ACC_CXX_TRIGGER_FUNCTION_IMPL(klass) \ const void* klass::acc_cxx_trigger_function() const { return 0; } # endif # endif # endif #endif #if defined(ACC_WANT_ACC_CHK_CH) # undef ACC_WANT_ACC_CHK_CH # if !defined(ACCCHK_ASSERT) # define ACCCHK_ASSERT(expr) ACC_COMPILE_TIME_ASSERT_HEADER(expr) # endif # if !defined(ACCCHK_ASSERT_SIGN_T) # define ACCCHK_ASSERT_SIGN_T(type,relop) \ ACCCHK_ASSERT( (type) (-1) relop (type) 0 ) \ ACCCHK_ASSERT( (type) (~(type)0) relop (type) 0 ) \ ACCCHK_ASSERT( (type) (~(type)0) == (type) (-1) ) # endif # if !defined(ACCCHK_ASSERT_IS_SIGNED_T) # define ACCCHK_ASSERT_IS_SIGNED_T(type) ACCCHK_ASSERT_SIGN_T(type,<) # endif # if !defined(ACCCHK_ASSERT_IS_UNSIGNED_T) # if (ACC_BROKEN_INTEGRAL_PROMOTION) # define ACCCHK_ASSERT_IS_UNSIGNED_T(type) \ ACCCHK_ASSERT( (type) (-1) > (type) 0 ) # else # define ACCCHK_ASSERT_IS_UNSIGNED_T(type) ACCCHK_ASSERT_SIGN_T(type,>) # endif # endif # if (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0550) && (__BORLANDC__ < 0x0560)) # pragma option push -w-8055 # elif (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0530) && (__BORLANDC__ < 0x0550)) # pragma option push -w-osh # endif # if (ACC_0xffffffffL - ACC_UINT32_C(4294967294) != 1) # error "preprocessor error 1" # endif # if (ACC_0xffffffffL - ACC_UINT32_C(0xfffffffd) != 2) # error "preprocessor error 2" # endif # define ACCCHK_VAL 1 # define ACCCHK_TMP1 ACCCHK_VAL # undef ACCCHK_VAL # define ACCCHK_VAL 2 # define ACCCHK_TMP2 ACCCHK_VAL # if (ACCCHK_TMP1 != 2) # error "preprocessor error 3a" # endif # if (ACCCHK_TMP2 != 2) # error "preprocessor error 3b" # endif # undef ACCCHK_VAL # if (ACCCHK_TMP2) # error "preprocessor error 3c" # endif # if (ACCCHK_TMP2 + 0 != 0) # error "preprocessor error 3d" # endif # undef ACCCHK_TMP1 # undef ACCCHK_TMP2 # if 0 || defined(ACCCHK_CFG_PEDANTIC) # if (ACC_ARCH_MIPS) && defined(_MIPS_SZINT) ACCCHK_ASSERT((_MIPS_SZINT) == 8 * sizeof(int)) # endif # if (ACC_ARCH_MIPS) && defined(_MIPS_SZLONG) ACCCHK_ASSERT((_MIPS_SZLONG) == 8 * sizeof(long)) # endif # if (ACC_ARCH_MIPS) && defined(_MIPS_SZPTR) ACCCHK_ASSERT((_MIPS_SZPTR) == 8 * sizeof(void *)) # endif # endif ACCCHK_ASSERT(1 == 1) ACCCHK_ASSERT(__ACC_MASK_GEN(1u, 2) == 3) ACCCHK_ASSERT(__ACC_MASK_GEN(1u, 8) == 255) # if (SIZEOF_INT >= 2) ACCCHK_ASSERT(__ACC_MASK_GEN(1, 15) == 32767) ACCCHK_ASSERT(__ACC_MASK_GEN(1u, 16) == 0xffffU) # else ACCCHK_ASSERT(__ACC_MASK_GEN(1ul, 16) == 0xffffUL) # endif # if (SIZEOF_INT >= 4) ACCCHK_ASSERT(__ACC_MASK_GEN(1, 31) == 2147483647) ACCCHK_ASSERT(__ACC_MASK_GEN(1u, 32) == 0xffffffffU) # endif # if (SIZEOF_LONG >= 4) ACCCHK_ASSERT(__ACC_MASK_GEN(1ul, 32) == 0xffffffffUL) # endif # if (SIZEOF_LONG >= 8) ACCCHK_ASSERT(__ACC_MASK_GEN(1ul, 64) == 0xffffffffffffffffUL) # endif # if !defined(ACC_BROKEN_INTEGRAL_PROMOTION) ACCCHK_ASSERT(__ACC_MASK_GEN(1u, SIZEOF_INT * 8) == ~0u) ACCCHK_ASSERT(__ACC_MASK_GEN(1ul, SIZEOF_LONG * 8) == ~0ul) # endif # if !defined(ACC_BROKEN_SIGNED_RIGHT_SHIFT) ACCCHK_ASSERT(((-1) >> 7) == -1) # endif ACCCHK_ASSERT(((1) >> 7) == 0) ACCCHK_ASSERT((~0l & ~0) == ~0l) ACCCHK_ASSERT((~0l & ~0u) == ~0u) ACCCHK_ASSERT((~0ul & ~0) == ~0ul) ACCCHK_ASSERT((~0ul & ~0u) == ~0u) # if defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0150) # elif (SIZEOF_INT == 2) ACCCHK_ASSERT((~0l & ~0u) == 0xffffU) ACCCHK_ASSERT((~0ul & ~0u) == 0xffffU) # elif (SIZEOF_INT == 4) ACCCHK_ASSERT((~0l & ~0u) == 0xffffffffU) ACCCHK_ASSERT((~0ul & ~0u) == 0xffffffffU) # endif ACCCHK_ASSERT_IS_SIGNED_T(signed char) ACCCHK_ASSERT_IS_UNSIGNED_T(unsigned char) ACCCHK_ASSERT(sizeof(signed char) == sizeof(char)) ACCCHK_ASSERT(sizeof(unsigned char) == sizeof(char)) ACCCHK_ASSERT(sizeof(char) == 1) # if (ACC_CC_CILLY) && (!defined(__CILLY__) || (__CILLY__ < 0x010302L)) # else ACCCHK_ASSERT(sizeof(char) == sizeof((char) 0)) # endif # if defined(__cplusplus) ACCCHK_ASSERT(sizeof('\0') == sizeof(char)) # else # if (ACC_CC_DMC) # else ACCCHK_ASSERT(sizeof('\0') == sizeof(int)) # endif # endif # if defined(__acc_alignof) ACCCHK_ASSERT(__acc_alignof(char) == 1) ACCCHK_ASSERT(__acc_alignof(signed char) == 1) ACCCHK_ASSERT(__acc_alignof(unsigned char) == 1) # if defined(acc_int16e_t) ACCCHK_ASSERT(__acc_alignof(acc_int16e_t) >= 1) ACCCHK_ASSERT(__acc_alignof(acc_int16e_t) <= 2) # endif # if defined(acc_int32e_t) ACCCHK_ASSERT(__acc_alignof(acc_int32e_t) >= 1) ACCCHK_ASSERT(__acc_alignof(acc_int32e_t) <= 4) # endif # endif ACCCHK_ASSERT_IS_SIGNED_T(short) ACCCHK_ASSERT_IS_UNSIGNED_T(unsigned short) ACCCHK_ASSERT(sizeof(short) == sizeof(unsigned short)) # if !defined(ACC_ABI_I8LP16) ACCCHK_ASSERT(sizeof(short) >= 2) # endif ACCCHK_ASSERT(sizeof(short) >= sizeof(char)) # if (ACC_CC_CILLY) && (!defined(__CILLY__) || (__CILLY__ < 0x010302L)) # else ACCCHK_ASSERT(sizeof(short) == sizeof((short) 0)) # endif # if (SIZEOF_SHORT > 0) ACCCHK_ASSERT(sizeof(short) == SIZEOF_SHORT) # endif ACCCHK_ASSERT_IS_SIGNED_T(int) ACCCHK_ASSERT_IS_UNSIGNED_T(unsigned int) ACCCHK_ASSERT(sizeof(int) == sizeof(unsigned int)) # if !defined(ACC_ABI_I8LP16) ACCCHK_ASSERT(sizeof(int) >= 2) # endif ACCCHK_ASSERT(sizeof(int) >= sizeof(short)) ACCCHK_ASSERT(sizeof(int) == sizeof(0)) ACCCHK_ASSERT(sizeof(int) == sizeof((int) 0)) # if (SIZEOF_INT > 0) ACCCHK_ASSERT(sizeof(int) == SIZEOF_INT) # endif ACCCHK_ASSERT(sizeof(0) == sizeof(int)) ACCCHK_ASSERT_IS_SIGNED_T(long) ACCCHK_ASSERT_IS_UNSIGNED_T(unsigned long) ACCCHK_ASSERT(sizeof(long) == sizeof(unsigned long)) # if !defined(ACC_ABI_I8LP16) ACCCHK_ASSERT(sizeof(long) >= 4) # endif ACCCHK_ASSERT(sizeof(long) >= sizeof(int)) ACCCHK_ASSERT(sizeof(long) == sizeof(0L)) ACCCHK_ASSERT(sizeof(long) == sizeof((long) 0)) # if (SIZEOF_LONG > 0) ACCCHK_ASSERT(sizeof(long) == SIZEOF_LONG) # endif ACCCHK_ASSERT(sizeof(0L) == sizeof(long)) ACCCHK_ASSERT_IS_UNSIGNED_T(size_t) ACCCHK_ASSERT(sizeof(size_t) >= sizeof(int)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(sizeof(0))) # if (SIZEOF_SIZE_T > 0) ACCCHK_ASSERT(sizeof(size_t) == SIZEOF_SIZE_T) # endif ACCCHK_ASSERT_IS_SIGNED_T(ptrdiff_t) ACCCHK_ASSERT(sizeof(ptrdiff_t) >= sizeof(int)) ACCCHK_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t)) # if !defined(ACC_BROKEN_SIZEOF) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof((char *)0 - (char *)0)) # if (ACC_HAVE_MM_HUGE_PTR) ACCCHK_ASSERT(4 == sizeof((char __huge *) 0 - (char __huge *)0)) # endif # endif # if (SIZEOF_PTRDIFF_T > 0) ACCCHK_ASSERT(sizeof(ptrdiff_t) == SIZEOF_PTRDIFF_T) # endif ACCCHK_ASSERT(sizeof(void *) >= sizeof(char *)) # if (SIZEOF_VOID_P > 0) ACCCHK_ASSERT(sizeof(void *) == SIZEOF_VOID_P) ACCCHK_ASSERT(sizeof(char *) == SIZEOF_VOID_P) # endif # if (ACC_HAVE_MM_HUGE_PTR) ACCCHK_ASSERT(4 == sizeof(void __huge *)) ACCCHK_ASSERT(4 == sizeof(char __huge *)) # endif # if defined(ACC_ABI_I8LP16) ACCCHK_ASSERT((((1u << 7) + 1) >> 7) == 1) ACCCHK_ASSERT((((1ul << 15) + 1) >> 15) == 1) # else ACCCHK_ASSERT((((1u << 15) + 1) >> 15) == 1) ACCCHK_ASSERT((((1ul << 31) + 1) >> 31) == 1) # endif # if defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0150) # elif 1 && (ACC_CC_SUNPROC) && !defined(ACCCHK_CFG_PEDANTIC) # else ACCCHK_ASSERT((1 << (8 * SIZEOF_INT - 1)) < 0) # endif ACCCHK_ASSERT((1u << (8 * SIZEOF_INT - 1)) > 0) # if 1 && (ACC_CC_SUNPROC) && !defined(ACCCHK_CFG_PEDANTIC) # else ACCCHK_ASSERT((1l << (8 * SIZEOF_LONG - 1)) < 0) # endif ACCCHK_ASSERT((1ul << (8 * SIZEOF_LONG - 1)) > 0) # if defined(acc_int16e_t) ACCCHK_ASSERT(sizeof(acc_int16e_t) == 2) ACCCHK_ASSERT(sizeof(acc_int16e_t) == SIZEOF_ACC_INT16E_T) ACCCHK_ASSERT(sizeof(acc_uint16e_t) == 2) ACCCHK_ASSERT(sizeof(acc_int16e_t) == sizeof(acc_uint16e_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int16e_t) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint16e_t) # if defined(__MSDOS__) && defined(__TURBOC__) && (__TURBOC__ < 0x0150) # else ACCCHK_ASSERT(((acc_uint16e_t) (~(acc_uint16e_t) 0ul) >> 15) == 1) # endif ACCCHK_ASSERT((acc_int16e_t) (1 + ~(acc_int16e_t) 0) == 0) # if defined(ACCCHK_CFG_PEDANTIC) ACCCHK_ASSERT((acc_uint16e_t) (1 + ~(acc_uint16e_t) 0) == 0) # endif # endif # if defined(acc_int32e_t) ACCCHK_ASSERT(sizeof(acc_int32e_t) == 4) ACCCHK_ASSERT(sizeof(acc_int32e_t) == SIZEOF_ACC_INT32E_T) ACCCHK_ASSERT(sizeof(acc_uint32e_t) == 4) ACCCHK_ASSERT(sizeof(acc_int32e_t) == sizeof(acc_uint32e_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int32e_t) ACCCHK_ASSERT(((((acc_int32e_t) 1 << 30) + 1) >> 30) == 1) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint32e_t) ACCCHK_ASSERT(((((acc_uint32e_t) 1 << 31) + 1) >> 31) == 1) ACCCHK_ASSERT(((acc_uint32e_t) (~(acc_uint32e_t) 0ul) >> 31) == 1) ACCCHK_ASSERT((acc_int32e_t) (1 + ~(acc_int32e_t) 0) == 0) # if defined(ACCCHK_CFG_PEDANTIC) ACCCHK_ASSERT((acc_uint32e_t) (1 + ~(acc_uint32e_t) 0) == 0) # endif # endif # if defined(acc_int32e_t) ACCCHK_ASSERT(sizeof(acc_int32l_t) >= sizeof(acc_int32e_t)) # endif ACCCHK_ASSERT(sizeof(acc_int32l_t) >= 4) ACCCHK_ASSERT(sizeof(acc_int32l_t) == SIZEOF_ACC_INT32L_T) ACCCHK_ASSERT(sizeof(acc_uint32l_t) >= 4) ACCCHK_ASSERT(sizeof(acc_int32l_t) == sizeof(acc_uint32l_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int32l_t) ACCCHK_ASSERT(((((acc_int32l_t) 1 << 30) + 1) >> 30) == 1) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint32l_t) ACCCHK_ASSERT(((((acc_uint32l_t) 1 << 31) + 1) >> 31) == 1) ACCCHK_ASSERT(sizeof(acc_int32f_t) >= sizeof(int)) # if defined(acc_int32e_t) ACCCHK_ASSERT(sizeof(acc_int32f_t) >= sizeof(acc_int32e_t)) # endif ACCCHK_ASSERT(sizeof(acc_int32f_t) >= sizeof(acc_int32l_t)) ACCCHK_ASSERT(sizeof(acc_int32f_t) >= 4) ACCCHK_ASSERT(sizeof(acc_int32f_t) >= sizeof(acc_int32l_t)) ACCCHK_ASSERT(sizeof(acc_int32f_t) == SIZEOF_ACC_INT32F_T) ACCCHK_ASSERT(sizeof(acc_uint32f_t) >= 4) ACCCHK_ASSERT(sizeof(acc_uint32f_t) >= sizeof(acc_uint32l_t)) ACCCHK_ASSERT(sizeof(acc_int32f_t) == sizeof(acc_uint32f_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int32f_t) ACCCHK_ASSERT(((((acc_int32f_t) 1 << 30) + 1) >> 30) == 1) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint32f_t) ACCCHK_ASSERT(((((acc_uint32f_t) 1 << 31) + 1) >> 31) == 1) # if defined(acc_int64e_t) ACCCHK_ASSERT(sizeof(acc_int64e_t) == 8) ACCCHK_ASSERT(sizeof(acc_int64e_t) == SIZEOF_ACC_INT64E_T) ACCCHK_ASSERT(sizeof(acc_uint64e_t) == 8) ACCCHK_ASSERT(sizeof(acc_int64e_t) == sizeof(acc_uint64e_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int64e_t) # if (ACC_CC_BORLANDC && (__BORLANDC__ < 0x0530)) # else ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint64e_t) # endif # endif # if defined(acc_int64l_t) # if defined(acc_int64e_t) ACCCHK_ASSERT(sizeof(acc_int64l_t) >= sizeof(acc_int64e_t)) # endif ACCCHK_ASSERT(sizeof(acc_int64l_t) >= 8) ACCCHK_ASSERT(sizeof(acc_int64l_t) == SIZEOF_ACC_INT64L_T) ACCCHK_ASSERT(sizeof(acc_uint64l_t) >= 8) ACCCHK_ASSERT(sizeof(acc_int64l_t) == sizeof(acc_uint64l_t)) ACCCHK_ASSERT_IS_SIGNED_T(acc_int64l_t) ACCCHK_ASSERT(((((acc_int64l_t) 1 << 62) + 1) >> 62) == 1) ACCCHK_ASSERT((((ACC_INT64_C(1) << 62) + 1) >> 62) == 1) # if (ACC_CC_BORLANDC && (__BORLANDC__ < 0x0530)) # else ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uint64l_t) ACCCHK_ASSERT(ACC_UINT64_C(18446744073709551615) > 0) # endif ACCCHK_ASSERT(((((acc_uint64l_t) 1 << 63) + 1) >> 63) == 1) ACCCHK_ASSERT((((ACC_UINT64_C(1) << 63) + 1) >> 63) == 1) # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020600ul)) ACCCHK_ASSERT(ACC_INT64_C(9223372036854775807) > ACC_INT64_C(0)) # else ACCCHK_ASSERT(ACC_INT64_C(9223372036854775807) > 0) # endif ACCCHK_ASSERT(ACC_INT64_C(-9223372036854775807) - 1 < 0) ACCCHK_ASSERT(ACC_INT64_C(9223372036854775807) % ACC_INT32_C(2147483629) == 721) ACCCHK_ASSERT(ACC_INT64_C(9223372036854775807) % ACC_INT32_C(2147483647) == 1) ACCCHK_ASSERT(ACC_UINT64_C(9223372036854775807) % ACC_UINT32_C(2147483629) == 721) ACCCHK_ASSERT(ACC_UINT64_C(9223372036854775807) % ACC_UINT32_C(2147483647) == 1) # endif # if !defined(__ACC_INTPTR_T_IS_POINTER) ACCCHK_ASSERT_IS_SIGNED_T(acc_intptr_t) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_uintptr_t) # endif ACCCHK_ASSERT(sizeof(acc_intptr_t) >= sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == SIZEOF_ACC_INTPTR_T) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(acc_uintptr_t)) # if defined(acc_word_t) ACCCHK_ASSERT(ACC_WORDSIZE == SIZEOF_ACC_WORD_T) ACCCHK_ASSERT_IS_UNSIGNED_T(acc_word_t) ACCCHK_ASSERT_IS_SIGNED_T(acc_sword_t) ACCCHK_ASSERT(sizeof(acc_word_t) == SIZEOF_ACC_WORD_T) ACCCHK_ASSERT(sizeof(acc_word_t) == sizeof(acc_sword_t)) # endif # if defined(ACC_INT16_C) ACCCHK_ASSERT(sizeof(ACC_INT16_C(0)) >= 2) ACCCHK_ASSERT(sizeof(ACC_UINT16_C(0)) >= 2) ACCCHK_ASSERT((ACC_UINT16_C(0xffff) >> 15) == 1) # endif # if defined(ACC_INT32_C) ACCCHK_ASSERT(sizeof(ACC_INT32_C(0)) >= 4) ACCCHK_ASSERT(sizeof(ACC_UINT32_C(0)) >= 4) ACCCHK_ASSERT((ACC_UINT32_C(0xffffffff) >> 31) == 1) # endif # if defined(ACC_INT64_C) # if (ACC_CC_BORLANDC && (__BORLANDC__ < 0x0560)) # else ACCCHK_ASSERT(sizeof(ACC_INT64_C(0)) >= 8) ACCCHK_ASSERT(sizeof(ACC_UINT64_C(0)) >= 8) # endif ACCCHK_ASSERT((ACC_UINT64_C(0xffffffffffffffff) >> 63) == 1) ACCCHK_ASSERT((ACC_UINT64_C(0xffffffffffffffff) & ~0) == ACC_UINT64_C(0xffffffffffffffff)) ACCCHK_ASSERT((ACC_UINT64_C(0xffffffffffffffff) & ~0l) == ACC_UINT64_C(0xffffffffffffffff)) # if (SIZEOF_INT == 4) # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020000ul)) # else ACCCHK_ASSERT((ACC_UINT64_C(0xffffffffffffffff) & ~0u) == 0xffffffffu) # endif # endif # if (SIZEOF_LONG == 4) # if (ACC_CC_GNUC && (ACC_CC_GNUC < 0x020000ul)) # else ACCCHK_ASSERT((ACC_UINT64_C(0xffffffffffffffff) & ~0ul) == 0xfffffffful) # endif # endif # endif # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM) ACCCHK_ASSERT(sizeof(void *) == 2) ACCCHK_ASSERT(sizeof(ptrdiff_t) == 2) # elif (ACC_MM_COMPACT || ACC_MM_LARGE || ACC_MM_HUGE) ACCCHK_ASSERT(sizeof(void *) == 4) # endif # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_COMPACT) ACCCHK_ASSERT(sizeof(void (*)(void)) == 2) # elif (ACC_MM_MEDIUM || ACC_MM_LARGE || ACC_MM_HUGE) ACCCHK_ASSERT(sizeof(void (*)(void)) == 4) # endif # if (ACC_ABI_ILP32) ACCCHK_ASSERT(sizeof(int) == 4) ACCCHK_ASSERT(sizeof(long) == 4) ACCCHK_ASSERT(sizeof(void *) == 4) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ABI_ILP64) ACCCHK_ASSERT(sizeof(int) == 8) ACCCHK_ASSERT(sizeof(long) == 8) ACCCHK_ASSERT(sizeof(void *) == 8) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ABI_IP32L64) ACCCHK_ASSERT(sizeof(int) == 4) ACCCHK_ASSERT(sizeof(long) == 8) ACCCHK_ASSERT(sizeof(void *) == 4) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ABI_LLP64) ACCCHK_ASSERT(sizeof(int) == 4) ACCCHK_ASSERT(sizeof(long) == 4) ACCCHK_ASSERT(sizeof(void *) == 8) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ABI_LP32) ACCCHK_ASSERT(sizeof(int) == 2) ACCCHK_ASSERT(sizeof(long) == 4) ACCCHK_ASSERT(sizeof(void *) == 4) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ABI_LP64) ACCCHK_ASSERT(sizeof(int) == 4) ACCCHK_ASSERT(sizeof(long) == 8) ACCCHK_ASSERT(sizeof(void *) == 8) ACCCHK_ASSERT(sizeof(ptrdiff_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(size_t) == sizeof(void *)) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_ARCH_I086) ACCCHK_ASSERT(sizeof(size_t) == 2) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # elif (ACC_ARCH_I386 || ACC_ARCH_M68K) ACCCHK_ASSERT(sizeof(size_t) == 4) ACCCHK_ASSERT(sizeof(ptrdiff_t) == 4) ACCCHK_ASSERT(sizeof(acc_intptr_t) == sizeof(void *)) # endif # if (ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_WIN32) ACCCHK_ASSERT(sizeof(size_t) == 4) ACCCHK_ASSERT(sizeof(ptrdiff_t) == 4) ACCCHK_ASSERT(sizeof(void (*)(void)) == 4) # elif (ACC_OS_WIN64) ACCCHK_ASSERT(sizeof(size_t) == 8) ACCCHK_ASSERT(sizeof(ptrdiff_t) == 8) ACCCHK_ASSERT(sizeof(void (*)(void)) == 8) # endif # if (ACC_CC_NDPC) # elif (SIZEOF_INT > 1) ACCCHK_ASSERT((int)((unsigned char)((signed char)-1)) == 255) # endif # if (ACC_CC_KEILC) # elif (ACC_CC_NDPC) # elif 1 && (ACC_CC_LCC || ACC_CC_LCCWIN32) && !defined(ACCCHK_CFG_PEDANTIC) # elif 1 && (ACC_CC_SUNPROC) && !defined(ACCCHK_CFG_PEDANTIC) # elif !defined(ACC_BROKEN_INTEGRAL_PROMOTION) && (SIZEOF_INT > 1) ACCCHK_ASSERT((((unsigned char)128) << (int)(8 * sizeof(int) - 8)) < 0) # endif # if (ACC_CC_BORLANDC && (__BORLANDC__ >= 0x0530) && (__BORLANDC__ < 0x0560)) # pragma option pop # endif #endif #if defined(ACC_WANT_ACCLIB_UA) # undef ACC_WANT_ACCLIB_UA # define __ACCLIB_UA_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif ACCLIB_PUBLIC(unsigned, acc_ua_get_be16) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_BE16) return ACC_UA_GET_BE16(p); # else const acc_hbyte_p b = (const acc_hbyte_p)p; return ((unsigned)b[1]) | ((unsigned)b[0] << 8); # endif } ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_be24) (const acc_hvoid_p p) { const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint32l_t) b[2]) | ((acc_uint32l_t) b[1] << 8) | ((acc_uint32l_t) b[0] << 16); } ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_be32) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_BE32) return ACC_UA_GET_BE32(p); # else const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint32l_t) b[3]) | ((acc_uint32l_t) b[2] << 8) | ((acc_uint32l_t) b[1] << 16) | ((acc_uint32l_t) b[0] << 24); # endif } ACCLIB_PUBLIC(void, acc_ua_set_be16)(acc_hvoid_p p, unsigned v) { # if defined(ACC_UA_SET_BE16) ACC_UA_SET_BE16(p, v); # else acc_hbyte_p b = (acc_hbyte_p) p; b[1] = (unsigned char)((v >> 0) & 0xff); b[0] = (unsigned char)((v >> 8) & 0xff); # endif } ACCLIB_PUBLIC(void, acc_ua_set_be24) (acc_hvoid_p p, acc_uint32l_t v) { acc_hbyte_p b = (acc_hbyte_p) p; b[2] = (unsigned char)((v >> 0) & 0xff); b[1] = (unsigned char)((v >> 8) & 0xff); b[0] = (unsigned char)((v >> 16) & 0xff); } ACCLIB_PUBLIC(void, acc_ua_set_be32) (acc_hvoid_p p, acc_uint32l_t v) { # if defined(ACC_UA_SET_BE32) ACC_UA_SET_BE32(p, v); # else acc_hbyte_p b = (acc_hbyte_p) p; b[3] = (unsigned char)((v >> 0) & 0xff); b[2] = (unsigned char)((v >> 8) & 0xff); b[1] = (unsigned char)((v >> 16) & 0xff); b[0] = (unsigned char)((v >> 24) & 0xff); # endif } ACCLIB_PUBLIC(unsigned, acc_ua_get_le16) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_LE16) return ACC_UA_GET_LE16(p); # else const acc_hbyte_p b = (const acc_hbyte_p)p; return ((unsigned)b[0]) | ((unsigned)b[1] << 8); # endif } ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le24) (const acc_hvoid_p p) { const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint32l_t) b[0]) | ((acc_uint32l_t) b[1] << 8) | ((acc_uint32l_t) b[2] << 16); } ACCLIB_PUBLIC(acc_uint32l_t, acc_ua_get_le32) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_LE32) return ACC_UA_GET_LE32(p); # else const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint32l_t) b[0]) | ((acc_uint32l_t) b[1] << 8) | ((acc_uint32l_t) b[2] << 16) | ((acc_uint32l_t) b[3] << 24); # endif } ACCLIB_PUBLIC(void, acc_ua_set_le16)(acc_hvoid_p p, unsigned v) { # if defined(ACC_UA_SET_LE16) ACC_UA_SET_LE16(p, v); # else acc_hbyte_p b = (acc_hbyte_p) p; b[0] = (unsigned char)((v >> 0) & 0xff); b[1] = (unsigned char)((v >> 8) & 0xff); # endif } ACCLIB_PUBLIC(void, acc_ua_set_le24) (acc_hvoid_p p, acc_uint32l_t v) { acc_hbyte_p b = (acc_hbyte_p) p; b[0] = (unsigned char)((v >> 0) & 0xff); b[1] = (unsigned char)((v >> 8) & 0xff); b[2] = (unsigned char)((v >> 16) & 0xff); } ACCLIB_PUBLIC(void, acc_ua_set_le32) (acc_hvoid_p p, acc_uint32l_t v) { # if defined(ACC_UA_SET_LE32) ACC_UA_SET_LE32(p, v); # else acc_hbyte_p b = (acc_hbyte_p) p; b[0] = (unsigned char)((v >> 0) & 0xff); b[1] = (unsigned char)((v >> 8) & 0xff); b[2] = (unsigned char)((v >> 16) & 0xff); b[3] = (unsigned char)((v >> 24) & 0xff); # endif } # if defined(acc_int64l_t) ACCLIB_PUBLIC(acc_uint64l_t, acc_ua_get_be64) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_BE64) return ACC_UA_GET_BE64(p); # elif defined(ACC_UA_GET_BE32) const acc_hbyte_p b = (const acc_hbyte_p)p; acc_uint32e_t v0, v1; v1 = ACC_UA_GET_BE32(b + 0); v0 = ACC_UA_GET_BE32(b + 4); return ((acc_uint64l_t) v0) | ((acc_uint64l_t) v1 << 32); # elif (ACC_SIZEOF_LONG >= 8) || (ACC_SIZEOF_SIZE_T >= 8) const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint64l_t) b[7]) | ((acc_uint64l_t) b[6] << 8) | ((acc_uint64l_t) b[5] << 16) | ((acc_uint64l_t) b[4] << 24) | ((acc_uint64l_t) b[3] << 32) | ((acc_uint64l_t) b[2] << 40) | ((acc_uint64l_t) b[1] << 48) | ((acc_uint64l_t) b[0] << 56); # else const acc_hbyte_p b = (const acc_hbyte_p)p; acc_uint32l_t v0, v1; v1 = ((acc_uint32l_t) b[3]) | ((acc_uint32l_t) b[2] << 8) | ((acc_uint32l_t) b[1] << 16) | ((acc_uint32l_t) b[0] << 24); b += 4; v0 = ((acc_uint32l_t) b[3]) | ((acc_uint32l_t) b[2] << 8) | ((acc_uint32l_t) b[1] << 16) | ((acc_uint32l_t) b[0] << 24); return ((acc_uint64l_t) v0) | ((acc_uint64l_t) v1 << 32); # endif } ACCLIB_PUBLIC(void, acc_ua_set_be64)(acc_hvoid_p p, acc_uint64l_t v) { # if defined(ACC_UA_SET_BE64) ACC_UA_SET_BE64(p, v); # elif defined(ACC_UA_SET_BE32) acc_hbyte_p b = (acc_hbyte_p) p; ACC_UA_SET_BE32(b + 4, (v >> 0)); ACC_UA_SET_BE32(b + 0, (v >> 32)); # elif (ACC_SIZEOF_LONG >= 8) || (ACC_SIZEOF_SIZE_T >= 8) acc_hbyte_p b = (acc_hbyte_p) p; b[7] = (unsigned char)((v >> 0) & 0xff); b[6] = (unsigned char)((v >> 8) & 0xff); b[5] = (unsigned char)((v >> 16) & 0xff); b[4] = (unsigned char)((v >> 24) & 0xff); b[3] = (unsigned char)((v >> 32) & 0xff); b[2] = (unsigned char)((v >> 40) & 0xff); b[1] = (unsigned char)((v >> 48) & 0xff); b[0] = (unsigned char)((v >> 56) & 0xff); # else acc_hbyte_p b = (acc_hbyte_p) p; acc_uint32l_t x; x = (acc_uint32l_t) (v >> 0); b[7] = (unsigned char)((x >> 0) & 0xff); b[6] = (unsigned char)((x >> 8) & 0xff); b[5] = (unsigned char)((x >> 16) & 0xff); b[4] = (unsigned char)((x >> 24) & 0xff); x = (acc_uint32l_t) (v >> 32); b[3] = (unsigned char)((x >> 0) & 0xff); b[2] = (unsigned char)((x >> 8) & 0xff); b[1] = (unsigned char)((x >> 16) & 0xff); b[0] = (unsigned char)((x >> 24) & 0xff); # endif } # endif # if defined(acc_int64l_t) ACCLIB_PUBLIC(acc_uint64l_t, acc_ua_get_le64) (const acc_hvoid_p p) { # if defined(ACC_UA_GET_LE64) return ACC_UA_GET_LE64(p); # elif defined(ACC_UA_GET_LE32) const acc_hbyte_p b = (const acc_hbyte_p)p; acc_uint32e_t v0, v1; v0 = ACC_UA_GET_LE32(b + 0); v1 = ACC_UA_GET_LE32(b + 4); return ((acc_uint64l_t) v0) | ((acc_uint64l_t) v1 << 32); # elif (ACC_SIZEOF_LONG >= 8) || (ACC_SIZEOF_SIZE_T >= 8) const acc_hbyte_p b = (const acc_hbyte_p)p; return ((acc_uint64l_t) b[0]) | ((acc_uint64l_t) b[1] << 8) | ((acc_uint64l_t) b[2] << 16) | ((acc_uint64l_t) b[3] << 24) | ((acc_uint64l_t) b[4] << 32) | ((acc_uint64l_t) b[5] << 40) | ((acc_uint64l_t) b[6] << 48) | ((acc_uint64l_t) b[7] << 56); # else const acc_hbyte_p b = (const acc_hbyte_p)p; acc_uint32l_t v0, v1; v0 = ((acc_uint32l_t) b[0]) | ((acc_uint32l_t) b[1] << 8) | ((acc_uint32l_t) b[2] << 16) | ((acc_uint32l_t) b[3] << 24); b += 4; v1 = ((acc_uint32l_t) b[0]) | ((acc_uint32l_t) b[1] << 8) | ((acc_uint32l_t) b[2] << 16) | ((acc_uint32l_t) b[3] << 24); return ((acc_uint64l_t) v0) | ((acc_uint64l_t) v1 << 32); # endif } ACCLIB_PUBLIC(void, acc_ua_set_le64)(acc_hvoid_p p, acc_uint64l_t v) { # if defined(ACC_UA_SET_LE64) ACC_UA_SET_LE64(p, v); # elif defined(ACC_UA_SET_LE32) acc_hbyte_p b = (acc_hbyte_p) p; ACC_UA_SET_LE32(b + 0, (v >> 0)); ACC_UA_SET_LE32(b + 4, (v >> 32)); # elif (ACC_SIZEOF_LONG >= 8) || (ACC_SIZEOF_SIZE_T >= 8) acc_hbyte_p b = (acc_hbyte_p) p; b[0] = (unsigned char)((v >> 0) & 0xff); b[1] = (unsigned char)((v >> 8) & 0xff); b[2] = (unsigned char)((v >> 16) & 0xff); b[3] = (unsigned char)((v >> 24) & 0xff); b[4] = (unsigned char)((v >> 32) & 0xff); b[5] = (unsigned char)((v >> 40) & 0xff); b[6] = (unsigned char)((v >> 48) & 0xff); b[7] = (unsigned char)((v >> 56) & 0xff); # else acc_hbyte_p b = (acc_hbyte_p) p; acc_uint32l_t x; x = (acc_uint32l_t) (v >> 0); b[0] = (unsigned char)((x >> 0) & 0xff); b[1] = (unsigned char)((x >> 8) & 0xff); b[2] = (unsigned char)((x >> 16) & 0xff); b[3] = (unsigned char)((x >> 24) & 0xff); x = (acc_uint32l_t) (v >> 32); b[4] = (unsigned char)((x >> 0) & 0xff); b[5] = (unsigned char)((x >> 8) & 0xff); b[6] = (unsigned char)((x >> 16) & 0xff); b[7] = (unsigned char)((x >> 24) & 0xff); # endif } # endif #endif #if defined(ACC_WANT_ACCLIB_VGET) # undef ACC_WANT_ACCLIB_VGET # define __ACCLIB_VGET_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if !defined(ACCLIB_PUBLIC_NOINLINE) # if !defined(__acc_noinline) # define ACCLIB_PUBLIC_NOINLINE(r,f) r __ACCLIB_FUNCNAME(f) # elif (ACC_CC_GNUC >= 0x030400ul) || (ACC_CC_LLVM) # define ACCLIB_PUBLIC_NOINLINE(r,f) __acc_noinline __attribute__((__used__)) r __ACCLIB_FUNCNAME(f) # else # define ACCLIB_PUBLIC_NOINLINE(r,f) __acc_noinline r __ACCLIB_FUNCNAME(f) # endif # endif # if (ACC_CC_GNUC >= 0x030400ul) || (ACC_CC_LLVM) extern void *volatile __acc_vget_ptr; void *volatile __attribute__ ((__used__)) __acc_vget_ptr = (void *)0; # else extern void *volatile __acc_vget_ptr; void *volatile __acc_vget_ptr = (void *)0; # endif # ifndef __ACCLIB_VGET_BODY # define __ACCLIB_VGET_BODY(T) \ if __acc_unlikely(__acc_vget_ptr) { \ * (T *) __acc_vget_ptr = v; \ * (int *) __acc_vget_ptr = expr; \ v = * (T *) __acc_vget_ptr; \ } \ return v; # endif ACCLIB_PUBLIC_NOINLINE(short, acc_vget_short) (short v, int expr) { __ACCLIB_VGET_BODY(short) } ACCLIB_PUBLIC_NOINLINE(int, acc_vget_int) (int v, int expr) { __ACCLIB_VGET_BODY(int) } ACCLIB_PUBLIC_NOINLINE(long, acc_vget_long) (long v, int expr) { __ACCLIB_VGET_BODY(long) } # if defined(acc_int64l_t) ACCLIB_PUBLIC_NOINLINE(acc_int64l_t, acc_vget_acc_int64l_t) (acc_int64l_t v, int expr) { __ACCLIB_VGET_BODY(acc_int64l_t) } # endif ACCLIB_PUBLIC_NOINLINE(acc_hsize_t, acc_vget_acc_hsize_t) (acc_hsize_t v, int expr) { __ACCLIB_VGET_BODY(acc_hsize_t) } # if !defined(ACC_CFG_NO_FLOAT) ACCLIB_PUBLIC_NOINLINE(float, acc_vget_float) (float v, int expr) { __ACCLIB_VGET_BODY(float) } # endif # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_PUBLIC_NOINLINE(double, acc_vget_double) (double v, int expr) { __ACCLIB_VGET_BODY(double) } # endif ACCLIB_PUBLIC_NOINLINE(acc_hvoid_p, acc_vget_acc_hvoid_p) (acc_hvoid_p v, int expr) { __ACCLIB_VGET_BODY(acc_hvoid_p) } # if (ACC_ARCH_I086 && ACC_CC_TURBOC && (__TURBOC__ == 0x0295)) && !defined(__cplusplus) ACCLIB_PUBLIC_NOINLINE(acc_hvoid_p, acc_vget_acc_hvoid_cp) (const acc_hvoid_p vv, int expr) { acc_hvoid_p v = (acc_hvoid_p) vv; __ACCLIB_VGET_BODY(acc_hvoid_p) } # else ACCLIB_PUBLIC_NOINLINE(const acc_hvoid_p, acc_vget_acc_hvoid_cp) (const acc_hvoid_p v, int expr) { __ACCLIB_VGET_BODY(const acc_hvoid_p) } # endif #endif #if defined(ACC_WANT_ACCLIB_HMEMCPY) # undef ACC_WANT_ACCLIB_HMEMCPY # define __ACCLIB_HMEMCPY_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif ACCLIB_PUBLIC(int, acc_hmemcmp) (const acc_hvoid_p s1, const acc_hvoid_p s2, acc_hsize_t len) { # if (ACC_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCMP) const acc_hbyte_p p1 = (const acc_hbyte_p)s1; const acc_hbyte_p p2 = (const acc_hbyte_p)s2; if __acc_likely (len > 0) do { int d = *p1 - *p2; if (d != 0) return d; p1++; p2++; } while __acc_likely (--len > 0); return 0; # else return memcmp(s1, s2, len); # endif } ACCLIB_PUBLIC(acc_hvoid_p, acc_hmemcpy) (acc_hvoid_p dest, const acc_hvoid_p src, acc_hsize_t len) { # if (ACC_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMCPY) acc_hbyte_p p1 = (acc_hbyte_p) dest; const acc_hbyte_p p2 = (const acc_hbyte_p)src; if (!(len > 0) || p1 == p2) return dest; do *p1++ = *p2++; while __acc_likely (--len > 0); return dest; # else return memcpy(dest, src, len); # endif } ACCLIB_PUBLIC(acc_hvoid_p, acc_hmemmove) (acc_hvoid_p dest, const acc_hvoid_p src, acc_hsize_t len) { # if (ACC_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMMOVE) acc_hbyte_p p1 = (acc_hbyte_p) dest; const acc_hbyte_p p2 = (const acc_hbyte_p)src; if (!(len > 0) || p1 == p2) return dest; if (p1 < p2) { do *p1++ = *p2++; while __acc_likely (--len > 0); } else { p1 += len; p2 += len; do *--p1 = *--p2; while __acc_likely (--len > 0); } return dest; # else return memmove(dest, src, len); # endif } ACCLIB_PUBLIC(acc_hvoid_p, acc_hmemset) (acc_hvoid_p s, int c, acc_hsize_t len) { # if (ACC_HAVE_MM_HUGE_PTR) || !defined(HAVE_MEMSET) acc_hbyte_p p = (acc_hbyte_p) s; if __acc_likely (len > 0) do *p++ = (unsigned char)c; while __acc_likely (--len > 0); return s; # else return memset(s, c, len); # endif } #endif #if defined(ACC_WANT_ACCLIB_RAND) # undef ACC_WANT_ACCLIB_RAND # define __ACCLIB_RAND_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif ACCLIB_PUBLIC(void, acc_srand31)(acc_rand31_p r, acc_uint32l_t seed) { r->seed = seed & ACC_UINT32_C(0xffffffff); } ACCLIB_PUBLIC(acc_uint32l_t, acc_rand31) (acc_rand31_p r) { r->seed = r->seed * ACC_UINT32_C(1103515245) + 12345; r->seed &= ACC_UINT32_C(0x7fffffff); return r->seed; } # if defined(acc_int64l_t) ACCLIB_PUBLIC(void, acc_srand48)(acc_rand48_p r, acc_uint32l_t seed) { r->seed = seed & ACC_UINT32_C(0xffffffff); r->seed <<= 16; r->seed |= 0x330e; } ACCLIB_PUBLIC(acc_uint32l_t, acc_rand48) (acc_rand48_p r) { r->seed = r->seed * ACC_UINT64_C(25214903917) + 11; r->seed &= ACC_UINT64_C(0xffffffffffff); return (acc_uint32l_t) (r->seed >> 17); } ACCLIB_PUBLIC(acc_uint32l_t, acc_rand48_r32) (acc_rand48_p r) { r->seed = r->seed * ACC_UINT64_C(25214903917) + 11; r->seed &= ACC_UINT64_C(0xffffffffffff); return (acc_uint32l_t) (r->seed >> 16); } # endif # if defined(acc_int64l_t) ACCLIB_PUBLIC(void, acc_srand64)(acc_rand64_p r, acc_uint64l_t seed) { r->seed = seed & ACC_UINT64_C(0xffffffffffffffff); } ACCLIB_PUBLIC(acc_uint32l_t, acc_rand64) (acc_rand64_p r) { r->seed = r->seed * ACC_UINT64_C(6364136223846793005) + 1; # if (ACC_SIZEOF_ACC_INT64L_T > 8) r->seed &= ACC_UINT64_C(0xffffffffffffffff); # endif return (acc_uint32l_t) (r->seed >> 33); } ACCLIB_PUBLIC(acc_uint32l_t, acc_rand64_r32) (acc_rand64_p r) { r->seed = r->seed * ACC_UINT64_C(6364136223846793005) + 1; # if (ACC_SIZEOF_ACC_INT64L_T > 8) r->seed &= ACC_UINT64_C(0xffffffffffffffff); # endif return (acc_uint32l_t) (r->seed >> 32); } # endif ACCLIB_PUBLIC(void, acc_srandmt)(acc_randmt_p r, acc_uint32l_t seed) { unsigned i = 0; do { r->s[i++] = (seed &= ACC_UINT32_C(0xffffffff)); seed ^= seed >> 30; seed = seed * ACC_UINT32_C(0x6c078965) + i; } while (i != 624); r->n = i; } ACCLIB_PUBLIC(acc_uint32l_t, acc_randmt) (acc_randmt_p r) { return (__ACCLIB_FUNCNAME(acc_randmt_r32) (r)) >> 1; } ACCLIB_PUBLIC(acc_uint32l_t, acc_randmt_r32) (acc_randmt_p r) { acc_uint32l_t v; if __acc_unlikely (r->n == 624) { int i = 0, j; r->n = 0; do { j = i - 623; if (j < 0) j += 624; v = (r->s[i] & ACC_UINT32_C(0x80000000)) ^ (r->s[j] & ACC_UINT32_C(0x7fffffff)); j = i - 227; if (j < 0) j += 624; r->s[i] = r->s[j] ^ (v >> 1); if (v & 1) r->s[i] ^= ACC_UINT32_C(0x9908b0df); } while (++i != 624); } v = r->s[r->n++]; v ^= v >> 11; v ^= (v & ACC_UINT32_C(0x013a58ad)) << 7; v ^= (v & ACC_UINT32_C(0x0001df8c)) << 15; v ^= v >> 18; return v; } # if defined(acc_int64l_t) ACCLIB_PUBLIC(void, acc_srandmt64)(acc_randmt64_p r, acc_uint64l_t seed) { unsigned i = 0; do { r->s[i++] = (seed &= ACC_UINT64_C(0xffffffffffffffff)); seed ^= seed >> 62; seed = seed * ACC_UINT64_C(0x5851f42d4c957f2d) + i; } while (i != 312); r->n = i; } # if 0 ACCLIB_PUBLIC(acc_uint32l_t, acc_randmt64) (acc_randmt64_p r) { acc_uint64l_t v; v = (__ACCLIB_FUNCNAME(acc_randmt64_r64) (r)) >> 33; return (acc_uint32l_t) v; } # endif ACCLIB_PUBLIC(acc_uint64l_t, acc_randmt64_r64) (acc_randmt64_p r) { acc_uint64l_t v; if __acc_unlikely (r->n == 312) { int i = 0, j; r->n = 0; do { j = i - 311; if (j < 0) j += 312; v = (r->s[i] & ACC_UINT64_C(0xffffffff80000000)) ^ (r->s[j] & ACC_UINT64_C(0x7fffffff)); j = i - 156; if (j < 0) j += 312; r->s[i] = r->s[j] ^ (v >> 1); if (v & 1) r->s[i] ^= ACC_UINT64_C(0xb5026f5aa96619e9); } while (++i != 312); } v = r->s[r->n++]; v ^= (v & ACC_UINT64_C(0xaaaaaaaaa0000000)) >> 29; v ^= (v & ACC_UINT64_C(0x38eb3ffff6d3)) << 17; v ^= (v & ACC_UINT64_C(0x7ffbf77)) << 37; return v ^ (v >> 43); } # endif #endif #if defined(ACC_WANT_ACCLIB_RDTSC) # undef ACC_WANT_ACCLIB_RDTSC # define __ACCLIB_RDTSC_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if defined(acc_int32e_t) # if (ACC_OS_WIN32 && ACC_CC_PELLESC && (__POCC__ >= 290)) # pragma warn(push) # pragma warn(disable:2007) # endif # if (ACC_ARCH_AMD64 || ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) # if (ACC_ARCH_AMD64 && ACC_CC_PATHSCALE) # define __ACCLIB_RDTSC_REGS : : "c" (t) : "cc", "memory", "rax", "rdx" # elif (ACC_ARCH_AMD64 && ACC_CC_INTELC) # define __ACCLIB_RDTSC_REGS : : "r" (t) : "memory", "rax", "rdx" # elif (ACC_ARCH_AMD64) # define __ACCLIB_RDTSC_REGS : : "r" (t) : "cc", "memory", "rax", "rdx" # elif (ACC_ARCH_I386 && ACC_CC_GNUC && (ACC_CC_GNUC < 0x020000ul)) # define __ACCLIB_RDTSC_REGS : : "r" (t) : "ax", "dx" # elif (ACC_ARCH_I386 && ACC_CC_INTELC) # define __ACCLIB_RDTSC_REGS : : "r" (t) : "memory", "eax", "edx" # elif (ACC_ARCH_I386 && ACC_CC_PATHSCALE) # define __ACCLIB_RDTSC_REGS : : "c" (t) : "memory", "eax", "edx" # else # define __ACCLIB_RDTSC_REGS : : "r" (t) : "cc", "memory", "eax", "edx" # endif # endif ACCLIB_PUBLIC(int, acc_tsc_read)(acc_uint32e_t * t) { # if (ACC_ARCH_AMD64 || ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) __asm__ __volatile__("clc \n" ".byte 0x0f,0x31\n" "movl %%eax,(%0)\n" "movl %%edx,4(%0)\n" __ACCLIB_RDTSC_REGS); return 0; # elif (ACC_ARCH_I386) && (ACC_ASM_SYNTAX_MSC) ACC_UNUSED(t); __asm { mov ecx, t clc # if (ACC_CC_MSC && (_MSC_VER < 1200)) _emit 0x0f _emit 0x31 # else rdtsc # endif mov[ecx], eax mov[ecx + 4], edx} return 0; # else t[0] = t[1] = 0; return -1; # endif } # if (ACC_OS_WIN32 && ACC_CC_PELLESC && (__POCC__ >= 290)) # pragma warn(pop) # endif # endif #endif #if defined(ACC_WANT_ACCLIB_DOSALLOC) # undef ACC_WANT_ACCLIB_DOSALLOC # define __ACCLIB_DOSALLOC_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if (ACC_OS_OS216) ACC_EXTERN_C unsigned short __far __pascal DosAllocHuge(unsigned short, unsigned short, unsigned short __far *, unsigned short, unsigned short); ACC_EXTERN_C unsigned short __far __pascal DosFreeSeg(unsigned short); # endif # if (ACC_OS_DOS16 || ACC_OS_WIN16) # if !defined(ACC_CC_AZTECC) ACCLIB_PUBLIC(void __far *, acc_dos_alloc) (unsigned long size) { void __far *p = 0; union REGS ri, ro; if ((long)size <= 0) return p; size = (size + 15) >> 4; if (size > 0xffffu) return p; ri.x.ax = 0x4800; ri.x.bx = (unsigned short)size; int86(0x21, &ri, &ro); if ((ro.x.cflag & 1) == 0) p = (void __far *)ACC_PTR_MK_FP(ro.x.ax, 0); return p; } ACCLIB_PUBLIC(int, acc_dos_free)(void __far * p) { union REGS ri, ro; struct SREGS rs; if (!p) return 0; if (ACC_PTR_FP_OFF(p) != 0) return -1; segread(&rs); ri.x.ax = 0x4900; rs.es = ACC_PTR_FP_SEG(p); int86x(0x21, &ri, &ro, &rs); if (ro.x.cflag & 1) return -1; return 0; } # endif # endif # if (ACC_OS_OS216) ACCLIB_PUBLIC(void __far *, acc_dos_alloc)(unsigned long size) { void __far *p = 0; unsigned short sel = 0; if ((long)size <= 0) return p; if (DosAllocHuge((unsigned short)(size >> 16), (unsigned short)size, &sel, 0, 0) == 0) p = (void __far *)ACC_PTR_MK_FP(sel, 0); return p; } ACCLIB_PUBLIC(int, acc_dos_free)(void __far * p) { if (!p) return 0; if (ACC_PTR_FP_OFF(p) != 0) return -1; if (DosFreeSeg(ACC_PTR_FP_SEG(p)) != 0) return -1; return 0; } # endif #endif #if defined(ACC_WANT_ACCLIB_HALLOC) # undef ACC_WANT_ACCLIB_HALLOC # define __ACCLIB_HALLOC_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if (ACC_HAVE_MM_HUGE_PTR) # if 1 && (ACC_OS_DOS16 && defined(BLX286)) # define __ACCLIB_HALLOC_USE_DAH 1 # elif 1 && (ACC_OS_DOS16 && defined(DOSX286)) # define __ACCLIB_HALLOC_USE_DAH 1 # elif 1 && (ACC_OS_OS216) # define __ACCLIB_HALLOC_USE_DAH 1 # elif 1 && (ACC_OS_WIN16) # define __ACCLIB_HALLOC_USE_GA 1 # elif 1 && (ACC_OS_DOS16) && (ACC_CC_BORLANDC) && defined(__DPMI16__) # define __ACCLIB_HALLOC_USE_GA 1 # endif # endif # if (__ACCLIB_HALLOC_USE_DAH) # if 0 && (ACC_OS_OS216) # include # else ACC_EXTERN_C unsigned short __far __pascal DosAllocHuge(unsigned short, unsigned short, unsigned short __far *, unsigned short, unsigned short); ACC_EXTERN_C unsigned short __far __pascal DosFreeSeg(unsigned short); # endif # endif # if (__ACCLIB_HALLOC_USE_GA) # if 0 # define STRICT 1 # include # else ACC_EXTERN_C const void __near *__far __pascal GlobalAlloc(unsigned, unsigned long); ACC_EXTERN_C const void __near *__far __pascal GlobalFree(const void __near *); ACC_EXTERN_C unsigned long __far __pascal GlobalHandle(unsigned); ACC_EXTERN_C void __far *__far __pascal GlobalLock(const void __near *); ACC_EXTERN_C int __far __pascal GlobalUnlock(const void __near *); # endif # endif ACCLIB_PUBLIC(acc_hvoid_p, acc_halloc) (acc_hsize_t size) { acc_hvoid_p p = 0; if (!(size > 0)) return p; # if 0 && defined(__palmos__) p = MemPtrNew(size); # elif !defined(ACC_HAVE_MM_HUGE_PTR) if (size < (size_t) - 1) p = malloc((size_t) size); # else if ((long)size <= 0) return p; { # if (__ACCLIB_HALLOC_USE_DAH) unsigned short sel = 0; if (DosAllocHuge((unsigned short)(size >> 16), (unsigned short)size, &sel, 0, 0) == 0) p = (acc_hvoid_p) ACC_PTR_MK_FP(sel, 0); # elif (__ACCLIB_HALLOC_USE_GA) const void __near *h = GlobalAlloc(2, size); if (h) { p = GlobalLock(h); if (p && ACC_PTR_FP_OFF(p) != 0) { GlobalUnlock(h); p = 0; } if (!p) GlobalFree(h); } # elif (ACC_CC_MSC && (_MSC_VER >= 700)) p = _halloc(size, 1); # elif (ACC_CC_MSC || ACC_CC_WATCOMC) p = halloc(size, 1); # elif (ACC_CC_DMC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) p = farmalloc(size); # elif (ACC_CC_BORLANDC || ACC_CC_TURBOC) p = farmalloc(size); # elif defined(ACC_CC_AZTECC) p = lmalloc(size); # else if (size < (size_t) - 1) p = malloc((size_t) size); # endif } # endif return p; } ACCLIB_PUBLIC(void, acc_hfree)(acc_hvoid_p p) { if (!p) return; # if 0 && defined(__palmos__) MemPtrFree(p); # elif !defined(ACC_HAVE_MM_HUGE_PTR) free(p); # else # if (__ACCLIB_HALLOC_USE_DAH) if (ACC_PTR_FP_OFF(p) == 0) DosFreeSeg((unsigned short)ACC_PTR_FP_SEG(p)); # elif (__ACCLIB_HALLOC_USE_GA) if (ACC_PTR_FP_OFF(p) == 0) { const void __near *h = (const void __near *)(unsigned)GlobalHandle(ACC_PTR_FP_SEG(p)); if (h) { GlobalUnlock(h); GlobalFree(h); } } # elif (ACC_CC_MSC && (_MSC_VER >= 700)) _hfree(p); # elif (ACC_CC_MSC || ACC_CC_WATCOMC) hfree(p); # elif (ACC_CC_DMC || ACC_CC_SYMANTECC || ACC_CC_ZORTECHC) farfree((void __far *)p); # elif (ACC_CC_BORLANDC || ACC_CC_TURBOC) farfree((void __far *)p); # elif defined(ACC_CC_AZTECC) lfree(p); # else free(p); # endif # endif } #endif #if defined(ACC_WANT_ACCLIB_HFREAD) # undef ACC_WANT_ACCLIB_HFREAD # define __ACCLIB_HFREAD_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif ACCLIB_PUBLIC(acc_hsize_t, acc_hfread) (void *vfp, acc_hvoid_p buf, acc_hsize_t size) { FILE *fp = (FILE *) vfp; # if (ACC_HAVE_MM_HUGE_PTR) # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM) # define __ACCLIB_REQUIRE_HMEMCPY_CH 1 unsigned char tmp[512]; acc_hsize_t l = 0; while (l < size) { size_t n = size - l > sizeof(tmp) ? sizeof(tmp) : (size_t) (size - l); n = fread(tmp, 1, n, fp); if (n == 0) break; __ACCLIB_FUNCNAME(acc_hmemcpy) ((acc_hbyte_p) buf + l, tmp, (acc_hsize_t) n); l += n; } return l; # elif (ACC_MM_COMPACT || ACC_MM_LARGE || ACC_MM_HUGE) acc_hbyte_p b = (acc_hbyte_p) buf; acc_hsize_t l = 0; while (l < size) { size_t n; n = ACC_PTR_FP_OFF(b); n = (n <= 1) ? 0x8000u : (0u - n); if ((acc_hsize_t) n > size - l) n = (size_t) (size - l); n = fread((void __far *)b, 1, n, fp); if (n == 0) break; b += n; l += n; } return l; # else # error "unknown memory model" # endif # else return fread(buf, 1, size, fp); # endif } ACCLIB_PUBLIC(acc_hsize_t, acc_hfwrite) (void *vfp, const acc_hvoid_p buf, acc_hsize_t size) { FILE *fp = (FILE *) vfp; # if (ACC_HAVE_MM_HUGE_PTR) # if (ACC_MM_TINY || ACC_MM_SMALL || ACC_MM_MEDIUM) # define __ACCLIB_REQUIRE_HMEMCPY_CH 1 unsigned char tmp[512]; acc_hsize_t l = 0; while (l < size) { size_t n = size - l > sizeof(tmp) ? sizeof(tmp) : (size_t) (size - l); __ACCLIB_FUNCNAME(acc_hmemcpy) (tmp, (const acc_hbyte_p)buf + l, (acc_hsize_t) n); n = fwrite(tmp, 1, n, fp); if (n == 0) break; l += n; } return l; # elif (ACC_MM_COMPACT || ACC_MM_LARGE || ACC_MM_HUGE) const acc_hbyte_p b = (const acc_hbyte_p)buf; acc_hsize_t l = 0; while (l < size) { size_t n; n = ACC_PTR_FP_OFF(b); n = (n <= 1) ? 0x8000u : (0u - n); if ((acc_hsize_t) n > size - l) n = (size_t) (size - l); n = fwrite((void __far *)b, 1, n, fp); if (n == 0) break; b += n; l += n; } return l; # else # error "unknown memory model" # endif # else return fwrite(buf, 1, size, fp); # endif } #endif #if defined(ACC_WANT_ACCLIB_HSREAD) # undef ACC_WANT_ACCLIB_HSREAD # define __ACCLIB_HSREAD_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif ACCLIB_PUBLIC(long, acc_safe_hread)(int fd, acc_hvoid_p buf, long size) { acc_hbyte_p b = (acc_hbyte_p) buf; long l = 0; int saved_errno; saved_errno = errno; while (l < size) { long n = size - l; # if (ACC_HAVE_MM_HUGE_PTR) # define __ACCLIB_REQUIRE_HREAD_CH 1 errno = 0; n = acc_hread(fd, b, n); # elif (ACC_OS_DOS32) && defined(__DJGPP__) errno = 0; n = _read(fd, b, n); # else errno = 0; n = read(fd, b, n); # endif if (n == 0) break; if (n < 0) { # if defined(EAGAIN) if (errno == (EAGAIN)) continue; # endif # if defined(EINTR) if (errno == (EINTR)) continue; # endif if (errno == 0) errno = 1; return l; } b += n; l += n; } errno = saved_errno; return l; } ACCLIB_PUBLIC(long, acc_safe_hwrite)(int fd, const acc_hvoid_p buf, long size) { const acc_hbyte_p b = (const acc_hbyte_p)buf; long l = 0; int saved_errno; saved_errno = errno; while (l < size) { long n = size - l; # if (ACC_HAVE_MM_HUGE_PTR) # define __ACCLIB_REQUIRE_HREAD_CH 1 errno = 0; n = acc_hwrite(fd, b, n); # elif (ACC_OS_DOS32) && defined(__DJGPP__) errno = 0; n = _write(fd, b, n); # else errno = 0; n = write(fd, b, n); # endif if (n == 0) break; if (n < 0) { # if defined(EAGAIN) if (errno == (EAGAIN)) continue; # endif # if defined(EINTR) if (errno == (EINTR)) continue; # endif if (errno == 0) errno = 1; return l; } b += n; l += n; } errno = saved_errno; return l; } #endif #if defined(ACC_WANT_ACCLIB_PCLOCK) # undef ACC_WANT_ACCLIB_PCLOCK # define __ACCLIB_PCLOCK_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if defined(HAVE_GETTIMEOFDAY) # ifndef acc_pclock_read_gettimeofday # define acc_pclock_read_gettimeofday acc_pclock_read_gettimeofday # endif static int acc_pclock_read_gettimeofday(acc_pclock_handle_p h, acc_pclock_p c) { struct timeval tv; if (gettimeofday(&tv, 0) != 0) return -1; # if defined(acc_int64l_t) c->tv_sec = tv.tv_sec; # else c->tv_sec_high = 0; c->tv_sec_low = tv.tv_sec; # endif c->tv_nsec = (acc_uint32l_t) (tv.tv_usec * 1000u); ACC_UNUSED(h); return 0; } # endif # if defined(CLOCKS_PER_SEC) # ifndef acc_pclock_read_clock # define acc_pclock_read_clock acc_pclock_read_clock # endif static int acc_pclock_read_clock(acc_pclock_handle_p h, acc_pclock_p c) { clock_t ticks; double secs; # if defined(acc_int64l_t) acc_uint64l_t nsecs; ticks = clock(); secs = (double)ticks / (CLOCKS_PER_SEC); nsecs = (acc_uint64l_t) (secs * 1000000000.0); c->tv_sec = (acc_int64l_t) (nsecs / 1000000000ul); c->tv_nsec = (acc_uint32l_t) (nsecs % 1000000000ul); # else ticks = clock(); secs = (double)ticks / (CLOCKS_PER_SEC); c->tv_sec_high = 0; c->tv_sec_low = (acc_uint32l_t) (secs + 0.5); c->tv_nsec = 0; # endif ACC_UNUSED(h); return 0; } # endif # if (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) && defined(UCLOCKS_PER_SEC) # ifndef acc_pclock_read_uclock # define acc_pclock_read_uclock acc_pclock_read_uclock # endif static int acc_pclock_read_uclock(acc_pclock_handle_p h, acc_pclock_p c) { acc_uint64l_t ticks; double secs; acc_uint64l_t nsecs; ticks = uclock(); secs = (double)ticks / (UCLOCKS_PER_SEC); nsecs = (acc_uint64l_t) (secs * 1000000000.0); c->tv_sec = nsecs / 1000000000ul; c->tv_nsec = (acc_uint32l_t) (nsecs % 1000000000ul); ACC_UNUSED(h); return 0; } # endif # if 0 && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) && defined(acc_int64l_t) # ifndef acc_pclock_read_clock_gettime_p # define acc_pclock_read_clock_gettime_p acc_pclock_read_clock_gettime_p # endif static int acc_pclock_read_clock_gettime_p(acc_pclock_handle_p h, acc_pclock_p c) { struct timespec ts; if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) != 0) return -1; c->tv_sec = ts.tv_sec; c->tv_nsec = ts.tv_nsec; ACC_UNUSED(h); return 0; } # endif # if (ACC_OS_CYGWIN || ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_HAVE_WINDOWS_H) && defined(acc_int64l_t) # ifndef acc_pclock_read_getprocesstimes # define acc_pclock_read_getprocesstimes acc_pclock_read_getprocesstimes # endif static int acc_pclock_read_getprocesstimes(acc_pclock_handle_p h, acc_pclock_p c) { FILETIME ct, et, kt, ut; acc_uint64l_t ticks; if (GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut) == 0) return -1; ticks = ((acc_uint64l_t) ut.dwHighDateTime << 32) | ut.dwLowDateTime; if __acc_unlikely (h->ticks_base == 0) h->ticks_base = ticks; else ticks -= h->ticks_base; c->tv_sec = (acc_int64l_t) (ticks / 10000000ul); c->tv_nsec = (acc_uint32l_t) (ticks % 10000000ul) * 100u; ACC_UNUSED(h); return 0; } # endif # if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF) # ifndef acc_pclock_read_getrusage # define acc_pclock_read_getrusage acc_pclock_read_getrusage # endif static int acc_pclock_read_getrusage(acc_pclock_handle_p h, acc_pclock_p c) { struct rusage ru; if (getrusage(RUSAGE_SELF, &ru) != 0) return -1; # if defined(acc_int64l_t) c->tv_sec = ru.ru_utime.tv_sec; # else c->tv_sec_high = 0; c->tv_sec_low = ru.ru_utime.tv_sec; # endif c->tv_nsec = (acc_uint32l_t) (ru.ru_utime.tv_usec * 1000u); ACC_UNUSED(h); return 0; } # endif # if (__ACCLIB_PCLOCK_USE_PERFCTR) # ifndef acc_pclock_read_perfctr # define acc_pclock_read_perfctr acc_pclock_read_perfctr # endif static int acc_pclock_read_perfctr(acc_pclock_handle_p h, acc_pclock_p c) { acc_perfctr_clock_t pcc; double secs; acc_uint64l_t nsecs; acc_perfctr_read(&h->pch, &pcc); if __acc_unlikely (h->ticks_base == 0) h->ticks_base = pcc.tsc; else pcc.tsc -= h->ticks_base; secs = pcc.tsc * h->pch.tsc_to_seconds; nsecs = (acc_uint64l_t) (secs * 1000000000.0); c->tv_sec = nsecs / 1000000000ul; c->tv_nsec = (acc_uint32l_t) (nsecs % 1000000000ul); ACC_UNUSED(h); return 0; } # endif # if 0 && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_THREAD_CPUTIME_ID) && defined(acc_int64l_t) # ifndef acc_pclock_read_clock_gettime_t # define acc_pclock_read_clock_gettime_t acc_pclock_read_clock_gettime_t # endif static int acc_pclock_read_clock_gettime_t(acc_pclock_handle_p h, acc_pclock_p c) { struct timespec ts; if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) != 0) return -1; c->tv_sec = ts.tv_sec; c->tv_nsec = ts.tv_nsec; ACC_UNUSED(h); return 0; } # endif # if (ACC_OS_CYGWIN || ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_HAVE_WINDOWS_H) && defined(acc_int64l_t) # ifndef acc_pclock_read_getthreadtimes # define acc_pclock_read_getthreadtimes acc_pclock_read_getthreadtimes # endif static int acc_pclock_read_getthreadtimes(acc_pclock_handle_p h, acc_pclock_p c) { FILETIME ct, et, kt, ut; acc_uint64l_t ticks; if (GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut) == 0) return -1; ticks = ((acc_uint64l_t) ut.dwHighDateTime << 32) | ut.dwLowDateTime; if __acc_unlikely (h->ticks_base == 0) h->ticks_base = ticks; else ticks -= h->ticks_base; c->tv_sec = (acc_int64l_t) (ticks / 10000000ul); c->tv_nsec = (acc_uint32l_t) (ticks % 10000000ul) * 100; ACC_UNUSED(h); return 0; } # endif ACCLIB_PUBLIC(int, acc_pclock_open)(acc_pclock_handle_p h, int mode) { acc_pclock_t c; int i; h->h = (acclib_handle_t) 0; h->mode = -1; h->name = NULL; h->gettime = 0; # if defined(acc_int64l_t) h->ticks_base = 0; # endif switch (mode) { case ACC_PCLOCK_REALTIME_HR: # if defined(acc_pclock_read_gettimeofday) h->gettime = acc_pclock_read_gettimeofday; h->name = "gettimeofday"; # endif break; case ACC_PCLOCK_REALTIME: # if defined(acc_pclock_read_gettimeofday) h->gettime = acc_pclock_read_gettimeofday; h->name = "gettimeofday"; # endif break; case ACC_PCLOCK_MONOTONIC_HR: # if defined(acc_pclock_read_uclock) h->gettime = acc_pclock_read_uclock; h->name = "uclock"; # endif break; case ACC_PCLOCK_MONOTONIC: # if defined(acc_pclock_read_clock) if (!h->gettime) { h->gettime = acc_pclock_read_clock; h->name = "clock"; } # endif break; case ACC_PCLOCK_PROCESS_CPUTIME_ID: # if defined(acc_pclock_read_perfctr) if (acc_perfctr_open(&h->pch) == 0) { h->gettime = acc_pclock_read_perfctr; h->name = "perfctr"; break; } # endif # if defined(acc_pclock_read_getprocesstimes) if (!h->gettime && acc_pclock_read_getprocesstimes(h, &c) == 0) { h->gettime = acc_pclock_read_getprocesstimes; h->name = "GetProcessTimes"; break; } # endif # if defined(acc_pclock_read_clock_gettime_p) if (!h->gettime && acc_pclock_read_clock_gettime_p(h, &c) == 0) { h->gettime = acc_pclock_read_clock_gettime_p; h->name = "CLOCK_PROCESS_CPUTIME_ID"; break; } # endif # if defined(acc_pclock_read_getrusage) h->gettime = acc_pclock_read_getrusage; h->name = "getrusage"; # endif break; case ACC_PCLOCK_THREAD_CPUTIME_ID: # if defined(acc_pclock_read_getthreadtimes) if (!h->gettime && acc_pclock_read_getthreadtimes(h, &c) == 0) { h->gettime = acc_pclock_read_getthreadtimes; h->name = "GetThreadTimes"; } # endif # if defined(acc_pclock_read_clock_gettime_t) if (!h->gettime && acc_pclock_read_clock_gettime_t(h, &c) == 0) { h->gettime = acc_pclock_read_clock_gettime_t; h->name = "CLOCK_THREAD_CPUTIME_ID"; break; } # endif break; } if (!h->gettime) return -1; if (!h->h) h->h = (acclib_handle_t) 1; h->mode = mode; if (!h->name) h->name = "unknown"; for (i = 0; i < 10; i++) { acc_pclock_read(h, &c); } return 0; } ACCLIB_PUBLIC(int, acc_pclock_open_default)(acc_pclock_handle_p h) { if (acc_pclock_open(h, ACC_PCLOCK_PROCESS_CPUTIME_ID) == 0) return 0; if (acc_pclock_open(h, ACC_PCLOCK_MONOTONIC_HR) == 0) return 0; if (acc_pclock_open(h, ACC_PCLOCK_REALTIME_HR) == 0) return 0; if (acc_pclock_open(h, ACC_PCLOCK_MONOTONIC) == 0) return 0; if (acc_pclock_open(h, ACC_PCLOCK_REALTIME) == 0) return 0; if (acc_pclock_open(h, ACC_PCLOCK_THREAD_CPUTIME_ID) == 0) return 0; return -1; } ACCLIB_PUBLIC(int, acc_pclock_close)(acc_pclock_handle_p h) { h->h = (acclib_handle_t) 0; h->mode = -1; h->name = NULL; h->gettime = 0; # if (__ACCLIB_PCLOCK_USE_PERFCTR) acc_perfctr_close(&h->pch); # endif return 0; } ACCLIB_PUBLIC(void, acc_pclock_read)(acc_pclock_handle_p h, acc_pclock_p c) { if (h->gettime) { if (h->gettime(h, c) == 0) return; } # if defined(acc_int64l_t) c->tv_sec = 0; # else c->tv_sec_high = 0; c->tv_sec_low = 0; # endif c->tv_nsec = 0; } # if !defined(ACC_CFG_NO_DOUBLE) ACCLIB_PUBLIC(double, acc_pclock_get_elapsed)(acc_pclock_handle_p h, const acc_pclock_p start, const acc_pclock_p stop) { double tstop, tstart; if (!h->h) { h->mode = -1; return 0.0; } # if defined(acc_int64l_t) tstop = stop->tv_sec + stop->tv_nsec / 1000000000.0; tstart = start->tv_sec + start->tv_nsec / 1000000000.0; # else tstop = stop->tv_sec_low + stop->tv_nsec / 1000000000.0; tstart = start->tv_sec_low + start->tv_nsec / 1000000000.0; # endif return tstop - tstart; } # endif ACCLIB_PUBLIC(int, acc_pclock_flush_cpu_cache)(acc_pclock_handle_p h, unsigned flags) { if (h->h) { # if (__ACCLIB_PCLOCK_USE_PERFCTR) return acc_perfctr_flush_cpu_cache(&h->pch, flags); # endif } ACC_UNUSED(h); ACC_UNUSED(flags); return -1; } # if defined(__ACCLIB_PCLOCK_NEED_WARN_POP) # if (ACC_CC_MSC && (_MSC_VER >= 1200)) # pragma warning(pop) # else # error "__ACCLIB_PCLOCK_NEED_WARN_POP" # endif # undef __ACCLIB_PCLOCK_NEED_WARN_POP # endif #endif #if defined(ACC_WANT_ACCLIB_UCLOCK) # undef ACC_WANT_ACCLIB_UCLOCK # define __ACCLIB_UCLOCK_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if (ACC_OS_DOS16 || ACC_OS_WIN16) # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) # elif (ACC_OS_CYGWIN || ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_HAVE_WINDOWS_H) # if ((ACC_CC_DMC && (__DMC__ < 0x838)) || ACC_CC_LCCWIN32) # define __ACCLIB_UCLOCK_USE_CLOCK 1 # else # define __ACCLIB_UCLOCK_USE_WINMM 1 # if (ACC_CC_MSC && (_MSC_VER >= 1200)) # pragma warning(push) # define __ACCLIB_UCLOCK_NEED_WARN_POP 1 # endif # if (ACC_CC_MSC && (_MSC_VER >= 900)) # pragma warning(disable: 4201) # elif (ACC_CC_MWERKS) # define LPUINT __ACC_MMSYSTEM_H_LPUINT # endif # if 1 # include # else # if (ACC_CC_INTELC || ACC_CC_MSC || ACC_CC_PELLESC) ACC_EXTERN_C __declspec(dllimport) unsigned long __stdcall timeGetTime(void); # else ACC_EXTERN_C unsigned long __stdcall timeGetTime(void); # endif # endif # if (ACC_CC_DMC) # pragma DMC includelib "winmm.lib" # elif (ACC_CC_INTELC || ACC_CC_MSC || ACC_CC_PELLESC) # pragma comment(lib, "winmm.lib") # elif (ACC_CC_MWERKS && (__MWERKS__ >= 0x3000)) # pragma comment(lib, "winmm.lib") # elif (ACC_CC_SYMANTECC) # pragma SC includelib "winmm.lib" # elif (ACC_CC_WATCOMC && (__WATCOMC__ >= 1050)) # pragma library("winmm.lib") # endif # endif # elif (ACC_OS_CYGWIN || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_TOS || ACC_OS_WIN32 || ACC_OS_WIN64) # define __ACCLIB_UCLOCK_USE_CLOCK 1 # elif (ACC_OS_CONSOLE) && defined(CLOCKS_PER_SEC) # define __ACCLIB_UCLOCK_USE_CLOCK 1 # elif (ACC_LIBC_ISOC90 || ACC_LIBC_ISOC99) && defined(CLOCKS_PER_SEC) # define __ACCLIB_UCLOCK_USE_CLOCK 1 # endif # if (__ACCLIB_UCLOCK_USE_CLOCK) && !defined(CLOCKS_PER_SEC) # if defined(CLK_TCK) # define CLOCKS_PER_SEC CLK_TCK # else # undef __ACCLIB_UCLOCK_USE_CLOCK # endif # endif # if (__ACCLIB_UCLOCK_USE_GETRUSAGE) # if !defined(RUSAGE_SELF) # undef __ACCLIB_UCLOCK_USE_GETRUSAGE # endif # endif ACCLIB_PUBLIC(int, acc_uclock_open)(acc_uclock_handle_p h) { int i; # if (__ACCLIB_UCLOCK_USE_QPC) LARGE_INTEGER li; # endif h->h = (acclib_handle_t) 1; h->mode = 0; h->name = NULL; # if (__ACCLIB_UCLOCK_USE_PERFCTR) h->pch.h = 0; if (h->mode == 0 && acc_perfctr_open(&h->pch) == 0) h->mode = 2; # endif # if (__ACCLIB_UCLOCK_USE_QPC) h->qpf = 0.0; if (h->mode == 0 && QueryPerformanceFrequency(&li) != 0) { double d = (double)li.QuadPart; if (d > 0.0 && QueryPerformanceCounter(&li) != 0) { h->mode = 3; h->qpf = d; } } # endif for (i = 0; i < 10; i++) { acc_uclock_t c; acc_uclock_read(h, &c); } return 0; } ACCLIB_PUBLIC(int, acc_uclock_close)(acc_uclock_handle_p h) { h->h = (acclib_handle_t) 0; h->mode = -1; h->name = NULL; # if (__ACCLIB_UCLOCK_USE_PERFCTR) acc_perfctr_close(&h->pch); # endif return 0; } ACCLIB_PUBLIC(void, acc_uclock_read)(acc_uclock_handle_p h, acc_uclock_p c) { # if (__ACCLIB_UCLOCK_USE_RDTSC) acc_tsc_read((acc_uint32e_t *) (void *)&c->tsc); # endif # if (__ACCLIB_UCLOCK_USE_PERFCTR) if (h->pch.h) { acc_perfctr_read(&h->pch, &c->pcc); if (h->mode > 0 && h->mode <= 2) return; } # endif # if (__ACCLIB_UCLOCK_USE_QPC) if (h->qpf > 0.0) { LARGE_INTEGER li; if (QueryPerformanceCounter(&li) != 0) { c->qpc = (acc_int64l_t) li.QuadPart; if (h->mode > 0 && h->mode <= 3) return; } else { h->mode = 0; h->qpf = 0.0; c->qpc = 0; } } # endif { # if (ACC_OS_DOS16 || ACC_OS_WIN16) # if (ACC_CC_AZTECC) c->ticks.t32 = 0; # else union REGS ri, ro; ri.x.ax = 0x2c00; int86(0x21, &ri, &ro); c->ticks.t32 = ro.h.ch * 60UL * 60UL * 100UL + ro.h.cl * 60UL * 100UL + ro.h.dh * 100UL + ro.h.dl; # endif # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) c->ticks.t64 = uclock(); # elif (__ACCLIB_UCLOCK_USE_CLOCK) && defined(acc_int64l_t) c->ticks.t64 = clock(); # elif (__ACCLIB_UCLOCK_USE_CLOCK) c->ticks.t32 = clock(); # elif (__ACCLIB_UCLOCK_USE_WINMM) c->ticks.t32 = timeGetTime(); # elif (__ACCLIB_UCLOCK_USE_GETRUSAGE) struct rusage ru; if (getrusage(RUSAGE_SELF, &ru) != 0) c->ticks.td = 0; else c->ticks.td = ru.ru_utime.tv_sec + ru.ru_utime.tv_usec / 1000000.0; # elif (HAVE_GETTIMEOFDAY) struct timeval tv; if (gettimeofday(&tv, 0) != 0) c->ticks.td = 0; else c->ticks.td = tv.tv_sec + tv.tv_usec / 1000000.0; # else ACC_UNUSED(c); # endif } ACC_UNUSED(h); } ACCLIB_PUBLIC(double, acc_uclock_get_elapsed) (acc_uclock_handle_p h, const acc_uclock_p start, const acc_uclock_p stop) { double d; if (!h->h) { h->mode = -1; return 0.0; } # if (__ACCLIB_UCLOCK_USE_RDTSC) if (h->mode == 1) { if (!h->name) h->name = "rdtsc"; d = (double)((acc_int64l_t) stop->tsc - (acc_int64l_t) start->tsc); return d / 1000000000.0; } # endif # if (__ACCLIB_UCLOCK_USE_PERFCTR) if (h->pch.h && h->mode == 2) { if (!h->name) h->name = "perfctr"; return acc_perfctr_get_elapsed(&h->pch, &start->pcc, &stop->pcc); } # endif # if (__ACCLIB_UCLOCK_USE_QPC) if (h->qpf > 0.0 && h->mode == 3) { if (!h->name) h->name = "qpc"; if (start->qpc == 0 || stop->qpc == 0) return 0.0; return (double)(stop->qpc - start->qpc) / h->qpf; } # endif # if (ACC_OS_DOS16 || ACC_OS_WIN16) h->mode = 11; if (!h->name) h->name = "uclock"; d = (double)(stop->ticks.t32 - start->ticks.t32) / 100.0; if (d < 0.0) d += 86400.0; # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) h->mode = 12; if (!h->name) h->name = "uclock"; d = (double)(stop->ticks.t64 - start->ticks.t64) / (UCLOCKS_PER_SEC); # elif (__ACCLIB_UCLOCK_USE_CLOCK) && defined(acc_int64l_t) h->mode = 13; if (!h->name) h->name = "clock"; { acc_int64l_t t; t = stop->ticks.t64 - start->ticks.t64; if (t < 0) t += sizeof(clock_t) == 4 ? ACC_INT64_C(0x100000000) : ACC_INT64_C(0); d = (double)t / (CLOCKS_PER_SEC); } # elif (__ACCLIB_UCLOCK_USE_CLOCK) h->mode = 14; if (!h->name) h->name = "clock"; d = (double)(stop->ticks.t32 - start->ticks.t32) / (CLOCKS_PER_SEC); # elif (__ACCLIB_UCLOCK_USE_WINMM) h->mode = 15; if (!h->name) h->name = "timeGetTime"; d = (double)(stop->ticks.t32 - start->ticks.t32) / 1000.0; # elif (__ACCLIB_UCLOCK_USE_GETRUSAGE) h->mode = 16; if (!h->name) h->name = "getrusage"; d = stop->ticks.td - start->ticks.td; # elif (HAVE_GETTIMEOFDAY) h->mode = 17; if (!h->name) h->name = "gettimeofday"; d = stop->ticks.td - start->ticks.td; # else h->mode = 0; d = 0.0; # endif return d; } ACCLIB_PUBLIC(int, acc_uclock_flush_cpu_cache)(acc_uclock_handle_p h, unsigned flags) { if (h->h) { # if (__ACCLIB_UCLOCK_USE_PERFCTR) return acc_perfctr_flush_cpu_cache(&h->pch, flags); # endif } ACC_UNUSED(h); ACC_UNUSED(flags); return -1; } # if defined(__ACCLIB_UCLOCK_NEED_WARN_POP) # if (ACC_CC_MSC && (_MSC_VER >= 1200)) # pragma warning(pop) # else # error "__ACCLIB_UCLOCK_NEED_WARN_POP" # endif # undef __ACCLIB_UCLOCK_NEED_WARN_POP # endif #endif #if defined(ACC_WANT_ACCLIB_MISC) # undef ACC_WANT_ACCLIB_MISC # define __ACCLIB_MISC_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if !defined(ACCLIB_PUBLIC_NOINLINE) # if !defined(__acc_noinline) # define ACCLIB_PUBLIC_NOINLINE(r,f) r __ACCLIB_FUNCNAME(f) # elif (ACC_CC_GNUC >= 0x030400ul) || (ACC_CC_LLVM) # define ACCLIB_PUBLIC_NOINLINE(r,f) __acc_noinline __attribute__((__used__)) r __ACCLIB_FUNCNAME(f) # else # define ACCLIB_PUBLIC_NOINLINE(r,f) __acc_noinline r __ACCLIB_FUNCNAME(f) # endif # endif # if (ACC_OS_WIN32 && ACC_CC_PELLESC && (__POCC__ >= 290)) # pragma warn(push) # pragma warn(disable:2007) # endif ACCLIB_PUBLIC(const char *, acc_getenv)(const char *s) { # if defined(HAVE_GETENV) return getenv(s); # else ACC_UNUSED(s); return (const char *)0; # endif } ACCLIB_PUBLIC(acclib_handle_t, acc_get_osfhandle) (int fd) { if (fd < 0) return -1; # if (ACC_OS_CYGWIN) return get_osfhandle(fd); # elif (ACC_OS_EMX && defined(__RSXNT__)) return -1; # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) return -1; # elif (ACC_OS_WIN32 || ACC_OS_WIN64) # if (ACC_CC_PELLESC && (__POCC__ < 280)) return -1; # elif (ACC_CC_WATCOMC && (__WATCOMC__ < 1000)) return -1; # elif (ACC_CC_WATCOMC && (__WATCOMC__ < 1100)) return _os_handle(fd); # else return _get_osfhandle(fd); # endif # else return fd; # endif } ACCLIB_PUBLIC(int, acc_set_binmode)(int fd, int binary) { # if (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__) FILE *fp; int old_binary; if (fd == STDIN_FILENO) fp = stdin; else if (fd == STDOUT_FILENO) fp = stdout; else if (fd == STDERR_FILENO) fp = stderr; else return -1; old_binary = fp->__mode.__binary; __set_binmode(fp, binary ? 1 : 0); return old_binary ? 1 : 0; # elif (ACC_ARCH_M68K && ACC_OS_TOS) ACC_UNUSED(fd); ACC_UNUSED(binary); return -1; # elif (ACC_OS_DOS16 && (ACC_CC_AZTECC || ACC_CC_PACIFICC)) ACC_UNUSED(fd); ACC_UNUSED(binary); return -1; # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) int r; unsigned old_flags = __djgpp_hwint_flags; ACC_COMPILE_TIME_ASSERT(O_BINARY > 0) ACC_COMPILE_TIME_ASSERT(O_TEXT > 0) if (fd < 0) return -1; r = setmode(fd, binary ? O_BINARY : O_TEXT); if ((old_flags & 1u) != (__djgpp_hwint_flags & 1u)) __djgpp_set_ctrl_c(!(old_flags & 1)); if (r == -1) return -1; return (r & O_TEXT) ? 0 : 1; # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) if (fd < 0) return -1; ACC_UNUSED(binary); return 1; # elif (ACC_OS_DOS32 && ACC_CC_HIGHC) FILE *fp; int r; if (fd == fileno(stdin)) fp = stdin; else if (fd == fileno(stdout)) fp = stdout; else if (fd == fileno(stderr)) fp = stderr; else return -1; r = _setmode(fp, binary ? _BINARY : _TEXT); if (r == -1) return -1; return (r & _BINARY) ? 1 : 0; # elif (ACC_OS_WIN32 && ACC_CC_MWERKS) && defined(__MSL__) ACC_UNUSED(fd); ACC_UNUSED(binary); return -1; # elif (ACC_OS_CYGWIN && (ACC_CC_GNUC < 0x025a00ul)) ACC_UNUSED(fd); ACC_UNUSED(binary); return -1; # elif (ACC_OS_CYGWIN || ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_EMX || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) int r; # if !defined(ACC_CC_ZORTECHC) ACC_COMPILE_TIME_ASSERT(O_BINARY > 0) # endif ACC_COMPILE_TIME_ASSERT(O_TEXT > 0) if (fd < 0) return -1; r = setmode(fd, binary ? O_BINARY : O_TEXT); if (r == -1) return -1; return (r & O_TEXT) ? 0 : 1; # else if (fd < 0) return -1; ACC_UNUSED(binary); return 1; # endif } ACCLIB_PUBLIC(int, acc_isatty)(int fd) { if (fd < 0) return 0; # if (ACC_OS_DOS16 && !defined(ACC_CC_AZTECC)) { union REGS ri, ro; ri.x.ax = 0x4400; ri.x.bx = fd; int86(0x21, &ri, &ro); if ((ro.x.cflag & 1) == 0) if ((ro.x.ax & 0x83) != 0x83) return 0; } # elif (ACC_OS_DOS32 && ACC_CC_WATCOMC) { union REGS ri, ro; ri.w.ax = 0x4400; ri.w.bx = (unsigned short)fd; int386(0x21, &ri, &ro); if ((ro.w.cflag & 1) == 0) if ((ro.w.ax & 0x83) != 0x83) return 0; } # elif (ACC_HAVE_WINDOWS_H) { acclib_handle_t h = __ACCLIB_FUNCNAME(acc_get_osfhandle) (fd); if ((HANDLE) h != INVALID_HANDLE_VALUE) { DWORD d = 0; if (GetConsoleMode((HANDLE) h, &d) == 0) return 0; } } # endif # if defined(HAVE_ISATTY) return (isatty(fd)) ? 1 : 0; # else return 0; # endif } ACCLIB_PUBLIC(int, acc_mkdir)(const char *name, unsigned mode) { # if !defined(HAVE_MKDIR) ACC_UNUSED(name); ACC_UNUSED(mode); return -1; # elif (ACC_ARCH_M68K && ACC_OS_TOS && (ACC_CC_PUREC || ACC_CC_TURBOC)) ACC_UNUSED(mode); return Dcreate(name); # elif (ACC_OS_DOS32 && ACC_CC_GNUC) && defined(__DJGPP__) return mkdir(name, mode); # elif (ACC_OS_WIN32 && ACC_CC_GNUC) && defined(__PW32__) return mkdir(name, mode); # elif (ACC_OS_DOS16 || ACC_OS_DOS32 || ACC_OS_OS2 || ACC_OS_OS216 || ACC_OS_WIN16 || ACC_OS_WIN32 || ACC_OS_WIN64) ACC_UNUSED(mode); # if (ACC_CC_HIGHC || ACC_CC_PACIFICC) return mkdir((char *)name); # else return mkdir(name); # endif # else return mkdir(name, mode); # endif } ACCLIB_PUBLIC(int, acc_rmdir)(const char *name) { # if !defined(HAVE_RMDIR) ACC_UNUSED(name); return -1; # elif ((ACC_OS_DOS16 || ACC_OS_DOS32) && (ACC_CC_HIGHC || ACC_CC_PACIFICC)) return rmdir((char *)name); # else return rmdir(name); # endif } # if defined(acc_int32e_t) ACCLIB_PUBLIC(acc_int32e_t, acc_muldiv32s) (acc_int32e_t a, acc_int32e_t b, acc_int32e_t x) { acc_int32e_t r = 0; if __acc_likely (x != 0) { # if defined(acc_int64l_t) r = (acc_int32e_t) (((acc_int64l_t) a * b) / x); # else ACC_UNUSED(a); ACC_UNUSED(b); # endif } return r; } ACCLIB_PUBLIC(acc_uint32e_t, acc_muldiv32u) (acc_uint32e_t a, acc_uint32e_t b, acc_uint32e_t x) { acc_uint32e_t r = 0; if __acc_likely (x != 0) { # if defined(acc_int64l_t) r = (acc_uint32e_t) (((acc_uint64l_t) a * b) / x); # else ACC_UNUSED(a); ACC_UNUSED(b); # endif } return r; } # endif # if 0 ACCLIB_PUBLIC_NOINLINE(int, acc_syscall_clock_gettime)(int c) { } # endif # if (ACC_OS_WIN16) ACC_EXTERN_C void __far __pascal DebugBreak(void); # endif ACCLIB_PUBLIC_NOINLINE(void, acc_debug_break) (void) { # if (ACC_OS_WIN16) DebugBreak(); # elif (ACC_ARCH_I086) # elif (ACC_OS_WIN64) && (ACC_HAVE_WINDOWS_H) DebugBreak(); # elif defined(ACC_CFG_NO_INLINE_ASM) && (ACC_OS_WIN32) && (ACC_HAVE_WINDOWS_H) DebugBreak(); # elif (ACC_ARCH_AMD64 || ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) __asm__ __volatile__("int $3\n":::__ACC_ASM_CLOBBER); # elif (ACC_ARCH_I386) && (ACC_ASM_SYNTAX_MSC) __asm { int 3} # elif (ACC_OS_WIN32) && (ACC_HAVE_WINDOWS_H) DebugBreak(); # else *(volatile int *)0x1 = -1; # endif } ACCLIB_PUBLIC_NOINLINE(void, acc_debug_nop) (void) { } ACCLIB_PUBLIC_NOINLINE(int, acc_debug_align_check_query) (void) { # if (ACC_ARCH_AMD64 || ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) size_t r; __asm__ __volatile__("pushf\n pop %0\n":"=a"(r)::__ACC_ASM_CLOBBER); return (int)(r >> 18) & 1; # elif (ACC_ARCH_I386) && (ACC_ASM_SYNTAX_MSC) unsigned long r; __asm { pushf pop eax mov r, eax} return (int)(r >> 18) & 1; # else return -1; # endif } ACCLIB_PUBLIC_NOINLINE(int, acc_debug_align_check_enable)(int v) { int r; # if (ACC_ARCH_AMD64) && (ACC_ASM_SYNTAX_GNUC) if (v) { __asm__ __volatile__("pushf\n orl $262144,(%%rsp)\n popf\n":::__ACC_ASM_CLOBBER); } else { __asm__ __volatile__("pushf\n andl $-262145,(%%rsp)\n popf\n":::__ACC_ASM_CLOBBER); } r = 0; # elif (ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) if (v) { __asm__ __volatile__("pushf\n orl $262144,(%%esp)\n popf\n":::__ACC_ASM_CLOBBER); } else { __asm__ __volatile__("pushf\n andl $-262145,(%%esp)\n popf\n":::__ACC_ASM_CLOBBER); } r = 0; # elif (ACC_ARCH_I386) && (ACC_ASM_SYNTAX_MSC) if (v) { __asm { pushf or dword ptr[esp], 262144 popf} } else { __asm { pushf and dword ptr[esp], -262145 popf} } r = 0; # else r = -1; # endif ACC_UNUSED(v); return r; } ACCLIB_PUBLIC_NOINLINE(unsigned, acc_debug_running_on_qemu)(void) { unsigned r = 0; # if (ACC_OS_POSIX_LINUX || ACC_OS_WIN32 || ACC_OS_WIN64) const char *p; p = acc_getenv("ACC_ENV_RUNNING_ON_QEMU"); if (p) { if (p[0] == 0) r = 0; else if ((p[0] >= '0' && p[0] <= '9') && p[1] == 0) r = p[0] - '0'; else r = 1; } # endif return r; } ACCLIB_PUBLIC_NOINLINE(unsigned, acc_debug_running_on_valgrind)(void) { # if (ACC_ARCH_AMD64 || ACC_ARCH_I386) && (ACC_ASM_SYNTAX_GNUC) volatile unsigned long args[5] = { 0x1001, 0, 0, 0, 0 }; unsigned long r = 0; __asm__ __volatile__(".byte 0xc1,0xc0,0x1d,0xc1,0xc0,0x03,0xc1,0xc8,0x1b,0xc1,0xc8,0x05,0xc1,0xc0,0x0d,0xc1,0xc0,0x13\n":"=d"(r):"a"(&args[0]), "d"(r):__ACC_ASM_CLOBBER); return (unsigned)r; # else return 0; # endif } # if (ACC_OS_WIN32 && ACC_CC_PELLESC && (__POCC__ >= 290)) # pragma warn(pop) # endif #endif #if defined(ACC_WANT_ACCLIB_WILDARGV) # undef ACC_WANT_ACCLIB_WILDARGV # define __ACCLIB_WILDARGV_CH_INCLUDED 1 # if !defined(ACCLIB_PUBLIC) # define ACCLIB_PUBLIC(r,f) r __ACCLIB_FUNCNAME(f) # endif # if (ACC_OS_DOS16 || ACC_OS216 || ACC_OS_WIN16) # if 0 && (ACC_CC_MSC) ACC_EXTERN_C int __acc_cdecl __setargv(void); ACC_EXTERN_C int __acc_cdecl _setargv(void); ACC_EXTERN_C int __acc_cdecl _setargv(void) { return __setargv(); } # endif # endif # if (ACC_OS_WIN32 || ACC_OS_WIN64) # if (ACC_CC_INTELC || ACC_CC_MSC) ACC_EXTERN_C int __acc_cdecl __setargv(void); ACC_EXTERN_C int __acc_cdecl _setargv(void); ACC_EXTERN_C int __acc_cdecl _setargv(void) { return __setargv(); } # endif # endif # if (ACC_OS_EMX) # define __ACCLIB_HAVE_ACC_WILDARGV 1 ACCLIB_PUBLIC(void, acc_wildargv)(int *argc, char ***argv) { if (argc && argv) { _response(argc, argv); _wildcard(argc, argv); } } # endif # if (ACC_OS_CONSOLE_PSP) && defined(__PSPSDK_DEBUG__) # define __ACCLIB_HAVE_ACC_WILDARGV 1 ACC_EXTERN_C int acc_psp_init_module(int *, char ***, int); ACCLIB_PUBLIC(void, acc_wildargv) (int *argc, char ***argv) { acc_psp_init_module(argc, argv, -1); } # endif # if !defined(__ACCLIB_HAVE_ACC_WILDARGV) # define __ACCLIB_HAVE_ACC_WILDARGV 1 ACCLIB_PUBLIC(void, acc_wildargv) (int *argc, char ***argv) { # if 1 && (ACC_ARCH_I086PM) if (ACC_MM_AHSHIFT != 3) { exit(1); } # elif 1 && (ACC_ARCH_M68K && ACC_OS_TOS && ACC_CC_GNUC) && defined(__MINT__) __binmode(1); if (isatty(1)) __set_binmode(stdout, 0); if (isatty(2)) __set_binmode(stderr, 0); # endif ACC_UNUSED(argc); ACC_UNUSED(argv); } # endif #endif /* vim:set ts=4 et: */ ================================================ FILE: include/lzo/portab.h ================================================ /* portab.h -- portability layer This file is part of the LZO real-time data compression library. Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library 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 2 of the License, or (at your option) any later version. The LZO library 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 the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer http://www.oberhumer.com/opensource/lzo/ */ #include "lzo/lzoconf.h" #if (LZO_CC_MSC && (_MSC_VER >= 1000 && _MSC_VER < 1200)) /* avoid `-W4' warnings in system header files */ # pragma warning(disable: 4201 4214 4514) #endif #if (LZO_CC_MSC && (_MSC_VER >= 1300)) /* avoid `-Wall' warnings in system header files */ # pragma warning(disable: 4163 4255 4820) /* avoid warnings about inlining */ # pragma warning(disable: 4710 4711) #endif #if (LZO_CC_MSC && (_MSC_VER >= 1400)) /* avoid warnings when using "deprecated" POSIX functions */ # pragma warning(disable: 4996) #endif #if (LZO_CC_PELLESC && (__POCC__ >= 290)) # pragma warn(disable:2002) #endif /************************************************************************* // **************************************************************************/ #if defined(__LZO_MMODEL_HUGE) || !(defined(LZO_LIBC_ISOC90) || defined(LZO_LIBC_ISOC99)) # include "portab_a.h" #else /* INFO: * The "portab_a.h" version above uses the ACC library to add * support for ancient systems (like 16-bit DOS) and to provide * some gimmicks like Windows high-resolution timers. * Still, on any halfway modern machine you can also use the * following pure ANSI-C code instead. */ # include # include # include # include # include # include # if defined(CLK_TCK) && !defined(CLOCKS_PER_SEC) # define CLOCKS_PER_SEC CLK_TCK # endif # if defined(WANT_LZO_MALLOC) # define lzo_malloc(a) (malloc(a)) # define lzo_free(a) (free(a)) # endif # if defined(WANT_LZO_FREAD) # define lzo_fread(f,b,s) (fread(b,1,s,f)) # define lzo_fwrite(f,b,s) (fwrite(b,1,s,f)) # endif # if defined(WANT_LZO_UCLOCK) # define lzo_uclock_handle_t int # define lzo_uclock_t double # define lzo_uclock_open(a) ((void)(a)) # define lzo_uclock_close(a) ((void)(a)) # define lzo_uclock_read(a,b) *(b) = (clock() / (double)(CLOCKS_PER_SEC)) # define lzo_uclock_get_elapsed(a,b,c) (*(c) - *(b)) # endif # if defined(WANT_LZO_WILDARGV) # define lzo_wildargv(a,b) ((void)0) # endif #endif /************************************************************************* // misc **************************************************************************/ /* turn on assertions */ #undef NDEBUG #include /* just in case */ #undef xmalloc #undef xfree #undef xread #undef xwrite #undef xputc #undef xgetc #undef xread32 #undef xwrite32 #if defined(WANT_LZO_UCLOCK) /* High quality benchmarking. * * Flush the CPU cache to get more accurate benchmark values. * This needs custom kernel patches. As a result - in combination with * the perfctr Linux kernel patches - accurate high-quality benchmarking * is possible. * * All other methods (rdtsc, QueryPerformanceCounter, gettimeofday, ...) * are completely unreliable for our purposes, and the only other * option is to boot into a legacy single-task operating system * like plain MSDOS and to directly reprogram the hardware clock. * [The djgpp2 port of the gcc compiler has support functions for this.] * * Also, for embedded systems it's best to benchmark by using a * CPU emulator/simulator software that can exactly count all * virtual clock ticks. */ # if !defined(lzo_uclock_flush_cpu_cache) # define lzo_uclock_flush_cpu_cache(h,flags) ((void)(h)) # endif #endif /* vi:ts=4:et */ ================================================ FILE: include/lzo/portab_a.h ================================================ /* portab_a.h -- advanced portability layer This file is part of the LZO real-time data compression library. Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. The LZO library 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 2 of the License, or (at your option) any later version. The LZO library 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 the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer http://www.oberhumer.com/opensource/lzo/ */ /************************************************************************* // use the ACC library for the hard work **************************************************************************/ #if defined(LZO_HAVE_CONFIG_H) # define ACC_CONFIG_NO_HEADER 1 #endif #define ACC_WANT_ACC_INCD_H 1 #define ACC_WANT_ACC_INCE_H 1 #if defined(__LZO_MMODEL_HUGE) || defined(WANT_LZO_UCLOCK) || defined(WANT_LZO_WILDARGV) # define ACC_WANT_ACC_INCI_H 1 # define ACC_WANT_ACC_LIB_H 1 #endif #include "miniacc.h" #if defined(WANT_LZO_MALLOC) # if defined(__LZO_MMODEL_HUGE) # define ACC_WANT_ACCLIB_HALLOC 1 # else # define acc_halloc(a) (malloc(a)) # define acc_hfree(a) (free(a)) # endif #endif #if defined(WANT_LZO_FREAD) # if defined(__LZO_MMODEL_HUGE) # define ACC_WANT_ACCLIB_HFREAD 1 # else # define acc_hfread(f,b,s) (fread(b,1,s,f)) # define acc_hfwrite(f,b,s) (fwrite(b,1,s,f)) # endif #endif #if defined(WANT_LZO_UCLOCK) # define ACC_WANT_ACCLIB_PCLOCK 1 # if 0 && (LZO_ARCH_AMD64 || LZO_ARCH_I386) # define __ACCLIB_PCLOCK_USE_RDTSC 1 # define ACC_WANT_ACCLIB_RDTSC 1 # endif #endif #if defined(WANT_LZO_WILDARGV) # define ACC_WANT_ACCLIB_WILDARGV 1 #endif #if defined(__ACCLIB_PCLOCK_USE_PERFCTR) # include "src/fullacc.h" # define lzo_uclock_flush_cpu_cache(h,flags) acc_pclock_flush_cpu_cache(h,flags) #else # include "miniacc.h" #endif #if (__ACCLIB_REQUIRE_HMEMCPY_CH) && !defined(__ACCLIB_HMEMCPY_CH_INCLUDED) # define ACC_WANT_ACCLIB_HMEMCPY 1 # include "src/miniacc.h" #endif /************************************************************************* // finally pull into the LZO namespace **************************************************************************/ #undef lzo_malloc #undef lzo_free #undef lzo_fread #undef lzo_fwrite #if defined(WANT_LZO_MALLOC) # define lzo_malloc(a) acc_halloc(a) # define lzo_free(a) acc_hfree(a) #endif #if defined(WANT_LZO_FREAD) # define lzo_fread(f,b,s) acc_hfread(f,b,s) # define lzo_fwrite(f,b,s) acc_hfwrite(f,b,s) #endif #if defined(WANT_LZO_UCLOCK) # define lzo_uclock_handle_t acc_pclock_handle_t # define lzo_uclock_t acc_pclock_t # define lzo_uclock_open(a) acc_pclock_open_default(a) # define lzo_uclock_close(a) acc_pclock_close(a) # define lzo_uclock_read(a,b) acc_pclock_read(a,b) # define lzo_uclock_get_elapsed(a,b,c) acc_pclock_get_elapsed(a,b,c) #endif #if defined(WANT_LZO_WILDARGV) # define lzo_wildargv(a,b) acc_wildargv(a,b) #endif /* vi:ts=4:et */ ================================================ FILE: include/main.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __MAIN_H #define __MAIN_H #include "config.h" int handle_file(const char *file, config_opts_t *config_opts); #endif //__MAIN_H ================================================ FILE: include/mediatek.h ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #ifndef __MEDIATEK_H #define __MEDIATEK_H #include #include #include "mfile.h" #define MTK_ROM_MAGIC "MTK/DTV/ROMCODE/NANDBOOT" //CPU ROM (maybe unsused if boot can occur on eMMC directly) #define MTK_ROM_SIZE 0x4000 //16kb #define MTK_PBL_MAGIC "MTK/DTV/ROMCODE/MSDCBOOT" //First Bootloader (MSDC: Mediatek SD Controller, eMMC) #define MTK_PBL_SIZE 0x9FFF #define MTK_LOADER_OFF 0xA040 #define MTK_LOADER_OFF1 0x4040 #define MTK_UBOOT_OFF 0x80000 #define MTK_HISENSE_UBOOT_OFF 0xA0000 #define MTK_ENV_SIZE 0x20000 #define MTK_TZ_OFF 0x200 //512 void extract_mtk_1bl(MFILE *in, const char *outname); void split_mtk_tz(MFILE *tz, const char *destdir); MFILE *is_mtk_boot(const char *filename); int is_elf_mem(Elf32_Ehdr * header); MFILE *is_elf(const char *filename); #endif ================================================ FILE: include/mediatek_pkg.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __MTKPKG_H #define __MTKPKG_H #include "config.h" #define UPG_HEADER_SIZE 0x70 /* Vendor Magics (all 4 bytes) */ #define HISENSE_PKG_MAGIC "hise" #define SHARP_PKG_MAGIC "Shar" #define TPV_PKG_MAGIC "TPV_" #define TPV_PKG_MAGIC2 "TPV\0" #define PHILIPS_PKG_MAGIC "PHIL" #define PHILIPS_PKG_MAGIC2 "Phil" #define PHILIPS_HEADER_SIZE 0x80 //at top before MTK header #define PHILIPS_SIGNATURE_SIZE 0x100 //RSA-2048 at the bottom #define MTK_FIRMWARE_MAGIC "#DH@FiRm" //after vendor magic #define MTK_RESERVED_MAGIC "reserved mtk inc" #define MTK_PAK_MAGIC "iMtK8" #define MTK_PAD_MAGIC "iPAd" #define MTK_EXTHDR_SIZE 64 #define PAK_FLAG_ENCRYPTED (1 << 0) #define MTK_EXT_LZHS_OFFSET 0x100000 #define SHARP_PKG_HEADER_SIZE 0x40 struct __attribute__((packed)) mtkupg_header { int8_t vendor_magic[4]; int8_t mtk_magic[8]; //MTK_FIRMWARE_MAGIC int8_t vendor_info[60]; //version and other stuff uint32_t fileSize; uint32_t platform; //0x50 on sharp. Platform type? (unsure) int8_t product_name[40]; uint32_t unk; //0x51 uint32_t unk1; //0 uint8_t hmac[16]; }; struct mtkpkg_plat { char platform[8]; uint32_t otaID_len; char otaID[]; }; struct mtkpkg_pad { char magic[8]; uint8_t padding[]; }; struct __attribute__((packed)) mtkpkg_crypted_header { uint8_t mtk_reserved[16]; //MTK_RESERVED_MAGIC uint8_t hmac[16]; uint8_t vendor_reserved[16]; }; struct __attribute__((packed)) mtkpkg_data { struct mtkpkg_crypted_header header; union { struct mtkpkg_plat platform; //package header, followed by optional mtkpkg_pad uint8_t pkgData[0]; //first package doesn't have headers } data; }; struct __attribute__((packed)) mtkpkg_header { char pakName[4]; uint32_t flags; uint32_t pakSize; //including any extra header, if present }; struct __attribute__((packed)) mtkpkg { struct mtkpkg_header header; struct mtkpkg_data content; }; MFILE *is_mtk_pkg(const char *pkgfile); MFILE *is_lzhs_fs(const char *pkg); MFILE *is_firm_image(const char *pkg); void extract_mtk_pkg(const char *pkgFile, config_opts_t *config_opts); void extract_lzhs_fs(MFILE *mf, const char *dest_file, config_opts_t *config_opts); int extract_firm_image(MFILE *mf); #endif ================================================ FILE: include/mfile.h ================================================ /* A mmap file wrapper Copyright 2016 Smx */ #ifndef __MFILE_H #define __MFILE_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #define MFILE_ANON(size) \ mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0) /* Gets the size of the memory mapped file */ #define msize(mfile) mfile->statBuf.st_size /* Gets the data, casted to the type specified in the second argument */ #define mdata(mfile, type) ((type *)(mfile->pMem)) /* Gets the file handler (for mfopen) */ #define mfh(mfile) mfile->fh /* Gets the file offset */ #define moff(mfile, ptr) (off_t)((uintptr_t)ptr - (uintptr_t)(mfile->pMem)) #define mwriteat(mfile, off, ptr, size) \ memcpy( \ (void *)(&(mdata(mfile, uint8_t))[off]), \ (void *)ptr, \ size \ ) #define mwrite(ptr, size, nmemb, mfile) \ mwriteat( \ mfile, \ mfile->offset, \ ptr, \ (size * nmemb) \ ); \ mfile->offset += (size * nmemb) #define mrewind(mfile) mfile->offset = 0 typedef struct { uint8_t *ptr; off_t offset; size_t size; } cursor_t; typedef struct { char *path; int fd; FILE *fh; off_t offset; int prot; struct stat statBuf; void *pMem; } MFILE; MFILE *mfile_new(); void *mfile_map(MFILE *file, size_t size); void *mfile_map_private(MFILE *file, size_t size); MFILE *mopen(const char *path, int oflags); MFILE *mopen_private(const char *path, int oflags); MFILE *mfopen(const char *path, const char *mode); MFILE *mfopen_private(const char *path, const char *mode); void mfile_flush(void *mem, size_t length); int mgetc(MFILE *stream); int mputc(int c, MFILE *stream); int cgetc(cursor_t *stream); int cputc(int c, cursor_t *stream); int mclose(MFILE *mfile); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/minigzip.h ================================================ #ifndef MINIGZIP_H #define MINIGZIP_H #include void error(const char *msg); void gz_compress(FILE * in, gzFile out); #ifdef USE_MMAP int gz_compress_mmap(FILE * in, gzFile out); #endif void gz_uncompress(gzFile in, FILE * out); void file_compress(char *file, char *mode); void file_uncompress(char *infile, char *outfile); char *file_uncompress_origname(char *infile, char *path); #endif /* MINIGZIP_H */ ================================================ FILE: include/os_byteswap.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef BYTESWAP_H #define BYTESWAP_H #define SWAP(x) SwapBytes(&x, sizeof(x)) #ifdef __APPLE__ # include # define bswap_16(x) OSSwapInt16(x) # define bswap_32(x) OSSwapInt32(x) #else # include #endif void SwapBytes(void *pv, size_t n); #endif /* BYTESWAP_H */ ================================================ FILE: include/osx/elf.h ================================================ /* This is the original elf.h file from the GNU C Library; I only removed the inclusion of feature.h, which is not needed. On OSX, simply copy the file to /usr/local/include/. Mathias Lafeldt */ /* This file defines standard ELF types, structures, and macros. Copyright (C) 1995-2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library 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. The GNU C Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #ifndef _ELF_H #define _ELF_H 1 __BEGIN_DECLS /* Standard ELF types. */ #include /* Type for a 16-bit quantity. */ typedef uint16_t Elf32_Half; typedef uint16_t Elf64_Half; /* Types for signed and unsigned 32-bit quantities. */ typedef uint32_t Elf32_Word; typedef int32_t Elf32_Sword; typedef uint32_t Elf64_Word; typedef int32_t Elf64_Sword; /* Types for signed and unsigned 64-bit quantities. */ typedef uint64_t Elf32_Xword; typedef int64_t Elf32_Sxword; typedef uint64_t Elf64_Xword; typedef int64_t Elf64_Sxword; /* Type of addresses. */ typedef uint32_t Elf32_Addr; typedef uint64_t Elf64_Addr; /* Type of file offsets. */ typedef uint32_t Elf32_Off; typedef uint64_t Elf64_Off; /* Type for section indices, which are 16-bit quantities. */ typedef uint16_t Elf32_Section; typedef uint16_t Elf64_Section; /* Type for version symbol information. */ typedef Elf32_Half Elf32_Versym; typedef Elf64_Half Elf64_Versym; /* The ELF file header. This appears at the start of every ELF file. */ #define EI_NIDENT (16) typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf32_Half e_type; /* Object file type */ Elf32_Half e_machine; /* Architecture */ Elf32_Word e_version; /* Object file version */ Elf32_Addr e_entry; /* Entry point virtual address */ Elf32_Off e_phoff; /* Program header table file offset */ Elf32_Off e_shoff; /* Section header table file offset */ Elf32_Word e_flags; /* Processor-specific flags */ Elf32_Half e_ehsize; /* ELF header size in bytes */ Elf32_Half e_phentsize; /* Program header table entry size */ Elf32_Half e_phnum; /* Program header table entry count */ Elf32_Half e_shentsize; /* Section header table entry size */ Elf32_Half e_shnum; /* Section header table entry count */ Elf32_Half e_shstrndx; /* Section header string table index */ } Elf32_Ehdr; typedef struct { unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ Elf64_Half e_type; /* Object file type */ Elf64_Half e_machine; /* Architecture */ Elf64_Word e_version; /* Object file version */ Elf64_Addr e_entry; /* Entry point virtual address */ Elf64_Off e_phoff; /* Program header table file offset */ Elf64_Off e_shoff; /* Section header table file offset */ Elf64_Word e_flags; /* Processor-specific flags */ Elf64_Half e_ehsize; /* ELF header size in bytes */ Elf64_Half e_phentsize; /* Program header table entry size */ Elf64_Half e_phnum; /* Program header table entry count */ Elf64_Half e_shentsize; /* Section header table entry size */ Elf64_Half e_shnum; /* Section header table entry count */ Elf64_Half e_shstrndx; /* Section header string table index */ } Elf64_Ehdr; /* Fields in the e_ident array. The EI_* macros are indices into the array. The macros under each EI_* macro are the values the byte may have. */ #define EI_MAG0 0 /* File identification byte 0 index */ #define ELFMAG0 0x7f /* Magic number byte 0 */ #define EI_MAG1 1 /* File identification byte 1 index */ #define ELFMAG1 'E' /* Magic number byte 1 */ #define EI_MAG2 2 /* File identification byte 2 index */ #define ELFMAG2 'L' /* Magic number byte 2 */ #define EI_MAG3 3 /* File identification byte 3 index */ #define ELFMAG3 'F' /* Magic number byte 3 */ /* Conglomeration of the identification bytes, for easy testing as a word. */ #define ELFMAG "\177ELF" #define SELFMAG 4 #define EI_CLASS 4 /* File class byte index */ #define ELFCLASSNONE 0 /* Invalid class */ #define ELFCLASS32 1 /* 32-bit objects */ #define ELFCLASS64 2 /* 64-bit objects */ #define ELFCLASSNUM 3 #define EI_DATA 5 /* Data encoding byte index */ #define ELFDATANONE 0 /* Invalid data encoding */ #define ELFDATA2LSB 1 /* 2's complement, little endian */ #define ELFDATA2MSB 2 /* 2's complement, big endian */ #define ELFDATANUM 3 #define EI_VERSION 6 /* File version byte index */ /* Value must be EV_CURRENT */ #define EI_OSABI 7 /* OS ABI identification */ #define ELFOSABI_NONE 0 /* UNIX System V ABI */ #define ELFOSABI_SYSV 0 /* Alias. */ #define ELFOSABI_HPUX 1 /* HP-UX */ #define ELFOSABI_NETBSD 2 /* NetBSD. */ #define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */ #define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */ #define ELFOSABI_SOLARIS 6 /* Sun Solaris. */ #define ELFOSABI_AIX 7 /* IBM AIX. */ #define ELFOSABI_IRIX 8 /* SGI Irix. */ #define ELFOSABI_FREEBSD 9 /* FreeBSD. */ #define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */ #define ELFOSABI_MODESTO 11 /* Novell Modesto. */ #define ELFOSABI_OPENBSD 12 /* OpenBSD. */ #define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ #define ELFOSABI_ARM 97 /* ARM */ #define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */ #define EI_ABIVERSION 8 /* ABI version */ #define EI_PAD 9 /* Byte index of padding bytes */ /* Legal values for e_type (object file type). */ #define ET_NONE 0 /* No file type */ #define ET_REL 1 /* Relocatable file */ #define ET_EXEC 2 /* Executable file */ #define ET_DYN 3 /* Shared object file */ #define ET_CORE 4 /* Core file */ #define ET_NUM 5 /* Number of defined types */ #define ET_LOOS 0xfe00 /* OS-specific range start */ #define ET_HIOS 0xfeff /* OS-specific range end */ #define ET_LOPROC 0xff00 /* Processor-specific range start */ #define ET_HIPROC 0xffff /* Processor-specific range end */ /* Legal values for e_machine (architecture). */ #define EM_NONE 0 /* No machine */ #define EM_M32 1 /* AT&T WE 32100 */ #define EM_SPARC 2 /* SUN SPARC */ #define EM_386 3 /* Intel 80386 */ #define EM_68K 4 /* Motorola m68k family */ #define EM_88K 5 /* Motorola m88k family */ #define EM_860 7 /* Intel 80860 */ #define EM_MIPS 8 /* MIPS R3000 big-endian */ #define EM_S370 9 /* IBM System/370 */ #define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ #define EM_PARISC 15 /* HPPA */ #define EM_VPP500 17 /* Fujitsu VPP500 */ #define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ #define EM_960 19 /* Intel 80960 */ #define EM_PPC 20 /* PowerPC */ #define EM_PPC64 21 /* PowerPC 64-bit */ #define EM_S390 22 /* IBM S390 */ #define EM_V800 36 /* NEC V800 series */ #define EM_FR20 37 /* Fujitsu FR20 */ #define EM_RH32 38 /* TRW RH-32 */ #define EM_RCE 39 /* Motorola RCE */ #define EM_ARM 40 /* ARM */ #define EM_FAKE_ALPHA 41 /* Digital Alpha */ #define EM_SH 42 /* Hitachi SH */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_TRICORE 44 /* Siemens Tricore */ #define EM_ARC 45 /* Argonaut RISC Core */ #define EM_H8_300 46 /* Hitachi H8/300 */ #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ #define EM_H8_500 49 /* Hitachi H8/500 */ #define EM_IA_64 50 /* Intel Merced */ #define EM_MIPS_X 51 /* Stanford MIPS-X */ #define EM_COLDFIRE 52 /* Motorola Coldfire */ #define EM_68HC12 53 /* Motorola M68HC12 */ #define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/ #define EM_PCP 55 /* Siemens PCP */ #define EM_NCPU 56 /* Sony nCPU embeeded RISC */ #define EM_NDR1 57 /* Denso NDR1 microprocessor */ #define EM_STARCORE 58 /* Motorola Start*Core processor */ #define EM_ME16 59 /* Toyota ME16 processor */ #define EM_ST100 60 /* STMicroelectronic ST100 processor */ #define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/ #define EM_X86_64 62 /* AMD x86-64 architecture */ #define EM_PDSP 63 /* Sony DSP Processor */ #define EM_FX66 66 /* Siemens FX66 microcontroller */ #define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */ #define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */ #define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */ #define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */ #define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */ #define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */ #define EM_SVX 73 /* Silicon Graphics SVx */ #define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */ #define EM_VAX 75 /* Digital VAX */ #define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ #define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */ #define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */ #define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */ #define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */ #define EM_HUANY 81 /* Harvard University machine-independent object files */ #define EM_PRISM 82 /* SiTera Prism */ #define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */ #define EM_FR30 84 /* Fujitsu FR30 */ #define EM_D10V 85 /* Mitsubishi D10V */ #define EM_D30V 86 /* Mitsubishi D30V */ #define EM_V850 87 /* NEC v850 */ #define EM_M32R 88 /* Mitsubishi M32R */ #define EM_MN10300 89 /* Matsushita MN10300 */ #define EM_MN10200 90 /* Matsushita MN10200 */ #define EM_PJ 91 /* picoJava */ #define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ #define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */ #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ #define EM_NUM 95 /* If it is necessary to assign new unofficial EM_* values, please pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision with official or non-GNU unofficial values. */ #define EM_ALPHA 0x9026 /* Legal values for e_version (version). */ #define EV_NONE 0 /* Invalid ELF version */ #define EV_CURRENT 1 /* Current version */ #define EV_NUM 2 /* Section header. */ typedef struct { Elf32_Word sh_name; /* Section name (string tbl index) */ Elf32_Word sh_type; /* Section type */ Elf32_Word sh_flags; /* Section flags */ Elf32_Addr sh_addr; /* Section virtual addr at execution */ Elf32_Off sh_offset; /* Section file offset */ Elf32_Word sh_size; /* Section size in bytes */ Elf32_Word sh_link; /* Link to another section */ Elf32_Word sh_info; /* Additional section information */ Elf32_Word sh_addralign; /* Section alignment */ Elf32_Word sh_entsize; /* Entry size if section holds table */ } Elf32_Shdr; typedef struct { Elf64_Word sh_name; /* Section name (string tbl index) */ Elf64_Word sh_type; /* Section type */ Elf64_Xword sh_flags; /* Section flags */ Elf64_Addr sh_addr; /* Section virtual addr at execution */ Elf64_Off sh_offset; /* Section file offset */ Elf64_Xword sh_size; /* Section size in bytes */ Elf64_Word sh_link; /* Link to another section */ Elf64_Word sh_info; /* Additional section information */ Elf64_Xword sh_addralign; /* Section alignment */ Elf64_Xword sh_entsize; /* Entry size if section holds table */ } Elf64_Shdr; /* Special section indices. */ #define SHN_UNDEF 0 /* Undefined section */ #define SHN_LORESERVE 0xff00 /* Start of reserved indices */ #define SHN_LOPROC 0xff00 /* Start of processor-specific */ #define SHN_BEFORE 0xff00 /* Order section before all others (Solaris). */ #define SHN_AFTER 0xff01 /* Order section after all others (Solaris). */ #define SHN_HIPROC 0xff1f /* End of processor-specific */ #define SHN_LOOS 0xff20 /* Start of OS-specific */ #define SHN_HIOS 0xff3f /* End of OS-specific */ #define SHN_ABS 0xfff1 /* Associated symbol is absolute */ #define SHN_COMMON 0xfff2 /* Associated symbol is common */ #define SHN_XINDEX 0xffff /* Index is in extra table. */ #define SHN_HIRESERVE 0xffff /* End of reserved indices */ /* Legal values for sh_type (section type). */ #define SHT_NULL 0 /* Section header table entry unused */ #define SHT_PROGBITS 1 /* Program data */ #define SHT_SYMTAB 2 /* Symbol table */ #define SHT_STRTAB 3 /* String table */ #define SHT_RELA 4 /* Relocation entries with addends */ #define SHT_HASH 5 /* Symbol hash table */ #define SHT_DYNAMIC 6 /* Dynamic linking information */ #define SHT_NOTE 7 /* Notes */ #define SHT_NOBITS 8 /* Program space with no data (bss) */ #define SHT_REL 9 /* Relocation entries, no addends */ #define SHT_SHLIB 10 /* Reserved */ #define SHT_DYNSYM 11 /* Dynamic linker symbol table */ #define SHT_INIT_ARRAY 14 /* Array of constructors */ #define SHT_FINI_ARRAY 15 /* Array of destructors */ #define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ #define SHT_LOOS 0x60000000 /* Start OS-specific. */ #define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */ #define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ #define SHT_SUNW_move 0x6ffffffa #define SHT_SUNW_COMDAT 0x6ffffffb #define SHT_SUNW_syminfo 0x6ffffffc #define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */ #define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */ #define SHT_GNU_versym 0x6fffffff /* Version symbol table. */ #define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */ #define SHT_HIOS 0x6fffffff /* End OS-specific type */ #define SHT_LOPROC 0x70000000 /* Start of processor-specific */ #define SHT_HIPROC 0x7fffffff /* End of processor-specific */ #define SHT_LOUSER 0x80000000 /* Start of application-specific */ #define SHT_HIUSER 0x8fffffff /* End of application-specific */ /* Legal values for sh_flags (section flags). */ #define SHF_WRITE (1 << 0) /* Writable */ #define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ #define SHF_EXECINSTR (1 << 2) /* Executable */ #define SHF_MERGE (1 << 4) /* Might be merged */ #define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ #define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */ #define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */ #define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling required */ #define SHF_GROUP (1 << 9) /* Section is member of a group. */ #define SHF_TLS (1 << 10) /* Section hold thread-local data. */ #define SHF_MASKOS 0x0ff00000 /* OS-specific. */ #define SHF_MASKPROC 0xf0000000 /* Processor-specific */ #define SHF_ORDERED (1 << 30) /* Special ordering requirement (Solaris). */ #define SHF_EXCLUDE (1 << 31) /* Section is excluded unless referenced or allocated (Solaris).*/ /* Section group handling. */ #define GRP_COMDAT 0x1 /* Mark group as COMDAT. */ /* Symbol table entry. */ typedef struct { Elf32_Word st_name; /* Symbol name (string tbl index) */ Elf32_Addr st_value; /* Symbol value */ Elf32_Word st_size; /* Symbol size */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf32_Section st_shndx; /* Section index */ } Elf32_Sym; typedef struct { Elf64_Word st_name; /* Symbol name (string tbl index) */ unsigned char st_info; /* Symbol type and binding */ unsigned char st_other; /* Symbol visibility */ Elf64_Section st_shndx; /* Section index */ Elf64_Addr st_value; /* Symbol value */ Elf64_Xword st_size; /* Symbol size */ } Elf64_Sym; /* The syminfo section if available contains additional information about every dynamic symbol. */ typedef struct { Elf32_Half si_boundto; /* Direct bindings, symbol bound to */ Elf32_Half si_flags; /* Per symbol flags */ } Elf32_Syminfo; typedef struct { Elf64_Half si_boundto; /* Direct bindings, symbol bound to */ Elf64_Half si_flags; /* Per symbol flags */ } Elf64_Syminfo; /* Possible values for si_boundto. */ #define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */ #define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */ #define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */ /* Possible bitmasks for si_flags. */ #define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */ #define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */ #define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */ #define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */ /* Syminfo version values. */ #define SYMINFO_NONE 0 #define SYMINFO_CURRENT 1 #define SYMINFO_NUM 2 /* How to extract and insert information held in the st_info field. */ #define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4) #define ELF32_ST_TYPE(val) ((val) & 0xf) #define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf)) /* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */ #define ELF64_ST_BIND(val) ELF32_ST_BIND (val) #define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val) #define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type)) /* Legal values for ST_BIND subfield of st_info (symbol binding). */ #define STB_LOCAL 0 /* Local symbol */ #define STB_GLOBAL 1 /* Global symbol */ #define STB_WEAK 2 /* Weak symbol */ #define STB_NUM 3 /* Number of defined types. */ #define STB_LOOS 10 /* Start of OS-specific */ #define STB_GNU_UNIQUE 10 /* Unique symbol. */ #define STB_HIOS 12 /* End of OS-specific */ #define STB_LOPROC 13 /* Start of processor-specific */ #define STB_HIPROC 15 /* End of processor-specific */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_NOTYPE 0 /* Symbol type is unspecified */ #define STT_OBJECT 1 /* Symbol is a data object */ #define STT_FUNC 2 /* Symbol is a code object */ #define STT_SECTION 3 /* Symbol associated with a section */ #define STT_FILE 4 /* Symbol's name is file name */ #define STT_COMMON 5 /* Symbol is a common data object */ #define STT_TLS 6 /* Symbol is thread-local data object*/ #define STT_NUM 7 /* Number of defined types. */ #define STT_LOOS 10 /* Start of OS-specific */ #define STT_GNU_IFUNC 10 /* Symbol is indirect code object */ #define STT_HIOS 12 /* End of OS-specific */ #define STT_LOPROC 13 /* Start of processor-specific */ #define STT_HIPROC 15 /* End of processor-specific */ /* Symbol table indices are found in the hash buckets and chain table of a symbol hash table section. This special index value indicates the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ /* How to extract and insert information held in the st_other field. */ #define ELF32_ST_VISIBILITY(o) ((o) & 0x03) /* For ELF64 the definitions are the same. */ #define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o) /* Symbol visibility specification encoded in the st_other field. */ #define STV_DEFAULT 0 /* Default symbol visibility rules */ #define STV_INTERNAL 1 /* Processor specific hidden class */ #define STV_HIDDEN 2 /* Sym unavailable in other modules */ #define STV_PROTECTED 3 /* Not preemptible, not exported */ /* Relocation table entry without addend (in section of type SHT_REL). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ } Elf32_Rel; /* I have seen two different definitions of the Elf64_Rel and Elf64_Rela structures, so we'll leave them out until Novell (or whoever) gets their act together. */ /* The following, at least, is used on Sparc v9, MIPS, and Alpha. */ typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ } Elf64_Rel; /* Relocation table entry with addend (in section of type SHT_RELA). */ typedef struct { Elf32_Addr r_offset; /* Address */ Elf32_Word r_info; /* Relocation type and symbol index */ Elf32_Sword r_addend; /* Addend */ } Elf32_Rela; typedef struct { Elf64_Addr r_offset; /* Address */ Elf64_Xword r_info; /* Relocation type and symbol index */ Elf64_Sxword r_addend; /* Addend */ } Elf64_Rela; /* How to extract and insert information held in the r_info field. */ #define ELF32_R_SYM(val) ((val) >> 8) #define ELF32_R_TYPE(val) ((val) & 0xff) #define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff)) #define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_TYPE(i) ((i) & 0xffffffff) #define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type)) /* Program segment header. */ typedef struct { Elf32_Word p_type; /* Segment type */ Elf32_Off p_offset; /* Segment file offset */ Elf32_Addr p_vaddr; /* Segment virtual address */ Elf32_Addr p_paddr; /* Segment physical address */ Elf32_Word p_filesz; /* Segment size in file */ Elf32_Word p_memsz; /* Segment size in memory */ Elf32_Word p_flags; /* Segment flags */ Elf32_Word p_align; /* Segment alignment */ } Elf32_Phdr; typedef struct { Elf64_Word p_type; /* Segment type */ Elf64_Word p_flags; /* Segment flags */ Elf64_Off p_offset; /* Segment file offset */ Elf64_Addr p_vaddr; /* Segment virtual address */ Elf64_Addr p_paddr; /* Segment physical address */ Elf64_Xword p_filesz; /* Segment size in file */ Elf64_Xword p_memsz; /* Segment size in memory */ Elf64_Xword p_align; /* Segment alignment */ } Elf64_Phdr; /* Special value for e_phnum. This indicates that the real number of program headers is too large to fit into e_phnum. Instead the real value is in the field sh_info of section 0. */ #define PN_XNUM 0xffff /* Legal values for p_type (segment type). */ #define PT_NULL 0 /* Program header table entry unused */ #define PT_LOAD 1 /* Loadable program segment */ #define PT_DYNAMIC 2 /* Dynamic linking information */ #define PT_INTERP 3 /* Program interpreter */ #define PT_NOTE 4 /* Auxiliary information */ #define PT_SHLIB 5 /* Reserved */ #define PT_PHDR 6 /* Entry for header table itself */ #define PT_TLS 7 /* Thread-local storage segment */ #define PT_NUM 8 /* Number of defined types */ #define PT_LOOS 0x60000000 /* Start of OS-specific */ #define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */ #define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */ #define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */ #define PT_LOSUNW 0x6ffffffa #define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */ #define PT_SUNWSTACK 0x6ffffffb /* Stack segment */ #define PT_HISUNW 0x6fffffff #define PT_HIOS 0x6fffffff /* End of OS-specific */ #define PT_LOPROC 0x70000000 /* Start of processor-specific */ #define PT_HIPROC 0x7fffffff /* End of processor-specific */ /* Legal values for p_flags (segment flags). */ #define PF_X (1 << 0) /* Segment is executable */ #define PF_W (1 << 1) /* Segment is writable */ #define PF_R (1 << 2) /* Segment is readable */ #define PF_MASKOS 0x0ff00000 /* OS-specific */ #define PF_MASKPROC 0xf0000000 /* Processor-specific */ /* Legal values for note segment descriptor types for core files. */ #define NT_PRSTATUS 1 /* Contains copy of prstatus struct */ #define NT_FPREGSET 2 /* Contains copy of fpregset struct */ #define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */ #define NT_PRXREG 4 /* Contains copy of prxregset struct */ #define NT_TASKSTRUCT 4 /* Contains copy of task structure */ #define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */ #define NT_AUXV 6 /* Contains copy of auxv array */ #define NT_GWINDOWS 7 /* Contains copy of gwindows struct */ #define NT_ASRS 8 /* Contains copy of asrset struct */ #define NT_PSTATUS 10 /* Contains copy of pstatus struct */ #define NT_PSINFO 13 /* Contains copy of psinfo struct */ #define NT_PRCRED 14 /* Contains copy of prcred struct */ #define NT_UTSNAME 15 /* Contains copy of utsname struct */ #define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */ #define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */ #define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */ #define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */ #define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ #define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ #define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ #define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ #define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ #define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ /* Legal values for the note segment descriptor types for object files. */ #define NT_VERSION 1 /* Contains a version string. */ /* Dynamic section entry. */ typedef struct { Elf32_Sword d_tag; /* Dynamic entry type */ union { Elf32_Word d_val; /* Integer value */ Elf32_Addr d_ptr; /* Address value */ } d_un; } Elf32_Dyn; typedef struct { Elf64_Sxword d_tag; /* Dynamic entry type */ union { Elf64_Xword d_val; /* Integer value */ Elf64_Addr d_ptr; /* Address value */ } d_un; } Elf64_Dyn; /* Legal values for d_tag (dynamic entry type). */ #define DT_NULL 0 /* Marks end of dynamic section */ #define DT_NEEDED 1 /* Name of needed library */ #define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */ #define DT_PLTGOT 3 /* Processor defined value */ #define DT_HASH 4 /* Address of symbol hash table */ #define DT_STRTAB 5 /* Address of string table */ #define DT_SYMTAB 6 /* Address of symbol table */ #define DT_RELA 7 /* Address of Rela relocs */ #define DT_RELASZ 8 /* Total size of Rela relocs */ #define DT_RELAENT 9 /* Size of one Rela reloc */ #define DT_STRSZ 10 /* Size of string table */ #define DT_SYMENT 11 /* Size of one symbol table entry */ #define DT_INIT 12 /* Address of init function */ #define DT_FINI 13 /* Address of termination function */ #define DT_SONAME 14 /* Name of shared object */ #define DT_RPATH 15 /* Library search path (deprecated) */ #define DT_SYMBOLIC 16 /* Start symbol search here */ #define DT_REL 17 /* Address of Rel relocs */ #define DT_RELSZ 18 /* Total size of Rel relocs */ #define DT_RELENT 19 /* Size of one Rel reloc */ #define DT_PLTREL 20 /* Type of reloc in PLT */ #define DT_DEBUG 21 /* For debugging; unspecified */ #define DT_TEXTREL 22 /* Reloc might modify .text */ #define DT_JMPREL 23 /* Address of PLT relocs */ #define DT_BIND_NOW 24 /* Process relocations of object */ #define DT_INIT_ARRAY 25 /* Array with addresses of init fct */ #define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */ #define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */ #define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */ #define DT_RUNPATH 29 /* Library search path */ #define DT_FLAGS 30 /* Flags for the object being loaded */ #define DT_ENCODING 32 /* Start of encoded range */ #define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/ #define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */ #define DT_NUM 34 /* Number used */ #define DT_LOOS 0x6000000d /* Start of OS-specific */ #define DT_HIOS 0x6ffff000 /* End of OS-specific */ #define DT_LOPROC 0x70000000 /* Start of processor-specific */ #define DT_HIPROC 0x7fffffff /* End of processor-specific */ #define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */ /* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's approach. */ #define DT_VALRNGLO 0x6ffffd00 #define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */ #define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */ #define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */ #define DT_CHECKSUM 0x6ffffdf8 #define DT_PLTPADSZ 0x6ffffdf9 #define DT_MOVEENT 0x6ffffdfa #define DT_MOVESZ 0x6ffffdfb #define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */ #define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */ #define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */ #define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */ #define DT_VALRNGHI 0x6ffffdff #define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */ #define DT_VALNUM 12 /* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the Dyn.d_un.d_ptr field of the Elf*_Dyn structure. If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 #define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ #define DT_TLSDESC_PLT 0x6ffffef6 #define DT_TLSDESC_GOT 0x6ffffef7 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */ #define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */ #define DT_AUDIT 0x6ffffefc /* Object auditing. */ #define DT_PLTPAD 0x6ffffefd /* PLT padding. */ #define DT_MOVETAB 0x6ffffefe /* Move table. */ #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ #define DT_ADDRNUM 11 /* The versioning entry types. The next are defined as part of the GNU extension. */ #define DT_VERSYM 0x6ffffff0 #define DT_RELACOUNT 0x6ffffff9 #define DT_RELCOUNT 0x6ffffffa /* These were chosen by Sun. */ #define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */ #define DT_VERDEF 0x6ffffffc /* Address of version definition table */ #define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */ #define DT_VERNEED 0x6ffffffe /* Address of table with needed versions */ #define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */ #define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ #define DT_VERSIONTAGNUM 16 /* Sun added these machine-independent extensions in the "processor-specific" range. Be compatible. */ #define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */ #define DT_FILTER 0x7fffffff /* Shared object to get values from */ #define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1) #define DT_EXTRANUM 3 /* Values of `d_un.d_val' in the DT_FLAGS entry. */ #define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */ #define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */ #define DF_TEXTREL 0x00000004 /* Object contains text relocations */ #define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */ #define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */ /* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1 entry in the dynamic section. */ #define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */ #define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */ #define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */ #define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/ #define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/ #define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/ #define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */ #define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */ #define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */ #define DF_1_TRANS 0x00000200 #define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */ #define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */ #define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */ #define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/ #define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */ #define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */ #define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */ /* Flags for the feature selection in DT_FEATURE_1. */ #define DTF_1_PARINIT 0x00000001 #define DTF_1_CONFEXP 0x00000002 /* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */ #define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */ #define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not generally available. */ /* Version definition sections. */ typedef struct { Elf32_Half vd_version; /* Version revision */ Elf32_Half vd_flags; /* Version information */ Elf32_Half vd_ndx; /* Version Index */ Elf32_Half vd_cnt; /* Number of associated aux entries */ Elf32_Word vd_hash; /* Version name hash value */ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */ Elf32_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf32_Verdef; typedef struct { Elf64_Half vd_version; /* Version revision */ Elf64_Half vd_flags; /* Version information */ Elf64_Half vd_ndx; /* Version Index */ Elf64_Half vd_cnt; /* Number of associated aux entries */ Elf64_Word vd_hash; /* Version name hash value */ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */ Elf64_Word vd_next; /* Offset in bytes to next verdef entry */ } Elf64_Verdef; /* Legal values for vd_version (version revision). */ #define VER_DEF_NONE 0 /* No version */ #define VER_DEF_CURRENT 1 /* Current version */ #define VER_DEF_NUM 2 /* Given version number */ /* Legal values for vd_flags (version information flags). */ #define VER_FLG_BASE 0x1 /* Version definition of file itself */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Versym symbol index values. */ #define VER_NDX_LOCAL 0 /* Symbol is local. */ #define VER_NDX_GLOBAL 1 /* Symbol is global. */ #define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */ #define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */ /* Auxialiary version information. */ typedef struct { Elf32_Word vda_name; /* Version or dependency names */ Elf32_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf32_Verdaux; typedef struct { Elf64_Word vda_name; /* Version or dependency names */ Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */ } Elf64_Verdaux; /* Version dependency section. */ typedef struct { Elf32_Half vn_version; /* Version of structure */ Elf32_Half vn_cnt; /* Number of associated aux entries */ Elf32_Word vn_file; /* Offset of filename for this dependency */ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */ Elf32_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf32_Verneed; typedef struct { Elf64_Half vn_version; /* Version of structure */ Elf64_Half vn_cnt; /* Number of associated aux entries */ Elf64_Word vn_file; /* Offset of filename for this dependency */ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */ Elf64_Word vn_next; /* Offset in bytes to next verneed entry */ } Elf64_Verneed; /* Legal values for vn_version (version revision). */ #define VER_NEED_NONE 0 /* No version */ #define VER_NEED_CURRENT 1 /* Current version */ #define VER_NEED_NUM 2 /* Given version number */ /* Auxiliary needed version information. */ typedef struct { Elf32_Word vna_hash; /* Hash value of dependency name */ Elf32_Half vna_flags; /* Dependency specific information */ Elf32_Half vna_other; /* Unused */ Elf32_Word vna_name; /* Dependency name string offset */ Elf32_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf32_Vernaux; typedef struct { Elf64_Word vna_hash; /* Hash value of dependency name */ Elf64_Half vna_flags; /* Dependency specific information */ Elf64_Half vna_other; /* Unused */ Elf64_Word vna_name; /* Dependency name string offset */ Elf64_Word vna_next; /* Offset in bytes to next vernaux entry */ } Elf64_Vernaux; /* Legal values for vna_flags. */ #define VER_FLG_WEAK 0x2 /* Weak version identifier */ /* Auxiliary vector. */ /* This vector is normally only used by the program interpreter. The usual definition in an ABI supplement uses the name auxv_t. The vector is not usually defined in a standard file, but it can't hurt. We rename it to avoid conflicts. The sizes of these types are an arrangement between the exec server and the program interpreter, so we don't fully specify them here. */ typedef struct { uint32_t a_type; /* Entry type */ union { uint32_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; } Elf32_auxv_t; typedef struct { uint64_t a_type; /* Entry type */ union { uint64_t a_val; /* Integer value */ /* We use to have pointer elements added here. We cannot do that, though, since it does not work when using 32-bit definitions on 64-bit platforms and vice versa. */ } a_un; } Elf64_auxv_t; /* Legal values for a_type (entry type). */ #define AT_NULL 0 /* End of vector */ #define AT_IGNORE 1 /* Entry should be ignored */ #define AT_EXECFD 2 /* File descriptor of program */ #define AT_PHDR 3 /* Program headers for program */ #define AT_PHENT 4 /* Size of program header entry */ #define AT_PHNUM 5 /* Number of program headers */ #define AT_PAGESZ 6 /* System page size */ #define AT_BASE 7 /* Base address of interpreter */ #define AT_FLAGS 8 /* Flags */ #define AT_ENTRY 9 /* Entry point of program */ #define AT_NOTELF 10 /* Program is not ELF */ #define AT_UID 11 /* Real uid */ #define AT_EUID 12 /* Effective uid */ #define AT_GID 13 /* Real gid */ #define AT_EGID 14 /* Effective gid */ #define AT_CLKTCK 17 /* Frequency of times() */ /* Some more special a_type values describing the hardware. */ #define AT_PLATFORM 15 /* String identifying platform. */ #define AT_HWCAP 16 /* Machine dependent hints about processor capabilities. */ /* This entry gives some information about the FPU initialization performed by the kernel. */ #define AT_FPUCW 18 /* Used FPU control word. */ /* Cache block sizes. */ #define AT_DCACHEBSIZE 19 /* Data cache block size. */ #define AT_ICACHEBSIZE 20 /* Instruction cache block size. */ #define AT_UCACHEBSIZE 21 /* Unified cache block size. */ /* A special ignored value for PPC, used by the kernel to control the interpretation of the AUXV. Must be > 16. */ #define AT_IGNOREPPC 22 /* Entry should be ignored. */ #define AT_SECURE 23 /* Boolean, was exec setuid-like? */ #define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/ #define AT_RANDOM 25 /* Address of 16 random bytes. */ #define AT_EXECFN 31 /* Filename of executable. */ /* Pointer to the global system page used for system calls and other nice things. */ #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 /* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains log2 of line size; mask those to get cache size. */ #define AT_L1I_CACHESHAPE 34 #define AT_L1D_CACHESHAPE 35 #define AT_L2_CACHESHAPE 36 #define AT_L3_CACHESHAPE 37 /* Note section contents. Each entry in the note section begins with a header of a fixed form. */ typedef struct { Elf32_Word n_namesz; /* Length of the note's name. */ Elf32_Word n_descsz; /* Length of the note's descriptor. */ Elf32_Word n_type; /* Type of the note. */ } Elf32_Nhdr; typedef struct { Elf64_Word n_namesz; /* Length of the note's name. */ Elf64_Word n_descsz; /* Length of the note's descriptor. */ Elf64_Word n_type; /* Type of the note. */ } Elf64_Nhdr; /* Known names of notes. */ /* Solaris entries in the note section have this name. */ #define ELF_NOTE_SOLARIS "SUNW Solaris" /* Note entries for GNU systems have this name. */ #define ELF_NOTE_GNU "GNU" /* Defined types of notes for Solaris. */ /* Value of descriptor (one word) is desired pagesize for the binary. */ #define ELF_NOTE_PAGESIZE_HINT 1 /* Defined note types for GNU systems. */ /* ABI information. The descriptor consists of words: word 0: OS descriptor word 1: major version of the ABI word 2: minor version of the ABI word 3: subminor version of the ABI */ #define NT_GNU_ABI_TAG 1 #define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */ /* Known OSes. These values can appear in word 0 of an NT_GNU_ABI_TAG note section entry. */ #define ELF_NOTE_OS_LINUX 0 #define ELF_NOTE_OS_GNU 1 #define ELF_NOTE_OS_SOLARIS2 2 #define ELF_NOTE_OS_FREEBSD 3 /* Synthetic hwcap information. The descriptor begins with two words: word 0: number of entries word 1: bitmask of enabled entries Then follow variable-length entries, one byte followed by a '\0'-terminated hwcap name string. The byte gives the bit number to test if enabled, (1U << bit) & bitmask. */ #define NT_GNU_HWCAP 2 /* Build ID bits as generated by ld --build-id. The descriptor consists of any nonzero number of bytes. */ #define NT_GNU_BUILD_ID 3 /* Version note generated by GNU gold containing a version string. */ #define NT_GNU_GOLD_VERSION 4 /* Move records. */ typedef struct { Elf32_Xword m_value; /* Symbol value. */ Elf32_Word m_info; /* Size and index. */ Elf32_Word m_poffset; /* Symbol offset. */ Elf32_Half m_repeat; /* Repeat count. */ Elf32_Half m_stride; /* Stride info. */ } Elf32_Move; typedef struct { Elf64_Xword m_value; /* Symbol value. */ Elf64_Xword m_info; /* Size and index. */ Elf64_Xword m_poffset; /* Symbol offset. */ Elf64_Half m_repeat; /* Repeat count. */ Elf64_Half m_stride; /* Stride info. */ } Elf64_Move; /* Macro to construct move records. */ #define ELF32_M_SYM(info) ((info) >> 8) #define ELF32_M_SIZE(info) ((unsigned char) (info)) #define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size)) #define ELF64_M_SYM(info) ELF32_M_SYM (info) #define ELF64_M_SIZE(info) ELF32_M_SIZE (info) #define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size) /* Motorola 68k specific definitions. */ /* Values for Elf32_Ehdr.e_flags. */ #define EF_CPU32 0x00810000 /* m68k relocs. */ #define R_68K_NONE 0 /* No reloc */ #define R_68K_32 1 /* Direct 32 bit */ #define R_68K_16 2 /* Direct 16 bit */ #define R_68K_8 3 /* Direct 8 bit */ #define R_68K_PC32 4 /* PC relative 32 bit */ #define R_68K_PC16 5 /* PC relative 16 bit */ #define R_68K_PC8 6 /* PC relative 8 bit */ #define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */ #define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */ #define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */ #define R_68K_GOT32O 10 /* 32 bit GOT offset */ #define R_68K_GOT16O 11 /* 16 bit GOT offset */ #define R_68K_GOT8O 12 /* 8 bit GOT offset */ #define R_68K_PLT32 13 /* 32 bit PC relative PLT address */ #define R_68K_PLT16 14 /* 16 bit PC relative PLT address */ #define R_68K_PLT8 15 /* 8 bit PC relative PLT address */ #define R_68K_PLT32O 16 /* 32 bit PLT offset */ #define R_68K_PLT16O 17 /* 16 bit PLT offset */ #define R_68K_PLT8O 18 /* 8 bit PLT offset */ #define R_68K_COPY 19 /* Copy symbol at runtime */ #define R_68K_GLOB_DAT 20 /* Create GOT entry */ #define R_68K_JMP_SLOT 21 /* Create PLT entry */ #define R_68K_RELATIVE 22 /* Adjust by program base */ #define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */ #define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */ #define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */ #define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */ #define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */ #define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */ #define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */ #define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */ #define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */ #define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */ #define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */ #define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */ #define R_68K_TLS_LE32 37 /* 32 bit offset relative to static TLS block */ #define R_68K_TLS_LE16 38 /* 16 bit offset relative to static TLS block */ #define R_68K_TLS_LE8 39 /* 8 bit offset relative to static TLS block */ #define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */ #define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */ #define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */ /* Keep this the last entry. */ #define R_68K_NUM 43 /* Intel 80386 specific definitions. */ /* i386 relocs. */ #define R_386_NONE 0 /* No reloc */ #define R_386_32 1 /* Direct 32 bit */ #define R_386_PC32 2 /* PC relative 32 bit */ #define R_386_GOT32 3 /* 32 bit GOT entry */ #define R_386_PLT32 4 /* 32 bit PLT address */ #define R_386_COPY 5 /* Copy symbol at runtime */ #define R_386_GLOB_DAT 6 /* Create GOT entry */ #define R_386_JMP_SLOT 7 /* Create PLT entry */ #define R_386_RELATIVE 8 /* Adjust by program base */ #define R_386_GOTOFF 9 /* 32 bit offset to GOT */ #define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */ #define R_386_32PLT 11 #define R_386_TLS_TPOFF 14 /* Offset in static TLS block */ #define R_386_TLS_IE 15 /* Address of GOT entry for static TLS block offset */ #define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block offset */ #define R_386_TLS_LE 17 /* Offset relative to static TLS block */ #define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of general dynamic thread local data */ #define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of local dynamic thread local data in LE code */ #define R_386_16 20 #define R_386_PC16 21 #define R_386_8 22 #define R_386_PC8 23 #define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic thread local data */ #define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */ #define R_386_TLS_GD_CALL 26 /* Relocation for call to __tls_get_addr() */ #define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */ #define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic thread local data in LE code */ #define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */ #define R_386_TLS_LDM_CALL 30 /* Relocation for call to __tls_get_addr() in LDM code */ #define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */ #define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */ #define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS block offset */ #define R_386_TLS_LE_32 34 /* Negated offset relative to static TLS block */ #define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */ #define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */ #define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */ /* 38? */ #define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */ #define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS descriptor for relaxation. */ #define R_386_TLS_DESC 41 /* TLS descriptor containing pointer to code and to argument, returning the TLS offset for the symbol. */ #define R_386_IRELATIVE 42 /* Adjust indirectly by program base */ /* Keep this the last entry. */ #define R_386_NUM 43 /* SUN SPARC specific definitions. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_SPARC_REGISTER 13 /* Global register reserved to app. */ /* Values for Elf64_Ehdr.e_flags. */ #define EF_SPARCV9_MM 3 #define EF_SPARCV9_TSO 0 #define EF_SPARCV9_PSO 1 #define EF_SPARCV9_RMO 2 #define EF_SPARC_LEDATA 0x800000 /* little endian data */ #define EF_SPARC_EXT_MASK 0xFFFF00 #define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */ #define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */ #define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */ #define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */ /* SPARC relocs. */ #define R_SPARC_NONE 0 /* No reloc */ #define R_SPARC_8 1 /* Direct 8 bit */ #define R_SPARC_16 2 /* Direct 16 bit */ #define R_SPARC_32 3 /* Direct 32 bit */ #define R_SPARC_DISP8 4 /* PC relative 8 bit */ #define R_SPARC_DISP16 5 /* PC relative 16 bit */ #define R_SPARC_DISP32 6 /* PC relative 32 bit */ #define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */ #define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */ #define R_SPARC_HI22 9 /* High 22 bit */ #define R_SPARC_22 10 /* Direct 22 bit */ #define R_SPARC_13 11 /* Direct 13 bit */ #define R_SPARC_LO10 12 /* Truncated 10 bit */ #define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */ #define R_SPARC_GOT13 14 /* 13 bit GOT entry */ #define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */ #define R_SPARC_PC10 16 /* PC relative 10 bit truncated */ #define R_SPARC_PC22 17 /* PC relative 22 bit shifted */ #define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */ #define R_SPARC_COPY 19 /* Copy symbol at runtime */ #define R_SPARC_GLOB_DAT 20 /* Create GOT entry */ #define R_SPARC_JMP_SLOT 21 /* Create PLT entry */ #define R_SPARC_RELATIVE 22 /* Adjust by program base */ #define R_SPARC_UA32 23 /* Direct 32 bit unaligned */ /* Additional Sparc64 relocs. */ #define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */ #define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */ #define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */ #define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */ #define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */ #define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */ #define R_SPARC_10 30 /* Direct 10 bit */ #define R_SPARC_11 31 /* Direct 11 bit */ #define R_SPARC_64 32 /* Direct 64 bit */ #define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */ #define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */ #define R_SPARC_HM10 35 /* High middle 10 bits of ... */ #define R_SPARC_LM22 36 /* Low middle 22 bits of ... */ #define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */ #define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */ #define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */ #define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */ #define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */ #define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */ #define R_SPARC_7 43 /* Direct 7 bit */ #define R_SPARC_5 44 /* Direct 5 bit */ #define R_SPARC_6 45 /* Direct 6 bit */ #define R_SPARC_DISP64 46 /* PC relative 64 bit */ #define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */ #define R_SPARC_HIX22 48 /* High 22 bit complemented */ #define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */ #define R_SPARC_H44 50 /* Direct high 12 of 44 bit */ #define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */ #define R_SPARC_L44 52 /* Direct low 10 of 44 bit */ #define R_SPARC_REGISTER 53 /* Global register usage */ #define R_SPARC_UA64 54 /* Direct 64 bit unaligned */ #define R_SPARC_UA16 55 /* Direct 16 bit unaligned */ #define R_SPARC_TLS_GD_HI22 56 #define R_SPARC_TLS_GD_LO10 57 #define R_SPARC_TLS_GD_ADD 58 #define R_SPARC_TLS_GD_CALL 59 #define R_SPARC_TLS_LDM_HI22 60 #define R_SPARC_TLS_LDM_LO10 61 #define R_SPARC_TLS_LDM_ADD 62 #define R_SPARC_TLS_LDM_CALL 63 #define R_SPARC_TLS_LDO_HIX22 64 #define R_SPARC_TLS_LDO_LOX10 65 #define R_SPARC_TLS_LDO_ADD 66 #define R_SPARC_TLS_IE_HI22 67 #define R_SPARC_TLS_IE_LO10 68 #define R_SPARC_TLS_IE_LD 69 #define R_SPARC_TLS_IE_LDX 70 #define R_SPARC_TLS_IE_ADD 71 #define R_SPARC_TLS_LE_HIX22 72 #define R_SPARC_TLS_LE_LOX10 73 #define R_SPARC_TLS_DTPMOD32 74 #define R_SPARC_TLS_DTPMOD64 75 #define R_SPARC_TLS_DTPOFF32 76 #define R_SPARC_TLS_DTPOFF64 77 #define R_SPARC_TLS_TPOFF32 78 #define R_SPARC_TLS_TPOFF64 79 #define R_SPARC_GOTDATA_HIX22 80 #define R_SPARC_GOTDATA_LOX10 81 #define R_SPARC_GOTDATA_OP_HIX22 82 #define R_SPARC_GOTDATA_OP_LOX10 83 #define R_SPARC_GOTDATA_OP 84 #define R_SPARC_H34 85 #define R_SPARC_SIZE32 86 #define R_SPARC_SIZE64 87 #define R_SPARC_JMP_IREL 248 #define R_SPARC_IRELATIVE 249 #define R_SPARC_GNU_VTINHERIT 250 #define R_SPARC_GNU_VTENTRY 251 #define R_SPARC_REV32 252 /* Keep this the last entry. */ #define R_SPARC_NUM 253 /* For Sparc64, legal values for d_tag of Elf64_Dyn. */ #define DT_SPARC_REGISTER 0x70000001 #define DT_SPARC_NUM 2 /* MIPS R3000 specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used */ #define EF_MIPS_PIC 2 /* Contains PIC code */ #define EF_MIPS_CPIC 4 /* Uses PIC calling sequence */ #define EF_MIPS_XGOT 8 #define EF_MIPS_64BIT_WHIRL 16 #define EF_MIPS_ABI2 32 #define EF_MIPS_ABI_ON32 64 #define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level */ /* Legal values for MIPS architecture level. */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define EF_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define EF_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* The following are non-official names and should not be used. */ #define E_MIPS_ARCH_1 0x00000000 /* -mips1 code. */ #define E_MIPS_ARCH_2 0x10000000 /* -mips2 code. */ #define E_MIPS_ARCH_3 0x20000000 /* -mips3 code. */ #define E_MIPS_ARCH_4 0x30000000 /* -mips4 code. */ #define E_MIPS_ARCH_5 0x40000000 /* -mips5 code. */ #define E_MIPS_ARCH_32 0x60000000 /* MIPS32 code. */ #define E_MIPS_ARCH_64 0x70000000 /* MIPS64 code. */ /* Special section indices. */ #define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols */ #define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */ #define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */ #define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols */ #define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link */ #define SHT_MIPS_MSYM 0x70000001 #define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols */ #define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes */ #define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */ #define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging information*/ #define SHT_MIPS_REGINFO 0x70000006 /* Register usage information */ #define SHT_MIPS_PACKAGE 0x70000007 #define SHT_MIPS_PACKSYM 0x70000008 #define SHT_MIPS_RELD 0x70000009 #define SHT_MIPS_IFACE 0x7000000b #define SHT_MIPS_CONTENT 0x7000000c #define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */ #define SHT_MIPS_SHDR 0x70000010 #define SHT_MIPS_FDESC 0x70000011 #define SHT_MIPS_EXTSYM 0x70000012 #define SHT_MIPS_DENSE 0x70000013 #define SHT_MIPS_PDESC 0x70000014 #define SHT_MIPS_LOCSYM 0x70000015 #define SHT_MIPS_AUXSYM 0x70000016 #define SHT_MIPS_OPTSYM 0x70000017 #define SHT_MIPS_LOCSTR 0x70000018 #define SHT_MIPS_LINE 0x70000019 #define SHT_MIPS_RFDESC 0x7000001a #define SHT_MIPS_DELTASYM 0x7000001b #define SHT_MIPS_DELTAINST 0x7000001c #define SHT_MIPS_DELTACLASS 0x7000001d #define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */ #define SHT_MIPS_DELTADECL 0x7000001f #define SHT_MIPS_SYMBOL_LIB 0x70000020 #define SHT_MIPS_EVENTS 0x70000021 /* Event section. */ #define SHT_MIPS_TRANSLATE 0x70000022 #define SHT_MIPS_PIXIE 0x70000023 #define SHT_MIPS_XLATE 0x70000024 #define SHT_MIPS_XLATE_DEBUG 0x70000025 #define SHT_MIPS_WHIRL 0x70000026 #define SHT_MIPS_EH_REGION 0x70000027 #define SHT_MIPS_XLATE_OLD 0x70000028 #define SHT_MIPS_PDR_EXCEPTION 0x70000029 /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_MIPS_GPREL 0x10000000 /* Must be part of global data area */ #define SHF_MIPS_MERGE 0x20000000 #define SHF_MIPS_ADDR 0x40000000 #define SHF_MIPS_STRINGS 0x80000000 #define SHF_MIPS_NOSTRIP 0x08000000 #define SHF_MIPS_LOCAL 0x04000000 #define SHF_MIPS_NAMES 0x02000000 #define SHF_MIPS_NODUPE 0x01000000 /* Symbol tables. */ /* MIPS specific values for `st_other'. */ #define STO_MIPS_DEFAULT 0x0 #define STO_MIPS_INTERNAL 0x1 #define STO_MIPS_HIDDEN 0x2 #define STO_MIPS_PROTECTED 0x3 #define STO_MIPS_PLT 0x8 #define STO_MIPS_SC_ALIGN_UNUSED 0xff /* MIPS specific values for `st_info'. */ #define STB_MIPS_SPLIT_COMMON 13 /* Entries found in sections of type SHT_MIPS_GPTAB. */ typedef union { struct { Elf32_Word gt_current_g_value; /* -G value used for compilation */ Elf32_Word gt_unused; /* Not used */ } gt_header; /* First entry in section */ struct { Elf32_Word gt_g_value; /* If this value were used for -G */ Elf32_Word gt_bytes; /* This many bytes would be used */ } gt_entry; /* Subsequent entries in section */ } Elf32_gptab; /* Entry found in sections of type SHT_MIPS_REGINFO. */ typedef struct { Elf32_Word ri_gprmask; /* General registers used */ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used */ Elf32_Sword ri_gp_value; /* $gp register value */ } Elf32_RegInfo; /* Entries found in sections of type SHT_MIPS_OPTIONS. */ typedef struct { unsigned char kind; /* Determines interpretation of the variable part of descriptor. */ unsigned char size; /* Size of descriptor, including header. */ Elf32_Section section; /* Section header index of section affected, 0 for global options. */ Elf32_Word info; /* Kind-specific information. */ } Elf_Options; /* Values for `kind' field in Elf_Options. */ #define ODK_NULL 0 /* Undefined. */ #define ODK_REGINFO 1 /* Register usage information. */ #define ODK_EXCEPTIONS 2 /* Exception processing options. */ #define ODK_PAD 3 /* Section padding options. */ #define ODK_HWPATCH 4 /* Hardware workarounds performed */ #define ODK_FILL 5 /* record the fill value used by the linker. */ #define ODK_TAGS 6 /* reserve space for desktop tools to write. */ #define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */ #define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */ /* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */ #define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */ #define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */ #define OEX_PAGE0 0x10000 /* page zero must be mapped. */ #define OEX_SMM 0x20000 /* Force sequential memory mode? */ #define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */ #define OEX_PRECISEFP OEX_FPDBUG #define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */ #define OEX_FPU_INVAL 0x10 #define OEX_FPU_DIV0 0x08 #define OEX_FPU_OFLO 0x04 #define OEX_FPU_UFLO 0x02 #define OEX_FPU_INEX 0x01 /* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */ #define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */ #define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */ #define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */ #define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */ #define OPAD_PREFIX 0x1 #define OPAD_POSTFIX 0x2 #define OPAD_SYMBOL 0x4 /* Entry found in `.options' section. */ typedef struct { Elf32_Word hwp_flags1; /* Extra flags. */ Elf32_Word hwp_flags2; /* Extra flags. */ } Elf_Options_Hw; /* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */ #define OHWA0_R4KEOP_CHECKED 0x00000001 #define OHWA1_R4KEOP_CLEAN 0x00000002 /* MIPS relocs. */ #define R_MIPS_NONE 0 /* No reloc */ #define R_MIPS_16 1 /* Direct 16 bit */ #define R_MIPS_32 2 /* Direct 32 bit */ #define R_MIPS_REL32 3 /* PC relative 32 bit */ #define R_MIPS_26 4 /* Direct 26 bit shifted */ #define R_MIPS_HI16 5 /* High 16 bit */ #define R_MIPS_LO16 6 /* Low 16 bit */ #define R_MIPS_GPREL16 7 /* GP relative 16 bit */ #define R_MIPS_LITERAL 8 /* 16 bit literal entry */ #define R_MIPS_GOT16 9 /* 16 bit GOT entry */ #define R_MIPS_PC16 10 /* PC relative 16 bit */ #define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */ #define R_MIPS_GPREL32 12 /* GP relative 32 bit */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 #define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ #define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ #define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ #define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ #define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ #define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ #define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ #define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ #define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ #define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ #define R_MIPS_GLOB_DAT 51 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 /* Keep this the last entry. */ #define R_MIPS_NUM 128 /* Legal values for p_type field of Elf32_Phdr. */ #define PT_MIPS_REGINFO 0x70000000 /* Register usage information */ #define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */ #define PT_MIPS_OPTIONS 0x70000002 /* Special program header types. */ #define PF_MIPS_LOCAL 0x10000000 /* Legal values for d_tag field of Elf32_Dyn. */ #define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */ #define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */ #define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */ #define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */ #define DT_MIPS_FLAGS 0x70000005 /* Flags */ #define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */ #define DT_MIPS_MSYM 0x70000007 #define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */ #define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */ #define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */ #define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */ #define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */ #define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */ #define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */ #define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */ #define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */ #define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */ #define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */ #define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in DT_MIPS_DELTA_CLASS. */ #define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */ #define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in DT_MIPS_DELTA_INSTANCE. */ #define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */ #define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in DT_MIPS_DELTA_RELOC. */ #define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta relocations refer to. */ #define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in DT_MIPS_DELTA_SYM. */ #define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the class declaration. */ #define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in DT_MIPS_DELTA_CLASSSYM. */ #define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */ #define DT_MIPS_PIXIE_INIT 0x70000023 #define DT_MIPS_SYMBOL_LIB 0x70000024 #define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025 #define DT_MIPS_LOCAL_GOTIDX 0x70000026 #define DT_MIPS_HIDDEN_GOTIDX 0x70000027 #define DT_MIPS_PROTECTED_GOTIDX 0x70000028 #define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */ #define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */ #define DT_MIPS_DYNSTR_ALIGN 0x7000002b #define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */ #define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve function stored in GOT. */ #define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added by rld on dlopen() calls. */ #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */ #define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */ #define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */ /* The address of .got.plt in an executable using the new non-PIC ABI. */ #define DT_MIPS_PLTGOT 0x70000032 /* The base of the PLT in an executable using the new non-PIC ABI if that PLT is writable. For a non-writable PLT, this is omitted or has a zero value. */ #define DT_MIPS_RWPLT 0x70000034 #define DT_MIPS_NUM 0x35 /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */ #define RHF_NONE 0 /* No flags */ #define RHF_QUICKSTART (1 << 0) /* Use quickstart */ #define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */ #define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */ #define RHF_NO_MOVE (1 << 3) #define RHF_SGI_ONLY (1 << 4) #define RHF_GUARANTEE_INIT (1 << 5) #define RHF_DELTA_C_PLUS_PLUS (1 << 6) #define RHF_GUARANTEE_START_INIT (1 << 7) #define RHF_PIXIE (1 << 8) #define RHF_DEFAULT_DELAY_LOAD (1 << 9) #define RHF_REQUICKSTART (1 << 10) #define RHF_REQUICKSTARTED (1 << 11) #define RHF_CORD (1 << 12) #define RHF_NO_UNRES_UNDEF (1 << 13) #define RHF_RLD_ORDER_SAFE (1 << 14) /* Entries found in sections of type SHT_MIPS_LIBLIST. */ typedef struct { Elf32_Word l_name; /* Name (string table index) */ Elf32_Word l_time_stamp; /* Timestamp */ Elf32_Word l_checksum; /* Checksum */ Elf32_Word l_version; /* Interface version */ Elf32_Word l_flags; /* Flags */ } Elf32_Lib; typedef struct { Elf64_Word l_name; /* Name (string table index) */ Elf64_Word l_time_stamp; /* Timestamp */ Elf64_Word l_checksum; /* Checksum */ Elf64_Word l_version; /* Interface version */ Elf64_Word l_flags; /* Flags */ } Elf64_Lib; /* Legal values for l_flags. */ #define LL_NONE 0 #define LL_EXACT_MATCH (1 << 0) /* Require exact match */ #define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */ #define LL_REQUIRE_MINOR (1 << 2) #define LL_EXPORTS (1 << 3) #define LL_DELAY_LOAD (1 << 4) #define LL_DELTA (1 << 5) /* Entries found in sections of type SHT_MIPS_CONFLICT. */ typedef Elf32_Addr Elf32_Conflict; /* HPPA specific definitions. */ /* Legal values for e_flags field of Elf32_Ehdr. */ #define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */ #define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */ #define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */ #define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */ #define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch prediction. */ #define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */ #define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */ /* Defined values for `e_flags & EF_PARISC_ARCH' are: */ #define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */ #define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */ #define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */ /* Additional section indeces. */ #define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared symbols in ANSI C. */ #define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */ /* Legal values for sh_type field of Elf32_Shdr. */ #define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */ #define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */ #define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */ /* Legal values for sh_flags field of Elf32_Shdr. */ #define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */ #define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */ #define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */ /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */ #define STT_HP_OPAQUE (STT_LOOS + 0x1) #define STT_HP_STUB (STT_LOOS + 0x2) /* HPPA relocs. */ #define R_PARISC_NONE 0 /* No reloc. */ #define R_PARISC_DIR32 1 /* Direct 32-bit reference. */ #define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */ #define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */ #define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */ #define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */ #define R_PARISC_PCREL32 9 /* 32-bit rel. address. */ #define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */ #define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */ #define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */ #define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */ #define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */ #define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */ #define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */ #define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */ #define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */ #define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */ #define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */ #define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */ #define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */ #define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */ #define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */ #define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */ #define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */ #define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */ #define R_PARISC_FPTR64 64 /* 64 bits function address. */ #define R_PARISC_PLABEL32 65 /* 32 bits function address. */ #define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */ #define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */ #define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */ #define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */ #define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */ #define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */ #define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */ #define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */ #define R_PARISC_DIR64 80 /* 64 bits of eff. address. */ #define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */ #define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */ #define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */ #define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */ #define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */ #define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */ #define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */ #define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */ #define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */ #define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */ #define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */ #define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */ #define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */ #define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */ #define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */ #define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */ #define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */ #define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */ #define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */ #define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */ #define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */ #define R_PARISC_LORESERVE 128 #define R_PARISC_COPY 128 /* Copy relocation. */ #define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */ #define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */ #define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */ #define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */ #define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */ #define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */ #define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */ #define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */ #define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */ #define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */ #define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */ #define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/ #define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */ #define R_PARISC_GNU_VTENTRY 232 #define R_PARISC_GNU_VTINHERIT 233 #define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */ #define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */ #define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */ #define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */ #define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */ #define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */ #define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */ #define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */ #define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */ #define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */ #define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */ #define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */ #define R_PARISC_TLS_LE21L R_PARISC_TPREL21L #define R_PARISC_TLS_LE14R R_PARISC_TPREL14R #define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L #define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R #define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32 #define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64 #define R_PARISC_HIRESERVE 255 /* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */ #define PT_HP_TLS (PT_LOOS + 0x0) #define PT_HP_CORE_NONE (PT_LOOS + 0x1) #define PT_HP_CORE_VERSION (PT_LOOS + 0x2) #define PT_HP_CORE_KERNEL (PT_LOOS + 0x3) #define PT_HP_CORE_COMM (PT_LOOS + 0x4) #define PT_HP_CORE_PROC (PT_LOOS + 0x5) #define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6) #define PT_HP_CORE_STACK (PT_LOOS + 0x7) #define PT_HP_CORE_SHM (PT_LOOS + 0x8) #define PT_HP_CORE_MMF (PT_LOOS + 0x9) #define PT_HP_PARALLEL (PT_LOOS + 0x10) #define PT_HP_FASTBIND (PT_LOOS + 0x11) #define PT_HP_OPT_ANNOT (PT_LOOS + 0x12) #define PT_HP_HSL_ANNOT (PT_LOOS + 0x13) #define PT_HP_STACK (PT_LOOS + 0x14) #define PT_PARISC_ARCHEXT 0x70000000 #define PT_PARISC_UNWIND 0x70000001 /* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */ #define PF_PARISC_SBP 0x08000000 #define PF_HP_PAGE_SIZE 0x00100000 #define PF_HP_FAR_SHARED 0x00200000 #define PF_HP_NEAR_SHARED 0x00400000 #define PF_HP_CODE 0x01000000 #define PF_HP_MODIFY 0x02000000 #define PF_HP_LAZYSWAP 0x04000000 #define PF_HP_SBP 0x08000000 /* Alpha specific definitions. */ /* Legal values for e_flags field of Elf64_Ehdr. */ #define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */ #define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */ /* Legal values for sh_type field of Elf64_Shdr. */ /* These two are primerily concerned with ECOFF debugging info. */ #define SHT_ALPHA_DEBUG 0x70000001 #define SHT_ALPHA_REGINFO 0x70000002 /* Legal values for sh_flags field of Elf64_Shdr. */ #define SHF_ALPHA_GPREL 0x10000000 /* Legal values for st_other field of Elf64_Sym. */ #define STO_ALPHA_NOPV 0x80 /* No PV required. */ #define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */ /* Alpha relocs. */ #define R_ALPHA_NONE 0 /* No reloc */ #define R_ALPHA_REFLONG 1 /* Direct 32 bit */ #define R_ALPHA_REFQUAD 2 /* Direct 64 bit */ #define R_ALPHA_GPREL32 3 /* GP relative 32 bit */ #define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */ #define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */ #define R_ALPHA_GPDISP 6 /* Add displacement to GP */ #define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */ #define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */ #define R_ALPHA_SREL16 9 /* PC relative 16 bit */ #define R_ALPHA_SREL32 10 /* PC relative 32 bit */ #define R_ALPHA_SREL64 11 /* PC relative 64 bit */ #define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */ #define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */ #define R_ALPHA_GPREL16 19 /* GP relative 16 bit */ #define R_ALPHA_COPY 24 /* Copy symbol at runtime */ #define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */ #define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */ #define R_ALPHA_RELATIVE 27 /* Adjust by program base */ #define R_ALPHA_TLS_GD_HI 28 #define R_ALPHA_TLSGD 29 #define R_ALPHA_TLS_LDM 30 #define R_ALPHA_DTPMOD64 31 #define R_ALPHA_GOTDTPREL 32 #define R_ALPHA_DTPREL64 33 #define R_ALPHA_DTPRELHI 34 #define R_ALPHA_DTPRELLO 35 #define R_ALPHA_DTPREL16 36 #define R_ALPHA_GOTTPREL 37 #define R_ALPHA_TPREL64 38 #define R_ALPHA_TPRELHI 39 #define R_ALPHA_TPRELLO 40 #define R_ALPHA_TPREL16 41 /* Keep this the last entry. */ #define R_ALPHA_NUM 46 /* Magic values of the LITUSE relocation addend. */ #define LITUSE_ALPHA_ADDR 0 #define LITUSE_ALPHA_BASE 1 #define LITUSE_ALPHA_BYTOFF 2 #define LITUSE_ALPHA_JSR 3 #define LITUSE_ALPHA_TLS_GD 4 #define LITUSE_ALPHA_TLS_LDM 5 /* Legal values for d_tag of Elf64_Dyn. */ #define DT_ALPHA_PLTRO (DT_LOPROC + 0) #define DT_ALPHA_NUM 1 /* PowerPC specific declarations */ /* Values for Elf32/64_Ehdr.e_flags. */ #define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */ /* Cygnus local bits below */ #define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/ #define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib flag */ /* PowerPC relocations defined by the ABIs */ #define R_PPC_NONE 0 #define R_PPC_ADDR32 1 /* 32bit absolute address */ #define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */ #define R_PPC_ADDR16 3 /* 16bit absolute address */ #define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */ #define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */ #define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */ #define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */ #define R_PPC_ADDR14_BRTAKEN 8 #define R_PPC_ADDR14_BRNTAKEN 9 #define R_PPC_REL24 10 /* PC relative 26 bit */ #define R_PPC_REL14 11 /* PC relative 16 bit */ #define R_PPC_REL14_BRTAKEN 12 #define R_PPC_REL14_BRNTAKEN 13 #define R_PPC_GOT16 14 #define R_PPC_GOT16_LO 15 #define R_PPC_GOT16_HI 16 #define R_PPC_GOT16_HA 17 #define R_PPC_PLTREL24 18 #define R_PPC_COPY 19 #define R_PPC_GLOB_DAT 20 #define R_PPC_JMP_SLOT 21 #define R_PPC_RELATIVE 22 #define R_PPC_LOCAL24PC 23 #define R_PPC_UADDR32 24 #define R_PPC_UADDR16 25 #define R_PPC_REL32 26 #define R_PPC_PLT32 27 #define R_PPC_PLTREL32 28 #define R_PPC_PLT16_LO 29 #define R_PPC_PLT16_HI 30 #define R_PPC_PLT16_HA 31 #define R_PPC_SDAREL16 32 #define R_PPC_SECTOFF 33 #define R_PPC_SECTOFF_LO 34 #define R_PPC_SECTOFF_HI 35 #define R_PPC_SECTOFF_HA 36 /* PowerPC relocations defined for the TLS access ABI. */ #define R_PPC_TLS 67 /* none (sym+add)@tls */ #define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */ #define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */ #define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */ #define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */ #define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */ #define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */ #define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */ #define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */ #define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */ /* The remaining relocs are from the Embedded ELF ABI, and are not in the SVR4 ELF ABI. */ #define R_PPC_EMB_NADDR32 101 #define R_PPC_EMB_NADDR16 102 #define R_PPC_EMB_NADDR16_LO 103 #define R_PPC_EMB_NADDR16_HI 104 #define R_PPC_EMB_NADDR16_HA 105 #define R_PPC_EMB_SDAI16 106 #define R_PPC_EMB_SDA2I16 107 #define R_PPC_EMB_SDA2REL 108 #define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */ #define R_PPC_EMB_MRKREF 110 #define R_PPC_EMB_RELSEC16 111 #define R_PPC_EMB_RELST_LO 112 #define R_PPC_EMB_RELST_HI 113 #define R_PPC_EMB_RELST_HA 114 #define R_PPC_EMB_BIT_FLD 115 #define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */ /* Diab tool relocations. */ #define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */ #define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */ #define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */ #define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */ #define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */ #define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */ /* GNU extension to support local ifunc. */ #define R_PPC_IRELATIVE 248 /* GNU relocs used in PIC code sequences. */ #define R_PPC_REL16 249 /* half16 (sym+add-.) */ #define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */ #define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* This is a phony reloc to handle any old fashioned TOC16 references that may still be in object files. */ #define R_PPC_TOC16 255 /* PowerPC specific values for the Dyn d_tag field. */ #define DT_PPC_GOT (DT_LOPROC + 0) #define DT_PPC_NUM 1 /* PowerPC64 relocations defined by the ABIs */ #define R_PPC64_NONE R_PPC_NONE #define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */ #define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */ #define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */ #define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */ #define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */ #define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */ #define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */ #define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN #define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN #define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */ #define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */ #define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN #define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN #define R_PPC64_GOT16 R_PPC_GOT16 #define R_PPC64_GOT16_LO R_PPC_GOT16_LO #define R_PPC64_GOT16_HI R_PPC_GOT16_HI #define R_PPC64_GOT16_HA R_PPC_GOT16_HA #define R_PPC64_COPY R_PPC_COPY #define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT #define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT #define R_PPC64_RELATIVE R_PPC_RELATIVE #define R_PPC64_UADDR32 R_PPC_UADDR32 #define R_PPC64_UADDR16 R_PPC_UADDR16 #define R_PPC64_REL32 R_PPC_REL32 #define R_PPC64_PLT32 R_PPC_PLT32 #define R_PPC64_PLTREL32 R_PPC_PLTREL32 #define R_PPC64_PLT16_LO R_PPC_PLT16_LO #define R_PPC64_PLT16_HI R_PPC_PLT16_HI #define R_PPC64_PLT16_HA R_PPC_PLT16_HA #define R_PPC64_SECTOFF R_PPC_SECTOFF #define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO #define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI #define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA #define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */ #define R_PPC64_ADDR64 38 /* doubleword64 S + A */ #define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */ #define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */ #define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */ #define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */ #define R_PPC64_UADDR64 43 /* doubleword64 S + A */ #define R_PPC64_REL64 44 /* doubleword64 S + A - P */ #define R_PPC64_PLT64 45 /* doubleword64 L + A */ #define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */ #define R_PPC64_TOC16 47 /* half16* S + A - .TOC */ #define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */ #define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */ #define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */ #define R_PPC64_TOC 51 /* doubleword64 .TOC */ #define R_PPC64_PLTGOT16 52 /* half16* M + A */ #define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */ #define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */ #define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */ #define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */ #define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */ #define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */ #define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */ #define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */ #define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */ #define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */ #define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */ #define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */ #define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */ #define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */ /* PowerPC64 relocations defined for the TLS access ABI. */ #define R_PPC64_TLS 67 /* none (sym+add)@tls */ #define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */ #define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */ #define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */ #define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */ #define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */ #define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */ #define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */ #define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */ #define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */ #define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */ #define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */ #define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */ #define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */ #define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */ #define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */ #define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */ #define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */ #define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */ #define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */ #define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */ #define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */ #define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */ #define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */ #define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */ #define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */ #define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */ #define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */ #define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */ #define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */ #define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */ #define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */ #define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */ #define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */ #define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */ #define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */ /* GNU extension to support local ifunc. */ #define R_PPC64_JMP_IREL 247 #define R_PPC64_IRELATIVE 248 #define R_PPC64_REL16 249 /* half16 (sym+add-.) */ #define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */ #define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */ #define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */ /* PowerPC64 specific values for the Dyn d_tag field. */ #define DT_PPC64_GLINK (DT_LOPROC + 0) #define DT_PPC64_OPD (DT_LOPROC + 1) #define DT_PPC64_OPDSZ (DT_LOPROC + 2) #define DT_PPC64_NUM 3 /* ARM specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_ARM_RELEXEC 0x01 #define EF_ARM_HASENTRY 0x02 #define EF_ARM_INTERWORK 0x04 #define EF_ARM_APCS_26 0x08 #define EF_ARM_APCS_FLOAT 0x10 #define EF_ARM_PIC 0x20 #define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */ #define EF_ARM_NEW_ABI 0x80 #define EF_ARM_OLD_ABI 0x100 #define EF_ARM_SOFT_FLOAT 0x200 #define EF_ARM_VFP_FLOAT 0x400 #define EF_ARM_MAVERICK_FLOAT 0x800 /* Other constants defined in the ARM ELF spec. version B-01. */ /* NB. These conflict with values defined above. */ #define EF_ARM_SYMSARESORTED 0x04 #define EF_ARM_DYNSYMSUSESEGIDX 0x08 #define EF_ARM_MAPSYMSFIRST 0x10 #define EF_ARM_EABIMASK 0XFF000000 /* Constants defined in AAELF. */ #define EF_ARM_BE8 0x00800000 #define EF_ARM_LE8 0x00400000 #define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK) #define EF_ARM_EABI_UNKNOWN 0x00000000 #define EF_ARM_EABI_VER1 0x01000000 #define EF_ARM_EABI_VER2 0x02000000 #define EF_ARM_EABI_VER3 0x03000000 #define EF_ARM_EABI_VER4 0x04000000 #define EF_ARM_EABI_VER5 0x05000000 /* Additional symbol types for Thumb. */ #define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */ #define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */ /* ARM-specific values for sh_flags */ #define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */ #define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined in the input to a link step. */ /* ARM-specific program header flags */ #define PF_ARM_SB 0x10000000 /* Segment contains the location addressed by the static base. */ #define PF_ARM_PI 0x20000000 /* Position-independent segment. */ #define PF_ARM_ABS 0x40000000 /* Absolute segment. */ /* Processor specific values for the Phdr p_type field. */ #define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */ #define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */ #define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */ /* ARM relocs. */ #define R_ARM_NONE 0 /* No reloc */ #define R_ARM_PC24 1 /* PC relative 26 bit branch */ #define R_ARM_ABS32 2 /* Direct 32 bit */ #define R_ARM_REL32 3 /* PC relative 32 bit */ #define R_ARM_PC13 4 #define R_ARM_ABS16 5 /* Direct 16 bit */ #define R_ARM_ABS12 6 /* Direct 12 bit */ #define R_ARM_THM_ABS5 7 #define R_ARM_ABS8 8 /* Direct 8 bit */ #define R_ARM_SBREL32 9 #define R_ARM_THM_PC22 10 #define R_ARM_THM_PC8 11 #define R_ARM_AMP_VCALL9 12 #define R_ARM_SWI24 13 /* Obsolete static relocation. */ #define R_ARM_TLS_DESC 13 /* Dynamic relocation. */ #define R_ARM_THM_SWI8 14 #define R_ARM_XPC25 15 #define R_ARM_THM_XPC22 16 #define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */ #define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */ #define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */ #define R_ARM_COPY 20 /* Copy symbol at runtime */ #define R_ARM_GLOB_DAT 21 /* Create GOT entry */ #define R_ARM_JUMP_SLOT 22 /* Create PLT entry */ #define R_ARM_RELATIVE 23 /* Adjust by program base */ #define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */ #define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */ #define R_ARM_GOT32 26 /* 32 bit GOT entry */ #define R_ARM_PLT32 27 /* 32 bit PLT address */ #define R_ARM_ALU_PCREL_7_0 32 #define R_ARM_ALU_PCREL_15_8 33 #define R_ARM_ALU_PCREL_23_15 34 #define R_ARM_LDR_SBREL_11_0 35 #define R_ARM_ALU_SBREL_19_12 36 #define R_ARM_ALU_SBREL_27_20 37 #define R_ARM_TLS_GOTDESC 90 #define R_ARM_TLS_CALL 91 #define R_ARM_TLS_DESCSEQ 92 #define R_ARM_THM_TLS_CALL 93 #define R_ARM_GNU_VTENTRY 100 #define R_ARM_GNU_VTINHERIT 101 #define R_ARM_THM_PC11 102 /* thumb unconditional branch */ #define R_ARM_THM_PC9 103 /* thumb conditional branch */ #define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic thread local data */ #define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic thread local data */ #define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS block */ #define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of static TLS block offset */ #define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static TLS block */ #define R_ARM_THM_TLS_DESCSEQ 129 #define R_ARM_IRELATIVE 160 #define R_ARM_RXPC25 249 #define R_ARM_RSBREL32 250 #define R_ARM_THM_RPC22 251 #define R_ARM_RREL32 252 #define R_ARM_RABS22 253 #define R_ARM_RPC24 254 #define R_ARM_RBASE 255 /* Keep this the last entry. */ #define R_ARM_NUM 256 /* IA-64 specific declarations. */ /* Processor specific flags for the Ehdr e_flags field. */ #define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */ #define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */ #define EF_IA_64_ARCH 0xff000000 /* arch. version mask */ /* Processor specific values for the Phdr p_type field. */ #define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */ #define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */ #define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12) #define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13) #define PT_IA_64_HP_STACK (PT_LOOS + 0x14) /* Processor specific flags for the Phdr p_flags field. */ #define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */ /* Processor specific values for the Shdr sh_type field. */ #define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */ #define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */ /* Processor specific flags for the Shdr sh_flags field. */ #define SHF_IA_64_SHORT 0x10000000 /* section near gp */ #define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */ /* Processor specific values for the Dyn d_tag field. */ #define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0) #define DT_IA_64_NUM 1 /* IA-64 relocations. */ #define R_IA64_NONE 0x00 /* none */ #define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */ #define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */ #define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */ #define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */ #define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */ #define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */ #define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */ #define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */ #define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */ #define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */ #define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */ #define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */ #define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */ #define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */ #define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */ #define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */ #define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */ #define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */ #define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */ #define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */ #define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */ #define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */ #define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */ #define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */ #define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */ #define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */ #define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */ #define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */ #define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */ #define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */ #define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */ #define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */ #define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */ #define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */ #define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */ #define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */ #define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */ #define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */ #define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */ #define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */ #define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */ #define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */ #define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */ #define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */ #define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */ #define R_IA64_REL32MSB 0x6c /* data 4 + REL */ #define R_IA64_REL32LSB 0x6d /* data 4 + REL */ #define R_IA64_REL64MSB 0x6e /* data 8 + REL */ #define R_IA64_REL64LSB 0x6f /* data 8 + REL */ #define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */ #define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */ #define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */ #define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */ #define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */ #define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */ #define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */ #define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */ #define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */ #define R_IA64_COPY 0x84 /* copy relocation */ #define R_IA64_SUB 0x85 /* Addend and symbol difference */ #define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */ #define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */ #define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */ #define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */ #define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */ #define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */ #define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */ #define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */ #define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */ #define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */ #define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */ #define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */ #define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */ #define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */ #define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */ #define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */ #define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */ /* SH specific declarations */ /* Processor specific flags for the ELF header e_flags field. */ #define EF_SH_MACH_MASK 0x1f #define EF_SH_UNKNOWN 0x0 #define EF_SH1 0x1 #define EF_SH2 0x2 #define EF_SH3 0x3 #define EF_SH_DSP 0x4 #define EF_SH3_DSP 0x5 #define EF_SH4AL_DSP 0x6 #define EF_SH3E 0x8 #define EF_SH4 0x9 #define EF_SH2E 0xb #define EF_SH4A 0xc #define EF_SH2A 0xd #define EF_SH4_NOFPU 0x10 #define EF_SH4A_NOFPU 0x11 #define EF_SH4_NOMMU_NOFPU 0x12 #define EF_SH2A_NOFPU 0x13 #define EF_SH3_NOMMU 0x14 #define EF_SH2A_SH4_NOFPU 0x15 #define EF_SH2A_SH3_NOFPU 0x16 #define EF_SH2A_SH4 0x17 #define EF_SH2A_SH3E 0x18 /* SH relocs. */ #define R_SH_NONE 0 #define R_SH_DIR32 1 #define R_SH_REL32 2 #define R_SH_DIR8WPN 3 #define R_SH_IND12W 4 #define R_SH_DIR8WPL 5 #define R_SH_DIR8WPZ 6 #define R_SH_DIR8BP 7 #define R_SH_DIR8W 8 #define R_SH_DIR8L 9 #define R_SH_SWITCH16 25 #define R_SH_SWITCH32 26 #define R_SH_USES 27 #define R_SH_COUNT 28 #define R_SH_ALIGN 29 #define R_SH_CODE 30 #define R_SH_DATA 31 #define R_SH_LABEL 32 #define R_SH_SWITCH8 33 #define R_SH_GNU_VTINHERIT 34 #define R_SH_GNU_VTENTRY 35 #define R_SH_TLS_GD_32 144 #define R_SH_TLS_LD_32 145 #define R_SH_TLS_LDO_32 146 #define R_SH_TLS_IE_32 147 #define R_SH_TLS_LE_32 148 #define R_SH_TLS_DTPMOD32 149 #define R_SH_TLS_DTPOFF32 150 #define R_SH_TLS_TPOFF32 151 #define R_SH_GOT32 160 #define R_SH_PLT32 161 #define R_SH_COPY 162 #define R_SH_GLOB_DAT 163 #define R_SH_JMP_SLOT 164 #define R_SH_RELATIVE 165 #define R_SH_GOTOFF 166 #define R_SH_GOTPC 167 /* Keep this the last entry. */ #define R_SH_NUM 256 /* S/390 specific definitions. */ /* Valid values for the e_flags field. */ #define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */ /* Additional s390 relocs */ #define R_390_NONE 0 /* No reloc. */ #define R_390_8 1 /* Direct 8 bit. */ #define R_390_12 2 /* Direct 12 bit. */ #define R_390_16 3 /* Direct 16 bit. */ #define R_390_32 4 /* Direct 32 bit. */ #define R_390_PC32 5 /* PC relative 32 bit. */ #define R_390_GOT12 6 /* 12 bit GOT offset. */ #define R_390_GOT32 7 /* 32 bit GOT offset. */ #define R_390_PLT32 8 /* 32 bit PC relative PLT address. */ #define R_390_COPY 9 /* Copy symbol at runtime. */ #define R_390_GLOB_DAT 10 /* Create GOT entry. */ #define R_390_JMP_SLOT 11 /* Create PLT entry. */ #define R_390_RELATIVE 12 /* Adjust by program base. */ #define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */ #define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */ #define R_390_GOT16 15 /* 16 bit GOT offset. */ #define R_390_PC16 16 /* PC relative 16 bit. */ #define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */ #define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */ #define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */ #define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */ #define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */ #define R_390_64 22 /* Direct 64 bit. */ #define R_390_PC64 23 /* PC relative 64 bit. */ #define R_390_GOT64 24 /* 64 bit GOT offset. */ #define R_390_PLT64 25 /* 64 bit PC relative PLT address. */ #define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */ #define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */ #define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */ #define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */ #define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */ #define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */ #define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */ #define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */ #define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */ #define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */ #define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */ #define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */ #define R_390_TLS_GDCALL 38 /* Tag for function call in general dynamic TLS code. */ #define R_390_TLS_LDCALL 39 /* Tag for function call in local dynamic TLS code. */ #define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic thread local data. */ #define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic thread local data. */ #define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS block offset. */ #define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS block offset. */ #define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic thread local data in LE code. */ #define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for negated static TLS block offset. */ #define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for negated static TLS block offset. */ #define R_390_TLS_LE32 50 /* 32 bit negated offset relative to static TLS block. */ #define R_390_TLS_LE64 51 /* 64 bit negated offset relative to static TLS block. */ #define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS block. */ #define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS block. */ #define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */ #define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */ #define R_390_TLS_TPOFF 56 /* Negated offset in static TLS block. */ #define R_390_20 57 /* Direct 20 bit. */ #define R_390_GOT20 58 /* 20 bit GOT offset. */ #define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */ #define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS block offset. */ /* Keep this the last entry. */ #define R_390_NUM 61 /* CRIS relocations. */ #define R_CRIS_NONE 0 #define R_CRIS_8 1 #define R_CRIS_16 2 #define R_CRIS_32 3 #define R_CRIS_8_PCREL 4 #define R_CRIS_16_PCREL 5 #define R_CRIS_32_PCREL 6 #define R_CRIS_GNU_VTINHERIT 7 #define R_CRIS_GNU_VTENTRY 8 #define R_CRIS_COPY 9 #define R_CRIS_GLOB_DAT 10 #define R_CRIS_JUMP_SLOT 11 #define R_CRIS_RELATIVE 12 #define R_CRIS_16_GOT 13 #define R_CRIS_32_GOT 14 #define R_CRIS_16_GOTPLT 15 #define R_CRIS_32_GOTPLT 16 #define R_CRIS_32_GOTREL 17 #define R_CRIS_32_PLT_GOTREL 18 #define R_CRIS_32_PLT_PCREL 19 #define R_CRIS_NUM 20 /* AMD x86-64 relocations. */ #define R_X86_64_NONE 0 /* No reloc */ #define R_X86_64_64 1 /* Direct 64 bit */ #define R_X86_64_PC32 2 /* PC relative 32 bit signed */ #define R_X86_64_GOT32 3 /* 32 bit GOT entry */ #define R_X86_64_PLT32 4 /* 32 bit PLT address */ #define R_X86_64_COPY 5 /* Copy symbol at runtime */ #define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ #define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ #define R_X86_64_RELATIVE 8 /* Adjust by program base */ #define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative offset to GOT */ #define R_X86_64_32 10 /* Direct 32 bit zero extended */ #define R_X86_64_32S 11 /* Direct 32 bit sign extended */ #define R_X86_64_16 12 /* Direct 16 bit zero extended */ #define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ #define R_X86_64_8 14 /* Direct 8 bit sign extended */ #define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ #define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */ #define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */ #define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */ #define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset to two GOT entries for GD symbol */ #define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset to two GOT entries for LD symbol */ #define R_X86_64_DTPOFF32 21 /* Offset in TLS block */ #define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset to GOT entry for IE symbol */ #define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */ #define R_X86_64_PC64 24 /* PC relative 64 bit */ #define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */ #define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative offset to GOT */ #define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */ #define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset to GOT entry */ #define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */ #define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */ #define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset to PLT entry */ #define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */ #define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */ #define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */ #define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS descriptor. */ #define R_X86_64_TLSDESC 36 /* TLS descriptor. */ #define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */ #define R_X86_64_NUM 38 /* AM33 relocations. */ #define R_MN10300_NONE 0 /* No reloc. */ #define R_MN10300_32 1 /* Direct 32 bit. */ #define R_MN10300_16 2 /* Direct 16 bit. */ #define R_MN10300_8 3 /* Direct 8 bit. */ #define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */ #define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */ #define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */ #define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */ #define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */ #define R_MN10300_24 9 /* Direct 24 bit. */ #define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */ #define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */ #define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */ #define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */ #define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */ #define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */ #define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */ #define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */ #define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */ #define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */ #define R_MN10300_COPY 20 /* Copy symbol at runtime. */ #define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */ #define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */ #define R_MN10300_RELATIVE 23 /* Adjust by program base. */ #define R_MN10300_NUM 24 /* M32R relocs. */ #define R_M32R_NONE 0 /* No reloc. */ #define R_M32R_16 1 /* Direct 16 bit. */ #define R_M32R_32 2 /* Direct 32 bit. */ #define R_M32R_24 3 /* Direct 24 bit. */ #define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */ #define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */ #define R_M32R_LO16 9 /* Low 16 bit. */ #define R_M32R_SDA16 10 /* 16 bit offset in SDA. */ #define R_M32R_GNU_VTINHERIT 11 #define R_M32R_GNU_VTENTRY 12 /* M32R relocs use SHT_RELA. */ #define R_M32R_16_RELA 33 /* Direct 16 bit. */ #define R_M32R_32_RELA 34 /* Direct 32 bit. */ #define R_M32R_24_RELA 35 /* Direct 24 bit. */ #define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */ #define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */ #define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */ #define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */ #define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */ #define R_M32R_LO16_RELA 41 /* Low 16 bit */ #define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */ #define R_M32R_RELA_GNU_VTINHERIT 43 #define R_M32R_RELA_GNU_VTENTRY 44 #define R_M32R_REL32 45 /* PC relative 32 bit. */ #define R_M32R_GOT24 48 /* 24 bit GOT entry */ #define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */ #define R_M32R_COPY 50 /* Copy symbol at runtime */ #define R_M32R_GLOB_DAT 51 /* Create GOT entry */ #define R_M32R_JMP_SLOT 52 /* Create PLT entry */ #define R_M32R_RELATIVE 53 /* Adjust by program base */ #define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */ #define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */ #define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned low */ #define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed low */ #define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */ #define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to GOT with unsigned low */ #define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to GOT with signed low */ #define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to GOT */ #define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT with unsigned low */ #define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT with signed low */ #define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */ #define R_M32R_NUM 256 /* Keep this the last entry. */ __END_DECLS #endif /* elf.h */ ================================================ FILE: include/philips.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __PHILIPS_H #define __PHILIPS_H #include #include "config.h" #define PHILIPS_FUSION1_MAGIC "NFWB" //partition table start = headerSize struct philips_fusion1_part { uint32_t unk0; uint32_t unk1; uint32_t unk2; uint32_t unk3; uint32_t index; uint32_t size; uint32_t offset; }; struct philips_fusion1_upg { uint32_t magic; uint32_t flags; uint32_t headerSize; uint32_t padding[5]; uint8_t unk[16]; //crc or hash? uint32_t unk0; //part of unk? uint32_t numPartitions; uint32_t firstPartition; //offset of first part }; void extract_philips_fusion1(MFILE *mf, config_opts_t *config_opts); MFILE *is_philips_fusion1(const char *filename); #endif ================================================ FILE: include/realtek/rtsplit.h ================================================ #ifndef __RT_AVSPLIT_H__ #define __RT_AVSPLIT_H__ #define HEADER_AUDIO1_IMAGE 0x5353beef #define HEADER_AUDIO2_IMAGE 0x4141beef #define HEADER_VIDEO1_IMAGE 0x5656beef #define HEADER_VIDEO2_IMAGE 0x7878beef typedef struct _kernel_image_header { unsigned int magic; unsigned int offset; unsigned int size; unsigned int version; unsigned int reserved[4]; } kernel_image_header; #endif // __RT_AVSPLIT_H__ ================================================ FILE: include/realtek.h ================================================ #ifndef __REALTEK_H #define __REALTEK_H #include "mfile.h" MFILE *is_rtk_bspfw(const char *filename); void split_rtk_bspfw(MFILE *mf, const char *destdir); #endif ================================================ FILE: include/sniptype.h ================================================ /* ** SNIPTYPE.H - Include file for SNIPPETS data types and commonly used macros */ #ifndef SNIPTYPE__H # define SNIPTYPE__H # include /* For free() */ # include /* For NULL & strlen() */ typedef enum { Error_ = -1, Success_, False_ = 0, True_ } Boolean_T; # if defined(__unix__) typedef unsigned char BYTE; typedef unsigned long DWORD; typedef unsigned short WORD; # if !defined(FAR) # define FAR # endif # if !defined(NEAR) # define NEAR # endif # if !defined(HUGE) # define HUGE # endif # if !defined(PASCAL) # define PASCAL # endif # if !defined(CDECL) # define CDECL # endif # if !defined(INTERRUPT) # define INTERRUPT # endif # elif !defined(WIN32) && !defined(_WIN32) && !defined(__NT__) \ && !defined(_WINDOWS) # if !defined(OS2) typedef unsigned char BYTE; typedef unsigned long DWORD; # endif typedef unsigned short WORD; # else # define WIN32_LEAN_AND_MEAN # define NOGDI # define NOSERVICE # undef INC_OLE1 # undef INC_OLE2 # include # define HUGE # endif typedef union { signed char c; BYTE b; } VAR8_; typedef union { VAR8_ v8[2]; signed short s; WORD w; } VAR16_; typedef union { VAR16_ v16[2]; signed long l; DWORD dw; float f; void *p; } VAR32_; typedef union { VAR32_ v32[2]; double d; } VAR64_; # define NUL '\0' # define LAST_CHAR(s) (((char *)s)[strlen(s) - 1]) # define TOBOOL(x) (!(!(x))) # define FREE(p) (free(p),(p)=NULL) #endif /* SNIPTYPE__H */ ================================================ FILE: include/squashfs/action.h ================================================ #ifndef ACTION_H # define ACTION_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2011, 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * action.h */ /* * Lexical analyser definitions */ # define TOK_OPEN_BRACKET 0 # define TOK_CLOSE_BRACKET 1 # define TOK_AND 2 # define TOK_OR 3 # define TOK_NOT 4 # define TOK_COMMA 5 # define TOK_AT 6 # define TOK_WHITE_SPACE 7 # define TOK_STRING 8 # define TOK_EOF 9 # define TOK_TO_STR(OP, S) ({ \ char *s; \ switch(OP) { \ case TOK_EOF: \ s = "EOF"; \ break; \ case TOK_STRING: \ s = S; \ break; \ default: \ s = token_table[OP].string; \ break; \ } \ s; \ }) struct token_entry { char *string; int token; int size; }; /* * Expression parser definitions */ # define OP_TYPE 0 # define ATOM_TYPE 1 # define UNARY_TYPE 2 # define SYNTAX_ERROR(S, ARGS...) { \ char *src = strdup(source); \ src[cur_ptr - source] = '\0'; \ fprintf(stderr, "Failed to parse action \"%s\"\n", source); \ fprintf(stderr, "Syntax error: "S, ##ARGS); \ fprintf(stderr, "Got here \"%s\"\n", src); \ free(src); \ } # define TEST_SYNTAX_ERROR(TEST, ARG, S, ARGS...) { \ char *src = strdup(source); \ src[cur_ptr - source] = '\0'; \ fprintf(stderr, "Failed to parse action \"%s\"\n", source); \ fprintf(stderr, "Syntax error in \"%s()\", arg %d: "S, TEST->name, \ ARG, ##ARGS); \ fprintf(stderr, "Got here \"%s\"\n", src); \ free(src); \ } struct expr; struct expr_op { struct expr *lhs; struct expr *rhs; int op; }; struct atom { struct test_entry *test; char **argv; void *data; }; struct unary_op { struct expr *expr; int op; }; struct expr { int type; union { struct atom atom; struct expr_op expr_op; struct unary_op unary_op; }; }; /* * Test operation definitions */ # define NUM_EQ 1 # define NUM_LESS 2 # define NUM_GREATER 3 struct test_number_arg { long long size; int range; }; struct test_range_args { long long start; long long end; }; struct action; struct action_data; struct test_entry { char *name; int args; int (*fn) (struct atom *, struct action_data *); int (*parse_args) (struct test_entry *, struct atom *); }; /* * Type test specific definitions */ struct type_entry { int value; char type; }; /* * Action definitions */ # define FRAGMENT_ACTION 0 # define EXCLUDE_ACTION 1 # define FRAGMENTS_ACTION 2 # define NO_FRAGMENTS_ACTION 3 # define ALWAYS_FRAGS_ACTION 4 # define NO_ALWAYS_FRAGS_ACTION 5 # define COMPRESSED_ACTION 6 # define UNCOMPRESSED_ACTION 7 # define UID_ACTION 8 # define GID_ACTION 9 # define GUID_ACTION 10 # define MODE_ACTION 11 # define EMPTY_ACTION 12 # define MOVE_ACTION 13 /* * Define what file types each action operates over */ # define ACTION_DIR S_IFDIR # define ACTION_REG S_IFREG # define ACTION_ALL_LNK (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | \ S_IFIFO | S_IFLNK) # define ACTION_ALL (S_IFDIR | S_IFREG | S_IFBLK | S_IFCHR | S_IFSOCK | S_IFIFO) struct action_entry { char *name; int type; int args; int file_types; int (*parse_args) (struct action_entry *, int, char **, void **); void (*run_action) (struct action *, struct dir_ent *); }; struct action_data { int depth; char *name; char *pathname; char *subpath; struct stat *buf; }; struct action { int type; struct action_entry *action; int args; char **argv; struct expr *expr; void *data; }; /* * Uid/gid action specific definitions */ struct uid_info { uid_t uid; }; struct gid_info { gid_t gid; }; struct guid_info { uid_t uid; gid_t gid; }; /* * Mode action specific definitions */ # define ACTION_MODE_SET 0 # define ACTION_MODE_ADD 1 # define ACTION_MODE_REM 2 # define ACTION_MODE_OCT 3 struct mode_data { struct mode_data *next; int operation; int mode; unsigned int mask; char X; }; /* * Empty action specific definitions */ # define EMPTY_ALL 0 # define EMPTY_SOURCE 1 # define EMPTY_EXCLUDED 2 struct empty_data { int val; }; /* * Move action specific definitions */ # define ACTION_MOVE_RENAME 1 # define ACTION_MOVE_MOVE 2 struct move_ent { int ops; struct dir_ent *dir_ent; char *name; struct dir_info *dest; struct move_ent *next; }; /* * External function definitions */ extern int parse_action(char *); extern void dump_actions(); extern void *eval_frag_actions(struct dir_ent *); extern void *get_frag_action(void *); extern int eval_exclude_actions(char *, char *, char *, struct stat *, int); extern void eval_actions(struct dir_ent *); extern int eval_empty_actions(struct dir_ent *dir_ent); extern void eval_move_actions(struct dir_info *, struct dir_ent *); extern void do_move_actions(); extern int read_bytes(int, void *, int); extern int actions(); extern int move_actions(); extern int empty_actions(); extern int read_action_file(char *); extern int exclude_actions(); #endif ================================================ FILE: include/squashfs/caches-queues-lists.h ================================================ #ifndef CACHES_QUEUES_LISTS_H # define CACHES_QUEUES_LISTS_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * caches-queues-lists.h */ # define INSERT_LIST(NAME, TYPE) \ void insert_##NAME##_list(TYPE **list, TYPE *entry) { \ if(*list) { \ entry->NAME##_next = *list; \ entry->NAME##_prev = (*list)->NAME##_prev; \ (*list)->NAME##_prev->NAME##_next = entry; \ (*list)->NAME##_prev = entry; \ } else { \ *list = entry; \ entry->NAME##_prev = entry->NAME##_next = entry; \ } \ } # define REMOVE_LIST(NAME, TYPE) \ void remove_##NAME##_list(TYPE **list, TYPE *entry) { \ if(entry->NAME##_prev == entry && entry->NAME##_next == entry) { \ /* only this entry in the list */ \ *list = NULL; \ } else if(entry->NAME##_prev != NULL && entry->NAME##_next != NULL) { \ /* more than one entry in the list */ \ entry->NAME##_next->NAME##_prev = entry->NAME##_prev; \ entry->NAME##_prev->NAME##_next = entry->NAME##_next; \ if(*list == entry) \ *list = entry->NAME##_next; \ } \ entry->NAME##_prev = entry->NAME##_next = NULL; \ } # define INSERT_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \ void insert_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \ { \ int hash = HASH_FUNCTION(entry->FIELD); \ \ entry->LINK##_next = container->hash_table[hash]; \ container->hash_table[hash] = entry; \ entry->LINK##_prev = NULL; \ if(entry->LINK##_next) \ entry->LINK##_next->LINK##_prev = entry; \ } # define REMOVE_HASH_TABLE(NAME, TYPE, HASH_FUNCTION, FIELD, LINK) \ void remove_##NAME##_hash_table(TYPE *container, struct file_buffer *entry) \ { \ if(entry->LINK##_prev) \ entry->LINK##_prev->LINK##_next = entry->LINK##_next; \ else \ container->hash_table[HASH_FUNCTION(entry->FIELD)] = \ entry->LINK##_next; \ if(entry->LINK##_next) \ entry->LINK##_next->LINK##_prev = entry->LINK##_prev; \ \ entry->LINK##_prev = entry->LINK##_next = NULL; \ } # define HASH_SIZE 65536 # define CALCULATE_HASH(n) ((n) & 0xffff) /* struct describing a cache entry passed between threads */ struct file_buffer { union { long long index; long long sequence; }; long long file_size; union { long long block; unsigned short checksum; }; struct cache *cache; union { struct file_info *dupl_start; struct file_buffer *hash_next; }; union { int duplicate; struct file_buffer *hash_prev; }; union { struct { struct file_buffer *free_next; struct file_buffer *free_prev; }; struct { struct file_buffer *seq_next; struct file_buffer *seq_prev; }; }; int size; int c_byte; char used; char fragment; char error; char locked; char wait_on_unlock; char noD; char data[0]; }; /* struct describing queues used to pass data between threads */ struct queue { int size; int readp; int writep; pthread_mutex_t mutex; pthread_cond_t empty; pthread_cond_t full; void **data; }; /* * struct describing seq_queues used to pass data between the read * thread and the deflate and main threads */ struct seq_queue { int fragment_count; int block_count; struct file_buffer *hash_table[HASH_SIZE]; pthread_mutex_t mutex; pthread_cond_t wait; }; /* Cache status struct. Caches are used to keep track of memory buffers passed between different threads */ struct cache { int max_buffers; int count; int buffer_size; int noshrink_lookup; int first_freelist; union { int used; int max_count; }; pthread_mutex_t mutex; pthread_cond_t wait_for_free; pthread_cond_t wait_for_unlock; struct file_buffer *free_list; struct file_buffer *hash_table[HASH_SIZE]; }; extern struct queue *queue_init(int); extern void queue_put(struct queue *, void *); extern void *queue_get(struct queue *); extern int queue_empty(struct queue *); extern void queue_flush(struct queue *); extern void dump_queue(struct queue *); extern struct seq_queue *seq_queue_init(); extern void seq_queue_put(struct seq_queue *, struct file_buffer *); extern void dump_seq_queue(struct seq_queue *, int); extern struct file_buffer *seq_queue_get(struct seq_queue *); extern void seq_queue_flush(struct seq_queue *); extern struct cache *cache_init(int, int, int, int); extern struct file_buffer *cache_lookup(struct cache *, long long); extern struct file_buffer *cache_get(struct cache *, long long); extern struct file_buffer *cache_get_nohash(struct cache *); extern void cache_hash(struct file_buffer *, long long); extern void cache_block_put(struct file_buffer *); extern void dump_cache(struct cache *); extern struct file_buffer *cache_get_nowait(struct cache *, long long); extern struct file_buffer *cache_lookup_nowait(struct cache *, long long, char *); extern void cache_wait_unlock(struct file_buffer *); extern void cache_unlock(struct file_buffer *); extern int first_freelist; #endif ================================================ FILE: include/squashfs/compressor.h ================================================ #ifndef COMPRESSOR_H # define COMPRESSOR_H /* * * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * compressor.h */ struct compressor { int id; char *name; int supported; int (*init) (void **, int, int); int (*compress) (void *, void *, void *, int, int, int *); int (*uncompress) (void *, void *, int, int, int *); int (*options) (char **, int); int (*options_post) (int); void *(*dump_options) (int, int *); int (*extract_options) (int, void *, int); int (*check_options) (int, void *, int); void (*display_options) (void *, int); void (*usage) (); }; extern struct compressor *lookup_compressor(char *); extern struct compressor *lookup_compressor_id(int); extern void display_compressors(char *, char *); extern void display_compressor_usage(char *); static inline int compressor_init(struct compressor *comp, void **stream, int block_size, int datablock) { if (comp->init == NULL) return 0; return comp->init(stream, block_size, datablock); } static inline int compressor_compress(struct compressor *comp, void *strm, void *dest, void *src, int size, int block_size, int *error) { return comp->compress(strm, dest, src, size, block_size, error); } static inline int compressor_uncompress(struct compressor *comp, void *dest, void *src, int size, int block_size, int *error) { return comp->uncompress(dest, src, size, block_size, error); } /* * For the following functions please see the lzo, lz4 or xz * compressors for commented examples of how they are used. */ static inline int compressor_options(struct compressor *comp, char *argv[], int argc) { if (comp->options == NULL) return -1; return comp->options(argv, argc); } static inline int compressor_options_post(struct compressor *comp, int block_size) { if (comp->options_post == NULL) return 0; return comp->options_post(block_size); } static inline void *compressor_dump_options(struct compressor *comp, int block_size, int *size) { if (comp->dump_options == NULL) return NULL; return comp->dump_options(block_size, size); } static inline int compressor_extract_options(struct compressor *comp, int block_size, void *buffer, int size) { if (comp->extract_options == NULL) return size ? -1 : 0; return comp->extract_options(block_size, buffer, size); } static inline int compressor_check_options(struct compressor *comp, int block_size, void *buffer, int size) { if (comp->check_options == NULL) return 0; return comp->check_options(block_size, buffer, size); } static inline void compressor_display_options(struct compressor *comp, void *buffer, int size) { if (comp->display_options != NULL) comp->display_options(buffer, size); } #endif ================================================ FILE: include/squashfs/error.h ================================================ #ifndef ERROR_H # define ERROR_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * error.h */ extern int exit_on_error; extern void prep_exit(); extern void progressbar_error(char *fmt, ...); extern void progressbar_info(char *fmt, ...); # ifdef SQUASHFS_TRACE # define TRACE(s, args...) \ do { \ progressbar_info("squashfs: "s, ## args);\ } while(0) # else # define TRACE(s, args...) # endif # define INFO(s, args...) \ do {\ if(!silent)\ progressbar_info(s, ## args);\ } while(0) # define ERROR(s, args...) \ do {\ progressbar_error(s, ## args); \ } while(0) # define ERROR_START(s, args...) \ do { \ disable_progress_bar(); \ fprintf(stderr, s, ## args); \ } while(0) # define ERROR_EXIT(s, args...) \ do {\ if (exit_on_error) { \ fprintf(stderr, "\n"); \ EXIT_MKSQUASHFS(); \ } else { \ fprintf(stderr, s, ## args); \ enable_progress_bar(); \ } \ } while(0) # define EXIT_MKSQUASHFS() \ do {\ prep_exit();\ exit(1);\ } while(0) # define BAD_ERROR(s, args...) \ do {\ progressbar_error("FATAL ERROR:" s, ##args); \ EXIT_MKSQUASHFS();\ } while(0) # define EXIT_UNSQUASH(s, args...) BAD_ERROR(s, ##args) # define MEM_ERROR() \ do {\ progressbar_error("FATAL ERROR: Out of memory (%s)\n", \ __func__); \ EXIT_MKSQUASHFS();\ } while(0) #endif ================================================ FILE: include/squashfs/gzip_wrapper.h ================================================ #ifndef GZIP_WRAPPER_H # define GZIP_WRAPPER_H /* * Squashfs * * Copyright (c) 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * gzip_wrapper.h * */ # if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # else # include # endif # if __BYTE_ORDER == __BIG_ENDIAN extern unsigned int inswap_le16(unsigned short); extern unsigned int inswap_le32(unsigned int); # define SQUASHFS_INSWAP_COMP_OPTS(s) { \ (s)->compression_level = inswap_le32((s)->compression_level); \ (s)->window_size = inswap_le16((s)->window_size); \ (s)->strategy = inswap_le16((s)->strategy); \ } # else # define SQUASHFS_INSWAP_COMP_OPTS(s) # endif /* Default compression */ # define GZIP_DEFAULT_COMPRESSION_LEVEL 9 # define GZIP_DEFAULT_WINDOW_SIZE 15 struct gzip_comp_opts { int compression_level; short window_size; short strategy; }; struct strategy { char *name; int strategy; int selected; }; struct gzip_strategy { int strategy; int length; void *buffer; }; struct gzip_stream { z_stream stream; int strategies; struct gzip_strategy strategy[0]; }; #endif ================================================ FILE: include/squashfs/info.h ================================================ #ifndef INFO_H # define INFO_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * info.h */ extern void disable_info(); extern void update_info(struct dir_ent *); extern void init_info(); #endif ================================================ FILE: include/squashfs/lz4_wrapper.h ================================================ #ifndef LZ4_WRAPPER_H # define LZ4_WRAPPER_H /* * Squashfs * * Copyright (c) 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lz4_wrapper.h * */ # if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # else # include # endif # if __BYTE_ORDER == __BIG_ENDIAN extern unsigned int inswap_le32(unsigned int); # define SQUASHFS_INSWAP_COMP_OPTS(s) { \ (s)->version = inswap_le32((s)->version); \ (s)->flags = inswap_le32((s)->flags); \ } # else # define SQUASHFS_INSWAP_COMP_OPTS(s) # endif /* * Define the various stream formats recognised. * Currently omly legacy stream format is supported by the * kernel */ # define LZ4_LEGACY 1 # define LZ4_FLAGS_MASK 1 /* Define the compression flags recognised. */ # define LZ4_HC 1 struct lz4_comp_opts { int version; int flags; }; #endif ================================================ FILE: include/squashfs/lzo_wrapper.h ================================================ #ifndef LZO_WRAPPER_H # define LZO_WRAPPER_H /* * Squashfs * * Copyright (c) 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lzo_wrapper.h * */ # if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # else # include # endif # if __BYTE_ORDER == __BIG_ENDIAN extern unsigned int inswap_le32(unsigned int); # define SQUASHFS_INSWAP_COMP_OPTS(s) { \ (s)->algorithm = inswap_le32((s)->algorithm); \ (s)->compression_level = inswap_le32((s)->compression_level); \ } # else # define SQUASHFS_INSWAP_COMP_OPTS(s) # endif /* Define the compression flags recognised. */ # define SQUASHFS_LZO1X_1 0 # define SQUASHFS_LZO1X_1_11 1 # define SQUASHFS_LZO1X_1_12 2 # define SQUASHFS_LZO1X_1_15 3 # define SQUASHFS_LZO1X_999 4 /* Default compression level used by SQUASHFS_LZO1X_999 */ # define SQUASHFS_LZO1X_999_COMP_DEFAULT 8 struct lzo_comp_opts { int algorithm; int compression_level; }; struct lzo_algorithm { char *name; int size; int (*compress) (const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp, lzo_voidp); }; struct lzo_stream { void *workspace; void *buffer; }; # define LZO_MAX_EXPANSION(size) (size + (size / 16) + 64 + 3) int lzo1x_999_wrapper(const lzo_bytep, lzo_uint, lzo_bytep, lzo_uintp, lzo_voidp); #endif ================================================ FILE: include/squashfs/mksquashfs.h ================================================ #ifndef MKSQUASHFS_H # define MKSQUASHFS_H /* * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 * 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * mksquashfs.h * */ struct dir_info { char *pathname; char *subpath; unsigned int count; unsigned int directory_count; int depth; unsigned int excluded; char dir_is_ldir; struct dir_ent *dir_ent; struct dir_ent *list; DIR *linuxdir; }; struct dir_ent { char *name; char *source_name; char *nonstandard_pathname; struct inode_info *inode; struct dir_info *dir; struct dir_info *our_dir; struct dir_ent *next; }; struct inode_info { struct stat buf; struct inode_info *next; squashfs_inode inode; unsigned int inode_number; unsigned int nlink; int pseudo_id; char type; char read; char root_entry; char pseudo_file; char no_fragments; char always_use_fragments; char noD; char noF; }; /* in memory file info */ struct file_info { long long file_size; long long bytes; long long start; unsigned int *block_list; struct file_info *next; struct fragment *fragment; unsigned short checksum; unsigned short fragment_checksum; char have_frag_checksum; char have_checksum; }; /* fragment block data structures */ struct fragment { unsigned int index; int offset; int size; }; /* in memory uid tables */ # define ID_ENTRIES 256 # define ID_HASH(id) (id & (ID_ENTRIES - 1)) # define ISA_UID 1 # define ISA_GID 2 struct id { unsigned int id; int index; char flags; struct id *next; }; /* fragment to file mapping used when appending */ struct append_file { struct file_info *file; struct append_file *next; }; # define PSEUDO_FILE_OTHER 1 # define PSEUDO_FILE_PROCESS 2 # define IS_PSEUDO(a) ((a)->pseudo_file) # define IS_PSEUDO_PROCESS(a) ((a)->pseudo_file & PSEUDO_FILE_PROCESS) # define IS_PSEUDO_OTHER(a) ((a)->pseudo_file & PSEUDO_FILE_OTHER) /* * Amount of physical memory to use by default, and the default queue * ratios */ # define SQUASHFS_TAKE 4 # define SQUASHFS_READQ_MEM 4 # define SQUASHFS_BWRITEQ_MEM 4 # define SQUASHFS_FWRITEQ_MEM 4 /* * Lowest amount of physical memory considered viable for Mksquashfs * to run in Mbytes */ # define SQUASHFS_LOWMEM 64 /* offset of data in compressed metadata blocks (allowing room for * compressed size */ # define BLOCK_OFFSET 2 extern struct cache *reader_buffer, *fragment_buffer, *reserve_cache; struct cache *bwriter_buffer, *fwriter_buffer; extern struct queue *to_reader, *to_deflate, *to_writer, *from_writer, *to_frag, *locked_fragment, *to_process_frag; extern struct append_file **file_mapping; extern struct seq_queue *to_main; extern pthread_mutex_t fragment_mutex, dup_mutex; extern struct squashfs_fragment_entry *fragment_table; extern struct compressor *comp; extern int block_size; extern struct file_info *dupl[]; extern int read_fs_bytes(int, long long, int, void *); extern void add_file(long long, long long, long long, unsigned int *, int, unsigned int, int, int); extern struct id *create_id(unsigned int); extern unsigned int get_uid(unsigned int); extern unsigned int get_guid(unsigned int); extern int read_bytes(int, void *, int); extern unsigned short get_checksum_mem(char *, int); #endif ================================================ FILE: include/squashfs/process_fragments.h ================================================ #ifndef PROCESS_FRAGMENTS_H # define PROCESS_FRAGMENTS_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * process_fragments.h */ # define DUP_HASH(a) (a & 0xffff) extern void *frag_thrd(void *); #endif ================================================ FILE: include/squashfs/progressbar.h ================================================ #ifndef PROGRESSBAR_H # define PROGRESSBAR_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * progressbar.h */ extern void inc_progress_bar(); extern void dec_progress_bar(int count); extern void progress_bar_size(int count); extern void enable_progress_bar(); extern void disable_progress_bar(); extern void init_progress_bar(); extern void set_progressbar_state(int); #endif ================================================ FILE: include/squashfs/pseudo.h ================================================ #ifndef PSEUDO_H # define PSEUDO_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * pseudo.h */ struct pseudo_dev { char type; unsigned int mode; unsigned int uid; unsigned int gid; unsigned int major; unsigned int minor; int pseudo_id; char *command; }; struct pseudo_entry { char *name; char *pathname; struct pseudo *pseudo; struct pseudo_dev *dev; }; struct pseudo { int names; int count; struct pseudo_entry *name; }; extern int read_pseudo_def(char *); extern int read_pseudo_file(char *); extern struct pseudo *pseudo_subdir(char *, struct pseudo *); extern struct pseudo_entry *pseudo_readdir(struct pseudo *); extern struct pseudo_dev *get_pseudo_file(int); extern int pseudo_exec_file(struct pseudo_dev *, int *); extern struct pseudo *get_pseudo(); extern void dump_pseudos(); #endif ================================================ FILE: include/squashfs/read_fs.h ================================================ #ifndef READ_FS_H # define READ_FS_H /* * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * read_fs.h * */ extern struct compressor *read_super(int, struct squashfs_super_block *, char *); extern long long read_filesystem(char *, int, struct squashfs_super_block *, char **, char **, char **, char **, unsigned int *, unsigned int *, unsigned int *, unsigned int *, unsigned int *, int *, int *, int *, int *, int *, int *, long long *, unsigned int *, unsigned int *, unsigned int *, unsigned int *, void (push_directory_entry) (char *, squashfs_inode, int, int), struct squashfs_fragment_entry **, squashfs_inode **); #endif ================================================ FILE: include/squashfs/restore.h ================================================ #ifndef RESTORE_H # define RESTORE_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * restore.h */ extern pthread_t *init_restore_thread(); #endif ================================================ FILE: include/squashfs/sort.h ================================================ #ifndef SORT_H # define SORT_H /* * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * sort.h */ struct priority_entry { struct dir_ent *dir; struct priority_entry *next; }; extern int read_sort_file(char *, int, char *[]); extern void sort_files_and_write(struct dir_info *); extern void generate_file_priorities(struct dir_info *, int priority, struct stat *); extern struct priority_entry *priority_list[65536]; #endif ================================================ FILE: include/squashfs/squashfs_compat.h ================================================ #ifndef SQUASHFS_COMPAT # define SQUASHFS_COMPAT /* * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * squashfs_compat.h */ /* * definitions for structures on disk - layout 3.x */ # define SQUASHFS_CHECK 2 # define SQUASHFS_CHECK_DATA(flags) SQUASHFS_BIT(flags, \ SQUASHFS_CHECK) /* Max number of uids and gids */ # define SQUASHFS_UIDS 256 # define SQUASHFS_GUIDS 255 struct squashfs_super_block_3 { unsigned int s_magic; unsigned int inodes; unsigned int bytes_used_2; unsigned int uid_start_2; unsigned int guid_start_2; unsigned int inode_table_start_2; unsigned int directory_table_start_2; unsigned int s_major:16; unsigned int s_minor:16; unsigned int block_size_1:16; unsigned int block_log:16; unsigned int flags:8; unsigned int no_uids:8; unsigned int no_guids:8; int mkfs_time /* time of filesystem creation */ ; squashfs_inode root_inode; unsigned int block_size; unsigned int fragments; unsigned int fragment_table_start_2; long long bytes_used; long long uid_start; long long guid_start; long long inode_table_start; long long directory_table_start; long long fragment_table_start; long long lookup_table_start; } __attribute__ ((packed)); struct squashfs_dir_index_3 { unsigned int index; unsigned int start_block; unsigned char size; unsigned char name[0]; } __attribute__ ((packed)); struct squashfs_base_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; } __attribute__ ((packed)); struct squashfs_ipc_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; } __attribute__ ((packed)); struct squashfs_dev_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; unsigned short rdev; } __attribute__ ((packed)); struct squashfs_symlink_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; unsigned short symlink_size; char symlink[0]; } __attribute__ ((packed)); struct squashfs_reg_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; squashfs_block start_block; unsigned int fragment; unsigned int offset; unsigned int file_size; unsigned short block_list[0]; } __attribute__ ((packed)); struct squashfs_lreg_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; squashfs_block start_block; unsigned int fragment; unsigned int offset; long long file_size; unsigned short block_list[0]; } __attribute__ ((packed)); struct squashfs_dir_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int file_size:19; unsigned int offset:13; unsigned int start_block; unsigned int parent_inode; } __attribute__ ((packed)); struct squashfs_ldir_inode_header_3 { unsigned int inode_type:4; unsigned int mode:12; unsigned int uid:8; unsigned int guid:8; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int file_size:27; unsigned int offset:13; unsigned int start_block; unsigned int i_count:16; unsigned int parent_inode; struct squashfs_dir_index_3 index[0]; } __attribute__ ((packed)); union squashfs_inode_header_3 { struct squashfs_base_inode_header_3 base; struct squashfs_dev_inode_header_3 dev; struct squashfs_symlink_inode_header_3 symlink; struct squashfs_reg_inode_header_3 reg; struct squashfs_lreg_inode_header_3 lreg; struct squashfs_dir_inode_header_3 dir; struct squashfs_ldir_inode_header_3 ldir; struct squashfs_ipc_inode_header_3 ipc; }; struct squashfs_dir_entry_3 { unsigned int offset:13; unsigned int type:3; unsigned int size:8; int inode_number:16; char name[0]; } __attribute__ ((packed)); struct squashfs_dir_header_3 { unsigned int count:8; unsigned int start_block; unsigned int inode_number; } __attribute__ ((packed)); struct squashfs_fragment_entry_3 { long long start_block; unsigned int size; unsigned int pending; } __attribute__ ((packed)); typedef struct squashfs_super_block_3 squashfs_super_block_3; typedef struct squashfs_dir_index_3 squashfs_dir_index_3; typedef struct squashfs_base_inode_header_3 squashfs_base_inode_header_3; typedef struct squashfs_ipc_inode_header_3 squashfs_ipc_inode_header_3; typedef struct squashfs_dev_inode_header_3 squashfs_dev_inode_header_3; typedef struct squashfs_symlink_inode_header_3 squashfs_symlink_inode_header_3; typedef struct squashfs_reg_inode_header_3 squashfs_reg_inode_header_3; typedef struct squashfs_lreg_inode_header_3 squashfs_lreg_inode_header_3; typedef struct squashfs_dir_inode_header_3 squashfs_dir_inode_header_3; typedef struct squashfs_ldir_inode_header_3 squashfs_ldir_inode_header_3; typedef struct squashfs_dir_entry_3 squashfs_dir_entry_3; typedef struct squashfs_dir_header_3 squashfs_dir_header_3; typedef struct squashfs_fragment_entry_3 squashfs_fragment_entry_3; /* * macros to convert each packed bitfield structure from little endian to big * endian and vice versa. These are needed when creating or using a filesystem * on a machine with different byte ordering to the target architecture. * */ # define SQUASHFS_SWAP_START \ int bits;\ int b_pos;\ unsigned long long val;\ unsigned char *s;\ unsigned char *d; # define SQUASHFS_SWAP_SUPER_BLOCK_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block_3));\ SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\ SQUASHFS_SWAP((s)->inodes, d, 32, 32);\ SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\ SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\ SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\ SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\ SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\ SQUASHFS_SWAP((s)->s_major, d, 224, 16);\ SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\ SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\ SQUASHFS_SWAP((s)->block_log, d, 272, 16);\ SQUASHFS_SWAP((s)->flags, d, 288, 8);\ SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\ SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\ SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\ SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\ SQUASHFS_SWAP((s)->block_size, d, 408, 32);\ SQUASHFS_SWAP((s)->fragments, d, 440, 32);\ SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\ SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\ SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\ SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\ SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\ SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\ SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\ SQUASHFS_SWAP((s)->lookup_table_start, d, 888, 64);\ } # define SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ SQUASHFS_SWAP((s)->inode_number, d, 64, 32); # define SQUASHFS_SWAP_BASE_INODE_HEADER_3(s, d, n) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, n)\ } # define SQUASHFS_SWAP_IPC_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_ipc_inode_header_3))\ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ } # define SQUASHFS_SWAP_DEV_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_dev_inode_header_3)); \ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ SQUASHFS_SWAP((s)->rdev, d, 128, 16);\ } # define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_symlink_inode_header_3));\ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\ } # define SQUASHFS_SWAP_REG_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_reg_inode_header_3));\ SQUASHFS_SWAP((s)->start_block, d, 96, 64);\ SQUASHFS_SWAP((s)->fragment, d, 160, 32);\ SQUASHFS_SWAP((s)->offset, d, 192, 32);\ SQUASHFS_SWAP((s)->file_size, d, 224, 32);\ } # define SQUASHFS_SWAP_LREG_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_lreg_inode_header_3));\ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ SQUASHFS_SWAP((s)->start_block, d, 128, 64);\ SQUASHFS_SWAP((s)->fragment, d, 192, 32);\ SQUASHFS_SWAP((s)->offset, d, 224, 32);\ SQUASHFS_SWAP((s)->file_size, d, 256, 64);\ } # define SQUASHFS_SWAP_DIR_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_dir_inode_header_3));\ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ SQUASHFS_SWAP((s)->file_size, d, 128, 19);\ SQUASHFS_SWAP((s)->offset, d, 147, 13);\ SQUASHFS_SWAP((s)->start_block, d, 160, 32);\ SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\ } # define SQUASHFS_SWAP_LDIR_INODE_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_3(s, d, \ sizeof(struct squashfs_ldir_inode_header_3));\ SQUASHFS_SWAP((s)->nlink, d, 96, 32);\ SQUASHFS_SWAP((s)->file_size, d, 128, 27);\ SQUASHFS_SWAP((s)->offset, d, 155, 13);\ SQUASHFS_SWAP((s)->start_block, d, 168, 32);\ SQUASHFS_SWAP((s)->i_count, d, 200, 16);\ SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\ } # define SQUASHFS_SWAP_DIR_INDEX_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_3));\ SQUASHFS_SWAP((s)->index, d, 0, 32);\ SQUASHFS_SWAP((s)->start_block, d, 32, 32);\ SQUASHFS_SWAP((s)->size, d, 64, 8);\ } # define SQUASHFS_SWAP_DIR_HEADER_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_3));\ SQUASHFS_SWAP((s)->count, d, 0, 8);\ SQUASHFS_SWAP((s)->start_block, d, 8, 32);\ SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\ } # define SQUASHFS_SWAP_DIR_ENTRY_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_3));\ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ SQUASHFS_SWAP((s)->type, d, 13, 3);\ SQUASHFS_SWAP((s)->size, d, 16, 8);\ SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\ } # define SQUASHFS_SWAP_INODE_T_3(s, d) SQUASHFS_SWAP_LONG_LONGS_3(s, d, 1) # define SQUASHFS_SWAP_SHORTS_3(s, d, n) {\ int entry;\ int bit_position;\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 2);\ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ 16)\ SQUASHFS_SWAP(s[entry], d, bit_position, 16);\ } # define SQUASHFS_SWAP_INTS_3(s, d, n) {\ int entry;\ int bit_position;\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 4);\ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ 32)\ SQUASHFS_SWAP(s[entry], d, bit_position, 32);\ } # define SQUASHFS_SWAP_LONG_LONGS_3(s, d, n) {\ int entry;\ int bit_position;\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * 8);\ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ 64)\ SQUASHFS_SWAP(s[entry], d, bit_position, 64);\ } # define SQUASHFS_SWAP_DATA(s, d, n, bits) {\ int entry;\ int bit_position;\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, n * bits / 8);\ for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \ bits)\ SQUASHFS_SWAP(s[entry], d, bit_position, bits);\ } # define SQUASHFS_SWAP_FRAGMENT_INDEXES_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n) # define SQUASHFS_SWAP_LOOKUP_BLOCKS_3(s, d, n) SQUASHFS_SWAP_LONG_LONGS_3(s, d, n) # define SQUASHFS_SWAP_FRAGMENT_ENTRY_3(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_3));\ SQUASHFS_SWAP((s)->start_block, d, 0, 64);\ SQUASHFS_SWAP((s)->size, d, 64, 32);\ } /* fragment and fragment table defines */ # define SQUASHFS_FRAGMENT_BYTES_3(A) ((A) * sizeof(struct squashfs_fragment_entry_3)) # define SQUASHFS_FRAGMENT_INDEX_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_OFFSET_3(A) (SQUASHFS_FRAGMENT_BYTES_3(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEXES_3(A) ((SQUASHFS_FRAGMENT_BYTES_3(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_BYTES_3(A) (SQUASHFS_FRAGMENT_INDEXES_3(A) *\ sizeof(long long)) /* * definitions for structures on disk - layout 1.x */ # define SQUASHFS_TYPES 5 # define SQUASHFS_IPC_TYPE 0 struct squashfs_base_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ } __attribute__ ((packed)); struct squashfs_ipc_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int type:4; unsigned int offset:4; } __attribute__ ((packed)); struct squashfs_dev_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short rdev; } __attribute__ ((packed)); struct squashfs_symlink_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned short symlink_size; char symlink[0]; } __attribute__ ((packed)); struct squashfs_reg_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ int mtime; unsigned int start_block; unsigned int file_size:32; unsigned short block_list[0]; } __attribute__ ((packed)); struct squashfs_dir_inode_header_1 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:4; /* index into uid table */ unsigned int guid:4; /* index into guid table */ unsigned int file_size:19; unsigned int offset:13; int mtime; unsigned int start_block:24; } __attribute__ ((packed)); union squashfs_inode_header_1 { struct squashfs_base_inode_header_1 base; struct squashfs_dev_inode_header_1 dev; struct squashfs_symlink_inode_header_1 symlink; struct squashfs_reg_inode_header_1 reg; struct squashfs_dir_inode_header_1 dir; struct squashfs_ipc_inode_header_1 ipc; }; typedef struct squashfs_dir_index_1 squashfs_dir_index_1; typedef struct squashfs_base_inode_header_1 squashfs_base_inode_header_1; typedef struct squashfs_ipc_inode_header_1 squashfs_ipc_inode_header_1; typedef struct squashfs_dev_inode_header_1 squashfs_dev_inode_header_1; typedef struct squashfs_symlink_inode_header_1 squashfs_symlink_inode_header_1; typedef struct squashfs_reg_inode_header_1 squashfs_reg_inode_header_1; typedef struct squashfs_dir_inode_header_1 squashfs_dir_inode_header_1; # define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 4);\ SQUASHFS_SWAP((s)->guid, d, 20, 4); # define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\ } # define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ sizeof(struct squashfs_ipc_inode_header_1));\ SQUASHFS_SWAP((s)->type, d, 24, 4);\ SQUASHFS_SWAP((s)->offset, d, 28, 4);\ } # define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ sizeof(struct squashfs_dev_inode_header_1));\ SQUASHFS_SWAP((s)->rdev, d, 24, 16);\ } # define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ sizeof(struct squashfs_symlink_inode_header_1));\ SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\ } # define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ sizeof(struct squashfs_reg_inode_header_1));\ SQUASHFS_SWAP((s)->mtime, d, 24, 32);\ SQUASHFS_SWAP((s)->start_block, d, 56, 32);\ SQUASHFS_SWAP((s)->file_size, d, 88, 32);\ } # define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \ sizeof(struct squashfs_dir_inode_header_1));\ SQUASHFS_SWAP((s)->file_size, d, 24, 19);\ SQUASHFS_SWAP((s)->offset, d, 43, 13);\ SQUASHFS_SWAP((s)->mtime, d, 56, 32);\ SQUASHFS_SWAP((s)->start_block, d, 88, 24);\ } /* * definitions for structures on disk - layout 2.x */ struct squashfs_dir_index_2 { unsigned int index:27; unsigned int start_block:29; unsigned char size; unsigned char name[0]; } __attribute__ ((packed)); struct squashfs_base_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ } __attribute__ ((packed)); struct squashfs_ipc_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ } __attribute__ ((packed)); struct squashfs_dev_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ unsigned short rdev; } __attribute__ ((packed)); struct squashfs_symlink_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ unsigned short symlink_size; char symlink[0]; } __attribute__ ((packed)); struct squashfs_reg_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ int mtime; unsigned int start_block; unsigned int fragment; unsigned int offset; unsigned int file_size:32; unsigned short block_list[0]; } __attribute__ ((packed)); struct squashfs_dir_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ unsigned int file_size:19; unsigned int offset:13; int mtime; unsigned int start_block:24; } __attribute__ ((packed)); struct squashfs_ldir_inode_header_2 { unsigned int inode_type:4; unsigned int mode:12; /* protection */ unsigned int uid:8; /* index into uid table */ unsigned int guid:8; /* index into guid table */ unsigned int file_size:27; unsigned int offset:13; int mtime; unsigned int start_block:24; unsigned int i_count:16; struct squashfs_dir_index_2 index[0]; } __attribute__ ((packed)); union squashfs_inode_header_2 { struct squashfs_base_inode_header_2 base; struct squashfs_dev_inode_header_2 dev; struct squashfs_symlink_inode_header_2 symlink; struct squashfs_reg_inode_header_2 reg; struct squashfs_dir_inode_header_2 dir; struct squashfs_ldir_inode_header_2 ldir; struct squashfs_ipc_inode_header_2 ipc; }; struct squashfs_dir_header_2 { unsigned int count:8; unsigned int start_block:24; } __attribute__ ((packed)); struct squashfs_dir_entry_2 { unsigned int offset:13; unsigned int type:3; unsigned int size:8; char name[0]; } __attribute__ ((packed)); struct squashfs_fragment_entry_2 { unsigned int start_block; unsigned int size; } __attribute__ ((packed)); typedef struct squashfs_dir_index_2 squashfs_dir_index_2; typedef struct squashfs_base_inode_header_2 squashfs_base_inode_header_2; typedef struct squashfs_ipc_inode_header_2 squashfs_ipc_inode_header_2; typedef struct squashfs_dev_inode_header_2 squashfs_dev_inode_header_2; typedef struct squashfs_symlink_inode_header_2 squashfs_symlink_inode_header_2; typedef struct squashfs_reg_inode_header_2 squashfs_reg_inode_header_2; typedef struct squashfs_lreg_inode_header_2 squashfs_lreg_inode_header_2; typedef struct squashfs_dir_inode_header_2 squashfs_dir_inode_header_2; typedef struct squashfs_ldir_inode_header_2 squashfs_ldir_inode_header_2; typedef struct squashfs_dir_entry_2 squashfs_dir_entry_2; typedef struct squashfs_dir_header_2 squashfs_dir_header_2; typedef struct squashfs_fragment_entry_2 squashfs_fragment_entry_2; # define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ SQUASHFS_MEMSET(s, d, n);\ SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\ SQUASHFS_SWAP((s)->mode, d, 4, 12);\ SQUASHFS_SWAP((s)->uid, d, 16, 8);\ SQUASHFS_SWAP((s)->guid, d, 24, 8);\ # define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\ } # define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \ SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2)) # define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ sizeof(struct squashfs_dev_inode_header_2)); \ SQUASHFS_SWAP((s)->rdev, d, 32, 16);\ } # define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ sizeof(struct squashfs_symlink_inode_header_2));\ SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\ } # define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ sizeof(struct squashfs_reg_inode_header_2));\ SQUASHFS_SWAP((s)->mtime, d, 32, 32);\ SQUASHFS_SWAP((s)->start_block, d, 64, 32);\ SQUASHFS_SWAP((s)->fragment, d, 96, 32);\ SQUASHFS_SWAP((s)->offset, d, 128, 32);\ SQUASHFS_SWAP((s)->file_size, d, 160, 32);\ } # define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ sizeof(struct squashfs_dir_inode_header_2));\ SQUASHFS_SWAP((s)->file_size, d, 32, 19);\ SQUASHFS_SWAP((s)->offset, d, 51, 13);\ SQUASHFS_SWAP((s)->mtime, d, 64, 32);\ SQUASHFS_SWAP((s)->start_block, d, 96, 24);\ } # define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \ sizeof(struct squashfs_ldir_inode_header_2));\ SQUASHFS_SWAP((s)->file_size, d, 32, 27);\ SQUASHFS_SWAP((s)->offset, d, 59, 13);\ SQUASHFS_SWAP((s)->mtime, d, 72, 32);\ SQUASHFS_SWAP((s)->start_block, d, 104, 24);\ SQUASHFS_SWAP((s)->i_count, d, 128, 16);\ } # define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\ SQUASHFS_SWAP((s)->index, d, 0, 27);\ SQUASHFS_SWAP((s)->start_block, d, 27, 29);\ SQUASHFS_SWAP((s)->size, d, 56, 8);\ } # define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\ SQUASHFS_SWAP((s)->count, d, 0, 8);\ SQUASHFS_SWAP((s)->start_block, d, 8, 24);\ } # define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\ SQUASHFS_SWAP((s)->offset, d, 0, 13);\ SQUASHFS_SWAP((s)->type, d, 13, 3);\ SQUASHFS_SWAP((s)->size, d, 16, 8);\ } # define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\ SQUASHFS_SWAP_START\ SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\ SQUASHFS_SWAP((s)->start_block, d, 0, 32);\ SQUASHFS_SWAP((s)->size, d, 32, 32);\ } # define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS_3(s, d, n) /* fragment and fragment table defines */ # define SQUASHFS_FRAGMENT_BYTES_2(A) ((A) * sizeof(struct squashfs_fragment_entry_2)) # define SQUASHFS_FRAGMENT_INDEX_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A) (SQUASHFS_FRAGMENT_BYTES_2(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEXES_2(A) ((SQUASHFS_FRAGMENT_BYTES_2(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A) (SQUASHFS_FRAGMENT_INDEXES_2(A) *\ sizeof(int)) /* * macros used to swap each structure entry, taking into account * bitfields and different bitfield placing conventions on differing architectures */ # if __BYTE_ORDER == __BIG_ENDIAN /* convert from big endian to little endian */ # define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, b_pos) # else /* convert from little endian to big endian */ # define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, tbits, 64 - tbits - b_pos) # endif # define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\ b_pos = pos % 8;\ val = 0;\ s = (unsigned char *)p + (pos / 8);\ d = ((unsigned char *) &val) + 7;\ for(bits = 0; bits < (tbits + b_pos); bits += 8) \ *d-- = *s++;\ value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\ } # define SQUASHFS_MEMSET(s, d, n) memset(s, 0, n); #endif ================================================ FILE: include/squashfs/squashfs_fs.h ================================================ #ifndef SQUASHFS_FS # define SQUASHFS_FS /* * Squashfs * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, * 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * squashfs_fs.h */ # define SQUASHFS_CACHED_FRAGMENTS CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE # define SQUASHFS_MAJOR 4 # define SQUASHFS_MINOR 0 # define SQUASHFS_MAGIC 0x73717368 # define SQUASHFS_MAGIC_SWAP 0x68737173 # define SQUASHFS_START 0 /* size of metadata (inode and directory) blocks */ # define SQUASHFS_METADATA_SIZE 8192 # define SQUASHFS_METADATA_LOG 13 /* default size of data blocks */ # define SQUASHFS_FILE_SIZE 131072 # define SQUASHFS_FILE_MAX_SIZE 1048576 # define SQUASHFS_FILE_MAX_LOG 20 /* Max number of uids and gids */ # define SQUASHFS_IDS 65536 /* Max length of filename (not 255) */ # define SQUASHFS_NAME_LEN 256 # define SQUASHFS_INVALID ((long long) 0xffffffffffff) # define SQUASHFS_INVALID_FRAG ((unsigned int) 0xffffffff) # define SQUASHFS_INVALID_XATTR ((unsigned int) 0xffffffff) # define SQUASHFS_INVALID_BLK ((long long) -1) # define SQUASHFS_USED_BLK ((long long) -2) /* Filesystem flags */ # define SQUASHFS_NOI 0 # define SQUASHFS_NOD 1 # define SQUASHFS_CHECK 2 # define SQUASHFS_NOF 3 # define SQUASHFS_NO_FRAG 4 # define SQUASHFS_ALWAYS_FRAG 5 # define SQUASHFS_DUPLICATE 6 # define SQUASHFS_EXPORT 7 # define SQUASHFS_NOX 8 # define SQUASHFS_NO_XATTR 9 # define SQUASHFS_COMP_OPT 10 # define SQUASHFS_BIT(flag, bit) ((flag >> bit) & 1) # define SQUASHFS_UNCOMPRESSED_INODES(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NOI) # define SQUASHFS_UNCOMPRESSED_DATA(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NOD) # define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NOF) # define SQUASHFS_NO_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NO_FRAG) # define SQUASHFS_ALWAYS_FRAGMENTS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_ALWAYS_FRAG) # define SQUASHFS_DUPLICATES(flags) SQUASHFS_BIT(flags, \ SQUASHFS_DUPLICATE) # define SQUASHFS_EXPORTABLE(flags) SQUASHFS_BIT(flags, \ SQUASHFS_EXPORT) # define SQUASHFS_UNCOMPRESSED_XATTRS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NOX) # define SQUASHFS_NO_XATTRS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_NO_XATTR) # define SQUASHFS_COMP_OPTS(flags) SQUASHFS_BIT(flags, \ SQUASHFS_COMP_OPT) # define SQUASHFS_MKFLAGS(noi, nod, nof, nox, no_frag, always_frag, \ duplicate_checking, exportable, no_xattr, comp_opt) (noi | \ (nod << 1) | (nof << 3) | (no_frag << 4) | \ (always_frag << 5) | (duplicate_checking << 6) | \ (exportable << 7) | (nox << 8) | (no_xattr << 9) | \ (comp_opt << 10)) /* Max number of types and file types */ # define SQUASHFS_DIR_TYPE 1 # define SQUASHFS_FILE_TYPE 2 # define SQUASHFS_SYMLINK_TYPE 3 # define SQUASHFS_BLKDEV_TYPE 4 # define SQUASHFS_CHRDEV_TYPE 5 # define SQUASHFS_FIFO_TYPE 6 # define SQUASHFS_SOCKET_TYPE 7 # define SQUASHFS_LDIR_TYPE 8 # define SQUASHFS_LREG_TYPE 9 # define SQUASHFS_LSYMLINK_TYPE 10 # define SQUASHFS_LBLKDEV_TYPE 11 # define SQUASHFS_LCHRDEV_TYPE 12 # define SQUASHFS_LFIFO_TYPE 13 # define SQUASHFS_LSOCKET_TYPE 14 /* Xattr types */ # define SQUASHFS_XATTR_USER 0 # define SQUASHFS_XATTR_TRUSTED 1 # define SQUASHFS_XATTR_SECURITY 2 # define SQUASHFS_XATTR_VALUE_OOL 256 # define SQUASHFS_XATTR_PREFIX_MASK 0xff /* Flag whether block is compressed or uncompressed, bit is set if block is * uncompressed */ # define SQUASHFS_COMPRESSED_BIT (1 << 15) # define SQUASHFS_COMPRESSED_SIZE(B) (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \ (B) & ~SQUASHFS_COMPRESSED_BIT : SQUASHFS_COMPRESSED_BIT) # define SQUASHFS_COMPRESSED(B) (!((B) & SQUASHFS_COMPRESSED_BIT)) # define SQUASHFS_COMPRESSED_BIT_BLOCK (1 << 24) # define SQUASHFS_COMPRESSED_SIZE_BLOCK(B) ((B) & \ ~SQUASHFS_COMPRESSED_BIT_BLOCK) # define SQUASHFS_COMPRESSED_BLOCK(B) (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK)) /* * Inode number ops. Inodes consist of a compressed block number, and an * uncompressed offset within that block */ # define SQUASHFS_INODE_BLK(a) ((unsigned int) ((a) >> 16)) # define SQUASHFS_INODE_OFFSET(a) ((unsigned int) ((a) & 0xffff)) # define SQUASHFS_MKINODE(A, B) ((squashfs_inode)(((squashfs_inode) (A)\ << 16) + (B))) /* Compute 32 bit VFS inode number from squashfs inode number */ # define SQUASHFS_MK_VFS_INODE(a, b) ((unsigned int) (((a) << 8) + \ ((b) >> 2) + 1)) /* Translate between VFS mode and squashfs mode */ # define SQUASHFS_MODE(a) ((a) & 0xfff) /* fragment and fragment table defines */ # define SQUASHFS_FRAGMENT_BYTES(A) ((A) * \ sizeof(struct squashfs_fragment_entry)) # define SQUASHFS_FRAGMENT_INDEX(A) (SQUASHFS_FRAGMENT_BYTES(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_OFFSET(A) (SQUASHFS_FRAGMENT_BYTES(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEXES(A) ((SQUASHFS_FRAGMENT_BYTES(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_FRAGMENT_INDEX_BYTES(A) (SQUASHFS_FRAGMENT_INDEXES(A) *\ sizeof(long long)) /* inode lookup table defines */ # define SQUASHFS_LOOKUP_BYTES(A) ((A) * sizeof(squashfs_inode)) # define SQUASHFS_LOOKUP_BLOCK(A) (SQUASHFS_LOOKUP_BYTES(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_LOOKUP_BLOCK_OFFSET(A) (SQUASHFS_LOOKUP_BYTES(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_LOOKUP_BLOCKS(A) ((SQUASHFS_LOOKUP_BYTES(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_LOOKUP_BLOCK_BYTES(A) (SQUASHFS_LOOKUP_BLOCKS(A) *\ sizeof(long long)) /* uid lookup table defines */ # define SQUASHFS_ID_BYTES(A) ((A) * sizeof(unsigned int)) # define SQUASHFS_ID_BLOCK(A) (SQUASHFS_ID_BYTES(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_ID_BLOCK_OFFSET(A) (SQUASHFS_ID_BYTES(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_ID_BLOCKS(A) ((SQUASHFS_ID_BYTES(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ sizeof(long long)) /* xattr id lookup table defines */ # define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) # define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \ SQUASHFS_METADATA_SIZE - 1) / \ SQUASHFS_METADATA_SIZE) # define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\ sizeof(long long)) # define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16)) # define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff)) /* cached data constants for filesystem */ # define SQUASHFS_CACHED_BLKS 8 # define SQUASHFS_MAX_FILE_SIZE_LOG 64 # define SQUASHFS_MAX_FILE_SIZE ((long long) 1 << \ (SQUASHFS_MAX_FILE_SIZE_LOG - 2)) # define SQUASHFS_MARKER_BYTE 0xff /* meta index cache */ # define SQUASHFS_META_INDEXES (SQUASHFS_METADATA_SIZE / sizeof(unsigned int)) # define SQUASHFS_META_ENTRIES 31 # define SQUASHFS_META_NUMBER 8 # define SQUASHFS_SLOTS 4 struct meta_entry { long long data_block; unsigned int index_block; unsigned short offset; unsigned short pad; }; struct meta_index { unsigned int inode_number; unsigned int offset; unsigned short entries; unsigned short skip; unsigned short locked; unsigned short pad; struct meta_entry meta_entry[SQUASHFS_META_ENTRIES]; }; /* * definitions for structures on disk */ typedef long long squashfs_block; typedef long long squashfs_inode; # define ZLIB_COMPRESSION 1 # define LZMA_COMPRESSION 2 # define LZO_COMPRESSION 3 # define XZ_COMPRESSION 4 # define LZ4_COMPRESSION 5 struct squashfs_super_block { unsigned int s_magic; unsigned int inodes; int mkfs_time /* time of filesystem creation */ ; unsigned int block_size; unsigned int fragments; unsigned short compression; unsigned short block_log; unsigned short flags; unsigned short no_ids; unsigned short s_major; unsigned short s_minor; squashfs_inode root_inode; long long bytes_used; long long id_table_start; long long xattr_id_table_start; long long inode_table_start; long long directory_table_start; long long fragment_table_start; long long lookup_table_start; }; struct squashfs_dir_index { unsigned int index; unsigned int start_block; unsigned int size; unsigned char name[0]; }; struct squashfs_base_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; }; struct squashfs_ipc_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; }; struct squashfs_lipc_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int xattr; }; struct squashfs_dev_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int rdev; }; struct squashfs_ldev_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int rdev; unsigned int xattr; }; struct squashfs_symlink_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int symlink_size; char symlink[0]; }; struct squashfs_reg_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int start_block; unsigned int fragment; unsigned int offset; unsigned int file_size; unsigned int block_list[0]; }; struct squashfs_lreg_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; squashfs_block start_block; long long file_size; long long sparse; unsigned int nlink; unsigned int fragment; unsigned int offset; unsigned int xattr; unsigned int block_list[0]; }; struct squashfs_dir_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int start_block; unsigned int nlink; unsigned short file_size; unsigned short offset; unsigned int parent_inode; }; struct squashfs_ldir_inode_header { unsigned short inode_type; unsigned short mode; unsigned short uid; unsigned short guid; int mtime; unsigned int inode_number; unsigned int nlink; unsigned int file_size; unsigned int start_block; unsigned int parent_inode; unsigned short i_count; unsigned short offset; unsigned int xattr; struct squashfs_dir_index index[0]; }; union squashfs_inode_header { struct squashfs_base_inode_header base; struct squashfs_dev_inode_header dev; struct squashfs_ldev_inode_header ldev; struct squashfs_symlink_inode_header symlink; struct squashfs_reg_inode_header reg; struct squashfs_lreg_inode_header lreg; struct squashfs_dir_inode_header dir; struct squashfs_ldir_inode_header ldir; struct squashfs_ipc_inode_header ipc; struct squashfs_lipc_inode_header lipc; }; struct squashfs_dir_entry { unsigned short offset; short inode_number; unsigned short type; unsigned short size; char name[0]; }; struct squashfs_dir_header { unsigned int count; unsigned int start_block; unsigned int inode_number; }; struct squashfs_fragment_entry { long long start_block; unsigned int size; unsigned int unused; }; struct squashfs_xattr_entry { unsigned short type; unsigned short size; }; struct squashfs_xattr_val { unsigned int vsize; }; struct squashfs_xattr_id { long long xattr; unsigned int count; unsigned int size; }; struct squashfs_xattr_table { long long xattr_table_start; unsigned int xattr_ids; unsigned int unused; }; #endif ================================================ FILE: include/squashfs/squashfs_swap.h ================================================ #ifndef SQUASHFS_SWAP_H # define SQUASHFS_SWAP_H /* * Squashfs * * Copyright (c) 2008, 2009, 2010, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * squashfs_swap.h */ /* * macros to convert each stucture from big endian to little endian */ # if __BYTE_ORDER == __BIG_ENDIAN # include extern void swap_le16(void *, void *); extern void swap_le32(void *, void *); extern void swap_le64(void *, void *); extern void swap_le16_num(void *, void *, int); extern void swap_le32_num(void *, void *, int); extern void swap_le64_num(void *, void *, int); extern unsigned short inswap_le16(unsigned short); extern unsigned int inswap_le32(unsigned int); extern long long inswap_le64(long long); extern void inswap_le16_num(unsigned short *, int); extern void inswap_le32_num(unsigned int *, int); extern void inswap_le64_num(long long *, int); # define _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_FUNC) {\ SWAP_FUNC(32, s, d, s_magic, struct squashfs_super_block);\ SWAP_FUNC(32, s, d, inodes, struct squashfs_super_block);\ SWAP_FUNC##S(32, s, d, mkfs_time, struct squashfs_super_block);\ SWAP_FUNC(32, s, d, block_size, struct squashfs_super_block);\ SWAP_FUNC(32, s, d, fragments, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, compression, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, block_log, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, flags, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, no_ids, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, s_major, struct squashfs_super_block);\ SWAP_FUNC(16, s, d, s_minor, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, root_inode, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, bytes_used, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, id_table_start, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, xattr_id_table_start, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, inode_table_start, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, directory_table_start, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, fragment_table_start, struct squashfs_super_block);\ SWAP_FUNC(64, s, d, lookup_table_start, struct squashfs_super_block);\ } # define _SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_FUNC) {\ SWAP_FUNC(32, s, d, index, struct squashfs_dir_index);\ SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_index);\ SWAP_FUNC(32, s, d, size, struct squashfs_dir_index);\ } # define _SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_base_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_base_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_base_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_base_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_base_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_base_inode_header);\ } # define _SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_ipc_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_ipc_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_ipc_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_ipc_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ipc_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_ipc_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_ipc_inode_header);\ } # define _SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_lipc_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_lipc_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_lipc_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_lipc_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lipc_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_lipc_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_lipc_inode_header);\ SWAP_FUNC(32, s, d, xattr, struct squashfs_lipc_inode_header);\ } # define _SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_dev_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_dev_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_dev_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_dev_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dev_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_dev_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_dev_inode_header);\ SWAP_FUNC(32, s, d, rdev, struct squashfs_dev_inode_header);\ } # define _SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldev_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_ldev_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_ldev_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_ldev_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldev_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldev_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_ldev_inode_header);\ SWAP_FUNC(32, s, d, rdev, struct squashfs_ldev_inode_header);\ SWAP_FUNC(32, s, d, xattr, struct squashfs_ldev_inode_header);\ } # define _SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_symlink_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_symlink_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_symlink_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_symlink_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_symlink_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_symlink_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_symlink_inode_header);\ SWAP_FUNC(32, s, d, symlink_size, struct squashfs_symlink_inode_header);\ } # define _SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_reg_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_reg_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_reg_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_reg_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_reg_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_reg_inode_header);\ SWAP_FUNC(32, s, d, start_block, struct squashfs_reg_inode_header);\ SWAP_FUNC(32, s, d, fragment, struct squashfs_reg_inode_header);\ SWAP_FUNC(32, s, d, offset, struct squashfs_reg_inode_header);\ SWAP_FUNC(32, s, d, file_size, struct squashfs_reg_inode_header);\ } # define _SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_lreg_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_lreg_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_lreg_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_lreg_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_lreg_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_lreg_inode_header);\ SWAP_FUNC(64, s, d, start_block, struct squashfs_lreg_inode_header);\ SWAP_FUNC(64, s, d, file_size, struct squashfs_lreg_inode_header);\ SWAP_FUNC(64, s, d, sparse, struct squashfs_lreg_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_lreg_inode_header);\ SWAP_FUNC(32, s, d, fragment, struct squashfs_lreg_inode_header);\ SWAP_FUNC(32, s, d, offset, struct squashfs_lreg_inode_header);\ SWAP_FUNC(32, s, d, xattr, struct squashfs_lreg_inode_header);\ } # define _SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_dir_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_dir_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_dir_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_dir_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_dir_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_inode_header);\ SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_dir_inode_header);\ SWAP_FUNC(16, s, d, file_size, struct squashfs_dir_inode_header);\ SWAP_FUNC(16, s, d, offset, struct squashfs_dir_inode_header);\ SWAP_FUNC(32, s, d, parent_inode, struct squashfs_dir_inode_header);\ } # define _SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, inode_type, struct squashfs_ldir_inode_header);\ SWAP_FUNC(16, s, d, mode, struct squashfs_ldir_inode_header);\ SWAP_FUNC(16, s, d, uid, struct squashfs_ldir_inode_header);\ SWAP_FUNC(16, s, d, guid, struct squashfs_ldir_inode_header);\ SWAP_FUNC##S(32, s, d, mtime, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, nlink, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, file_size, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, start_block, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, parent_inode, struct squashfs_ldir_inode_header);\ SWAP_FUNC(16, s, d, i_count, struct squashfs_ldir_inode_header);\ SWAP_FUNC(16, s, d, offset, struct squashfs_ldir_inode_header);\ SWAP_FUNC(32, s, d, xattr, struct squashfs_ldir_inode_header);\ } # define _SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, offset, struct squashfs_dir_entry);\ SWAP_FUNC##S(16, s, d, inode_number, struct squashfs_dir_entry);\ SWAP_FUNC(16, s, d, type, struct squashfs_dir_entry);\ SWAP_FUNC(16, s, d, size, struct squashfs_dir_entry);\ } # define _SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_FUNC) {\ SWAP_FUNC(32, s, d, count, struct squashfs_dir_header);\ SWAP_FUNC(32, s, d, start_block, struct squashfs_dir_header);\ SWAP_FUNC(32, s, d, inode_number, struct squashfs_dir_header);\ } # define _SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_FUNC) {\ SWAP_FUNC(64, s, d, start_block, struct squashfs_fragment_entry);\ SWAP_FUNC(32, s, d, size, struct squashfs_fragment_entry);\ } # define _SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_FUNC) {\ SWAP_FUNC(16, s, d, type, struct squashfs_xattr_entry);\ SWAP_FUNC(16, s, d, size, struct squashfs_xattr_entry);\ } # define _SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_FUNC) {\ SWAP_FUNC(32, s, d, vsize, struct squashfs_xattr_val);\ } # define _SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_FUNC) {\ SWAP_FUNC(64, s, d, xattr, struct squashfs_xattr_id);\ SWAP_FUNC(32, s, d, count, struct squashfs_xattr_id);\ SWAP_FUNC(32, s, d, size, struct squashfs_xattr_id);\ } # define _SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_FUNC) {\ SWAP_FUNC(64, s, d, xattr_table_start, struct squashfs_xattr_table);\ SWAP_FUNC(32, s, d, xattr_ids, struct squashfs_xattr_table);\ } /* big endian architecture copy and swap macros */ # define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \ _SQUASHFS_SWAP_SUPER_BLOCK(s, d, SWAP_LE) # define SQUASHFS_SWAP_DIR_INDEX(s, d) \ _SQUASHFS_SWAP_DIR_INDEX(s, d, SWAP_LE) # define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_IPC_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_DEV_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_REG_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_LREG_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_DIR_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \ _SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_DIR_ENTRY(s, d) \ _SQUASHFS_SWAP_DIR_ENTRY(s, d, SWAP_LE) # define SQUASHFS_SWAP_DIR_HEADER(s, d) \ _SQUASHFS_SWAP_DIR_HEADER(s, d, SWAP_LE) # define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \ _SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d, SWAP_LE) # define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \ _SQUASHFS_SWAP_XATTR_ENTRY(s, d, SWAP_LE) # define SQUASHFS_SWAP_XATTR_VAL(s, d) \ _SQUASHFS_SWAP_XATTR_VAL(s, d, SWAP_LE) # define SQUASHFS_SWAP_XATTR_ID(s, d) \ _SQUASHFS_SWAP_XATTR_ID(s, d, SWAP_LE) # define SQUASHFS_SWAP_XATTR_TABLE(s, d) \ _SQUASHFS_SWAP_XATTR_TABLE(s, d, SWAP_LE) # define SWAP_LE(bits, s, d, field, type) \ SWAP_LE##bits(((void *)(s)) + offsetof(type, field), \ ((void *)(d)) + offsetof(type, field)) # define SWAP_LES(bits, s, d, field, type) \ SWAP_LE(bits, s, d, field, type) # define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) # define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \ SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_SWAP_SHORTS(s, d, n) swap_le16_num(s, d, n) # define SQUASHFS_SWAP_INTS(s, d, n) swap_le32_num(s, d, n) # define SQUASHFS_SWAP_LONG_LONGS(s, d, n) swap_le64_num(s, d, n) # define SWAP_LE16(s, d) swap_le16(s, d) # define SWAP_LE32(s, d) swap_le32(s, d) # define SWAP_LE64(s, d) swap_le64(s, d) /* big endian architecture swap in-place macros */ # define SQUASHFS_INSWAP_SUPER_BLOCK(s) \ _SQUASHFS_SWAP_SUPER_BLOCK(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_DIR_INDEX(s) \ _SQUASHFS_SWAP_DIR_INDEX(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_BASE_INODE_HEADER(s) \ _SQUASHFS_SWAP_BASE_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_IPC_INODE_HEADER(s) \ _SQUASHFS_SWAP_IPC_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s) \ _SQUASHFS_SWAP_LIPC_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_DEV_INODE_HEADER(s) \ _SQUASHFS_SWAP_DEV_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s) \ _SQUASHFS_SWAP_LDEV_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s) \ _SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_REG_INODE_HEADER(s) \ _SQUASHFS_SWAP_REG_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_LREG_INODE_HEADER(s) \ _SQUASHFS_SWAP_LREG_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_DIR_INODE_HEADER(s) \ _SQUASHFS_SWAP_DIR_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s) \ _SQUASHFS_SWAP_LDIR_INODE_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_DIR_ENTRY(s) \ _SQUASHFS_SWAP_DIR_ENTRY(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_DIR_HEADER(s) \ _SQUASHFS_SWAP_DIR_HEADER(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s) \ _SQUASHFS_SWAP_FRAGMENT_ENTRY(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_XATTR_ENTRY(s) \ _SQUASHFS_SWAP_XATTR_ENTRY(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_XATTR_VAL(s) \ _SQUASHFS_SWAP_XATTR_VAL(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_XATTR_ID(s) \ _SQUASHFS_SWAP_XATTR_ID(s, s, INSWAP_LE) # define SQUASHFS_INSWAP_XATTR_TABLE(s) \ _SQUASHFS_SWAP_XATTR_TABLE(s, s, INSWAP_LE) # define INSWAP_LE(bits, s, d, field, type) \ (s)->field = inswap_le##bits((s)->field) # define INSWAP_LES(bits, s, d, field, type) \ (s)->field = INSWAP_LES##bits((s)->field) # define INSWAP_LES16(num) (short) inswap_le16((unsigned short) (num)) # define INSWAP_LES32(num) (int) inswap_le32((unsigned int) (num)) # define SQUASHFS_INSWAP_INODE_T(s) s = inswap_le64(s) # define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) inswap_le64_num(s, n) # define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) inswap_le64_num(s, n) # define SQUASHFS_INSWAP_ID_BLOCKS(s, n) inswap_le64_num(s, n) # define SQUASHFS_INSWAP_SHORTS(s, n) inswap_le16_num(s, n) # define SQUASHFS_INSWAP_INTS(s, n) inswap_le32_num(s, n) # define SQUASHFS_INSWAP_LONG_LONGS(s, n) inswap_le64_num(s, n) # else /* little endian architecture, just copy */ # define SQUASHFS_SWAP_SUPER_BLOCK(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_super_block)) # define SQUASHFS_SWAP_DIR_INDEX(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_index)) # define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_base_inode_header)) # define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ipc_inode_header)) # define SQUASHFS_SWAP_LIPC_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lipc_inode_header)) # define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dev_inode_header)) # define SQUASHFS_SWAP_LDEV_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldev_inode_header)) # define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_symlink_inode_header)) # define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_reg_inode_header)) # define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_lreg_inode_header)) # define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_inode_header)) # define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_ldir_inode_header)) # define SQUASHFS_SWAP_DIR_ENTRY(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_entry)) # define SQUASHFS_SWAP_DIR_HEADER(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_dir_header)) # define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_fragment_entry)) # define SQUASHFS_SWAP_XATTR_ENTRY(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_entry)) # define SQUASHFS_SWAP_XATTR_VAL(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_val)) # define SQUASHFS_SWAP_XATTR_ID(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_id)) # define SQUASHFS_SWAP_XATTR_TABLE(s, d) \ SQUASHFS_MEMCPY(s, d, sizeof(struct squashfs_xattr_table)) # define SQUASHFS_SWAP_INODE_T(s, d) SQUASHFS_SWAP_LONG_LONGS(s, d, 1) # define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) \ SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_SWAP_LOOKUP_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_SWAP_ID_BLOCKS(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n) # define SQUASHFS_MEMCPY(s, d, n) memcpy(d, s, n) # define SQUASHFS_SWAP_SHORTS(s, d, n) memcpy(d, s, n * sizeof(short)) # define SQUASHFS_SWAP_INTS(s, d, n) memcpy(d, s, n * sizeof(int)) # define SQUASHFS_SWAP_LONG_LONGS(s, d, n) \ memcpy(d, s, n * sizeof(long long)) /* little endian architecture, data already in place so do nothing */ # define SQUASHFS_INSWAP_SUPER_BLOCK(s) # define SQUASHFS_INSWAP_DIR_INDEX(s) # define SQUASHFS_INSWAP_BASE_INODE_HEADER(s) # define SQUASHFS_INSWAP_IPC_INODE_HEADER(s) # define SQUASHFS_INSWAP_LIPC_INODE_HEADER(s) # define SQUASHFS_INSWAP_DEV_INODE_HEADER(s) # define SQUASHFS_INSWAP_LDEV_INODE_HEADER(s) # define SQUASHFS_INSWAP_SYMLINK_INODE_HEADER(s) # define SQUASHFS_INSWAP_REG_INODE_HEADER(s) # define SQUASHFS_INSWAP_LREG_INODE_HEADER(s) # define SQUASHFS_INSWAP_DIR_INODE_HEADER(s) # define SQUASHFS_INSWAP_LDIR_INODE_HEADER(s) # define SQUASHFS_INSWAP_DIR_ENTRY(s) # define SQUASHFS_INSWAP_DIR_HEADER(s) # define SQUASHFS_INSWAP_FRAGMENT_ENTRY(s) # define SQUASHFS_INSWAP_XATTR_ENTRY(s) # define SQUASHFS_INSWAP_XATTR_VAL(s) # define SQUASHFS_INSWAP_XATTR_ID(s) # define SQUASHFS_INSWAP_XATTR_TABLE(s) # define SQUASHFS_INSWAP_INODE_T(s) # define SQUASHFS_INSWAP_FRAGMENT_INDEXES(s, n) # define SQUASHFS_INSWAP_LOOKUP_BLOCKS(s, n) # define SQUASHFS_INSWAP_ID_BLOCKS(s, n) # define SQUASHFS_INSWAP_SHORTS(s, n) # define SQUASHFS_INSWAP_INTS(s, n) # define SQUASHFS_INSWAP_LONG_LONGS(s, n) # endif #endif ================================================ FILE: include/squashfs/unsquashfs.h ================================================ #ifndef UNSQUASHFS_H # define UNSQUASHFS_H /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquashfs.h */ # define TRUE 1 # define FALSE 0 # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # ifndef __APPLE__ # include # endif # if defined(__CYGWIN__) || defined(__APPLE__) # define FNM_EXTMATCH (1 << 5) # endif # if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # else # include # endif # include "squashfs_fs.h" # include "error.h" # define CALCULATE_HASH(start) (start & 0xffff) /* * Unified superblock containing fields for all superblocks */ struct super_block { struct squashfs_super_block s; /* fields only used by squashfs 3 and earlier layouts */ unsigned int no_uids; unsigned int no_guids; long long uid_start; long long guid_start; }; struct hash_table_entry { long long start; int bytes; struct hash_table_entry *next; }; struct inode { int blocks; char *block_ptr; long long data; int fragment; int frag_bytes; gid_t gid; int inode_number; int mode; int offset; long long start; char *symlink; time_t time; int type; uid_t uid; char sparse; unsigned int xattr; }; typedef struct squashfs_operations { struct dir *(*squashfs_opendir) (unsigned int block_start, unsigned int offset, struct inode ** i); void (*read_fragment) (unsigned int fragment, long long *start_block, int *size); int (*read_fragment_table) (long long *); void (*read_block_list) (unsigned int *block_list, char *block_ptr, int blocks); struct inode *(*read_inode) (unsigned int start_block, unsigned int offset); int (*read_uids_guids) (); } squashfs_operations; struct test { int mask; int value; int position; char mode; }; /* Cache status struct. Caches are used to keep track of memory buffers passed between different threads */ struct cache { int max_buffers; int count; int used; int buffer_size; int wait_free; int wait_pending; pthread_mutex_t mutex; pthread_cond_t wait_for_free; pthread_cond_t wait_for_pending; struct cache_entry *free_list; struct cache_entry *hash_table[65536]; }; /* struct describing a cache entry passed between threads */ struct cache_entry { struct cache *cache; long long block; int size; int used; int error; int pending; struct cache_entry *hash_next; struct cache_entry *hash_prev; struct cache_entry *free_next; struct cache_entry *free_prev; char *data; }; /* struct describing queues used to pass data between threads */ struct queue { int size; int readp; int writep; pthread_mutex_t mutex; pthread_cond_t empty; pthread_cond_t full; void **data; }; /* default size of fragment buffer in Mbytes */ # define FRAGMENT_BUFFER_DEFAULT 256 /* default size of data buffer in Mbytes */ # define DATA_BUFFER_DEFAULT 256 # define DIR_ENT_SIZE 16 struct dir_ent { char name[SQUASHFS_NAME_LEN + 1]; unsigned int start_block; unsigned int offset; unsigned int type; }; struct dir { int dir_count; int cur_entry; unsigned int mode; uid_t uid; gid_t guid; unsigned int mtime; unsigned int xattr; struct dir_ent *dirs; }; struct file_entry { int offset; int size; struct cache_entry *buffer; }; struct squashfs_file { int fd; int blocks; long long file_size; int mode; uid_t uid; gid_t gid; time_t time; char *pathname; char sparse; unsigned int xattr; }; struct path_entry { char *name; regex_t *preg; struct pathname *paths; }; struct pathname { int names; struct path_entry *name; }; struct pathnames { int count; struct pathname *path[0]; }; # define PATHS_ALLOC_SIZE 10 /* globals */ extern struct super_block sBlk; extern squashfs_operations s_ops; extern int swap; extern char *inode_table, *directory_table; extern struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; extern unsigned int *uid_table, *guid_table; extern pthread_mutex_t screen_mutex; extern int progress_enabled; extern int inode_number; extern int lookup_type[]; extern int fd; extern struct queue *to_reader, *to_inflate, *to_writer; extern struct cache *fragment_cache, *data_cache; /* unsquashfs.c */ extern int lookup_entry(struct hash_table_entry **, long long); extern int read_fs_bytes(int fd, long long, int, void *); extern int read_block(int, long long, long long *, int, void *); extern void enable_progress_bar(); extern void disable_progress_bar(); extern void dump_queue(struct queue *); extern void dump_cache(struct cache *); extern int is_squashfs(char *filename); extern int unsquashfs(char *squashfs, char *dest); /* unsquash-1.c */ extern void read_block_list_1(unsigned int *, char *, int); extern int read_fragment_table_1(long long *); extern struct inode *read_inode_1(unsigned int, unsigned int); extern struct dir *squashfs_opendir_1(unsigned int, unsigned int, struct inode **); extern int read_uids_guids_1(); /* unsquash-2.c */ extern void read_block_list_2(unsigned int *, char *, int); extern int read_fragment_table_2(long long *); extern void read_fragment_2(unsigned int, long long *, int *); extern struct inode *read_inode_2(unsigned int, unsigned int); /* unsquash-3.c */ extern int read_fragment_table_3(long long *); extern void read_fragment_3(unsigned int, long long *, int *); extern struct inode *read_inode_3(unsigned int, unsigned int); extern struct dir *squashfs_opendir_3(unsigned int, unsigned int, struct inode **); /* unsquash-4.c */ extern int read_fragment_table_4(long long *); extern void read_fragment_4(unsigned int, long long *, int *); extern struct inode *read_inode_4(unsigned int, unsigned int); extern struct dir *squashfs_opendir_4(unsigned int, unsigned int, struct inode **); extern int read_uids_guids_4(); #endif ================================================ FILE: include/squashfs/unsquashfs_info.h ================================================ #ifndef UNSQUASHFS_INFO_H # define UNSQUASHFS_INFO_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquashfs_info.h */ extern void disable_info(); extern void update_info(char *); extern void init_info(); #endif ================================================ FILE: include/squashfs/xattr.h ================================================ #ifndef XATTR_H # define XATTR_H /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2010, 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * xattr.h */ # define XATTR_VALUE_OOL SQUASHFS_XATTR_VALUE_OOL # define XATTR_PREFIX_MASK SQUASHFS_XATTR_PREFIX_MASK # define XATTR_VALUE_OOL_SIZE sizeof(long long) /* maximum size of xattr value data that will be inlined */ # define XATTR_INLINE_MAX 128 /* the target size of an inode's xattr name:value list. If it * exceeds this, then xattr value data will be successively out of lined * until it meets the target */ # define XATTR_TARGET_MAX 65536 # define IS_XATTR(a) (a != SQUASHFS_INVALID_XATTR) struct xattr_list { char *name; char *full_name; int size; int vsize; void *value; int type; long long ool_value; unsigned short vchecksum; struct xattr_list *vnext; }; struct dupl_id { struct xattr_list *xattr_list; int xattrs; int xattr_id; struct dupl_id *next; }; struct prefix { char *prefix; int type; }; extern int generate_xattrs(int, struct xattr_list *); # ifdef XATTR_SUPPORT extern int get_xattrs(int, struct squashfs_super_block *); extern int read_xattrs(void *); extern long long write_xattrs(); extern void save_xattrs(); extern void restore_xattrs(); extern unsigned int xattr_bytes, total_xattr_bytes; extern void write_xattr(char *, unsigned int); extern int read_xattrs_from_disk(int, struct squashfs_super_block *); extern struct xattr_list *get_xattr(int, unsigned int *, int); extern void free_xattr(struct xattr_list *, int); # else static inline int get_xattrs(int fd, struct squashfs_super_block *sBlk) { if (sBlk->xattr_id_table_start != SQUASHFS_INVALID_BLK) { fprintf(stderr, "Xattrs in filesystem! These are not " "supported on this version of Squashfs\n"); return 0; } else return SQUASHFS_INVALID_BLK; } static inline int read_xattrs(void *dir_ent) { return SQUASHFS_INVALID_XATTR; } static inline long long write_xattrs() { return SQUASHFS_INVALID_BLK; } static inline void save_xattrs() { } static inline void restore_xattrs() { } static inline void write_xattr(char *pathname, unsigned int xattr) { } static inline int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk) { if (sBlk->xattr_id_table_start != SQUASHFS_INVALID_BLK) { fprintf(stderr, "Xattrs in filesystem! These are not " "supported on this version of Squashfs\n"); return 0; } else return SQUASHFS_INVALID_BLK; } static inline struct xattr_list *get_xattr(int i, unsigned int *count, int j) { return NULL; } # endif # ifdef XATTR_SUPPORT # ifdef XATTR_DEFAULT # define NOXOPT_STR # define XOPT_STR " (default)" # define XATTR_DEF 0 # else # define NOXOPT_STR " (default)" # define XOPT_STR # define XATTR_DEF 1 # endif # else # define NOXOPT_STR " (default)" # define XOPT_STR " (unsupported)" # define XATTR_DEF 1 # endif #endif #ifdef __APPLE__ #define llistxattr(path, list, size) \ (listxattr(path, list, size, XATTR_NOFOLLOW)) #define lgetxattr(path, name, value, size) \ (getxattr(path, name, value, size, 0, XATTR_NOFOLLOW)) #define lsetxattr(path, name, value, size, flags) \ (setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW)) #endif ================================================ FILE: include/squashfs/xz_wrapper.h ================================================ #ifndef XZ_WRAPPER_H # define XZ_WRAPPER_H /* * Squashfs * * Copyright (c) 2010 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * xz_wrapper.h * */ # if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # else # include # endif # if __BYTE_ORDER == __BIG_ENDIAN extern unsigned int inswap_le32(unsigned int); # define SQUASHFS_INSWAP_COMP_OPTS(s) { \ (s)->dictionary_size = inswap_le32((s)->dictionary_size); \ (s)->flags = inswap_le32((s)->flags); \ } # else # define SQUASHFS_INSWAP_COMP_OPTS(s) # endif # define MEMLIMIT (32 * 1024 * 1024) struct bcj { char *name; lzma_vli id; int selected; }; struct filter { void *buffer; lzma_filter filter[3]; size_t length; }; struct xz_stream { struct filter *filter; int filters; int dictionary_size; lzma_options_lzma opt; }; struct comp_opts { int dictionary_size; int flags; }; #endif ================================================ FILE: include/stream/crc32.h ================================================ #ifndef CRC32_H #define CRC32_H #include uint32_t str_crc32(const unsigned char *data, int len); #endif /* CRC32_H */ ================================================ FILE: include/stream/tsfile.h ================================================ /** * Copyright 2016 lprot * All right reserved */ #ifndef __TSFILE_H #define __TSFILE_H #include struct tsfile_options { int video_stream_type; int audio_stream_type; uint8_t append; }; void convertSTR2TS(char *inFilename, struct tsfile_options *opts); void processPIF(const char *filename, char *dest_file); uint32_t str_crc32(const unsigned char *data, int len); #endif //__TSFILE_H ================================================ FILE: include/symfile.h ================================================ #ifndef _SYMFILE_H_ # define _SYMFILE_H_ /* * Copyright (c) 2011 Roman Tokarev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include # include struct sym_entry { uint32_t addr; uint32_t end; uint32_t sym_name_off; }; struct sym_table { uint32_t n_symbols; struct sym_entry *sym_entry; uint32_t *hash; uint32_t n_dwarf_lst; struct { uint32_t d1; uint32_t d2; } *dwarf_lst; unsigned char *dwarf_data; char *sym_name; }; extern struct sym_table sym_table; int symfile_load(const char *sym_fname); uint32_t symfile_addr_by_name(const char *name); const char *symfile_name_by_addr(uint32_t addr); uint32_t symfile_n_symbols(); void symfile_write_idc(const char *fname); #endif ================================================ FILE: include/thpool.h ================================================ /********************************** * @author Johan Hanssen Seferidis * License: MIT * **********************************/ #ifndef _THPOOL_ #define _THPOOL_ #ifdef __cplusplus extern "C" { #endif /* =================================== API ======================================= */ typedef struct thpool_* threadpool; /** * @brief Initialize threadpool * * Initializes a threadpool. This function will not return untill all * threads have initialized successfully. * * @example * * .. * threadpool thpool; //First we declare a threadpool * thpool = thpool_init(4); //then we initialize it to 4 threads * .. * * @param num_threads number of threads to be created in the threadpool * @return threadpool created threadpool on success, * NULL on error */ threadpool thpool_init(int num_threads); /** * @brief Add work to the job queue * * Takes an action and its argument and adds it to the threadpool's job queue. * If you want to add to work a function with more than one arguments then * a way to implement this is by passing a pointer to a structure. * * NOTICE: You have to cast both the function and argument to not get warnings. * * @example * * void print_num(int num){ * printf("%d\n", num); * } * * int main() { * .. * int a = 10; * thpool_add_work(thpool, (void*)print_num, (void*)a); * .. * } * * @param threadpool threadpool to which the work will be added * @param function_p pointer to function to add as work * @param arg_p pointer to an argument * @return 0 on successs, -1 otherwise. */ int thpool_add_work(threadpool, void (*function_p)(void*), void* arg_p); /** * @brief Wait for all queued jobs to finish * * Will wait for all jobs - both queued and currently running to finish. * Once the queue is empty and all work has completed, the calling thread * (probably the main program) will continue. * * Smart polling is used in wait. The polling is initially 0 - meaning that * there is virtually no polling at all. If after 1 seconds the threads * haven't finished, the polling interval starts growing exponentially * untill it reaches max_secs seconds. Then it jumps down to a maximum polling * interval assuming that heavy processing is being used in the threadpool. * * @example * * .. * threadpool thpool = thpool_init(4); * .. * // Add a bunch of work * .. * thpool_wait(thpool); * puts("All added work has finished"); * .. * * @param threadpool the threadpool to wait for * @return nothing */ void thpool_wait(threadpool); /** * @brief Pauses all threads immediately * * The threads will be paused no matter if they are idle or working. * The threads return to their previous states once thpool_resume * is called. * * While the thread is being paused, new work can be added. * * @example * * threadpool thpool = thpool_init(4); * thpool_pause(thpool); * .. * // Add a bunch of work * .. * thpool_resume(thpool); // Let the threads start their magic * * @param threadpool the threadpool where the threads should be paused * @return nothing */ void thpool_pause(threadpool); /** * @brief Unpauses all threads if they are paused * * @example * .. * thpool_pause(thpool); * sleep(10); // Delay execution 10 seconds * thpool_resume(thpool); * .. * * @param threadpool the threadpool where the threads should be unpaused * @return nothing */ void thpool_resume(threadpool); /** * @brief Destroy the threadpool * * This will wait for the currently active threads to finish and then 'kill' * the whole threadpool to free up memory. * * @example * int main() { * threadpool thpool1 = thpool_init(2); * threadpool thpool2 = thpool_init(2); * .. * thpool_destroy(thpool1); * .. * return 0; * } * * @param threadpool the threadpool to destroy * @return nothing */ void thpool_destroy(threadpool); #ifdef __cplusplus } #endif #endif ================================================ FILE: include/u-boot/image.h ================================================ /* * (C) Copyright 2000-2005 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * See file CREDITS for list of people who contributed to this * project. * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * ******************************************************************** * NOTE: This header file defines an interface to U-Boot. Including * this (unmodified) header file in another file is considered normal * use of U-Boot, and does *not* fall under the heading of "derived * work". ******************************************************************** */ #ifndef __IMAGE_H__ # define __IMAGE_H__ /* * Operating System Codes */ # define IH_OS_INVALID 0 /* Invalid OS */ # define IH_OS_OPENBSD 1 /* OpenBSD */ # define IH_OS_NETBSD 2 /* NetBSD */ # define IH_OS_FREEBSD 3 /* FreeBSD */ # define IH_OS_4_4BSD 4 /* 4.4BSD */ # define IH_OS_LINUX 5 /* Linux */ # define IH_OS_SVR4 6 /* SVR4 */ # define IH_OS_ESIX 7 /* Esix */ # define IH_OS_SOLARIS 8 /* Solaris */ # define IH_OS_IRIX 9 /* Irix */ # define IH_OS_SCO 10 /* SCO */ # define IH_OS_DELL 11 /* Dell */ # define IH_OS_NCR 12 /* NCR */ # define IH_OS_LYNXOS 13 /* LynxOS */ # define IH_OS_VXWORKS 14 /* VxWorks */ # define IH_OS_PSOS 15 /* pSOS */ # define IH_OS_QNX 16 /* QNX */ # define IH_OS_U_BOOT 17 /* Firmware */ # define IH_OS_RTEMS 18 /* RTEMS */ # define IH_OS_ARTOS 19 /* ARTOS */ # define IH_OS_UNITY 20 /* Unity OS */ /* * CPU Architecture Codes (supported by Linux) */ # define IH_CPU_INVALID 0 /* Invalid CPU */ # define IH_CPU_ALPHA 1 /* Alpha */ # define IH_CPU_ARM 2 /* ARM */ # define IH_CPU_I386 3 /* Intel x86 */ # define IH_CPU_IA64 4 /* IA64 */ # define IH_CPU_MIPS 5 /* MIPS */ # define IH_CPU_MIPS64 6 /* MIPS 64 Bit */ # define IH_CPU_PPC 7 /* PowerPC */ # define IH_CPU_S390 8 /* IBM S390 */ # define IH_CPU_SH 9 /* SuperH */ # define IH_CPU_SPARC 10 /* Sparc */ # define IH_CPU_SPARC64 11 /* Sparc 64 Bit */ # define IH_CPU_M68K 12 /* M68K */ # define IH_CPU_NIOS 13 /* Nios-32 */ # define IH_CPU_MICROBLAZE 14 /* MicroBlaze */ # define IH_CPU_NIOS2 15 /* Nios-II */ # define IH_CPU_BLACKFIN 16 /* Blackfin */ # define IH_CPU_AVR32 17 /* AVR32 */ /* * Image Types * * "Standalone Programs" are directly runnable in the environment * provided by U-Boot; it is expected that (if they behave * well) you can continue to work in U-Boot after return from * the Standalone Program. * "OS Kernel Images" are usually images of some Embedded OS which * will take over control completely. Usually these programs * will install their own set of exception handlers, device * drivers, set up the MMU, etc. - this means, that you cannot * expect to re-enter U-Boot except by resetting the CPU. * "RAMDisk Images" are more or less just data blocks, and their * parameters (address, size) are passed to an OS kernel that is * being started. * "Multi-File Images" contain several images, typically an OS * (Linux) kernel image and one or more data images like * RAMDisks. This construct is useful for instance when you want * to boot over the network using BOOTP etc., where the boot * server provides just a single image file, but you want to get * for instance an OS kernel and a RAMDisk image. * * "Multi-File Images" start with a list of image sizes, each * image size (in bytes) specified by an "uint32_t" in network * byte order. This list is terminated by an "(uint32_t)0". * Immediately after the terminating 0 follow the images, one by * one, all aligned on "uint32_t" boundaries (size rounded up to * a multiple of 4 bytes - except for the last file). * * "Firmware Images" are binary images containing firmware (like * U-Boot or FPGA images) which usually will be programmed to * flash memory. * * "Script files" are command sequences that will be executed by * U-Boot's command interpreter; this feature is especially * useful when you configure U-Boot to use a real shell (hush) * as command interpreter (=> Shell Scripts). */ # define IH_TYPE_INVALID 0 /* Invalid Image */ # define IH_TYPE_STANDALONE 1 /* Standalone Program */ # define IH_TYPE_KERNEL 2 /* OS Kernel Image */ # define IH_TYPE_RAMDISK 3 /* RAMDisk Image */ # define IH_TYPE_MULTI 4 /* Multi-File Image */ # define IH_TYPE_FIRMWARE 5 /* Firmware Image */ # define IH_TYPE_SCRIPT 6 /* Script file */ # define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */ # define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */ /* * Compression Types */ # define IH_COMP_NONE 0 /* No Compression Used */ # define IH_COMP_GZIP 1 /* gzip Compression Used */ # define IH_COMP_BZIP2 2 /* bzip2 Compression Used */ # define IH_MAGIC 0x27051956 /* Image Magic Number */ # define IH_NMLEN 32 /* Image Name Length */ /* * all data in network byte order (aka natural aka bigendian) */ typedef struct image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ uint32_t ih_time; /* Image Creation Timestamp */ uint32_t ih_size; /* Image Data Size */ uint32_t ih_load; /* Data Load Address */ uint32_t ih_ep; /* Entry Point Address */ uint32_t ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t; #endif /* __IMAGE_H__ */ ================================================ FILE: include/u-boot/mtdinfo.h ================================================ #ifndef _MTD_INFO_H_ # define _MTD_INFO_H_ # define STR_LEN_MAX 32 # define MTD_MAP_MAX 4 struct m_device_info { char name[STR_LEN_MAX]; unsigned int size; unsigned int phys; # if __x86_64__ unsigned int virt; unsigned int cached; # else void *virt; void *cached; # endif int bankwidth; unsigned int used; }; struct m_partition_info { char name[STR_LEN_MAX]; /* identifier string */ unsigned int offset; /* offset within the master MTD space */ unsigned int size; /* partition size */ char filename[STR_LEN_MAX]; /* file name */ unsigned int filesize; /* file size */ unsigned int sw_ver; /* software version */ unsigned char used; /* Is this partition is used? */ unsigned char valid; /* Is this partition is valid? */ unsigned char mask_flags; /* master MTD flags to mask out for this partition */ }; struct m_partmap_info { unsigned int magic; unsigned int cur_epk_ver; unsigned int old_epk_ver; unsigned char nmap; unsigned char npartition; struct m_device_info map[MTD_MAP_MAX]; struct m_partition_info partition[PM_PARTITION_MAX]; }; # define M_GET_PART_INFO(x) ((struct m_partition_info *)&(m_partinfo.partition[x])) # define M_GET_DEV_INFO(x) ((struct m_device_info *)&(m_partinfo.map[x])) extern struct m_partmap_info m_partinfo; #endif /* MTD_INFO_H_ */ ================================================ FILE: include/u-boot/partcommon.h ================================================ #ifndef _PART_COMMON_H_ #define _PART_COMMON_H_ #define U64_UPPER(x) (unsigned long)( (x) >> 32 ) #define U64_LOWER(x) (unsigned long)( (x) & 0xffffffff) /*#ifndef NO #define NO 0x00 #define YES 0x01 #endif*/ /*----------------------------------------------------------------------------- * partition info */ #define PART_FLG_FIXED 1 #define PART_FLG_MASTER 2 #define PART_FLG_IDKEY 4 #define PART_FLG_CACHE 8 #define PART_FLG_DATA 16 #define PART_FLG_SECURED 32 #define PART_FLG_ERASE 64 #define STR_LEN_MAX 32 #define PM_PARTITION_MAX 64 typedef enum PART_INFO { PART_INFO_IDX = 0, PART_INFO_OFFSET, PART_INFO_SIZE, PART_INFO_FILESIZE } PART_INFO_TYPE; typedef enum { STRUCT_INVALID, STRUCT_MTDINFO, STRUCT_PARTINFOv1, STRUCT_PARTINFOv2 } part_struct_type; unsigned int dump_partinfo(const char *filename, const char *outfile); extern const char *modelname; extern part_struct_type part_type; #endif /* _PART_COMMON_H_ */ ================================================ FILE: include/u-boot/partinfo.h ================================================ #ifndef _PARTINFO_H_ #define _PARTINFO_H_ #include "partcommon.h" #include "partinfov1.h" #include "partinfov2.h" #include "mtdinfo.h" #endif ================================================ FILE: include/u-boot/partinfov1.h ================================================ #ifndef _PART_INFO1_H_ #define _PART_INFO1_H_ struct p1_device_info { char name[STR_LEN_MAX]; unsigned int size; unsigned int phys; #if __x86_64__ unsigned int virt; unsigned int cached; #else void *virt; void *cached; #endif int bankwidth; unsigned int used; }; struct p1_partition_info { char name[STR_LEN_MAX]; /* identifier string */ unsigned int offset; /* offset within the master MTD space */ unsigned int size; /* partition size */ char filename[STR_LEN_MAX]; /* file name */ unsigned int filesize; /* file size */ unsigned int sw_ver; /* software version */ unsigned char used; /* Is this partition is used? */ unsigned char valid; /* Is this partition is valid? */ unsigned int mask_flags; /* master MTD flags to mask out for this partition */ }; struct p1_partmap_info { unsigned int magic; unsigned int cur_epk_ver; unsigned int old_epk_ver; unsigned char npartition; struct p1_device_info dev; struct p1_partition_info partition[PM_PARTITION_MAX]; }; #define P1_GET_PART_INFO(x) ((struct p1_partition_info *)&(p1_partinfo.partition[x])) #define P1_GET_DEV_INFO(x) ((struct p1_device_info *)&(p1_partinfo.dev)) extern struct p1_partmap_info p1_partinfo; #endif /* _PART_INFO1_H_ */ ================================================ FILE: include/u-boot/partinfov2.h ================================================ #ifndef _PART_INFO2_H_ #define _PART_INFO2_H_ #define P2_PARTITION_MAX 128 struct p2_device_info { char name[STR_LEN_MAX]; unsigned long long size; unsigned long long phys; #if __x86_64__ unsigned int virt; unsigned int cached; #else void *virt; void *cached; #endif int bankwidth; unsigned int used; }; struct p2_partition_info { char name[STR_LEN_MAX]; /* identifier string */ unsigned long long offset; /* offset within the master MTD space */ unsigned long long size; /* partition size */ char filename[STR_LEN_MAX]; /* file name */ unsigned int filesize; /* file size */ unsigned int sw_ver; /* software version */ unsigned char used; /* Is this partition is used? */ unsigned char valid; /* Is this partition is valid? */ unsigned int mask_flags; /* master MTD flags to mask out for this partition */ }; struct p2_partmap_info { unsigned int magic; unsigned int cur_epk_ver; unsigned int old_epk_ver; unsigned char npartition; struct p2_device_info dev; struct p2_partition_info partition[P2_PARTITION_MAX]; }; #define P2_GET_PART_INFO(x) ((struct p2_partition_info *)&(p2_partinfo.partition[x])) #define P2_GET_DEV_INFO(x) ((struct p2_device_info *)&(p2_partinfo.dev)) extern struct p2_partmap_info p2_partinfo; #endif /* _PART_INFO2_H_ */ ================================================ FILE: include/util.h ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #ifndef __UTIL_H #define __UTIL_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include "common.h" #include "mfile.h" #define member_size(type, member) sizeof(((type *)0)->member) #define err_exit(fmt, ...) \ exit(err_ret((fmt), ##__VA_ARGS__)) #ifdef __APPLE__ typedef unsigned int uint; #endif char *my_basename(const char *path); char *my_dirname(const char *path); int count_tokens(const char *str, char token, int sz); void getch(void); void hexdump(const void *pAddressIn, long lSize); void rmrf(const char *path); /* Print message and return EXIT_FAILURE. (On Cygwin, also waits for keypress.) */ int err_ret(const char *format, ...) FORMAT_PRINTF(1, 2); char *remove_ext(const char *mystr); char *get_ext(const char *mystr); void createFolder(const char *directory); MFILE *is_lz4(const char *lz4file); bool is_nfsb_mem(MFILE *file, off_t offset); MFILE *is_nfsb(const char *filename); void unnfsb(const char *filename, const char *extractedFile); MFILE *is_gzip(const char *filename); int is_jffs2(const char *filename); int isSTRfile(const char *filename); int isdatetime(const char *datetime); int isPartPakfile(const char *filename); int is_kernel(const char *image_file); void extract_kernel(const char *image_file, const char *destination_file); int asprintf_inplace(char **strp, const char *fmt, ...) FORMAT_PRINTF(2, 3); #include void print(int verbose, int newline, const char *fn, int lineno, const char *fmt, ...) FORMAT_PRINTF(5, 6); #define WHEREARG __FILE__, __LINE__ #define PRINT(...) print(0, 0 , WHEREARG, __VA_ARGS__) #define VERBOSE(N,...) print(N, 0, WHEREARG, __VA_ARGS__) #define VERBOSE_NN(N,...) print(N, 0, WHEREARG, __VA_ARGS__) #define PERROR_SE(fmt, ...) print(0, 0, WHEREARG, "ERROR: " fmt " (%s)", ## __VA_ARGS__, strerror(errno)) #define PERROR(...) print(0, 1, WHEREARG, "ERROR: " __VA_ARGS__) #ifdef __cplusplus } #endif #endif ================================================ FILE: include/util_crypto.h ================================================ /** * Copyright 2016 Smx * All right reserved */ #ifndef __UTIL_CRYPTO_H #define __UTIL_CRYPTO_H #include #include #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined (LIBRESSL_VERSION_NUMBER) #define EVP_MD_CTX_new EVP_MD_CTX_create #define EVP_MD_CTX_free EVP_MD_CTX_destroy #endif #define KEY_ECB (1 << 0) #define KEY_CBC (1 << 1) typedef int (*CompareFunc)(uint8_t *data, size_t size); void setKeyFile(const char *keyFile); void setKeyFile_LG(); void setKeyFile_MTK(); uint8_t *getLastKey(); uint8_t *getLastIV(); #define MAX_KEY_SIZE (AES_BLOCK_SIZE * 2) // AES-256 typedef struct { AES_KEY key; uint8_t keybuf[MAX_KEY_SIZE]; uint8_t ivec[MAX_KEY_SIZE]; } KeyPair; KeyPair *find_AES_key( uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, int verbose ); #endif ================================================ FILE: keys/AES.key ================================================ # OTAIDs are examples for testing keys # unknown 214BF3C129547AF31D32A5ECB4742192 # common 1F1E1D1C1B1A19180706050403020100 # BCM35230/early MTK5369 and LG1152 # old (pre-MStar) Mediatek 7184C9C428D03C445188234D5A827196 # mtk5369 - Mediatek GP4 - HE_DTV_GP4I_AFAAATAA 385A992430196A8C44F1985823C01440 # mtk5398 (a2) - Mediatek NetCast 4/4.5 - HE_LCD_NC5M_AAAAAIAA 8E32E4608871ECE9B6301999D5155A07 # mtka5lr (mt5882) - Mediatek webOS 2 (2015) - HE_DTV_W15L_AFAAABAA # Broadcom/MStar MIPS 6856A0482475A8B41728A35474810203 # new BCM35230 2F2E2D2C2B2A29281716151413121110 # Saturn7/BCM3556 212D3B2A5C2D3A2C4D5B234B1A321D2A # new Saturn7/old LM1 4F836AAEB4301F26172A9B0E1120EAF4 # LM1 PDP 4EE662C7A2C0917F7328DE73A0836C6B # LM1 LCD 2F534ABE34801A36B7DA6B3EB1C04AD4 # m1 - MStar non-webOS - LN45*, LN53*, LN54*, LN565*, LA61*, LA643*, MA53*, PN45*, PN65* 7B2CA5943D2E752CF58606228C5B2DAD # m1a - MStar non-webOS (L15 signage) - BS_LCD_LE15_AAAAAIAM # MISSING: m1ap - MStar L16 - HE_LCD_LE16_AAAAABAA # MISSING: m1a - MStar L18 signage - HE_IDD_LM18_DSAAGLAA # MISSING: m1a - MStar L19 signage - HE_IDD_LM19_AHAAAIAM # MStar ARM D55C6864035A8C8A2B35A6D6C4565596 # m2 - MStar SimpleSmart - HE_LCD_SS1A_AFAAAIAA ADB92D9E23035522F4708CC259B31EA2 # m2 - MStar webOS 3.0 (2016) - HE_DTV_W16R_AFAAABAA D2E6EE17639DFE2F81D3840FA0BC334A # m2r - MStar webOS 3.5 (2017) - HE_DTV_W17R_AFAAABAA 4F6DE80C0362FD562464BC2073D15567 # m3 - MStar webOS 4.0 (2018) - HE_DTV_W18R_AFAAABAA 88723D91920712D0BAFE87A25E6E8EC7 # m3r - MStar webOS 4.5 (2019) - HE_DTV_W19R_AFAAATAA 68A284B4953CAD15024BED2C4F852A09 # lm14 - MStar NetCast 4.5 (2014/2015) - HE_LCD_NC5U_AAADABAA 19F51EE9B949C89E41AE136F48BB405C # lm14a - MStar webOS 2 (2015) - HE_DTV_W15A_AFADABAA F8F6BD1AA24506C2759E1BE1D51BB43C # lm14alite - MStar webOS 2 (2015) - HE_DTV_W15B_AFADABAA 96F464CB29CDFF5441FD87D47D084FF8 # lm15u - MStar webOS 2 (2015) - HE_DTV_W15U_AFADABAA 6FCCC4AA3389B614BABE462498D2020A # lm18a - MStar webOS 4.0 (2018) - HE_DTV_W18A_AFADATAA 806B982279521809DBAD9E2E6BF377763903565A7EB4604BAB1E1503DBFC4326 # lm21a - MStar webOS 6 (2021) - HE_DTV_W21A_AFADATAA B65119E0E6CB5DB19C69B4CC78FAC3A87C747E5AEFDE8FF58F2CD47128D9E16D # lm21u (mt5889) - MStar webOS 6 (2021) - HE_DTV_W21U_AFADATAA FC9D81DEC206BA62614C949C43D2DA91D23E9FF3DF9674D69A444D13277BDF96 # lm21ut - MStar webOS 6 StanbyME (2022) - HE_DTV_N21D_AFAAATAA 3435663331313732316538383063663538306161643131653335323334613034 # lm21an - MStar webOS 7 (2022) - HE_DTV_W22A_AFADATAA 1FB2C3B789D5EA48ED16E79A0343986C691DACEC872BB07787D0F722AF5D1E2C # lm21ann - MStar webOS 8 (2023) - HE_DTV_W23A_AFADATAA # LX/LGE (GP, NetCast, webOS) 4813B5B63C998A2874EF3320684AC8D9 # lg1152 - LX GP4 - HE_DTV_GP4H_AFAAATAA 14B3623488212250C7C992AACD537447 # lg115x - LX NC4 - HE_LCD_NC4H_AAADABAA 12C344FDD2871C983CD0FBBC25143974 # lg1154 (h13, goldfinger) - LX webOS 1 (2014) - HE_DTV_WT1H_AFAAABAA 34CC219D3AFC102433109BBC1DA44095 # m14 (m14tv) - LX webOS 1 (2014) - HE_DTV_WT1M_AFAAATAA 5A167D8C342EF094800E7CFA2D10F2D0 # m14 (m14tv) - LX webOS 2 (2015) - HE_DTV_W15M_AFAAATAA 13F56BE4B4A0829598DB8F74065A263B # h15 - LX webOS 2 (2015) - HE_DTV_W15H_AFADATAA # MISSING: h15 - LX webOS 3.0 (2016) - HE_DTV_W16H_AFADATAA 3679EF1840B7FDEBC1FBF95A0CAFCE3E # m16 - LX webOS 3.0 (2016) - HE_DTV_W16M_AFADABAA 5804DF78CB8DC6A71C05DAB0F1EDE3E1 # m16lite - LX webOS 3.0 (2016) - HE_DTV_W16N_AFADABAA 1B3C76ADD3F5EE6B089DB253747A8CD4 # m16p - LX webOS 3.5 (2017) - HE_DTV_W17H_AFADABAA 3C9D30DF3A95C1AA41928813292BD947 # m16plite - LX webOS 3.5 (2017) - HE_DTV_W17M_AFADATAA # MISSING: m16pbno - LX webOS 3.5 (2017) - HE_DTV_W17B_AFADABAA 89E11D498392F5A521145738EF036AE5 # m16pstb - LX webOS 3.5 (2017) - HE_DTV_W17S_AFADATAA 437C02F0DF99F2072D1A64EEBBD2953B # m16pp - LX webOS 4.0 (2018) - HE_DTV_W18H_AFADABAA 3471D9BFC5F4B34A8997D56932F34D94 # m16pplite - LX webOS 4.0 (2018) - HE_DTV_W18M_AFADATAA 3FE1CBE11BD658BB37813E05052D5FE5 # m16p3 - LX webOS 4.5 (2019) - HE_DTV_W19H_AFADABAA A2FA48FCC1A22FD2F1944BEFA8403765EF178D4F4AB0E81AC7B5B267ACBDF14D # m23 - LX webOS 8 (2023) - HE_DTV_W23M_AFADATAA # LX/LGE OLED-specific (webOS) E529BCDEDF8E49667C0FA3A81174B65E # o18 - LX webOS 4.0 (2018) - HE_DTV_W18O_AFABABAA 4ACD2CA8425BBA6C49FD03A174300239 # o18 - LX webOS 4.5 (2019) - HE_DTV_W19O_AFABABAA C9EF645424A625BBAE7521394564025EC6252658FB650D33633111BD40C76011 # o20 - LX webOS 5 (2020) - HE_DTV_W20O_AFABATAA 944288798A122C6130B661BEE52DF4FE42120F60A61E312DCFC1411E300A29AE # o20n - LX webOS 6 (2021) - HE_DTV_W21O_AFABATAA 3861333237633238613136633438663239623238623037656335623433353862 # o22 - LX webOS 7 (2022) - HE_DTV_W22O_AFABATAA CF5D6DC934F18618B968382368E17BA971DEAA2ECDFC906874B327D87076E228 # o22n - LX webOS 8 (2023) - HE_DTV_W23O_AFABATAA 53D6DC79418C1A2371DC9F926CD3A3A06F4E7E4396464B5F41248083C2C65637 # o22n2 - LX webOS 9 (2024) - HE_DTV_W24G_AFABATAA B7724DBBF2AEA073131E8E7D62D114E2AA02F99D17CD7350C14466624528ED79 # o24 - LX webOS 9 (2024) - HE_DTV_W24O_AFABATAA FE90B0C1BE8CC28A9738333F95AC2C58777BDE7D4E8CABABA73B24FB7D1781C7 # o22n3 - LX webOS 10 (2025) - HE_DTV_W25G_AFABATAA 52A208FA24E7E70730A40999B1C22C148F4920484BC50B515D243E35D14689F1 # o24n - LX webOS 10 (2025) - HE_DTV_W25O_AFABATAA # LX/LGE 8K (webOS) CD4171FC9C06869627A67EA7B66D739D # o18k - LX webOS 4.5 (2019) - HE_DTV_W19K_AFADATAA 0EE52A12A2EB5DE2E13999187B14913F6D3367A79B39AC35979A51E5C12A4FDF # o208k - LX webOS 5 (2020) - HE_DTV_W20K_AFADATAA # MISSING: e60 - LX webOS 5 (2020) - HE_DTV_W20E_AFADATAA E27E6AFE44B7866D60C24ED27904ECB296CA69B4251478B5248C03851F08ECF5 # e60n - LX webOS 6 (2021) - HE_DTV_W21K_AFADATAA # MISSING: o228k - LX webOS 7 (2022) - HE_DTV_W22K_AFADATAA # MISSING: o22n8k - LX webOS 8 (2023) - HE_DTV_W23K_AFADATAA # MISSING: o22n28k - LX webOS 9 (2024) - HE_DTV_W24K_AFADATAA # Realtek (webOS) F2B78AEBAD6D86A17B4742B2B84B60F4 # k2l - Realtek webOS 3.0 (2016) - HE_DTV_W16K_AFADATAA C2FBBC5DDD9D366B7FD6CAEB90F86039 # k2lp - Realtek webOS 3.0 (2016) - HE_DTV_W16P_AFADABAA 1C966DFA0E5AE9946AAF8D2EC06B9E18 # k3lp - Realtek WebOS 3.5 (2017) - HE_DTV_W17P_AFADABAA AD17A5923B525FD21DB765A5B6822FBD # k5lp - Realtek webOS 4.5 (2019) - HE_DTV_W19P_AFADABAA 388BE4B04BD98E7C3CA45A4C6CA346DD2EB32BDCD05DC28FC4A87C9625294A5E # k6lp - Realtek webOS 5 (2020) - HE_DTV_W20P_AFADATAA 377050F9B9D91CD803ACAACCEA4046DD99B01CFBB0010451F4F87A1620C4BAEF # k6lpfhd - Realtek webOS 5 (2020) - HE_DTV_W20L_AFAAJAAA 395324AD369A529EABAC71FE1E72C25CE25594294D47303BCB2629241AFA4C98 # k6hp - Realtek webOS 5 (2020) - HE_DTV_W20H_AFADABAA 74514676D68B9A72A0093CEF56D3067484E1F4D5CF7D4B4ED389BED030FA1B09 # k7lp - Realtek webOS 6 (2021) - HE_DTV_W21P_AFADATAA 6A42D2485B716B25AE5C9921176588D167C25B902D4EF2903AF5C1FCC61D34C9 # k8lp - Realtek webOS 7 (2022) - HE_DTV_W22P_AFADATAA A35A57DFDD8266F7CE1AF991EC67BABF6723653ABB9A7D48A4B8AB2A2485BCFE # k8hp - Realtek webOS 7 (2022) - HE_DTV_W22H_AFADATAA 703373367638792F423F4528482B4D6251655468576D5A7134743777217A2443 # k8lp - Realtek webOS 7 hospitality (2022) - HE_IDD_H22P_AHAAATAA 6251655468576D5A7133743677397A24432646294A404E635266556A586E3272 # k8hp - Realtek webOS 7 hospitality (2022) - HE_IDD_H22H_AHAAATAA 3764336361633437326166373639383663353863363039316332383031626637 # k8ap - Realtek webOS 7 (2022) - HE_DTV_W22L_AFAAATAA 64E629FDD8B7BE4A3D4ECD85F1BFCE6FC49CDEF32CFFB16B4716A7BEE6F3B258 # k8hpt - Realtek webOS 7 StanbyME Go (2023) - HE_DTV_N22D_AFAAATAA DFFD1E4F093E305451D4F3752E63BA9A3E6A6404922D986DF36C00818F5595C1 # k8hpp - Realtek webOS 8 (2023) - HE_DTV_W23H_AFADATAA EC2C89B4AF45B5EB7EA9A83DD2387810C0815BD31BBFE1D17C809E7D68339112 # k8lpn - Realtek webOS 8 (2023) - HE_DTV_W23P_AFADATAA 90A21E96D39A933982B7508E59272040DCA34EB4782FF289D1AFEFEC0C68590C # kf23f - Realtek webOS 8 (2023) - HE_DTV_W23L_AFAAATAA F322A9CA1D523C358DD2FD97D5660E25386C9C60E423632AEC9723D282BE971D # kf23f - Realtek webOS 8 smart monitors (2023) - HE_MNT_S23Y_AAAAGLAA 6252A0816884997B2FCA30662561A721A4BCC40B18CBEA5D363FA844F17D7DE9 # kid23q - Realtek webOS 8 ultrawide monitors (2023) HE_MNT_S23Z_AAACGLAA 7638792F423F4528482B4D6251655368566D597133743677397A24432646294A # k8lpn - Realtek webOS 8 hospitality (2023) - HE_IDD_H23P_AHAAATAA 6B5AD1BE81D7A1A494F58EB659431850C1B681826EE4428394D4897052691756 # k8lpn2 - Realtek webOS 9 (2024) - HE_DTV_W24P_AFADATAA FA9EBB838B7BAFBA75EFE8D5A3560374EB0699A113411CA924051B4ADB52E10D # k24 - Realtek webOS 9 (2024) - HE_DTV_W24H_AFADATAA 1A8ADAB21D9FF995677DB32BCE2E0CD559AE86840EBF4A696872076E37DFFE8F # k24t - Realtek webOS 9 StanbyME 2 (2024) - HE_DTV_N24D_AFADATAA 25DF24166745B52EAB661455BED43DE376320FAA1F7824877B938DB869308B18 # k25lp - Realtek webOS 10 (2025) - HE_DTV_W25P_AFADATAA B2E8C3E214F044B823916E48FA074E606C7C5CD5E6902B6F99BD903DAC0C792F # k24n - Realtek webOS 10 (2025) - HE_DTV_W25H_AFADATAA # Realtek WEE (webOS) B23981FD3642CDF401E7A0C2FADBDA4399B6AAF9600B802144933B4F4E5855EA # k6lpwee - Realtek webOS 5 (2020) - HE_DTV_C20P_AFADATAA 3263653764623932376235323637653637633035363066353833303235383466 # k8lpwee - Realtek webOS 7 (2022) - HE_DTV_C22P_AFADATAA 46715DFBDE23C2D8CBA7EC4F36BA41AAD28E7EC00FEC51F2843F24654DB09BD3 # k8hpwee - Realtek webOS 7 (2022) - HE_DTV_C22H_AFABATAA 6238323334663232396632613762316537333731333832306664666136333564 # k8apwee - Realtek webOS 7 (2022) - HE_DTV_C22L_AFAAATAA 9E8D2BAC9DCBEFC878CC8203431A70E00C2122DEF82FD5099D04BA259B1B2E4B # kf23fwee - Realtek webOS 8 (2023) - HE_DTV_C23L_AFAAATAA ================================================ FILE: keys/MTK.key ================================================ 09291094092910940929109409291094,00000000000000000000000000000000 # Mediatek Generic (Hisense, Sharp, Philips) 53686172536861725348617253686172,00000000000000000000000000000000 # SharSharSHarShar (Sharp key for Sharp external partition) 5450565F5450565F5450565F5450565F,00000000000000000000000000000000 # TPVision(Philips) 2012 D378EAF81D378A801B556985789A7C31,73079FD19183715E130858588479C652 # Philips 2012 47FBF8CAD62BB95AF3AD9509E5C2175D,63120FB321B0410F216D6DC2D8641A11 # Philips 2013 55555555555555555555555555555555,B1BFAA407F70C80C650379DFEAFAA40F # TCL 2017 1B569AA7D2E4CCE66584A7A3D8A45679,A0E88D5D52A813260D3A34A14AA89416 # TPV_MTK2K17PLF_EU0 135AFB6DE91CD56496244BC7C0E08D63,C6A38C89F0AF5637EB6E19D35E12E257 # TPV_MTK2K14PLF_EU1 7B17F7764818AE2C897BA69D428D0CB3,672041CCB9FCD4272B11E57AB6047163 # TPV_MTK2K16PLF_EU0 ================================================ FILE: keys/README.md ================================================ keys =========== Place keys in this folder before running ./build.sh ================================================ FILE: keys/e60.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3pE29z9xS/7WmMScGR/q m/o7S3kN6vmuNgb9XjItG6K5z9sGmtyvvyBbQGe62PI2tQ3/sFL3seoR35cKyqCC SYdV0kgY+IEc/u8+9r2B+k5WWeGRkUXUkqDPXBtC+kNkDRg0PkavGMJcxhOzP2HR iPFYv2pqlgq7PXD+BrfGIcvZShgUnPcufuQkqDmR/BF0DAYJMbdmn8Y0gu9xNekW 5odvC31dGMss2xR/JCh32PeYoVv2+v5M29PhXlpDoDHlUeIuKp+TLajd76p84WSd dCRuCv/HIjBNBm0ip4K6wp1388HfXoG1ZMquRykiMnjR4RlkMOwlZkzcr31ovRN4 mwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/e60n.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvFix6BZ9npNUCNtzDDK0 jXPukBfR+VJ5tj21pq+R4YUf4ImrKVre+onh0/bCsJgEVAM822d7BRCGRytHHahB ypBd9e+yCFQzIQLVpM4MRiy/SM/xq0EcHeVKg5phgAxV0cElb8MKJ3Q6W5rqXi9B 7o9Q7fONLFAocQR7WN69OWhT72afswkrfuat9JAPtn05NgZ17UEbWzUzBDrU2uWw 5x5bFiUX5qHYeocuZK2Nn5n3q/zV7EyaRCgqbWBDb5WcWrQBu0QH+tmCoEiv829g hZtkrXJYiQxoh3W8rVqkwGzIE01Ci4yBMaYFRnxkAhogYV8uf+PuE2z6kNW+NVsl uwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/general_pub.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6cC7osaLYH//AoKB1LRSrtSVA xQ2335JyMhdnrGqR/xvJV5tT04qhzcWjx70FX0wW2xEQbNCouucJoDwcaNvRW2bF onNF1oiqkrJLWIhr8DYY81X2Yr1GddLgCf8S3EjJdfkpuWIn22/NIjJZPaEcidx2 pFAqFUk27yT8IkPnrQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/h15.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBc5hEow2FPG39zb01yc9Y6qSR q8c5oc/MxiK6xEFHNHEuDNLjYlPxuvdb+I3l8rgTPNMQbwIN4nYpkY6H7q/Pmfan 3tk7uuVzLNkstc+kYKgM2UxzVGh+D9GDphbIgalkYRFMyGQt8/SCXaVvtdkIa2KL De4gG+WGc8QLiFRxdwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k24.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwLZOuhlUJ18bJO7Psuy9 82Wf6b0k+JRc+H34HUiFeQcdZfHz5BL5ZqC/vCAt5LwrQuK/rgA2XLZa/fg4HaaR pcxlX/j7d7HmG93KyRR3NX6EsVts9CyDT3HMEvila1sBfpj1NScjBu25jguYOSr5 66P5ooLRwpM/yZAJzEii8isYysqcefxVL+VVKBv8HgaCcK2oAWrcEAGiLS2xvRXX 3ref/3BF0n4ZgDfzXdn+8kqBpGcNpwDmy347jtJAtgddE4d0gQaVr4YYn8mkR9tf O9M3ymo/IEtN9z9I9rKicce4ushOC1K9KZV64yZMUGx+s2xLrRbhjIkktF6O9PGg GwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k24n.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv/jTYXIo3u/Z9+lF6wt0 +b7boSJiOGuNMW1iBhkCQ5EkQIT28BkOPodOIOi7ofZF38rnDKdNU/dbmu0qt4Of IFL3eO0Wq+mMCI8Hi7Kb/5h59GW5V1wN0Xip6wbaFyz6tJ0jwMhcQUIi85QyUmJ2 t11zOXiXCGFRC4LC84rvteD799VxtcUgrQKYIhS4UYym0cViIt5Y126p9e63Qlx9 YQZ7gWWVRIc+dNpY3oGa9rpTTRWoVx8HFmWH7mNRX39uSSBNcK/LJuiibS76fQni Hll/kB0wsm4DSek4td7gk1hZHb4N59osJM+ex8PYXJMugWBIT8ebk33ygMU+Z1kj VwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k24t.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5BL+M/GUNZXNWQKXQk9z j9sGxiu7nNvaE8MNQaXE4IvgpgKNGkJPnqX1+CG3d411Nt9h2ms/ofrIzyNSb0C1 nsnuQAFLEuUnLthsIupXwYPEJf0ORNpUe9uoAG0+Xm9ArPPETXMPFKZviXDRVHpg XDwUkmy3jSjI4hXQAFTXBtw6SmHXph8NqJSwl3W7cTsL8B8n1bsnSRTzueaSrrS+ bToNy1+7ptHu0Yc2s5Ttgz45YqSjWhZbPvv/9fQrIe3qGhrE1wUtoJGkrw7xsX5v n/jQ32hZp/xWSQzF2OPWlBgWBKR0fX3Y1dXk/Syq2t7N75Me3hspdzhkni+EX3Ye 7wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k25lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0i/S5OoP3jXho4xqWOl1 iLwlY6VT1IUftj0HPIFw+Qrjj+YSxlJjkCA2YHOzA27pC3ICN0PefF0D3uGMbrnM N7YaHWw3ph46q4yCqiHND55eA6VeKyf2npIUwUx1/pEszpy1lQIZbY66FR/fqfTW LiZL5ioXH50phsvLfk3Lgn49qK94A+z82jcg0hOiuiwt0lXmb2gctxNf8Z69O2Jr QN9s21o92qnPoXM7eTfJINrN3jNHYKiywj3CuXt1yAjz6rasYr6EExBtmT4opNbH /c7jpeOFRGIacdYLnJhTe13xB9cIWQNJXF8nYwNJKxu04eqFfmmfjfn5q9unxsTg DQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k2l.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzsNSLkOElA4UKtRn7Qsp Ygj/LK8q6aRJMPxsYBd95D5ke19g43y2RlFR51vIlzcaEs24a+yKR9jr8MJqagfa qU0BXyaTmlSogANqKEjug87AjG1aNUeooquZS96k/2YfZ3QszRJDTWV0jfIKq0hY pjrYRTvkScQHdtStLlBIlP27WrCPf4Z6DS4xS3l4IGZZC940W36alpXciBAwV9y8 Z0rqkVnNWDsJXUGeMPfmakdFl498SeidopHnTalxL/DdmtlxMFjI8PfmMTutYyWJ gkx03Mv+fVv8Fb+6kFvzCV4fbFd53rQ69eGcXwGXkaVJw6LdO52pYiZhTsqtm8Gk 3wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k2lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbWxWkw05RXCaq/HQO81 dPH69hMfnZuoACcLzALdQPm8oqxj7hCbtT5+S1GgzPRaQ6ZmiE0zM5U/89wdYOIR 0Zpb012fiwtZDaH7wWodKYJxCQ+BkSURKSPXutFAKSvWKuy58Bjf8BqT8b92WuW5 Mb3IYv2cvddfrsew/UmRYswyDDzMTwLekYhwFxokpDmbwGm1iLckBji7H/l4OfOZ u42YN4gC5lAuT9wKyz/ugwaSYg3A23bd8lUe//ebjetCYmOLuLpOdoIJZIrtG6bJ TTEmqlLSaYZQyYh9kD0yORd9xLe2a3/prVFUSL1QeE8h17/ypO6dXoVvXfGFukOP KwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k3lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAum5ztLc/35cYpt0b0D32 Ze1ybhcfWbX9T825QDPE10ifscpP2PFhGEPqbtYi/9X9gLrXK+zMo1Sy04SuPrlH bMwpyKv2RKNrmJMneJ6SXMne3MbWzp3E41umjhHhlDZgvyIDFoExTrKlJYroHMG0 d6PDuE3Em8ReOq/pSQgQ2U4ch0FUeB1Qve7bYUf0QNpE1maMSF7/UD28ZcyP86NB 7lkttmlY01etIf9D/aATzA0p4kixetl2JlhFqKlNnU0IyUnnL3TPQogmNFYHZByQ ANpJ7GbVUnbNBuiqYRt3AzZIny92UWZi1zBgwvAUOMJGs4Lvx9/AOOm7fe40ly43 VwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k5lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwJHtUEdVgac2azz1Vox8 XZ/zz7aidg0GdQb7jJlUg/Juzce63ZJzKPb8UWLsn60UyMGVYdhx0C+PlzNzbQCP lnWQ+D/Nb2mG1Rm6KKULaOjwiwTY35fbwsJ/TbKzdCSvKIzhUfThz1iU1e8f+b67 3FQVON6KPCV7LH0E8WyOKdP9oPhlVFcMaOtQcU5AYqIbJPFtPBhDy4ACtIdmDbwd YKoAs6Oh7GfMUOsaZ9P0Tj+jc5dWTCZyivjirrTf0rAoeOGbCQTwHjuv9+JASnVH N8CXdyicr1y3lo1JODWioz+fW4dFOXHbd81ho478MiI1dfiIjPg+NJU27LsVj5lz 2wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k6hp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAraYnQnvLAx6FSUtZFdQN TpevqZEHW2uecg0lD29EeZtjRQOo5z6ukRjXVc3ryMdEVPJjMyTtzOVuRq3XwrHW 7COXXjENb8hO6oMeilBp+AX3DpJnnTeyq1HYW2Une/EgIM+/+YdclfFZJn9VSg45 B5uF+q0X2fGLq5DJL6ZR3p5Bxebid+gZLbJcBtWxyO8LJ6NpEo6BS+nLcHrL5f3L sGfomwYcU7iHYj2j+8leYdVCgSLEV1q5uypxUCL2n313oMozgLYN+/f0Q6M+d2PN 0r2uwBq4cqK5IRmw+wpnzhuVO29W+s9gjXD54ipAowmV0W67aa5SmDmB5MHKTXLF 7QIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k6lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA22/3Vjzu0ugJ8pqi7qBN jxYKOOWXMc7QuV1nLxPQJbYP5hqsutZtIBNbQagx1IvE5Hb55qwt6pCtHdmzsNzY HljD5BHiZl9hNRy45ViYJpLGzv6LYvoSVRGr3uQe4xSHj/03Yz/FpVkl0a/ICR+l HUjlQW8xoy2jZHh2nWSw20cbhc2+cFo4+VBEeX+vzK+/TYytaTS8VJgOIxGaNeXd okks4n8wz+snK3a5mI38BGIgBjS2uZmi//IBOsmRlbs3fqP3h6/KeX+QLyzH+TN4 7sUL2NTEAfhNxG8vB44kRZ59/DLvIKhEka3ofszJ71oGrwvY1ShLXBrQvZnFB35R IwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k6lpfhd.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAorYkswYwAHhkADI/WHX9 i3kyA3wNLofMLCowgDEA4kAIYiKAyLkhw/92OdkO25AytPe7Y/iRxOPtxLXCVsTb DcX3NY0235yUzUJwaFeAxRqqFi1g2me87/lOEO/QRe+tZwUHJ8qjzueXflKttK6F VxRIrGVjawP95Tiv2HXlCntJsujgugmjsdS7wIrPfC12tsN+BqYKa2kGDaRcuMmM WqJeIZ5uQDTkrk5oc37hH7L57AECcIzUwQrDZ1UZdq3XEvXgYvJIhR8+oIdCTQ9c OoUNYfWIdrLCBs+EOFY/Ye9ejlGQ/CmBEvRCK8qWdduYNc+wUKZ84ideCw+Rhiz2 +wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k6lpwee.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyrIvtRFT4n0WUgofQ1wY pwpmKqMu51ga9fc/d8xygJp90DVDg6+3ELngeoe9V83KWSx26hGcepIwx9DcCQG1 ZvWAqLaCTexeaArA4lqFJUnpAuvyfSe1cbHZSDzC8iXJIjKjpU8A17/3juIIyexP hXqMtaiu0RycqAO8wSz5V04sQOstNqLH320OkGvF+vfTkDPOuJM9l/8YWa0WVKEa XoovjBGgyS12nOI/2wqFfc3+pdHfLCNnIbRy139y+IyDnYOtS5n7VuCItutUpfg6 1XTjjRZRXHbT2vqosh2yTCqwJuTxsL1LtjtXlj7NoQ7JeJGid1R9huQQoeI6fdTC 7wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k7lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoy1elAjV817rKDn/XHP4 Mc/+SwF4AMwLrypz8XvPcMkJzY4RWu1P/pAlToiQxaZjKYYkCaYSotA8spk/lcoO dHTIb1Sn+R60Dsg2hhAC8fl7Zv4evGtZE5fWJR4ciePzBUVadxqgYIcnnYU/VW+g IMDcL8CnQsaP225RD6nGte78C4u8U/FECWOs6lauAsrNzAmG/qMNgukaIeiAVaK2 XW6xECCBjPmQdsU8wEf/RbzJvtPg5mfUyUSlHzUzz86XQ05Z68VZ1ONkxemH6JlW SI8XOyOJGhkU728v0i/ZWB054RSSP6NvY7UcV2sNRGnNHGYc2LwFmpxyGaFYZzy2 MwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8ap.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxtAEdg21wMUIoQlMkgG5 hRzL+4ygqRD5rzNjMSAvMBSg74v9QSCf69eYkMiObLh81ivLFl/By6+fw8S5JXKU SnwnjMvKp5YhMAZ8PrUW0txIHLIoiuVPRIPujrgMPo7o7JQINSVkd3y9LgF43iGA 9YEj7ufvst7vLTgz3w3H2PYHLxDXod5lJHaKbEvhLqi+YAOdfDQLmAsQY8y+fwUc BhlNpNTIAOj0hXdhTBmWo6rEvedU9u2o0pa73NOlp5rdqAdZngvGUMmqqOka8lPq lu3kclaU/xdCWrla6xYLoXLPSCppoExRESYEYFxJJMUDEQNr5cG8BfntEPyrzMhU dwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8apwee.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzjJEGvo2WtRM9dXNKLzt Wxz7b+RTZMI+W5odPdehFg4BSmre1kN1MkExk12KNnVE1q2Wrl5BvnYc6inW90gB NoOS4SjhXQZQnbQIXhQpj8atTkef8bB1LZY3s6rVg+JvUxibp9aJpc0hPZbqJJBR R/HAOZSneAL8LGyf7N/EJxJt3+Bo59glpwdU2T6bkoT22HKrioMxiA4jeTxWUTB4 9UfwgcHzODGo/cHVwE+gMtdxoj8XTVJblK8tsDq2Xap3vtg/wRcBUhIiAW35O0bW 7G6YRMrwjhdk2aQf9myu9mGNriAbYWeQ/mZL3+Q1oheFNU1TNIL7ge6aeckEoEsA qQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8hp-hotel.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuyyswa5/CCR1+MGKFT6M YM9r+uNWig3SmHiFeJwrGl24JUPuRnUcXWNs3fDiNkakDemRrp2cyqGVnDKcAS4e DVBARC7YGLTj2wcYS9hQ1t3H74brfz4CtGd+WcaivngBIDig7x0+s7MPQ+aRMSv0 gyaCqsHLdqrktkhAWyIpwM/73S5LKtaDesB0KdTxS1VqXemqifuoD2Zh/V2GFEW2 vZytjggzndkE2of7Ay+TOG9NPkDnLB0jlbojOG18GEhqgA5KxNbKtTMY9SeqtP0m ptljh8awGf4whvYTk7bHnlEJncj+Xe0uATyjlqpulwuNQ4khIRAygiRwQxLRkYNy vwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8hp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6Hjzub5HrR1OhHqrE7fN H3rL/GH8pAeYZZDvPNyrBiZeoBSoVULCYbVhbs1ODKG+Kb2W3FgDbRfr0m2eCGdX DZ1KMR5LWpmvCClZ8cz5OGuGFYjJh36pGTa2cvvWB2aMbjNkIaVuIgPSyZBpR6S+ WaEXeh3IQVPLAlCXgEGscvNDJpF1dv90NFZwtvKIioKXzXKjNk0Y/AUMHNHY7qS6 Blk4mbobtooEpe2/MhtPMrkKBpqr8poRS13cKzwQi8QjnxNqm4BpdaHkM7hKTRQs nzA/prVLM+OLsShKJUJ7K6Hr0ThoFilMIXcolPCLQV+hQh+T42zskEXPcDr8tDAu yQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8hpp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2MDSxR5OrlAXB48c7i0U FAz0fRKoy99oKK9J0s01tWhrO3aum4NKCPt6nMnmfdImFgxZBG/K1tN6Eo83dQ16 +6cmpTzfiZKvyMdJAZfuS0wwdvZsPjtQZxgWpgBKKycWUcfxmev1eCTgkeauxKPC ZpNmyiYmrWU5hvAboT+q/EqNiwdvCiVxtsIlu8f2IlrioFglRKCBmcQPjKxWAUF3 7lOG6iF/m2MSBBmL1p7qKXj0jTHobnSOvmWHCIJCkQdSunNr+QWgkd8aTHp1ydso MxOOYE8xGgaqKECextyY1IFO2eY0lXQo3FBisVTVDIvFXYWln8wclZHA1L82VXR/ rwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8hpt.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7E0eMvzsQWEdQGd1yuRQ i1HoICLdxX9e/cuOia/C347Lk5LLV/sK2GAhalHHi9KZCiPl8iFZiwSiOurjeecq ucTws4wceStHWH+Ol8I2yKBagC5Ls/herv/IXlys62hzSR5uZydQvi0hVzSDbtWL xcfCTEdCiHcpxem9fR9+KJmiakX1KJxT22GJjhCjsZ50m/QTOYN23T7vzDmymJ/y TXzM8lbgya9yoYYn6ryZ0XRaRf0pZ1/lEQiKKi8p75d3eSxets5Jh5xEYlI5KZom tCT5hPLOqp0EMJ1ctFV7n0XLMWW0uREbaRwzXatH1yiKit+0DKnvpqA/5O03Nx0v zQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8hpwee.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YJdfY4oum0tMLj87Hw6 YCYRg7Fcjxa6W0PzDyR+9kYAjw+Uxm6aYjQ393gkJXOuex29VxEUkEVZG5hNMOLa MYuqrT0FnFRfFL6Gg4ABNF0bFvgGfwwZPS/dBOIw2PIKyWYYR/4sV5JF/hrWwApk lx59zWMz/1eC3JDSneeYtbrBUIQncRREt+IsBiS8PP3iI1dMMjbw4kn3WvNIwiwt wXUf2WVQuEmdoCikl9PigOEGydTpIL0ACVVcJ7RSwKd6lq4XGhjyDrS2E1nlvdsR WT9uU4f1rET8GGEjCHg8XD2R8vNGPs92ODMMW3kOoBucyDNUmOmWeBzjsyiwg41P KwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lp-hotel.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8KDgT0wlg0ewQE/9Wok2 udDba0SaCzahjnliI/u8KZekWmMg8SaXOpBEaawh7yQmLhUCQ3pnWoAKklUyYJKz 8ELpen04FJ1gohJTY0KyvowI5GoqsxbxtbyC3MzP5bAst1c+eixk80KVjhXo/lRv 0cx6FIqC12TEoMPKIsxt2ADhmCZYhGemrrVTmUVPKcmUujp4ZC1VMcPURHZBqUPK BQrOj3/UB6TzRS9z04Dcs5BTXhhPpdaYbD/ZYF+z3dGiXLDNh+Xy7+W7ZgRanBvP yKqFUAsrZ6DMHp6EmC3eTY3WNEFbhB4fX/SZt4H2P8GpVoBV/EoC+TaeeFSi9VLX iQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAngeMYnN8sMfSeC0yHSi8 5vjv1TAscgAlXdAZFyr7FAjDyqDfjPbS5qVFBicQnr9C67eUvNwIsiKqB+lvwGhu eTmO3dDQTlWz/TABaWHZ4LfkGEeTM2JlTgy41REFBSv8v6YC0qYmTV8Esd7ZAxNn J9pHkMEgFznfFxG+lEF3kPoIQEIaQd0wRzDrLg2FF4rXR/SwZ5PpSFFAhIEUYwM6 4aofzCAbziL7qugKrk3Q3sysO6MDPIce6RBhpPZy9XgCXs2vuhF6493W+T/NK204 xyBrNG/J6dfu0UWUbulZS7tvRB0HD4mmFnoPYu90UxifmWmBGLt0saAai5azaQ9s aQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lpn-hotel.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvPBfk1NJ8kSGQp1s1vUK Plo2HlPBoxwmQ5I2JJ0SGOWzU7zv39L+42ciNpxazhHKzDbt54ciTbOWAHw4f/qx votGIhfHE5Zx/NTfDaxvEDM53eTrjuJZWcu0wRHZmPOza/+X49ZlHNrN97UWEsDs uZinBBHtJGRncBjpjaszE/cd+Z2Z7ctIU6H6iPhs7jg3y24mkfYKp+s2xDeyvo2a 5jO5XO80nCQLTnF1JGNHnnHz2+K51W9WttNUBpWr9K8kiJd1Y4yrK1WmcohOGNVT SPOh1fZyrZyTLwNDHet7DFWMJVagoyEGH/T1bI6eOKPILfx5mo92tZO/VhDr7dtu cQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lpn.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyeGtobAu/iCQunfBtoef A9AuuDk8Kduo8pM3aB6b5i8b6HoL5S6Q116ekfpg6U1G+Kodm69+b5tAukAl3A5t x7+zzQFejL2b1KPqkZMWlqj4syFmRE66lOKed/mZZz5MqEymW08PAASwpWGFdH4m cNWWUU3Hu+fjTXkqxR2s9sm2vQ9ErItPUHiXZ+1nhCNPEIzvVzAfzky68Nw+YP94 Gbponzjhrd8t7YW2IhQuXrz9xaoHR4Gtw1aH7SQDBzCaeo5iaXMhDGJO6RIgWxIP GgsolevTRzkuJMRipJOQzK6wLWarIDtK+TTe7QH494Uuj1zJvR/WZAi2jMNPomXM 7QIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lpn2.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8sedOqOxQqv+4yK07arG Wxt8j8IthE8G0YNN6Im9SB3MOWxiLmLCxxGRaQhcGq/W5j27Zr+MDLsBUY67eW5Q 667We3GorKzgoQ8e32rhCtfo/P3eZP3ZhRaDEiFOUdN9qc9E8vhi2wLiMm1dAnzn qkWSnvTQey2jJm0paFeidGB4/3DVwhDlbCoe6b6g1Z9ABKqEAXI7WLJjSq3l+5qO AynScJLkqZ8/igzxlNIHJTHPmSqLOgD8+Abzbb5SUp/wj5jyYBRqOBKM1qEnOE8T BTH6faCDB88BcZ9zLl8imndhlLqUVze/Te0DN80BDh0lZ2GlNpm14L9W9QdANuzQ wQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/k8lpwee.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkRlJrTu2qgIUibttxPqv 2unfjfDWk3aF7CjUrCCM3WV+RzjoF6lQKym57o3muIuXY+O84KExBrlWZvMe0zVM 6wN0fYU21urzSwcwCc2xetolg5BOLS9U4y5gR10UGuoOWeB5Z8r0deobuE9+YMEi RKIVrN8bDwLb8C/qWtrCVPz/BZ7nGhALYggTTzkdm1vrgWMOVR+pdb4mf0mDbiX1 3Fb273F2u7qOPqaIBX5JXAfPxMmsgguWjQEiEEN4C2fzYbRpzhwmL2dk+niey4+R 4zFdzNdNX3GlwBQHhGtbmt5mKivgE87ncnZ6LgCURdxhJ0doMuLusBEJgZ6EOitk 2wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/kf23f-mnt.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1msQhd8jun9HD6ZMJeLv 530rCgotQZRgvHVUBOhN95yQbmnVWKqZp3AAxCgBjfBoL6qXvmeiJiioCdJCZOEA f9AUH2keJOkFhu4xj5xG39aVss17dWqBPEV32JT9H/GZtXSCSe6xgvzLbtVsOQl7 lzksx52Y/Swe7yvdMMBTKTkcXry9RY6E5gHtVJblSG7QFLjSs3sndo9dfhLUaAys MxawIzoQjeZCOdJ5uKK5LkmB1mPEI0uvavCbqxLOitbccntyjOv8652iLjqD4/mx QXqnLR3IpYhl0Tnly1bHbYFmFBYUu4OLsdtR3tOa6U1frjG3RJrzu2C+CN2ulaX/ 5QIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/kf23f.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxHkWUXttsB/dAvjh0dLm BCd3h//QOmcBPvQUMirVHv6w0fnZ5irmUpCUaeJRkdSkc9xSunh5gYtE/M6CMne5 58yv+bpnDo9tHfUxIonRaktA0pgFw2i7uHyHA0XH6B2IycmyRCRotL3KJaygHkqI n8ysHJ6rYVvmY1Yu8YGo4Chzv96dlULAgzMdmJcxFiMG1B140qp1QK/AIArFr893 VqiShvJj6492/MpR/W7TYxz6AbRj/bOEh71MHqG+5fEVF6fn4+G37AaOUHL+oz8r MO+PVH1o2beibiPn+l5NC3i2TB7nF8KIvHrOCo05fnWpVfZO43ki3mO5MQDZCP1Y gwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/kf23fwee.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAse+KN3Tj1YZdkc9AUVx/ my7QekrbDY6xdcqifU1HRDJEYL7tfaJqofVtv9tiFn+NlcWpU/gSD9Q2dJFtsdN6 BaZyeVT4rhEr09WqkPFh8wGs5dbhAPYcyDzjdP2uGQnFawWV7rc7xSTJFhVCNRk6 4a8Hld/VC28QtCYFaR9mXvFygcSWZ0H9d/ofwg7AwwRNiRXAyFZ4UXYM7f+kOUmG Jbwwu2Te+Rao4H7i0xb50XbkysdSDQBkjaHO0SBL6zMml1XTFC1oDEYPi8N3Wdca Yk2DzJwfY6qdtNo9cOCEPgoWab7xMmu+XEi5W2bWHAF2BmHxAGK7bnY/OVAipyD9 IwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/kid23q.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApaY5LP7/8EMb/72h7prT T6k8v5heHhvqAYANOOcEI6zz9Q7oKShZ8swcN65re22ctwpwYCB3DOwmRVqVr8Fx /nZbhyS1MqjvvbaJECR5qnP+DWo9en7RrJ0wsXqV2su4VwMwoY6Tyh4/uK5xYABr yYjsqa12gJXMwboBEbvdAPrualkan35+qfoakajFOgECy2Ps1UF93rebXJaOt1O1 6R79V1isPiGdVIHrsoLawDyJRCBvDsCmb7B0fRzxVUxUldkbGmTDo5HlV67hEO6D T4DKHA6vQ46VRQUiqi7yYt+cuRVV0us0haOv279Mml1bKJCjtVjGKpxq8WaSzFFs iQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lg1152.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDkNkhcArb1al1SWazlsT6lAdA7 oq1lqOkC0ullyDveuJJTjfordgGxYBpk6fxUhJgmIZJgFXIkGcrj9Iv/iy5EomR+ 2lBokhh822ssLN6NqW8V+D6DA948qdX4IW6/4jswbXotSWRBv3Emhkh7l6zl2XY3 kKq2cQIffONSDjAANwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lg1154_netcast.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCkh+pwyk0MCwTkjTQTc7+SKhao WZ8RjphJHJo/J911E23waJS3uBU7xfck5lgLHc0MwHYocYUJ74mjBCrJ1QRt5ppt /1qIswG0xyTallg7+5m4wASqAilOtzXM1d2Iqeru9808rzSBmtac2zQzbkq+J6LB Wfh4w+gWUVDyVrILZwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lg1154_webos.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjyC+5bEEE25JvwZxASvbkoF1t /zs7jgkj2Vv2yoPMAdHan9PumHYo2IthEWjLdA6BfTskYSc9RPeDAKMIPmV6MzrU nQkkW4uxPXnV48gERtSnfQcGFHsQyJpeEBP3skcZC/38mpWnCDLFxeahJiG8zSmP wBc4bMW7Yv0a6vsAewIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm14.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC3CAuN+IdjzWOQIsL60Y7+I813 n7Ra0U1EmumjtO0YeLAY1k1HLhdpCF0WY2UNa0E4SzAWOsOOhmHBASJMWlIDEl8p eN9WXdInANwh0KhS6v4lyXTAhwH2BPy9JhoYrqAJpWhETIsgUYWHdWv2mdCN0PBZ itX+rRyeVFYOi+eFSQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm15u.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOJne7d1AULNFGTe/soOcYhUsN tKXlglSCxV9eR/WsfdOtMCJtoewBtohYBS09M7RgP4eSgwgmHWagL7qx3NldIAAa VgR0zSRx1vHFAs2Mbbppzc7rGuxHMOpXP8lMo0hGy4VTpisAhLdyIfc7QJib+9VS ujxGPrfiVbaplyNwjQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm18a.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq9yS4v9QyOoX5NP4y9mQ aAi6S4qoLTJon61p5PmyAS07xTU9ArYt5Rx/JjmVEAXoU9BAZAMU1n6hR3hxEovo lSy4JBlHAH+LbmvHON8XBFRPDtyrhjDRz3iaqM/7WpVEWtmoSaWlNfWdEb/9XChR CczLkZxvkeq+LlxKo/mG3mkzkBzEozq2Hx6ETmC9VsG9w7o1pU3Km0c2px1DcRby F1X3EEm2F6DYuwKk4E9jMtrvSAoXGQrZvffJtvccjffHBS2zHdu58YavQm4tpE/3 LQwypd2ueZGCJp5NegODHXDKKclAwGJniUC/2rTX/5ErZ49iurdyJHHZ4F0Khf25 AwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm21a.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtXZUiPWMvvDIzZi8bZHA rmSNQnXVgcYVLJG5Y8EnFFPcu4Yi9MF/ftoLnMTEBhtdu3XTtbxew3GPP5nrIbcm oqNwLMVXK9G4oJAhEeswgARWhLJwASE8WnJ+9MuxgZD2OZVp63P04/alolMZw+OM pNyeYF2xDuD4dHtzZAsj3adUmk7lw+IT8zVv31t+npxW2Vd6w0FG9j+eRPKTJ0jO gR3wXqGFoLfe7HxBX64uZEETF+gIQFEOEJsm+QskE1r9On98YIDckUlQ3azlxToH 0vrNDRWSj7jmgWZkVmBaLKNMxsAgwC/r+wgHI46I77qtqdy4JfgNLJJR05T2CaRo fwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm21an.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvmH6LxtCAWEbiSWDwfAj G4AVATdk5lc2zmPQB6Qv4rQfZcwSKbh5H4R4mKKHD/MKKAbFDQMTfMtdPgO9k8+Q 8y3UfyCk3lBF9SENeQlJ+I5tuIbMb0GAVCPES5e28DeVzdVAYZpUhidtq4HXa9QD /3bNnk0TpGy0TrUcvANJ4GniSxXiu30pH9D2vQHFZOiISWtRrHtEvUtWchmnnBKG nSiy6Tpin5mDcEwDw4d5mDB4tGBeA3QaQVGDGC2ypN0KlN//S6EVfcyhmQU+zWei Z0MOSU9RNn7w1ZYtNBAHWxXiSLp9+xAY2crOfChNisX+ywBsCCLjnSdf58//JmxD zQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm21ann.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApFnPQdukfvMBBW2euXBw Y2djHEecfMbc/GI8axwSFwldAo4M3+qbLCCP0W0qGvTAWOgpJZLqLCPoGI4SiS2b OzOK9Khy8xEoIVjM74FrUGQ8Vr30Zh3cmNWBn29VRgsjEhtjTlHTCIC/YfiGM7sT ZhwI0NjLyLJiGZtiPkacJWH02Gma8nsvIZMEYZPYviJenjJo8/PkNGQxXmQM+Ih+ +a+WGDQFmCUhMzbev/O61wybFpLG+NW4lIx6EtOxS2tRMrren6HqVRF4nW1wURWZ Tq4lEpBqFUEURk99qZPW0GHKMXUPWYiICrHwqGMB3eeZ6tjo8uR9IANKFQJbhOzD zwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm21u.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz49aVG3dPRd98oTlw5DN L8iGZacnoeRxkqjwAtlI9Bl7Rujf9R/o3B0gGQXCbdWQ62xsagxv/bOUCrYMtsaD ufOo7+bsukPX2Mz2OJFUaPKA22wMW5m2ccs+ZkdBt0t4OSLzd6ROdEmRTLG7tnj4 6AiAk8BTSiLrABE2GF5j+I7Q2fyg2hhHDWO3R8pC0lBMdSOG4hzNRxnzKcgmbo1j q0Ro1929tQ8VK49j6PY3iQUJQDvPNbzWdYAhDwfSp6sRE7ggRdR3gYPqRjyFVPYH xhakC4uowzT6JDlb3S29bgyxqdjrYjh+JgKLVOyxjlKR6b5U6LMaWKOXbB4tk9ci lwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/lm21ut.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3RrEqzeR8db8ZtpVGFl QSc48VYW/ckMHTStUhFOLz0G3h98nuNNhg+tfkUun9bZQAesENdkAerbs9DjaIi1 lRM88Ng2WfUY64p0cfBxdGEsjs1wepJ88BKy8bic4yC20zWcIyCshWy+oXM2Yry5 gCjJwTnntkrtOeO5QuThudvP2k2P1IzqgdRQ5gK2AuJAjeLmS8gs1p+lyDlBXqG5 BpVksBmnHnCYrUktLuR1z/cZN1bAPupX3ZWu8OWC4i3BT0QWakfOhYbyBRaa6lCX CodnsnUPT8uOgPioRPznJKJa1+kFYHnTcy5YKBJLWyI6ylb85Sf+qtCAZPNp76ZU XwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m14.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC94ihi++eWPZHV2x14kz8KvaWu suSOQPLMUvH4mppctZIMDm65XX1XuWuVlpRtDlwvoDT1UEz/A8Y9DVy7fSABeDyM ESvG5LxqDx56e3i3spsqQndx/+Y+dbu20B/8NNVdaN1CkW21oIkYYXt0QK2SLBF5 E1UYwCQFL7vbK6kfkQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m16.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8FNygls/BI8MQnLCczjr SjKWNyC3nuwrtmJYT51JzI2oq1Q/VHBCJlWD0pIYZKnFilWCCM68fxGGUj/n7ekU 2TPZJQ33fcF4jeP2iNu/PmXkLXwA8K9017NTjNcj31a7Z9OcKmpJ/Up2XSAPkrKc 9/edetzsmT5m0MsXo615Y+qleTbdUXmzE4A/8/hazNyan5jxjoBwCEhYdGQX1gXa wUJG4zyXo9sSfrR2JMlLX42F77EUYbG6XYO8FJlgreoLyw2TIBRIR4oKRTxv0ZVv nu6nh/1yPWE+AQL6nlkrZByDHpX1RxbzhvNp/bTbeBbzPMEazavFXvb8JrpBs7GS kwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m16p.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsFK3Fw+If1BMF2epkKBY /RuSPBMD448ZDq5Sved31VPtYflCM4c57K0HQPhnSL+AvwYrfCZ7Lv7T7GDbILOQ Oq2qWMmtqUMt0bBT90MbtxQRdvNs6KAoFwhE91+2JPtDfa0f8Tge51ZhYJqh4NbA hzkVgu6juVgSqXoKRZKy/YMO+ZmTAyqEWcqiczKpT84O/pGk2j33PXb4VE7UVslQ lYsk5akNdnLLGBA2H41qi/rDcCshggN/R9USeRgrTp2zr1c27RV9BIRPeCfN1jLf XtGvgcPbDcn8FWdbFrWLjhkHZYvT+cZ9ur7zKiB/i57MkQL2xtYyyTuqnH+082Tf 4wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m16p3.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7WrBwmE+jel2wBUeFtb oV93IbGcwoRVfGA6j0G5rN/oCGVseC5g2pkGm/U6gukaLVO6FC2Sp6jfnqG0LfB1 HY8Ezf7dQOVlgoMjPGtbGJKnW6SvhsukcCQViXwO33wm0biPcrPtH2mDYx5E3kJi 3+QhhKC+Em+Jb+ajSnAkMPhwCZpBvuvqqf4clorLbGWz2QdoOaS7z7FsmWS7GCN7 HKF0qFq0SSUsu/Plv2vxuJ3+R95qG2swVGSY/OXfzMK0JVdjU5onpzzXPfOKwTep OB+8fbTqsgERNfthSJP0psciKDmzXbtP/yjg51Sb4nWn2x97HaMjvsc/I1l2ysjh 3wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m16pp.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnP+kj6qXfiiSMa/mN/dC P/vasilwyu0DLKrOkJb+X00IY9LSS5O4g4wcTrG6RUJLZ0+r1y+mRWFS0zMIatlh 3NEe29u7SlhMFzvgPwjC29qWrxI1HfcXXrIV8VLeAW21sM0IaVLEVALmGy3itYIc XRO1o6RBYAQ/ABwbJha8ClEdDXcXWiDyqg9ZIBN3qmZ/aZxa4n3h5Ggf92/kRCKI FZFfe/1HzcfglOQAH0FRJlbzrPyj4ymVmM04V3wu0Ibgdl8wJXWenZHIsS5Y/n18 qR7dfOKwHjsRFGmLYqxk5U6Ks2WrMLzG6vnKji+oAcjf99fcPh950GMhMWQq67E7 HwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m23.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5cBUq+bAeiSsj45B4cvi oHxeKj1aU7VUrP+f/ll8TQg5dOG7F1J+o6E6tkH7WCfoImwnuKjIeEjIjVZQv0KP VCPIEJpQWYs2n0+bqQTDdt1LHbDzej5vu4AS5phW4c0XCl20THPlXysyppk3eKMJ NPjuIxeLHhmEOulv10JN94WEI33saLI7GNsWRuyRnvXaFKeVaDSrSvHM/rHtzWuq 5t+Te+rhglPBqjoD2swMuQIFtIvK6M/3TpUwAA0afTpwDc1kyI0NZDgH99AV7oaR jLGP46hwxU1f7MbW+enUG3g65bbvs9vMM4uHL7MwFrQTD6Ar7tganhBfcxuBdtHI 7wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m2_sspm.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEpUSxzbMqpwvKLn2FKTyQHuUY h5f/qydAwKOXPwN9IPVyxH3OiiyI5mxuw5lSEt+dgnkczbOLF54Xz4qBW4Dt8iD2 tO1rsKDVykEozdmLjxPmf3wDalM63IwNGe+QgosC7sB7xjtTAGq/DrWEOIh1nO1s /4079RA853cwga3YJQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/m3.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz4Vi5HM4NsE09eCLCQXX 8DNGWA/XFF2Fycs0Ki4aih2drl/GWu6W9AAaS8wafyNkJ2PpF7Krs5NwtqbwrayD zHRUiVx878ZcZVek6NbByjgXA9WXXjw55LeHpqr4wtyrBR7s4HPa5QdlyvKHx9EY gT5/9WGm261pBYkifnT1yLStqBs778WWLCJm828bIIs4jd2EystiTazP1Bk6Fa4E NJxjSkwmAUjuxTiyR7Q/pYnMjOdr09GyJRXQ4LagtdjX4uVMkObPFc98s5nHBxzP TfN/1IBQHdZFDTY4VRDXkT9UNMwxCHRF+ayCumf1zp/STcoTwVyleVacsg8Li++6 mQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/mtk5369.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDL0sBwpPjjT9yYZPpXej4/TW7f ERA/rCDHPtZwb3YBFy40g45XAvjukh9VUFY84uOA2cX7OaQKfoeM8WhtRQdqNEf3 Q0QyY/dQZiRqnnYQKYk8GALC3V9/CgXIfNy+yHP3VCBXuTluA9SpXBTGdFxJCQpa eJkeze3moUCZPnuQqQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/mtk5398.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDyVpYMXOhXKj4pkSv6ROs6kaQp TjCKzR71mf3Upw1YmrXhFT+nNCtjqo/JenuupxW1lCyovCMZFOVDdG+Y+OyM5oCc 0mgVJs6fyHAGz2FIUwULy3NU27/f4M0cmX/qCjOSEt4WPvHwtCIuT6KiWZ6X2qCp PbzFkkzNc1PF5yq2CQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/netflix_pub.pem ================================================ -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6Qu5GAw/ITjDcuHnSTZP56fRT jtdCZj2SDdDtMP7MOJ2GoCRA8kRkhj0sFtMwwCHiydEiv+A3bshJwGxI0lYYeZi8 d7LhELZZSALecT0pimbXc9EFMc7DCCSAIJfR5lXNeut+JIBU6fwLq/bTc22mUtfW iwc6Rx3nxN45HMMhUwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o18.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/HyMayJG0kzUA9XKbxi rE4vOqVZKtlVJj8bzQAUtoxxguQDz0T1t1HmbtDKLfhSlcwNM/rpilA5nIepArGe czNzYFTYYBV9HsSI1VuSrEfCILGtq0RbIMHCnvkt2RCwn1QWNS24k5dr0tI7kVmD b6DKmLNmmKUGsG5EdVvkTw4jB6g4bOk8Ji6LFq6MY7gS+90f3BdxDavKukEoQ8HI 6xNpZAHrCe+KDAOnLbkrILBzpXpJLD2aujJSYwDCr8vxNCVizENM8H0B1NLxDlef fvgh3P5ch6uVKFw2hwcZC3TRkfur1i1na4tyRCjPqS3Fg0p0kZrfjMUkLkFywT0k /QIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o18_2019.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2cLO2n6G4YkXuxOvGNoG h32B3Zl7a6fJEg1rOb6yjo1YsfQ2jijkpjlBeZKnsZGPodyzKmm21o7XArlwbn2c vFFk8kf7UjyuPR1a1SghsiuAnxJjGD31TcEgD/uBtWPyqrKSu8cu0FnyC63ZmfuZ LBgvgvnupqH1RbiQEOPoUnbwTryTFKyNtpt6MCwsRxExQxxLgcn+aHLoVs5jqkyu qSrMtI4ol5Udu9mmQ5VMdkOVjAXue1xvCEW4ld2NnNTDkmIlmXrqJrPjxQ2l+rRe W7cyzmV6ZZZYXCG4YWPdefW+EzjzOJzemG5dSeH2jUPfBb4cx2qYx2ToZS5Blnaz fwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o18k.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv4VvbWUx/5imL7lUyBJK ABGPNAPjVT4w3BRCwVOAkITtMk2VM3fWirZrH2UE40NL/wzdjqVCC0+PTHXvDeGj 3LLcyhaESNz2Pn2qavWgKP1YWA5ctqphrSrPQGZ3CBc/Iu+lMYJLnzx6LL2BGezn he4oxrkA6tOoiERgNnCGisnHZs5vHDZhU5lYAXQk3kYWzKG7+z5DOl/OA0C/wkDh 0gUGQ7OxDcQiCdi1SUyTkHoFgJK4fBXC62LTfaZzAI2yGDoMtz6JcipxX/WZKBwX 9XCaImnS020vWl4ikfGcq376gOAN+wUCwACyLPnfpdkmfFm+Cqfc2tmhKkz+bwaX 8wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o20.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwbLByTYxeXUTG/+8nndC foFPXU75yEi2LXTKrpa6vIO6AKFaE/0cvJz4ZJ6gEomf6LiQvjne9f+GLZgmzHs3 ndwl7JUdp5/TNnx8l1iITY8gAN4Gc46APT8RaR4hLTxY25r2MnxxM8S20U4g09Ql 8fjaZcYh8GXZDrmBTtpMfzDRsoKIF1wGyvWvLRYD097VEwgKjmP+HUUyxL3Pmnf1 H2R9o7wSzVJhRTui0eABklFT5SWH+GiaxjM7eEpO7vztJ0l9fxReNR9xnYjJV/YO CWWLidBvFjSXgmpH+NPJS8g5XvvQHxgLf6UJiLMTM+BtN8YQNWTvn38GPGQCvOcw LQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o208k.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn2T8zysvjAQgAAelDcZ0 B1ONDwzFYmSCS67vT1/mzOi8xuiV1uht0bY8o+ku9z54zHMZZ4DL3KpbcVRW06J3 X7htGX/FBnEA/Qrj9QRyxjq2rVhjgxwoToa9PPIySLXuSLF7RV5imB/dKld1RVNq f5R0RJL4OSMZ84usTVbN5Mdi1zghevMw76ZsHHIQqnXCBA49/VZdp3TGXqaw6pYS HYwrDYGTR3H+ICci4ZiqyVh/g81JL8GGtButyWGWw+ykffN1dUycH0rmu/DQ3F0M 6ZbMswnmRtEGq2fI7MlfOvsMIgSdC9Soq3hQul4uISCKi+4+DNY+VjMbI8I/oSkZ zQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o20n.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt+9X5Iu6Z9fxu5egIpsb 5yWadtIk8aYNggd5EFBJoiO/oD0zjLIc6aoAV01tJp3t93ngq3BS6hAIE+vSkGJI CwImAIMRtot0wmS5aPQB+4ImgChgZeEpU/86oWBtiap2eN6WEaRtKiA1InfLF4Ai 8qiQX1PXr9X4Z2UJDbOi0nJU1adVOm9v98O4k0m/Qtirw1YRDOD0xLlVXalgaaCS 640NsipAggowKm1esiCTupYmwSklvJtqLTR7LYy/9w4J8ePo0ZQscsVvVjlTnY4O V87/1dFOqzVRoP2TuCp501F/8YjkHVOuLb9P2uS+CZZzGkPLIowFtyCJ6HD43+rt dQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o22.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs+tQtULZxECErZGR9mfy f9ieRBkISQ7gOTCKcV6VD0e4ifnAjUR3YLDoZcMyaNfIuUlu7cd18mK6YvKDP9yn 1LhoUrby8EoqWAM7EltSW0K4TdSIUbn1HDT0WIb+lE1flLTlyuCfE2LWjjh6Y5gN JiIRiaI27CZLK+kbBfab2IUXtEJJpsNKwaQ7Is3ZkBJyoOFZu489nL1YDU/nwrVC 6rUgT0P+15S6ONuc63IY3TLqFPi/7TS3cwaYCoBjutVU2hGv+WdMx9IMVLGzHFMx PGulCb2uRQILBzONhibC+wCwVkC5ARqeK433fmG62tapOhMxTPrq9EjIrZPCsjFZ 3wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o22n.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwDunPi+oDUiwolB2kMZB IKHAHdd0zGMT+RrbqsQFKozRfdZjDtiTCFBj2Rugjnw62VBSffnLqBRDdRksYCqw i91wXkJb/FZ8CbKfndFkTOR4eMhUgS9p2iw7lRz4lwe50LI9ANcPJfWCLmwhxa4s W28Rc2tVOxyMbSS76HCnoql5hdMNoLsImtguS+ytGho0AHyIRGQejSv/scR1h1g5 xt0VL5hsKIsbTaAjnvqTYCalj55P9PkVcMJWLmac827ViwDZB5l5hfX2bNN1j41V YkHIUBCBikP+k/+/16kPD8Ow9ZPWb7ulrxmvXLewu5hy8A8kIHYBG8X+59zMI8A7 XwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o22n2.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhi0GGEK2o7GrmGsMXSz3 3pJNJ2sUdp36IdqJBgxYuJMO2QPvg5Axh+8Qdi3g9qqL3vvyWpMXJtDcS9lHIaxh sm3MYFETsUBk6y7fPM72Ob/RdTARs+vG5S9j5B5z6dGgoVPUTwnBBhfsTgJLIdek yER/xjV7EQ9blA1gY3htWWf6KIvlY3lIF8xp+L0olNy3zdTLzkPdboVMhPCCnacZ W1U6U4Y34s7YSEMQp2+QMzHwwXNtrZapDZjq8wooGxPAryDAdFLILvjILXtvGD89 Qv0J5E8/wS3GngxBL6jVnaPjk2yLJMnBPxhKTsd+uBRJ7X6/JXM86LebNVj5wTu+ 5wIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o22n28k.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7ktbTHcQcFld59Vn9dXy ivgkaVKYG8vhRdQRUMvEjP8O+NgasOhZ3PNy0bJsqihxhprj6wfSxIZbdqGkXhLs amWdykhOYWwAbs0rrh4yrHX2sa/IqZfxxEJlulCYaUu5gzi1tZ9/3ga2B4g4CVOO YcOmKtWCv/ZpRpSHaxNdevHK/PIYElMssuiksvqArMV6dwn05/B81U7kEMUFKvbP Bl0OHahmGcQ+HFBRCnys0YIUYd/IOvj7LXTOZQBsqCBIWLdCtBYSPkT+1rQTHb5Q eqA9BAJsKcbSqRu42g+j88lDJEa6rKuxTuqpJEabEhuyKgIMoK5mVzBdeLNu2qoU /QIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o22n3.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvEh5Njtd5dL7Bv0Bemo4 8KL0/kPtJeVF5Alc6n2nC6mLpSdEcNdONTlFKbCl3CpeYg1G0GL+WosG9gowSPuG SeG0u1ZWXprWeqALiwvaL637AK4jtM10u2oR4v0lP4/wrBBuLHbHp1xvXenQOZIT BN8tbFQoEtuHIu6HlCDjC11g+emzvvkXhHBpD+TGpGaz3jmnNqYYeCyvUTNsmoVL PKrQuRY4rFSmxiZvE0rsYWTckR4nNwrh4WJ1sNOmcJ910jmgcE4/EXJv2f5QVIYR X2zP76NTzlANclqzjfshISk73gxx9ZY3vLQKYShp9P3lH50ip9yGumML3I5lhjKj wQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o24.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3Tg2oafPMSxlLX8uPIXh 1rsn8Zx5GNvahJjxKYBftrgS96c8k9n717vRtE9bTssXRVjf7b3rKIOQ3odRMtpq wZIkml4ZSg2p/M8YNhHLN4oNxBS7CN26SajiZbwu9HabFHWYoS54LiUkrFQKh9fD KFGDY0PYY8BdjKBWyoljj9ZckqjQffaDJMtakJMIhfG7cLI+HcNNyPovUcA0AQU8 GBaFNvzMWiYEMuJMQu/C9kjWimRrAIXyH8AvP1gkc+yb6fdxO2K5Joo3/CrRfL1R vBs5F/QZCRX82WMNzhgtBycreAPxb5R62pfgf21QGeiz4uFsX8u0pKBNpOFMVUvQ WQIDAQAB -----END PUBLIC KEY----- ================================================ FILE: keys/o24n.pem ================================================ -----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApPw4IzWaja49cPlyZl15 7XAsJIETa1RhuN+gxih8iNZy2/hk8mGSWNc9w41K0lDvb+4TSP+1teUjEeFUZ9Rc lxe22PHki7nLArG1vO0jV4+2S5YJFdcspIJuCJG4E48VIk77x8tgzeseZY+maip+ ftCHCKYr70JWQsxRBblzsrbWuyKnbx5nfyVpzLdEBBZPKoS7CO5a8bkW1DGN0t4n +FZqbWuZqGsLRTls98/WkcD/mU7jwN1fQCidM0RJozlCGKqkFz9sMaQgBu30VAyr A2MTa/IlCVVDrTT3ZKkd58J2mTkgcUapQUpDB1927wPK1Hm+1NchIw5CxtW5/o6q SwIDAQAB -----END PUBLIC KEY----- ================================================ FILE: partinfo.py ================================================ #!/usr/bin/env python2 import os, struct, sys, binascii, datetime, fnmatch def allzero(string): for x in string: if ord(x): return False return True def allFF(string): for x in string: if ord(x) != 0xFF: return False return True def validate(date_text): try: datetime.datetime.strptime(date_text, '%Y-%m-%d') except ValueError: #raise ValueError("Invalid Partition Table File") sys.exit("Invalid Partition Table File") def fancyprint(str, pad): astr = "|" for c in range(pad): astr+=" " astr+=str for c in range(pad): astr+=" " astr+= "|" for c in range(len(astr)): sys.stdout.write('-') print "" print astr for c in range(len(astr)): sys.stdout.write('-') print "" if not len(sys.argv) == 2: print "Usage: %s part.pak" % sys.argv[0] sys.exit() if not os.path.exists(sys.argv[1]): sys.exit("Invalid file specified") with open(sys.argv[1], "rb") as partpak: #partinfo struct, used by: # mtk2013 # lg1154 partmap_struct = "<4s4s4sB3x" device_struct = "<32sQQ4s4siI" part_struct = "<32sQQ32sIIBBI2x" (magic, cur_epk_ver, old_epk_ver, npartition) = struct.unpack(partmap_struct, partpak.read(struct.calcsize(partmap_struct))) (devname, devsize, devphys, devvirt, devcached, devbandwith, devused) = struct.unpack(device_struct, partpak.read(struct.calcsize(device_struct))) devname = devname.replace("\x00","") #remove empty chars from string ismtk1 = fnmatch.fnmatchcase(devname, "mtk3569-emmc") #match mtk2012 ismtkm1 = fnmatch.fnmatchcase(devname, "mtk5369-emmc") #match mtk2012 ismtk2 = fnmatch.fnmatchcase(devname, "mtk3598-emmc") #match mtk2013 ismtkm2 = fnmatch.fnmatchcase(devname, "mtk5398-emmc") #match mtk2013 is1152 = fnmatch.fnmatchcase(devname, "l9_emmc") #match 1152 is1154 = fnmatch.fnmatchcase(devname, "h13_emmc") #match 1154 isbcm1 = fnmatch.fnmatchcase(devname, "bcm35xx_map0") #match broadcom isbcm2 = fnmatch.fnmatchcase(devname, "bcm35230_map0") #match broadcom ismstar= fnmatch.fnmatchcase(devname, "mstar_map0") #match mstar if ismtk1 or ismtkm1: model="Mtk 2012 - MTK5369" elif ismtk2 or ismtkm2: model="Mtk 2013 - MTK5398" elif is1152: model="LG1152" elif is1154: model="LG1154" elif isbcm1: model="BCM 2011 - BCM35230" elif isbcm2: model="BCM 2010 - BCM35XX" elif ismstar: model="Mstar Saturn/LM1" else: model="Unknown" if ismtk2 == False and is1154 == False: #alternative structs if ismtk1 == True or is1152 == True: #mixed struct, used by # mtk2012: # lg1152 # # partinfo header # mtdinfo device struct # Mixed mtdinfo AND partinfo struct # 32sII32s --> old mtdinfo part # sIIBBI2x --> new partinfo part partpak.seek(0) partmap_struct = "<4s4s4sB3x" device_struct = "<32sII4s4siI" part_struct = "<32sII32sIIBBI2x" (magic, cur_epk_ver, old_epk_ver, npartition) = struct.unpack(partmap_struct, partpak.read(struct.calcsize(partmap_struct))) (devname, devsize, devphys, devvirt, devcached, devbandwith, devused) = struct.unpack(device_struct, partpak.read(struct.calcsize(device_struct))) else: #mtdinfo struct, used by: # bcm # lm1 # mstar partpak.seek(0) partmap_struct = "<4s4s4sBB2x" device_struct = "<32sII4s4siI" part_struct = "<32sII32sIIBBBx" (magic, cur_epk_ver, old_epk_ver, nmap, npartition) = struct.unpack(partmap_struct, partpak.read(struct.calcsize(partmap_struct))) (devname, devsize, devphys, devvirt, devcached, devbandwith, devused) = struct.unpack(device_struct, partpak.read(struct.calcsize(device_struct))) #mtdinfo struct supports 4 mtd devices, but LG uses only one nand/device #seek ahead the 3 empty slots partpak.read(struct.calcsize(device_struct)*3) devname = devname.replace("\x00","") #remove empty chars from string devsize = float(devsize) if devsize%(1024*1024*1024) == 0: #Gigabytes devsize = devsize/1024/1024/1024 devsizeunit = "GB" else: #Small MTD, use Megabytes devsize = devsize/1024/1024 devsizeunit = "MB" #swap magic byte array magic = list(magic)[::-1] #if epk fields are not empty, swap them if not allzero(cur_epk_ver) and not allzero(old_epk_ver): cur_epk_ver = list(cur_epk_ver)[::-1] old_epk_ver = list(old_epk_ver)[::-1] epk_ver = 1 else: #empty apk fields, don't display epk_ver = 0 #encode magic and epk data (if present) to hex for e in range(4): magic[e] = magic[e].encode("hex") if epk_ver == 1: cur_epk_ver[e] = cur_epk_ver[e].encode("hex") old_epk_ver[e] = old_epk_ver[e].encode("hex") #join epk data with dot (.) cur_epk_ver = '.'.join([str(x) for x in cur_epk_ver]) old_epk_ver = '.'.join([str(x) for x in old_epk_ver]) #build magic string magic = magic[0]+magic[1]+"-"+magic[2]+"-"+magic[3] #check if it's a valid date validate(magic) fancyprint("Detected: "+model, 10) print "Partition Table Info:" print "-------------------------------" print "Date Magic: %s" %magic if not epk_ver == 0: print "Epk version: %s" % cur_epk_ver print "Old Epk version: %s" % old_epk_ver if not npartition == 1 and not npartition == 0: print "Partition Count: %d" % npartition print "MTD Name: %s, size %d %s" % (devname, devsize, devsizeunit) print "Partition Table:" print "-------------------------------" for part in range(npartition): (partname, partoff, partsize, partfn, partfs, partsw, partIsUsed, partIsValid, partflags) = struct.unpack(part_struct, partpak.read(struct.calcsize(part_struct))) partname = partname.strip() fancyprint("Partition "+str(part), 5) print "Name: \t\t\t %s"%partname if partsize%(1024*1024) == 0: partsize = partsize/1024/1024 partsizeunit = "MB" elif partsize%1024 == 0: partsize = partsize/1024 partsizeunit = "KB" else: partsizeunit = "bytes" print "Partition Size: \t %d %s"%(partsize, partsizeunit) print "Filename: \t\t %s"%partfn partfs = float(partfs) if partfs%(1024*1024) == 0: partfs = partfs/1024/1024 fsunit = "MB" elif partfs%1024 == 0: partfs = partfs/1024 fsunit = "KB" else: fsunit = "bytes" print "Filename Size: \t\t %d %s"%(partfs, fsunit) partsw="%08x"%partsw partsw=".".join(["".join(partsw[i:i+2]) for i in xrange(0, len(partsw), 2)]) partflags = '{0:08b}'.format(partflags) partflags=int(partflags) isFixed = bool(partflags & 1) isMaster = bool(partflags & 2) isKey = bool(partflags & 4) isCache = bool(partflags & 8) isData = bool(partflags & 16) isSecure = bool(partflags & 32) isErase = bool(partflags & 64) partflags = list() if isFixed: partflags.append("FIXED") if isMaster: partflags.append("MASTER") if isKey: partflags.append("IDKEY") if isCache: partflags.append("CACHE") if isData: partflags.append("DATA") if isSecure: partflags.append("SECURED") if isErase: partflags.append("ERASE") print "File Version: \t\t %s"%partsw print "Partition in use: \t %s"%bool(partIsUsed) print "Partition Flags: \t %s" %",".join(partflags) ================================================ FILE: sonar-project.properties ================================================ ## THIS FILE IS AUTOGENERATED ## edit .sonarcloud_gen.sh instead sonar.projectKey=openlgtv_epk2extract sonar.organization=openlgtv sonar.issue.ignore.multicriteria=r1 # format string is not a string literal sonar.issue.ignore.multicriteria.r1.ruleKey=c:S5281 sonar.issue.ignore.multicriteria.r1.resourceKey=** sonar.inclusions=src/*.c,src/lzhs/*.c,src/stream/*.c,src/tools/*.c,include/*.h,include/lzhs/*.h,include/realtek/*.h,include/stream/*.h ================================================ FILE: src/CMakeLists.txt ================================================ set(INC ${CMAKE_SOURCE_DIR}/include) add_definitions(-D_GNU_SOURCE) if(APPLE) include_directories(SYSTEM ${INC}/osx) endif() add_library(mfile mfile.c) add_library(utils util.c util_crypto.c thpool.c) target_include_directories(mfile PUBLIC ${INC}) target_include_directories(utils PUBLIC ${INC} ${INC}/u-boot ${OPENSSL_INCLUDE_DIR} ) target_link_libraries(utils ${OPENSSL_LIBRARIES} mfile) add_subdirectory(cramfs) add_subdirectory(squashfs) add_subdirectory(lz4) add_subdirectory(lzma) add_subdirectory(jffs2) add_subdirectory(lzhs) add_subdirectory(stream) add_subdirectory(tools) add_executable(epk2extract main.c crc32.c epk.c epk1.c epk2.c epk3.c mediatek_pkg.c mediatek.c philips.c symfile.c partinfo.c minigzip.c lzo-lg.c realtek.c ) target_compile_definitions(epk2extract PRIVATE -DUSE_MMAP #for gzip ) target_compile_options(epk2extract PRIVATE -Wunused ) target_link_libraries(epk2extract mfile utils cramfs squashfs lz4 jffs2 lzhs stream ${ZLIB_LIBRARIES} ${LZO_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${M_LIB} ) ================================================ FILE: src/cramfs/CMakeLists.txt ================================================ add_library(cramfs cramfsswap.c uncramfs.c) target_include_directories(cramfs PUBLIC ${INC} ${INC}/cramfs ) ================================================ FILE: src/cramfs/cramfsswap.c ================================================ /* cramfsswap - swaps endian of a cramfs file last modified on 2006-11-08 by kju Copyright (c) 2004-2006 by Michael Holzt, kju -at- fqdn.org To be distributed under the terms of the GPL2 license. */ #include #include #include #include #include #include /* for crc32 */ #include #include #include #include #define BUFFERSIZE 16384 #define MAXFILES 4096 #define BLKSIZE 4096 /* Should this be a command line option? */ int cramswap(char *sinfile, char *soutfile) { uint32_t superblock_in[16], superblock_out[16], flags, blockpointer_in, blockpointer_out, blockpointer_last, crc, *mapping; uint16_t endiantest; uint8_t inode_in[12], inode_out[12]; struct cramfs_inode inode; unsigned int filecnt, file, filepos, remaining, nblocks, copybytes, readbytes, x; unsigned int *fileoffset, *filesize; unsigned char buffer[BUFFERSIZE], is_hostorder, host_is_le, file_is_le; int infile, outfile; int size; /*if ( argc != 3 ) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } */ if ((infile = open(sinfile, O_RDONLY)) < 0) { perror("while trying to open binary input file"); return -1; } if ((outfile = open(soutfile, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0) { perror("while trying to open image output file"); exit(1); } if (read(infile, &superblock_in, sizeof(superblock_in)) != sizeof(superblock_in)) { perror("while trying to read superblock"); exit(1); } /* Detect endianness of host */ endiantest = 1; if (((uint8_t *) & endiantest)[0] == 1) host_is_le = 1; else host_is_le = 0; /* Detect endianness of file */ if (superblock_in[0] == CRAMFS_MAGIC) { is_hostorder = 1; file_is_le = host_is_le; } else if (superblock_in[0] == bswap_32(CRAMFS_MAGIC)) { is_hostorder = 0; file_is_le = !(host_is_le); } else { fprintf(stderr, "cramfs magic not detected\n"); exit(1); } if (file_is_le) //printf("Filesystem is little endian, will be converted to big endian.\n"); return -1; else printf("Filesystem is big endian, will be converted to little endian.\n"); /* Swap Superblock */ superblock_out[0] = bswap_32(superblock_in[0]); /* Magic */ superblock_out[1] = bswap_32(superblock_in[1]); /* Size */ superblock_out[2] = bswap_32(superblock_in[2]); /* Flags */ superblock_out[3] = bswap_32(superblock_in[3]); /* Future Use */ superblock_out[4] = superblock_in[4]; /* Sig 1/4 */ superblock_out[5] = superblock_in[5]; /* Sig 2/4 */ superblock_out[6] = superblock_in[6]; /* Sig 3/4 */ superblock_out[7] = superblock_in[7]; /* Sig 4/4 */ superblock_out[8] = bswap_32(superblock_in[8]); /* fsid crc */ superblock_out[9] = bswap_32(superblock_in[9]); /* fsid edition */ superblock_out[10] = bswap_32(superblock_in[10]); /* fsid blocks */ superblock_out[11] = bswap_32(superblock_in[11]); /* fsid files */ superblock_out[12] = superblock_in[12]; /* Name 1/4 */ superblock_out[13] = superblock_in[13]; /* Name 2/4 */ superblock_out[14] = superblock_in[14]; /* Name 3/4 */ superblock_out[15] = superblock_in[15]; /* Name 4/4 */ write(outfile, &superblock_out, sizeof(superblock_out)); /* Check Flags */ if (is_hostorder) flags = superblock_in[2]; else flags = superblock_out[2]; /* I'm not sure about the changes between v1 and v2. So for now don't support v1. */ if ((flags & 0x1) == 0) { fprintf(stderr, "Error: Not cramfs version 2!\n"); exit(1); } /* This should be done later */ if (flags & 0x100) { fprintf(stderr, "Error: Filesystem contains holes (not supported yet)\n"); exit(1); } /* Do we really need this? */ if (flags & 0x400) { fprintf(stderr, "Error: Filesystem has shifted root fs flag (not supported)\n"); exit(1); } /* Something else? */ if (flags & 0xFFFFFFFC) { fprintf(stderr, "Error: Filesystem has unknown/unsupported flag set!\n"); exit(1); } /* Get Filecounter (which is number of file entries plus 1 (for the root inode) */ if (is_hostorder) filecnt = superblock_in[11]; else filecnt = superblock_out[11]; printf("Filesystem contains %d files.\n", filecnt - 1); fileoffset = (unsigned int *)malloc(filecnt * sizeof(*fileoffset)); if (fileoffset == NULL) { perror("fileoffset malloc error"); exit(1); } filesize = (unsigned int *)malloc(filecnt * sizeof(*filesize)); if (filesize == NULL) { free(fileoffset); fileoffset = NULL; perror("filesize malloc error"); exit(1); } /* Set filepos (in words) */ filepos = 16; /* Initialise the counter for the "real" (stored) files */ remaining = 0; /* Read directory entries (first one is the root inode) */ for (file = 0; file < filecnt; file++) { /* Read and swap file inode */ if (read(infile, &inode_in, sizeof(inode_in)) != sizeof(inode_in)) { perror("while trying to read directory entry"); exit(1); } /* Swap the inode. */ inode_out[0] = inode_in[1]; /* 16 bit: mode */ inode_out[1] = inode_in[0]; inode_out[2] = inode_in[3]; /* 16 bit: uid */ inode_out[3] = inode_in[2]; inode_out[4] = inode_in[6]; /* 24 bit: size */ inode_out[5] = inode_in[5]; inode_out[6] = inode_in[4]; inode_out[7] = inode_in[7]; /* 8 bit: gid width */ /* Stop the madness! Outlaw C bitfields! They are unportable and nasty! See yourself what a mess this is: */ if (file_is_le) { inode_out[8] = ((inode_in[8] & 0x3F) << 2) | ((inode_in[11] & 0xC0) >> 6); inode_out[9] = ((inode_in[11] & 0x3F) << 2) | ((inode_in[10] & 0xC0) >> 6); inode_out[10] = ((inode_in[10] & 0x3F) << 2) | ((inode_in[9] & 0xC0) >> 6); inode_out[11] = ((inode_in[9] & 0x3F) << 2) | ((inode_in[8] & 0xC0) >> 6); } else { inode_out[8] = ((inode_in[8] & 0xFD) >> 2) | ((inode_in[11] & 0x03) << 6); inode_out[9] = ((inode_in[11] & 0xFD) >> 2) | ((inode_in[10] & 0x03) << 6); inode_out[10] = ((inode_in[10] & 0xFD) >> 2) | ((inode_in[9] & 0x03) << 6); inode_out[11] = ((inode_in[9] & 0xFD) >> 2) | ((inode_in[8] & 0x03) << 6); } if (is_hostorder) { /* copy the input for our use */ memcpy(&inode, &inode_in, sizeof(inode_in)); } else { /* copy the output for our use */ memcpy(&inode, &inode_out, sizeof(inode_in)); } /* write the converted inode */ write(outfile, &inode_out, sizeof(inode_out)); /* Copy filename */ if (read(infile, &buffer, inode.namelen << 2) != inode.namelen << 2) { perror("while trying to read filename"); exit(1); } write(outfile, &buffer, inode.namelen << 2); /* Store the file size and file offset */ filesize[file] = inode.size; fileoffset[file] = inode.offset; /* filepos is increased by namelen words + 3 words for the inode */ filepos += inode.namelen + 3; /* Has this entry a data chunk? */ if ((S_ISREG(inode.mode) || S_ISLNK(inode.mode)) && inode.size > 0) { remaining++; } } // Here we deal with LE XIP image stuffed into BE cramfs image. // We just convert superblock and inodes endianess while leaving the content of the rest as is... if (superblock_out[10] == 0) { do { readbytes = read(infile, &buffer, BUFFERSIZE); write(outfile, &buffer, readbytes); } while (readbytes > 0); close(infile); close(outfile); return 0; } /* Now process the individual files data. Because cramfs will share the compressed data for two identical input files, we do this by starting at the begin of the data, identifiying the accompanying file, process the file data, and move to the next until no file is left */ while (remaining) { /* Find the file */ for (file = 1; file < filecnt && fileoffset[file] != filepos; file++) ; if (fileoffset[file] != filepos) { /* Not found */ fprintf(stderr, "Did not find the file which starts at word %x, aborting...\n", filepos); exit(1); } /* Reduce file counter for each file which starts here (as said, can be more than one if the cramfs had identical input files) */ for (x = 1; x < filecnt; x++) if (fileoffset[x] == filepos) remaining--; /* Number of blocks of this file */ nblocks = (filesize[file] - 1) / BLKSIZE + 1; /* Swap the blockpointer */ for (x = 0; x < nblocks; x++) { if (read(infile, &blockpointer_in, 4) != 4) { perror("while trying to read blockpointer"); return 1; } blockpointer_out = bswap_32(blockpointer_in); write(outfile, &blockpointer_out, 4); filepos++; } /* Last blockpointer points to the byte after the end of the file */ if (is_hostorder) blockpointer_last = blockpointer_in; else blockpointer_last = blockpointer_out; /* Align to a word boundary */ blockpointer_last += (4 - (blockpointer_last % 4)) % 4; /* Copy the file data */ copybytes = blockpointer_last - (filepos << 2); while (copybytes > 0) { readbytes = (copybytes > BUFFERSIZE) ? BUFFERSIZE : copybytes; if (read(infile, &buffer, readbytes) != readbytes) { perror("while trying to read file data"); exit(1); } write(outfile, &buffer, readbytes); copybytes -= readbytes; } /* Set new filepos */ filepos = (blockpointer_last) >> 2; } /* Copy the remaining data (padding) */ do { readbytes = read(infile, &buffer, BUFFERSIZE); write(outfile, &buffer, readbytes); } while (readbytes > 0); /* recalculate the crc */ size = lseek(outfile, 0, SEEK_CUR); /* should not fail */ mapping = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, outfile, 0); if (mapping != MAP_FAILED) { crc = crc32(0L, Z_NULL, 0); mapping[8] = is_hostorder ? bswap_32(crc) : crc; crc = crc32(crc, (unsigned char *)mapping, size); printf("CRC: 0x%08x\n", crc); mapping[8] = is_hostorder ? bswap_32(crc) : crc; munmap(mapping, size); } else { perror("mapping failed"); } /* Done! */ close(infile); close(outfile); return 0; } ================================================ FILE: src/cramfs/uncramfs.c ================================================ // // Uncramfs // A program to unpack a cramfs image // // Copyright Andrew Stitcher, 2001 // // Licensed according to the GNU GPL v2 // // C things #include #include #include #include // Unix things #include #include //#include #include #include #include #include #ifndef __APPLE__ # include #endif // Application libraries #include // Cramfs definitions #include "cramfs.h" #include "os_byteswap.h" #define PAGE_CACHE_SIZE (4096) /* The kernel assumes PAGE_CACHE_SIZE as block size. */ static unsigned long blksize = PAGE_CACHE_SIZE; static char *opt_devfile = NULL; static char *opt_idsfile = NULL; static int DIR_GID = 0; void do_file_entry(const u8 * base, const char *dir, const char *path, const char *name, int namelen, const struct cramfs_inode *inode); void do_dir_entry(const u8 * base, const char *dir, const char *path, const char *name, int namelen, const struct cramfs_inode *inode); /////////////////////////////////////////////////////////////////////////////// u32 compressed_size(const u8 * base, const u8 * data, u32 size) { const u32 *buffs = (const u32 *)(data); int nblocks = (size - 1) / blksize + 1; const u8 *buffend = base + *(buffs + nblocks - 1); if (size == 0) return 0; else return buffend - data; } void uncompress_data(const u8 * base, const u8 * data, u32 size, u8 * dstdata) { const u32 *buffs = (const u32 *)(data); int nblocks = (size - 1) / blksize + 1; const u8 *buff = (const u8 *)(buffs + nblocks); const u8 *nbuff; int block = 0; uLongf len = size; if (size == 0) { return; } for (; block < nblocks; ++block, buff = nbuff, dstdata += blksize, len -= blksize) { uLongf tran = (len < blksize) ? len : blksize; nbuff = base + *(buffs + block); if (uncompress(dstdata, &tran, buff, nbuff - buff) != Z_OK) { fprintf(stderr, "Uncompression failed"); return; } } } /////////////////////////////////////////////////////////////////////////////// int stats_totalsize; int stats_totalcsize; int stats_count; int stats_compresses; int stats_expands; void clearstats() { stats_totalsize = 0; stats_totalcsize = 0; stats_count = 0; stats_compresses = 0; stats_expands = 0; } void updatestats(int size, int csize) { ++stats_count; stats_totalsize += size; stats_totalcsize += csize; if (size >= csize) { stats_compresses++; } else { stats_expands++; } } void printstats() { printf("\n[Summary:]\n"); printf("[Total uncompressed size: %9d]\n", stats_totalsize); printf("[Total compressed size: %9d]\n", stats_totalcsize); printf("[Number of entries: %9d]\n", stats_count); printf("[Number of files compressed: %9d]\n", stats_compresses); printf("[Number of files expanded: %9d]\n", stats_expands); printf("\n"); } /////////////////////////////////////////////////////////////////////////////// void printmode(const struct cramfs_inode *inode) { u16 mode = inode->mode; // Deal with file type bitsetc if (S_ISDIR(mode)) printf("d"); else if (S_ISLNK(mode)) printf("l"); else if (S_ISBLK(mode)) printf("b"); else if (S_ISCHR(mode)) printf("c"); else if (S_ISFIFO(mode)) printf("p"); else if (S_ISSOCK(mode)) printf("s"); else printf("-"); // Deal with mode bits if (mode & S_IRUSR) printf("r"); else printf("-"); if (mode & S_IWUSR) printf("w"); else printf("-"); if (mode & S_IXUSR) if (mode & S_ISUID) printf("s"); else printf("x"); else if (mode & S_ISUID) printf("S"); else printf("-"); if (mode & S_IRGRP) printf("r"); else printf("-"); if (mode & S_IWGRP) printf("w"); else printf("-"); if (mode & S_IXGRP) if (mode & S_ISGID) printf("s"); else printf("x"); else if (mode & S_ISGID) printf("S"); else printf("-"); if (mode & S_IROTH) printf("r"); else printf("-"); if (mode & S_IWOTH) printf("w"); else printf("-"); if (mode & S_IXOTH) if (mode & S_ISVTX) printf("t"); else printf("x"); else if (mode & S_ISVTX) printf("T"); else printf("-"); } void printuidgid(const struct cramfs_inode *inode) { char res[14]; snprintf(res, 14, "%d/%d", inode->uid, inode->gid); printf(" %-14s", res); } void printsize(int size, int csize) { char s[17]; // As a side effect update the size stats updatestats(size, csize); snprintf(s, 17, "%7d(%d)", size, csize); printf("%-16s ", s); } /////////////////////////////////////////////////////////////////////////////// void do_file(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode) { int fd; u8 *file_data; const u8 *srcdata; // Allow for uncompressed XIP executable if (mode & S_ISVTX) { // It seems that the offset may not necessarily be page // aligned. This is silly because mkcramfs wastes // the alignment space, whereas it might be used if it wasn't // bogusly in our file extent. // // blksize must be a power of 2 for the following to work, but it seems // quite likely. srcdata = (const u8 *)(((long)(base + offset) + blksize - 1) & ~(blksize - 1)); //printsize(size, srcdata + size - (base + offset)); //printf("%s", name); } else { //printsize(size, compressed_size(base, base + offset, size)); //printf("%s", name); } // Check if we are actually unpacking if (path[0] == '-') { return; } // Make local copy fd = open(path, O_CREAT | O_TRUNC | O_RDWR, mode); if (fd == -1) { perror("create"); return; }; if (ftruncate(fd, size) == -1) { perror("ftruncate"); close(fd); return; } file_data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (file_data == MAP_FAILED) { perror("mmap"); close(fd); return; } // Allow for uncompressed XIP executable if (mode & S_ISVTX) { memcpy(file_data, srcdata, size); } else { uncompress_data(base, base + offset, size, file_data); } munmap(file_data, size); close(fd); } void do_directory(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode) { //printsize(size, size); //printf("%s", name); // Check if we are actually unpacking if (path[0] == '-') { return; } // Make the local directory if (mkdir(path, mode) == -1) { perror(path); return; } } void do_symlink(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode) { // Allocate the uncompressed string u8 link_contents[size + 1]; // do uncompression uncompress_data(base, base + offset, size, link_contents); link_contents[size] = 0; printsize(size, compressed_size(base, base + offset, size)); printf("%s -> %s", name, link_contents); // Check if we are actually unpacking if (path[0] == '-') { return; } // Make local copy if (symlink((const char *)link_contents, path) == -1) { perror(path); exit(1); } } void do_chrdev(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode, int uid, int gid) { { char s[17]; snprintf(s, 17, "%3d, %3d", major(size), minor(size)); printf("%-16s %s", s, name); } // Check if we are actually unpacking if (path[0] == '-') { return; } // Make local copy if (geteuid() == 0) { if (mknod(path, S_IFCHR | mode, size) == -1) perror(path); } else if (opt_devfile) { char dfp[1024]; char *p; FILE *f; strcpy(dfp, path); p = strrchr(dfp, '/'); if (!p) { fprintf(stderr, "Could not find path in '%s'\n", path); return; } strcpy(p + 1, opt_devfile); f = fopen(dfp, "at"); if (!f) { perror(dfp); return; } fprintf(f, "%s,%08x,%u,%u,%08x\n", name, mode, uid, gid, size); fclose(f); } } void do_blkdev(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode, int uid, int gid) { { char s[17]; snprintf(s, 17, "%3d, %3d", major(size), minor(size)); //printf("%-16s %s", s, name); } // Check if we are actually unpacking if (path[0] == '-') { return; } // Make local copy if (geteuid() == 0) { if (mknod(path, S_IFBLK | mode, size) == -1) perror(path); } else if (opt_devfile) { char dfp[1024]; char *p; FILE *f; strcpy(dfp, path); p = strrchr(dfp, '/'); if (!p) { fprintf(stderr, "Could not find path in '%s'\n", path); return; } strcpy(p + 1, opt_devfile); f = fopen(dfp, "at"); if (!f) { perror(dfp); return; } fprintf(f, "%s,%08x,%u,%u,%08x\n", name, mode, uid, gid, size); fclose(f); } } void do_fifo(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode, int gid, int uid) { printf(" %s", name); // Check if we are actually unpacking if (path[0] == '-') { return; } // Make local copy if (geteuid() == 0) { if (mknod(path, S_IFIFO | mode, 0) == -1) perror(path); } else if (opt_devfile) { char dfp[1024]; char *p; FILE *f; strcpy(dfp, path); p = strrchr(dfp, '/'); if (!p) { fprintf(stderr, "Could not find path in '%s'\n", path); return; } strcpy(p + 1, opt_devfile); f = fopen(dfp, "at"); if (!f) { perror(dfp); return; } fprintf(f, "%s,%08x,%u,%u,%08x\n", name, mode, uid, gid, size); fclose(f); } } void do_socket(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode) { printf(" %s", name); // Check if we are actually unpacking if (path[0] == '-') { return; } } void do_unknown(const u8 * base, u32 offset, u32 size, const char *path, const char *name, int mode) { printf(" %s", name); } void process_directory(const u8 * base, const char *dir, u32 offset, u32 size, const char *path) { struct cramfs_inode *de; char *name; int namelen; u32 current = offset; u32 dirend = offset + size; // Do files while (current < dirend) { u32 nextoffset; de = (struct cramfs_inode *)(base + current); namelen = de->namelen << 2; nextoffset = current + sizeof(struct cramfs_inode) + namelen; name = (char *)(de + 1); while (1) { assert(namelen != 0); if (name[namelen - 1]) break; namelen--; } do_file_entry(base, dir, path, name, namelen, de); current = nextoffset; } // Recurse into directories current = offset; while (current < dirend) { u32 nextoffset; de = (struct cramfs_inode *)(base + current); namelen = de->namelen << 2; nextoffset = current + sizeof(struct cramfs_inode) + namelen; name = (char *)(de + 1); while (1) { assert(namelen != 0); if (name[namelen - 1]) break; namelen--; } do_dir_entry(base, dir, path, name, namelen, de); current = nextoffset; } } /////////////////////////////////////////////////////////////////////////////// void do_file_entry(const u8 * base, const char *dir, const char *path, const char *name, int namelen, const struct cramfs_inode *inode) { int dirlen = strlen(dir); int pathlen = strlen(path); char pname[dirlen + pathlen + namelen + 3]; const char *basename; u32 gid = inode->gid; if (dirlen) { strncpy(pname, dir, dirlen); } if (pathlen) { if (dirlen) { pname[dirlen] = '/'; ++dirlen; } strncpy(pname + dirlen, path, pathlen); } if (namelen) { if (pathlen + dirlen) { pname[dirlen + pathlen] = '/'; ++pathlen; } strncpy(pname + dirlen + pathlen, name, namelen); } pname[pathlen + dirlen + namelen] = 0; basename = namelen ? pname + dirlen + pathlen : "/"; // Create things here //printmode(inode); //printuidgid(inode); if (S_ISREG(inode->mode)) { u32 size = inode->size; if (gid > DIR_GID) { // sirius: this is a special LG encoding of the size. // misusing gid field to encode the most significant byte of the size int lg = gid - DIR_GID; gid -= lg; lg = lg * 0x1000000; size += (lg); } do_file(base, inode->offset << 2, size, pname, basename, inode->mode); } else if (S_ISDIR(inode->mode)) { if (DIR_GID == 0) { DIR_GID = gid; } do_directory(base, inode->offset << 2, inode->size, pname, basename, inode->mode); } else if (S_ISLNK(inode->mode)) { do_symlink(base, inode->offset << 2, inode->size, pname, basename, inode->mode); } else if (S_ISFIFO(inode->mode)) { do_fifo(base, inode->offset << 2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else if (S_ISSOCK(inode->mode)) { do_socket(base, inode->offset << 2, inode->size, pname, basename, inode->mode); } else if (S_ISCHR(inode->mode)) { do_chrdev(base, inode->offset << 2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else if (S_ISBLK(inode->mode)) { do_blkdev(base, inode->offset << 2, inode->size, pname, basename, inode->mode, inode->uid, inode->gid); } else { do_unknown(base, inode->offset << 2, inode->size, pname, basename, inode->mode); } if (geteuid() == 0) { if (lchown(pname, inode->uid, gid) == -1) perror("cannot change owner or group"); } else if (opt_idsfile && path && path[0]) { char dfp[1024]; char *p; FILE *f; strcpy(dfp, pname); p = strrchr(dfp, '/'); if (!p) { fprintf(stderr, "could not find path in '%s'\n", pname); return; } strcpy(p + 1, opt_idsfile); f = fopen(dfp, "at"); if (!f) { perror(dfp); return; } fprintf(f, "%s,%u,%u,%08x\n", basename, inode->uid, inode->gid, inode->mode); fclose(f); } if (geteuid() == 0 || !opt_idsfile) { if (inode->mode & (S_ISGID | S_ISUID | S_ISVTX)) { if (0 != chmod(pname, inode->mode)) { perror("chmod"); return; } } } //printf("\n"); } void do_dir_entry(const u8 * base, const char *dir, const char *path, const char *name, int namelen, const struct cramfs_inode *inode) { int pathlen = strlen(path); char pname[pathlen + namelen + 2]; if (pathlen) { strncpy(pname, path, pathlen); } if (namelen) { if (pathlen) { pname[pathlen] = '/'; ++pathlen; } strncpy(pname + pathlen, name, namelen); } pname[pathlen + namelen] = 0; // Only process directories here if (S_ISDIR(inode->mode)) { //printf("\n/%s:\n", pname); process_directory(base, dir, inode->offset << 2, inode->size, pname); } } /////////////////////////////////////////////////////////////////////////////// int is_cramfs_image(char const *imagefile, char *endian) { struct stat st; int fd, result; size_t fslen_ub; int *rom_image; struct cramfs_super const *sb; // Check the image file if (stat(imagefile, &st) == -1) { perror(imagefile); exit(1); } // Map the cramfs image fd = open(imagefile, O_RDONLY); fslen_ub = st.st_size; rom_image = mmap(0, fslen_ub, PROT_READ, MAP_SHARED, fd, 0); if (rom_image == MAP_FAILED) { perror("Mapping cramfs file"); exit(1); } sb = (struct cramfs_super const *)(rom_image); int cram_magic = CRAMFS_MAGIC; if (!memcmp(endian, "be", 2)) SWAP(cram_magic); result = 0; // Check cramfs magic number and signature if (cram_magic == sb->magic || (memcmp(endian, "be", 2) && 0 == memcmp(sb->signature, CRAMFS_SIGNATURE, sizeof(sb->signature)))) result = 1; munmap(rom_image, fslen_ub); close(fd); return result; } int uncramfs(char const *dirname, char const *imagefile) { struct stat st; int fd; size_t fslen_ub; u8 const *rom_image; struct cramfs_super const *sb; // Check the directory if (access(dirname, W_OK) == -1) { if (errno != ENOENT) { perror(dirname); exit(1); } } // Check the image file if (stat(imagefile, &st) == -1) { perror(imagefile); exit(1); } // Map the cramfs image fd = open(imagefile, O_RDONLY); fslen_ub = st.st_size; rom_image = mmap(0, fslen_ub, PROT_READ, MAP_SHARED, fd, 0); if (rom_image == MAP_FAILED) { perror("Mapping cramfs file"); exit(1); } sb = (struct cramfs_super const *)(rom_image); // Check cramfs magic number and signature if (CRAMFS_MAGIC != sb->magic || 0 != memcmp(sb->signature, CRAMFS_SIGNATURE, sizeof(sb->signature))) { fprintf(stderr, "The image file doesn't have cramfs signatures\n"); exit(1); } // Set umask to 0 to let the image modes shine through umask(0); clearstats(); // Start doing... do_file_entry(rom_image, dirname, "", "", 0, &sb->root); do_dir_entry(rom_image, dirname, "", "", 0, &sb->root); return 0; } ================================================ FILE: src/crc32.c ================================================ /* Crc - 32 BIT ANSI X3.66 CRC checksum files */ #include #include "crc.h" #ifdef __TURBOC__ # pragma warn -cln #endif /**********************************************************************\ |* Demonstration program to compute the 32-bit CRC used as the frame *| |* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71 *| |* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level *| |* protocol). The 32-bit FCS was added via the Federal Register, *| |* 1 June 1982, p.23798. I presume but don't know for certain that *| |* this polynomial is or will be included in CCITT V.41, which *| |* defines the 16-bit CRC (often called CRC-CCITT) polynomial. FIPS *| |* PUB 78 says that the 32-bit FCS reduces otherwise undetected *| |* errors by a factor of 10^-5 over 16-bit FCS. *| \**********************************************************************/ /* Need an unsigned type capable of holding 32 bits; */ typedef DWORD UNS_32_BITS; /* Copyright (C) 1986 Gary S. Brown. You may use this program, or code or tables extracted from it, as desired without restriction.*/ /* First, the polynomial itself and its table of feedback terms. The */ /* polynomial is */ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ /* Note that we take it "backwards" and put the highest-order term in */ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ /* the MSB being 1. */ /* Note that the usual hardware shift register implementation, which */ /* is what we're using (we're merely optimizing it by doing eight-bit */ /* chunks at a time) shifts bits into the lowest-order term. In our */ /* implementation, that means shifting towards the right. Why do we */ /* do it this way? Because the calculated CRC must be transmitted in */ /* order from highest-order term to lowest-order term. UARTs transmit */ /* characters in order from LSB to MSB. By storing the CRC this way, */ /* we hand it to the UART in the order low-byte to high-byte; the UART */ /* sends each low-bit to hight-bit; and the result is transmission bit */ /* by bit from highest- to lowest-order term without requiring any bit */ /* shuffling on our part. Reception works similarly. */ /* The feedback terms table consists of 256, 32-bit entries. Notes: */ /* */ /* 1. The table can be generated at runtime if desired; code to do so */ /* is shown later. It might not be obvious, but the feedback */ /* terms simply represent the results of eight shift/xor opera- */ /* tions for all combinations of data and CRC register values. */ /* */ /* 2. The CRC accumulation logic is the same for all CRC polynomials, */ /* be they sixteen or thirty-two bits wide. You simply choose the */ /* appropriate table. Alternatively, because the table can be */ /* generated at runtime, you can start by generating the table for */ /* the polynomial in question and use exactly the same "updcrc", */ /* if your application needn't simultaneously handle two CRC */ /* polynomials. (Note, however, that XMODEM is strange.) */ /* */ /* 3. For 16-bit CRCs, the table entries need be only 16 bits wide; */ /* of course, 32-bit entries work OK if the high 16 bits are zero. */ /* */ /* 4. The values must be right-shifted by eight bits by the "updcrc" */ /* logic; the shift must be unsigned (bring in zeroes). On some */ /* hardware you could probably optimize the shift in assembler by */ /* using byte-swap instructions. */ static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; DWORD updateCRC32(unsigned char ch, DWORD crc) { return UPDC32(ch, crc); } Boolean_T crc32file(char *name, DWORD * crc, long *charcnt) { FILE *fin; DWORD oldcrc32; int c; oldcrc32 = 0xFFFFFFFF; *charcnt = 0; #ifdef MSDOS if ((fin = fopen(name, "rb")) == NULL) #else if ((fin = fopen(name, "r")) == NULL) #endif { perror(name); return Error_; } while ((c = getc(fin)) != EOF) { ++*charcnt; oldcrc32 = UPDC32(c, oldcrc32); } if (ferror(fin)) { perror(name); *charcnt = -1; } fclose(fin); *crc = oldcrc32 = ~oldcrc32; return Success_; } DWORD crc32buf(char *buf, size_t len) { register DWORD oldcrc32; oldcrc32 = 0xFFFFFFFF; for (; len; --len, ++buf) { oldcrc32 = UPDC32(*buf, oldcrc32); } return ~oldcrc32; } #ifdef TEST main(int argc, char *argv[]) { DWORD crc; long charcnt; register errors = 0; while (--argc > 0) { errors |= crc32file(*++argv, &crc, &charcnt); printf("%08lX %7ld %s\n", crc, charcnt, *argv); } return (errors != 0); } #endif /* TEST */ ================================================ FILE: src/epk.c ================================================ /** * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "epk.h" #include "epk2.h" #include "epk3.h" #include "util.h" #include "util_crypto.h" static EVP_PKEY *_gpPubKey; static AES_KEY *aesKey; static int keyFound = 0; static int sigCheckAvailable = 0; static int firstAttempt = 1; /* * Checks if the given data is an EPK2 or EPK3 header */ int compare_epak_header(uint8_t *header, size_t headerSize){ if(compare_epk2_header(header, headerSize)){ return EPK_V2; } else if(compare_epk3_header(header, headerSize)){ return EPK_V3; } else if(compare_epk3_new_header(header, headerSize)){ return EPK_V3_NEW; } return 0; } /* * Loads the specified Public Key for Signature verification */ int SWU_CryptoInit_PEM(char *configuration_dir, char *pem_file) { OpenSSL_add_all_digests(); ERR_load_CRYPTO_strings(); char *pem_file_name; asprintf(&pem_file_name, "%s/%s", configuration_dir, pem_file); FILE *pubKeyFile = fopen(pem_file_name, "r"); if (pubKeyFile == NULL) { printf("Error: Can't open PEM file %s\n\n", pem_file); return 1; } EVP_PKEY *gpPubKey = PEM_read_PUBKEY(pubKeyFile, NULL, NULL, NULL); _gpPubKey = gpPubKey; if (_gpPubKey == NULL) { printf("Error: Can't read PEM signature from file %s\n\n", pem_file); fclose(pubKeyFile); return 1; } fclose(pubKeyFile); ERR_clear_error(); return 0; } /* * Verifies the signature of the given data against the loaded public key */ int API_SWU_VerifyImage(void *signature, void* data, size_t imageSize, SIG_TYPE_T sigType) { size_t hashSize; unsigned int sigSize; const EVP_MD *algo; switch(sigType) { case SIG_SHA1: hashSize = 0x40; sigSize = SIGNATURE_SIZE; algo = EVP_sha1(); break; case SIG_SHA256: hashSize = 0x80; sigSize = SIGNATURE_SIZE_NEW; algo = EVP_sha256(); break; default: printf("Invalid sigType: %d\n", sigType); return 0; } unsigned char md_value[hashSize]; unsigned int md_len = 0; int result = 0; EVP_MD_CTX *ctx1, *ctx2; if ((ctx1 = EVP_MD_CTX_new()) == NULL) return 0; if ((ctx2 = EVP_MD_CTX_new()) == NULL) { EVP_MD_CTX_free(ctx1); return 0; } EVP_DigestInit(ctx1, algo); EVP_DigestUpdate(ctx1, data, imageSize); EVP_DigestFinal(ctx1, md_value, &md_len); EVP_DigestInit(ctx2, algo); EVP_DigestUpdate(ctx2, md_value, md_len); result = EVP_VerifyFinal(ctx2, signature, sigSize, _gpPubKey); EVP_MD_CTX_free(ctx2); EVP_MD_CTX_free(ctx1); return result; } /* * Wrapper for signature verification. Retries by decrementing size if it fails */ int wrap_SWU_VerifyImage( void *signature, void* data, size_t signedSize, size_t *effectiveSignedSize, SIG_TYPE_T sigType ){ size_t curSize = signedSize; int verified; //int skipped = 0; while (curSize > 0) { verified = API_SWU_VerifyImage(signature, data, curSize, sigType); if (verified) { if(effectiveSignedSize != NULL){ *effectiveSignedSize = curSize; } //printf("Success!\nDigital signature is OK. Signed bytes: %d\n", curSize); //printf("Subtracted: %d\n", skipped); return 0; } else { //skipped++; } curSize--; } //printf("Failed\n"); return -1; } /* * High level wrapper for signature verification */ int wrap_verifyimage(void *signature, void *data, size_t signSize, char *config_dir, SIG_TYPE_T sigType){ size_t effectiveSignedSize; int result = -1; if(!sigCheckAvailable){ // No key available, fail early if(!firstAttempt){ return -1; } firstAttempt = 0; printf("Verifying %zu bytes\n", signSize); DIR* dirFile = opendir(config_dir); if (dirFile == NULL){ fprintf(stderr, "Failed to open dir '%s'\n", config_dir); } else { struct dirent* hFile; while ((hFile = readdir(dirFile)) != NULL) { if (!strcmp(hFile->d_name, ".") || !strcmp(hFile->d_name, "..") || hFile->d_name[0] == '.') continue; if (strstr(hFile->d_name, ".pem") || strstr(hFile->d_name, ".PEM")) { printf("Trying RSA key: %s...\n", hFile->d_name); SWU_CryptoInit_PEM(config_dir, hFile->d_name); result = wrap_SWU_VerifyImage(signature, data, signSize, &effectiveSignedSize, sigType); if(result > -1){ sigCheckAvailable = 1; break; } } } closedir(dirFile); } } else { result = wrap_SWU_VerifyImage(signature, data, signSize, &effectiveSignedSize, sigType); } if (result < 0) { fprintf(stderr, "WARNING: Cannot verify digital signature (maybe you don't have proper PEM file)\n\n"); } else { printf("Succesfully verified 0x%x out of 0x%x bytes\n", effectiveSignedSize, signSize); } return result; } /* * Decrypts the given data against the loaded AES key, with ECB mode */ void decryptImage(void *srcaddr, size_t len, void *dstaddr) { unsigned int remaining = len; unsigned int decrypted = 0; while (remaining >= AES_BLOCK_SIZE) { AES_decrypt(srcaddr, dstaddr, aesKey); srcaddr += AES_BLOCK_SIZE; dstaddr += AES_BLOCK_SIZE; remaining -= AES_BLOCK_SIZE; decrypted++; } if (remaining != 0) { decrypted = decrypted * AES_BLOCK_SIZE; memcpy(dstaddr, srcaddr, remaining); } } /* * Identifies correct key for decryption (if not previously identified) and decrypts data * The comparison function is selected from the passed file type * For EPK comparison, outType is used to store the detected type (EPK v2 or EPK v3) */ int wrap_decryptimage(void *src, size_t datalen, void *dest, char *config_dir, FILE_TYPE_T type, FILE_TYPE_T *outType){ CompareFunc compareFunc = NULL; switch(type){ case EPK: compareFunc = compare_epak_header; break; case EPK_V2: compareFunc = compare_epk2_header; break; case PAK_V2: compareFunc = compare_pak2_header; break; case EPK_V3: compareFunc = compare_epk3_header; break; } int decrypted = 0; uint8_t *decryptedData = NULL; // Check if we need decryption if(type != RAW && compareFunc(src, datalen)){ decrypted = 1; return decrypted; } if(!keyFound){ printf("Trying known AES keys...\n"); KeyPair *keyPair = find_AES_key(src, datalen, compareFunc, KEY_ECB, (void **)&decryptedData, 1); decrypted = keyFound = (keyPair != NULL); if(decrypted){ aesKey = &(keyPair->key); } if(decrypted && type != EPK){ memcpy(dest, decryptedData, datalen); free(decryptedData); } } else { decryptImage(src, datalen, dest); if(type == RAW) decrypted = 1; else decrypted = compareFunc(dest, datalen); } if (!decrypted){ PERROR("Cannot decrypt EPK content (proper AES key is missing).\n"); return -1; } else if(type == EPK){ if(outType != NULL){ *outType = compare_epak_header(decryptedData, datalen); } } return decrypted; } /* * Verifies if a string contains 2 dots and numbers (x.y.z) */ bool isEpkVersionString(const char *str){ // Size of string is the same across EPK2 and EPK3, for both Platform and SDK versions return count_tokens(str, '.', member_size(struct epk2_structure, platformVersion)) == 2; } /* * Detects if the EPK file is v2 or v3, and extracts it */ void extractEPKfile(const char *epk_file, config_opts_t *config_opts){ do { MFILE *epk = mopen_private(epk_file, O_RDONLY); if(!epk){ err_exit("\nCan't open file %s\n\n", epk_file); } //Make it R/W mprotect(epk->pMem, msize(epk), PROT_READ | PROT_WRITE); printf("File size: %d bytes\n", msize(epk)); struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); int result; FILE_TYPE_T epkType; if(compare_epk2_header((uint8_t *)epkHeader, sizeof(*epkHeader))){ epkType = EPK_V2; } else { printf("\nTrying to decrypt EPK header...\n"); /* Detect if the file is EPK v2 or EPK v3 */ result = wrap_decryptimage( epkHeader, sizeof(EPK_V2_HEADER_T), epkHeader, config_opts->config_dir, EPK, &epkType ); if(result < 0){ break; } } switch(epkType){ case EPK_V2: printf("[+] EPK v2 Detected\n"); extractEPK2(epk, config_opts); break; case EPK_V3: case EPK_V3_NEW: printf("[+] EPK v3 Detected\n"); extractEPK3(epk, epkType, config_opts); break; } } while(0); } ================================================ FILE: src/epk1.c ================================================ /** * EPK v1 handling * Copyright 2016 Smx * Copyright 2016 lprot * Copyright 20?? sirius * All right reserved */ #include #include #include #include #include "main.h" //for handle_file #include "epk1.h" #include "os_byteswap.h" #include "util.h" #define PAKNAME_LEN 4 bool isFileEPK1(const char *epk_file) { FILE *file = fopen(epk_file, "rb"); if (file == NULL) { err_exit("Can't open file %s\n\n", epk_file); } char magic[4]; size_t nRead = fread(&magic, 1, 4, file); fclose(file); if (nRead != 4) { return 0; } if (memcmp(&magic, "epak", 4) == 0) { return true; } else { return false; } } void printHeaderInfo(struct epk1Header_t *epakHeader) { printf("\nFirmware otaID: %s\n", epakHeader->otaID); printf("Firmware version: " EPKV1_VERSION_FORMAT "\n", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0]); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); } void printNewHeaderInfo(struct epk1NewHeader_t *epakHeader) { printf("\nFirmware otaID: %s\n", epakHeader->otaID); printf("Firmware version: " EPKV1_VERSION_FORMAT "\n", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0]); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); } void constructVerString(char *fw_version, struct epk1Header_t *epakHeader) { sprintf(fw_version, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); } void constructNewVerString(char *fw_version, struct epk1NewHeader_t *epakHeader) { sprintf(fw_version, EPKV1_VERSION_FORMAT "-%s", epakHeader->fwVer[2], epakHeader->fwVer[1], epakHeader->fwVer[0], epakHeader->otaID); } void extract_epk1_file(const char *epk_file, config_opts_t *config_opts) { int file; if ((file = open(epk_file, O_RDONLY)) == -1) { err_exit("\nCan't open file %s\n\n", epk_file); } struct stat statbuf; if (fstat(file, &statbuf) == -1) { err_exit("\nfstat error\n\n"); } int fileLength = statbuf.st_size; printf("File size: %d bytes\n", fileLength); void *buffer; if ((buffer = mmap(0, fileLength, PROT_READ, MAP_SHARED, file, 0)) == MAP_FAILED) { err_exit("\nCannot mmap input file (%s). Aborting\n\n", strerror(errno)); } char verString[12]; int index; uint32_t pakcount = ((struct epk1Header_t *)buffer)->pakCount; if (pakcount >> 8 != 0) { SWAP(pakcount); printf("\nFirmware type is EPK1 Big Endian...\n"); unsigned char *header = malloc(sizeof(struct epk1BEHeader_t)); //allocate space for header memcpy(header, buffer, sizeof(struct epk1BEHeader_t)); //copy header to buffer struct epk1BEHeader_t *epakHeader = (struct epk1BEHeader_t *)header; //make struct from buffer SWAP(epakHeader->fileSize); SWAP(epakHeader->pakCount); SWAP(epakHeader->offset); printf("\nFirmware otaID: %s\n", (char *)(buffer + epakHeader->offset + 8)); struct epk1BEVersion_t *fwVer = buffer + epakHeader->offset - 4; if (fwVer->pad != 0) { printf("Note: Padding byte is not zero (0x%" PRIx8 ")!\n", fwVer->pad); } sprintf(verString, EPKV1_VERSION_FORMAT, fwVer->major, fwVer->minor1, fwVer->minor2); printf("Firmware version: %s\n", verString); printf("PAK count: %d\n", epakHeader->pakCount); printf("PAKs total size: %d\n", epakHeader->fileSize); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, verString); createFolder(config_opts->dest_dir); unsigned long int offset = 0xC; for (index = 0; index < epakHeader->pakCount; index++) { struct pakRec_t *pakRecord = malloc(sizeof(struct pakRec_t)); //allocate space for header if (pakRecord == NULL) { err_exit("Error in %s: malloc() failed\n", __func__); } memcpy(pakRecord, buffer + offset, sizeof(struct pakRec_t)); //copy pakRecord to buffer if (pakRecord->offset == 0) { offset += 8; index--; continue; } SWAP(pakRecord->offset); SWAP(pakRecord->size); unsigned char *pheader = malloc(sizeof(struct pakHeader_t)); if (pheader == NULL) { err_exit("Error in %s: malloc() failed\n", __func__); } memcpy(pheader, (buffer + pakRecord->offset), sizeof(struct pakHeader_t)); struct pakHeader_t *pakHeader = (struct pakHeader_t *)pheader; SWAP(pakHeader->pakSize); pakHeader = (struct pakHeader_t *)(buffer + pakRecord->offset); char pakName[PAKNAME_LEN + 1] = ""; sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); char filename[PATH_MAX + 1] = ""; int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { err_exit("Error in %s: filename too long (%d > %d)\n", __func__, filename_len, PATH_MAX); } else if (filename_len < 0) { err_exit("Error in %s: snprintf() failed (%d)\n", __func__, filename_len); } printf("\n#%u/%u saving PAK (name='%s', platform='%s', offset=0x%x, size='%d') to file %s\n", index + 1, epakHeader->pakCount, pakName, pakHeader->platform, pakRecord->offset, pakRecord->size, filename); FILE *outfile = fopen(filename, "wb"); if (outfile == NULL) { err_exit("Error in %s: failed to open file '%s': %s.\n", __func__, filename, strerror(errno)); } fwrite(pakHeader->pakName + sizeof(struct pakHeader_t), 1, pakRecord->size - 132, outfile); fclose(outfile); handle_file(filename, config_opts); free(pakRecord); free(pheader); offset += 8; } free(header); } else if (pakcount < 21) { // old EPK1 header printf("\nFirmware type is EPK1...\n"); struct epk1Header_t *epakHeader = (struct epk1Header_t *)buffer; printHeaderInfo(epakHeader); constructVerString(verString, epakHeader); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, verString); createFolder(config_opts->dest_dir); for (index = 0; index < epakHeader->pakCount; index++) { struct pakRec_t pakRecord = epakHeader->pakRecs[index]; struct pakHeader_t *pakHeader; pakHeader = (struct pakHeader_t *)(buffer + pakRecord.offset); char pakName[PAKNAME_LEN + 1] = ""; sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); char filename[PATH_MAX + 1] = ""; int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { err_exit("Error in %s: filename too long (%d > %d)\n", __func__, filename_len, PATH_MAX); } else if (filename_len < 0) { err_exit("Error in %s: snprintf() failed (%d)\n", __func__, filename_len); } printf("\n#%u/%u saving PAK (name='%s', platform='%s', offset=0x%x, size='%d') to file %s\n", index + 1, epakHeader->pakCount, pakName, pakHeader->platform, pakRecord.offset, pakRecord.size, filename); FILE *outfile = fopen(((const char *)filename), "wb"); if (outfile == NULL) { err_exit("Error in %s: failed to open file '%s': %s.\n", __func__, filename, strerror(errno)); } fwrite(pakHeader->pakName + sizeof(struct pakHeader_t), 1, pakRecord.size - 132, outfile); fclose(outfile); handle_file(filename, config_opts); } } else { // new EPK1 header printf("\nFirmware type is EPK1(new)...\n"); struct epk1NewHeader_t *epakHeader = (struct epk1NewHeader_t *)(buffer); printNewHeaderInfo(epakHeader); constructNewVerString(verString, epakHeader); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, verString); createFolder(config_opts->dest_dir); for (index = 0; index < epakHeader->pakCount; index++) { struct pakRec_t pakRecord = epakHeader->pakRecs[index]; struct pakHeader_t *pakHeader = (struct pakHeader_t *)(buffer + pakRecord.offset); char pakName[PAKNAME_LEN + 1] = ""; sprintf(pakName, "%.*s", PAKNAME_LEN, pakHeader->pakName); char filename[PATH_MAX + 1] = ""; int filename_len = snprintf(filename, PATH_MAX + 1, "%s/%s.pak", config_opts->dest_dir, pakName); if (filename_len > PATH_MAX) { err_exit("Error in %s: filename too long (%d > %d)\n", __func__, filename_len, PATH_MAX); } else if (filename_len < 0) { err_exit("Error in %s: snprintf() failed (%d)\n", __func__, filename_len); } printf("\n#%u/%u saving PAK (name='%s', platform='%s', offset=0x%x, size='%d') to file %s\n", index + 1, epakHeader->pakCount, pakName, pakHeader->platform, pakRecord.offset, pakRecord.size, filename); FILE *outfile = fopen(filename, "wb"); if (outfile == NULL) { err_exit("Error in %s: failed to open file '%s': %s.\n", __func__, filename, strerror(errno)); } fwrite(pakHeader->pakName + sizeof(struct pakHeader_t), 1, pakHeader->pakSize + 4, outfile); fclose(outfile); handle_file(filename, config_opts); } } if (munmap(buffer, fileLength) == -1) { printf("Error un-mmapping the file"); } close(file); } ================================================ FILE: src/epk2.c ================================================ /** * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include "config.h" #include "common.h" #include "main.h" /* handle_file */ #include "epk.h" #include "epk2.h" #include "mfile.h" #include "util.h" #include "util_crypto.h" /* * Checks if the given data is a PAK2 header */ int compare_pak2_header(uint8_t *header, size_t headerSize){ PAK_V2_HEADER_T *hdr = (PAK_V2_HEADER_T *)header; return memcmp(hdr->pakMagic, PAK_MAGIC, sizeof(hdr->pakMagic)) == 0; } /* * Checks if the given data is an EPK2 header */ int compare_epk2_header(uint8_t *header, size_t headerSize){ EPK_V2_HEADER_T *hdr = (EPK_V2_HEADER_T *)header; return memcmp(hdr->epkMagic, EPK2_MAGIC, sizeof(hdr->epkMagic)) == 0; } MFILE *isFileEPK2(const char *epk_file) { setKeyFile_LG(); MFILE *file = mopen(epk_file, O_RDONLY); if (!file) { err_exit("Can't open file %s\n\n", epk_file); } struct epk2_structure *epk2 = mdata(file, struct epk2_structure); if(msize(file) < sizeof(*epk2)){ goto checkFail; } // check if the epk magic is present (decrypted) if(compare_epk2_header((uint8_t *)&(epk2->epkHeader), sizeof(EPK_V2_HEADER_T))){ goto checkOk; } bool has_versions = false; if(isEpkVersionString(epk2->platformVersion) && isEpkVersionString(epk2->sdkVersion)){ has_versions = true; goto checkOk; } checkFail: mclose(file); return NULL; checkOk: if(has_versions){ printf("[EPK2] Platform Version: %.*s\n", sizeof(epk2->platformVersion), epk2->platformVersion); printf("[EPK2] SDK Version: %.*s\n", sizeof(epk2->sdkVersion), epk2->sdkVersion); } return file; } void extractEPK2(MFILE *epk, config_opts_t *config_opts) { struct epk2_structure *epk2 = mdata(epk, struct epk2_structure); EPK_V2_HEADER_T *epkHeader = &(epk2->epkHeader); int result; if(config_opts->enableSignatureChecking){ size_t signed_size = ( member_size(struct epk2_structure, epkHeader) + member_size(struct epk2_structure, crc32Info) ); /** * Note: * The signature check is not strict but tries the given size and * tries with smaller sizes if unsuccesful. * This allows us to work with EPK2 headers of different size by using * the biggest header as base (64 partitions) */ printf("\nVerifying digital signature of EPK2 firmware header...\n"); result = wrap_verifyimage( // Signature to check against epk2->signature, // Header to verify epkHeader, signed_size, // Folder containing keys config_opts->config_dir, SIG_SHA1 ); } if (config_opts->signatureOnly) return; result = wrap_decryptimage( epkHeader, sizeof(EPK_V2_HEADER_T), epkHeader, config_opts->dest_dir, EPK_V2, NULL ); if(result < 0){ return; } PAK_V2_LOCATION_T *pakLocs = epkHeader->imageLocation; printf("\nFirmware info\n"); printf("-------------\n"); printf("Firmware magic: %.*s\n", 4, epkHeader->fileType); printf("Firmware type: %.*s\n", 4, epkHeader->epkMagic); printf("Firmware otaID: %s\n", epkHeader->otaId); printf("Firmware version: " EPK_VERSION_FORMAT "\n", epkHeader->epakVersion[3], epkHeader->epakVersion[2], epkHeader->epakVersion[1], epkHeader->epakVersion[0]); printf("PAK count: %d\n", epkHeader->fileNum); printf("PAKs total size: %d\n", epkHeader->fileSize); printf("Header length: %d\n\n", pakLocs[0].imageOffset); //first image after header char *fwVersion; asprintf(&fwVersion, EPK_VERSION_FORMAT "-%s", epkHeader->epakVersion[3], epkHeader->epakVersion[2], epkHeader->epakVersion[1], epkHeader->epakVersion[0], epkHeader->otaId ); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, fwVersion); createFolder(config_opts->dest_dir); unsigned int curPak=0, signatureCount=0; uintptr_t pakLoc; struct pak2_structure *pak; /* Process every pak in a loop */ for(curPak=0; curPak < epkHeader->fileNum; curPak++){ pakLoc = (uintptr_t)(epkHeader) + pakLocs[curPak].imageOffset + (sizeof(signature_t) * signatureCount); pak = (struct pak2_structure *)pakLoc; unsigned int curSeg, segCount; char *filename; char *pakPartitionShortName; MFILE *outFile; /* Process every segment in a loop. We don't know the segment count yet */ for (curSeg=0; ;){ ++signatureCount; size_t signed_size = pakLocs[curPak].imageSize; /* if the package is splitted, fallback to the segment size */ if(signed_size > pakLocs[curPak].segmentSize){ signed_size = pakLocs[curPak].segmentSize + sizeof(PAK_V2_HEADER_T); /* * We now need to check if the segment is trailing. If it is, we'd overflow into the next * package. Calculate the distance between us and the next package. If less than the segment size, truncate */ size_t distance; struct pak2_structure *nextPak = (struct pak2_structure *)( (uintptr_t)(epkHeader) + pakLocs[curPak + 1].imageOffset + (sizeof(signature_t) * signatureCount) ); // No need to subtract signature, as it's included in both (so it cancels out) distance = (size_t)( (uintptr_t)&(nextPak->pakHeader) - (uintptr_t)&(pak->pakHeader) ); // Last pak will have a distance < than the segment size // Because the data contained is less if(distance < pakLocs[curPak].segmentSize){ signed_size = distance - sizeof(signature_t); } } if(config_opts->enableSignatureChecking){ wrap_verifyimage( pak->signature, &(pak->pakHeader), signed_size, config_opts->config_dir, SIG_SHA1 ); } //printf("Decrypting PAK Header @0x%x\n", (uintptr_t)&(pak->pakHeader)-(uintptr_t)epk2); //decrypt the pak header int result = wrap_decryptimage( &(pak->pakHeader), sizeof(PAK_V2_HEADER_T), &(pak->pakHeader), config_opts->config_dir, (FILE_TYPE_T)PAK_V2, NULL ); if(result < 0){ return; } curSeg = pak->pakHeader.segmentIndex; segCount = pak->pakHeader.segmentCount; if(curSeg == 0){ //first pak, print segment count and open output file printf("\nPAK '%.4s' contains %d segment(s):\n", pak->pakHeader.imageType, pak->pakHeader.segmentCount); pakPartitionShortName = pak->pakHeader.imageType; asprintf(&filename, "%s/%.4s.pak", config_opts->dest_dir, pak->pakHeader.imageType); outFile = mfopen(filename, "w+"); if(!outFile){ PERROR_SE("Cannot open %s for writing", filename); return; } mfile_map(outFile, pak->pakHeader.imageSize); } size_t pakContentSize = pak->pakHeader.segmentSize; //printf("Decrypting PAK DATA @0x%x\n", (uintptr_t)pak-(uintptr_t)epk2); //decrypt the pak data wrap_decryptimage( &(pak->pData), pak->pakHeader.segmentSize, &(pak->pData), config_opts->config_dir, (FILE_TYPE_T)RAW, NULL ); mwrite(&(pak->pData), pakContentSize, 1, outFile); //write the decrypted data printf(" segment #%u (name='%.4s',", curSeg + 1, pak->pakHeader.imageType); printf(" version='%02x.%02x.%02x.%02x',", (pak->pakHeader.swVersion >> 24) & 0xff, (pak->pakHeader.swVersion >> 16) & 0xff, (pak->pakHeader.swVersion >> 8 ) & 0xff, (pak->pakHeader.swVersion ) & 0xff); printf(" platform='%s', offset='0x%x', size='%u bytes', ", pak->pakHeader.modelName, moff(epk, pak), pakContentSize); switch ((BUILD_TYPE_T) pak->pakHeader.devMode) { case RELEASE: printf("build=RELEASE"); break; case DEBUG: printf("build=DEBUG"); break; case TEST: printf("build=TEST"); break; default: printf("build=UNKNOWN 0x%x\n", pak->pakHeader.devMode); break; } printf(")\n"); if(curSeg + 1 == segCount){ printf("#%u/%u saved PAK (%.4s) to file %s\n", curPak + 1, epkHeader->fileNum, pakPartitionShortName, filename); mclose(outFile); handle_file(filename, config_opts); free(filename); break; } mfile_flush(&(pak->pData), pak->pakHeader.segmentSize); pakLoc += sizeof(*pak) + pakContentSize; pak = (struct pak2_structure *)pakLoc; } } } ================================================ FILE: src/epk3.c ================================================ /** * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include "main.h" #include "config.h" #include "mfile.h" #include "epk3.h" #include "util.h" #include "util_crypto.h" /* * Check for epk3 files with an additional heading signature (whole file signature?) */ int compare_epk3_new_header(uint8_t *header, size_t headerSize){ EPK_V3_HEADER_T *hdr = (EPK_V3_HEADER_T *)(header + SIGNATURE_SIZE); return memcmp(hdr->epkMagic, EPK3_MAGIC, sizeof(hdr->epkMagic)) == 0; } /* * Checks if the given data is an EPK3 header */ int compare_epk3_header(uint8_t *header, size_t headerSize){ EPK_V3_HEADER_T *hdr = (EPK_V3_HEADER_T *)header; return memcmp(hdr->epkMagic, EPK3_MAGIC, sizeof(hdr->epkMagic)) == 0; } MFILE *isFileEPK3(const char *epk_file) { setKeyFile_LG(); MFILE *file = mopen(epk_file, O_RDONLY); if (!file) { err_exit("Can't open file %s\n\n", epk_file); } struct epk3_structure *epk3 = mdata(file, struct epk3_structure); struct epk3_head_structure *head = &(epk3->head); if(msize(file) < sizeof(*epk3)){ goto checkFail; } // check if the epk magic is present (decrypted) if(compare_epk3_header((uint8_t *)&(head->epkHeader), sizeof(EPK_V3_HEADER_T))){ goto checkOk; } if(isEpkVersionString(head->platformVersion) && isEpkVersionString(head->sdkVersion)) goto checkOk; checkFail: mclose(file); return NULL; checkOk: printf("[EPK3] Platform Version: %.*s\n", sizeof(head->platformVersion), head->platformVersion); printf("[EPK3] SDK Version: %.*s\n", sizeof(head->sdkVersion), head->sdkVersion); return file; } void extractEPK3(MFILE *epk, FILE_TYPE_T epkType, config_opts_t *config_opts){ epk3_union *epk3 = mdata(epk, epk3_union); size_t headerSize, signed_size, sigSize, extraSegmentSize; SIG_TYPE_T sigType; { switch(epkType){ case EPK_V3: headerSize = sizeof(EPK_V3_HEADER_T); signed_size = ( sizeof(epk3->old.head.epkHeader) + sizeof(epk3->old.head.crc32Info) + sizeof(epk3->old.head.reserved) ); sigType = SIG_SHA1; sigSize = SIGNATURE_SIZE; extraSegmentSize = 0; break; case EPK_V3_NEW: headerSize = sizeof(EPK_V3_NEW_HEADER_T); signed_size = headerSize; sigType = SIG_SHA256; sigSize = SIGNATURE_SIZE_NEW; /* each segment has an index value */ extraSegmentSize = sizeof(uint32_t); break; default: err_exit("Unsupported EPK3 variant\n"); } } EPK_V3_HEADER_UNION *epkHeader; if (epkType == EPK_V3_NEW) { epkHeader = (EPK_V3_HEADER_UNION *) &(epk3->new.head.epkHeader); } else { epkHeader = (EPK_V3_HEADER_UNION *) &(epk3->old.head.epkHeader); } if(config_opts->enableSignatureChecking) { wrap_verifyimage( epk3->old.head.signature, /* same offset in old/new */ epkHeader, signed_size, config_opts->config_dir, sigType ); } int result = wrap_decryptimage( epkHeader, headerSize, epkHeader, config_opts->dest_dir, EPK_V3, NULL ); if(result < 0){ return; } size_t pak_signed_size; PAK_V3_LISTHEADER_UNION *packageInfo; PAK_V3_HEADER_T *pak; void *sigPtr; switch(epkType){ case EPK_V3: pak_signed_size = epkHeader->old.packageInfoSize; packageInfo = (PAK_V3_LISTHEADER_UNION *) &(epk3->old.packageInfo); pak = &(packageInfo->old.packages[0]); sigPtr = epk3->old.packageInfo_signature; break; case EPK_V3_NEW: pak_signed_size = epkHeader->new.packageInfoSize; packageInfo = (PAK_V3_LISTHEADER_UNION *) &(epk3->new.packageInfo); pak = &(packageInfo->new.packages[0]); sigPtr = epk3->new.packageInfo_signature; break; } if(config_opts->enableSignatureChecking){ wrap_verifyimage( sigPtr, packageInfo, pak_signed_size, config_opts->config_dir, sigType ); } printf("\nFirmware info\n"); printf("-------------\n"); printf("Firmware magic: %.*s\n", 4, epkHeader->old.epkMagic); printf("Firmware otaID: %s\n", epkHeader->old.otaId); printf("Firmware version: " EPK_VERSION_FORMAT "\n", epkHeader->old.epkVersion[3], epkHeader->old.epkVersion[2], epkHeader->old.epkVersion[1], epkHeader->old.epkVersion[0] ); printf("packageInfoSize: %d\n", epkHeader->old.packageInfoSize); printf("bChunked: %d\n", epkHeader->old.bChunked); if(epkType == EPK_V3_NEW){ printf("EncryptType: %.*s\n", sizeof(epkHeader->new.encryptType), epkHeader->new.encryptType ); printf("UpdateType: %.*s\n", sizeof(epkHeader->new.updateType), epkHeader->new.updateType ); printf("unknown: %02hhx %02hhx %02hhx\n", epkHeader->new.gap[0], epkHeader->new.gap[1], epkHeader->new.gap[2]); printf("updatePlatformVersion: %f\n", epkHeader->new.updatePlatformVersion); printf("compatibleMinimumVersion: %f\n", epkHeader->new.compatibleMinimumVersion); printf("needToCheckCompatibleVersion: %d\n", epkHeader->new.needToCheckCompatibleVersion); } if (config_opts->signatureOnly) return; char *fwVersion; asprintf(&fwVersion, EPK_VERSION_FORMAT "-%s", epkHeader->old.epkVersion[3], epkHeader->old.epkVersion[2], epkHeader->old.epkVersion[1], epkHeader->old.epkVersion[0], epkHeader->old.otaId ); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, fwVersion); createFolder(config_opts->dest_dir); free(fwVersion); printf("---- begin ----\n"); /* Decrypt packageInfo */ result = wrap_decryptimage( packageInfo, epkHeader->old.packageInfoSize, packageInfo, config_opts->dest_dir, RAW, NULL ); if(result < 0){ return; } if(epkType == EPK_V3_NEW){ if(packageInfo->new.pakInfoMagic != epkHeader->new.pakInfoMagic){ printf("pakInfoMagic mismatch! (expected: %04X, actual: %04X)\n", epkHeader->new.pakInfoMagic, packageInfo->new.pakInfoMagic ); return; } } uintptr_t dataPtr = (uintptr_t)packageInfo; dataPtr += epkHeader->old.packageInfoSize; int packageInfoCount; switch(epkType){ case EPK_V3: packageInfoCount = packageInfo->old.packageInfoCount; break; case EPK_V3_NEW: packageInfoCount = packageInfo->new.packageInfoCount; break; } for(uint i = 0; ipackageInfoSize != sizeof(*pak)){ printf("Warning: Unexpected packageInfoSize '%d', expected '%d'\n", pak->packageInfoSize, sizeof(*pak) ); } printf("\nPAK '%s' contains %d segment(s), size %d bytes:\n", pak->packageName, pak->segmentInfo.segmentCount, pak->packageSize ); char *pakFileName; asprintf(&pakFileName, "%s/%s.pak", config_opts->dest_dir, pak->packageName); MFILE *pakFile = mfopen(pakFileName, "w+"); if(!pakFile){ err_exit("Cannot open '%s' for writing\n", pakFileName); } mfile_map(pakFile, pak->packageSize); printf("Saving partition (%s) to file %s\n", pak->packageName, pakFileName); PACKAGE_SEGMENT_INFO_T segmentInfo = pak->segmentInfo; uint segNo; for(segNo = segmentInfo.segmentIndex; segNo < segmentInfo.segmentCount; segNo++, pak++, i++ ){ dataPtr += sigSize; if(config_opts->enableSignatureChecking) { wrap_verifyimage( (void *)(dataPtr - sigSize), (void *)dataPtr, pak->segmentInfo.segmentSize + extraSegmentSize, config_opts->config_dir, sigType ); } printf(" segment #%u (name='%s', version='%s', offset='0x%lx', size='%u bytes')\n", segNo + 1, pak->packageName, pak->packageVersion, moff(epk, dataPtr), pak->segmentInfo.segmentSize ); result = wrap_decryptimage( (void *)dataPtr, pak->segmentInfo.segmentSize, (void *)dataPtr, config_opts->dest_dir, RAW, NULL ); if(result < 0){ return; } if(epkType == EPK_V3_NEW){ uint32_t decryptedSegmentIndex = *(uint32_t *)dataPtr; if(decryptedSegmentIndex != i){ printf("Warning: Decrypted segment doesn't match expected index! (index: %d, expected: %d)\n", decryptedSegmentIndex, i ); } mwrite(dataPtr + 4, pak->segmentInfo.segmentSize, 1, pakFile); } else { mwrite(dataPtr, pak->segmentInfo.segmentSize, 1, pakFile); } dataPtr += pak->segmentInfo.segmentSize; /* for segment index in new EPK3 */ dataPtr += extraSegmentSize; } mclose(pakFile); handle_file(pakFileName, config_opts); free(pakFileName); } } ================================================ FILE: src/jffs2/CMakeLists.txt ================================================ add_library(jffs2 crc32.cpp jffs2extract.cpp mini_inflate.cpp) target_include_directories(jffs2 PUBLIC ${INC} ${LZO_INCLUDE_DIR} ${INC}/jffs2 ) target_link_libraries(jffs2 util mfile lzma ${LZO_LIBRARIES}) ================================================ FILE: src/jffs2/crc32.cpp ================================================ unsigned long crc32(unsigned long, const unsigned char *, unsigned int); static const unsigned long crc_table[256] = { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; #define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); unsigned long crc32_no_comp(unsigned long crc, const unsigned char *buf, int len) { while (len >= 8) { DO8(buf); len -= 8; } if (len) do { DO1(buf); } while (--len); return crc; } ================================================ FILE: src/jffs2/jffs2extract.cpp ================================================ /* * a very simple jffs2 unpacker. * algorithm is memory intensive but has (almost) linear complexity. * at first, the jffs2 is unpacked and put into a map, inode data blocks * sorted by version number. * then the data blocks are "replayed" in correct order, and memcpy'ed * into a buffer. * * usage: jffs2_unpack * ...where endianess is 4321 for big endian or 1234 for little endian. * * SECURITY NOTE: as you need to run this program as root, you could * easily build a fake-jffs2 file with relative pathnames, thus overwriting * any file on the host system! BE AWARE OF THIS! * (this could be easily avoided by checking directory. however, i don't * want to give any false sense of security. this program was NOT designed * with security in mind, and i know that this is no excuse.) * * License: GPL (due to the used unpack algorithms) * * (C) 2006 Felix Domke */ #include #include #include #include #include #include #include #include #include #ifdef __APPLE__ # include #else # include # include #endif #include #include #include #include #include #include "mfile.h" #include "common.h" #include "lzo/lzo1x.h" #include "lzma.h" #include "util.h" #include "os_byteswap.h" #include "jffs2/mini_inflate.h" #include "jffs2/jffs2.h" #define PAD_U32(x) ((x + 3) & ~3) #define PAD_X(x, y) ((x + (y - 1) & ~(y - 1))) #define RUBIN_REG_SIZE 16 #define UPPER_BIT_RUBIN (((long) 1)<<(RUBIN_REG_SIZE-1)) #define LOWER_BITS_RUBIN ((((long) 1)<<(RUBIN_REG_SIZE-1))-1) extern unsigned long crc32_no_comp(unsigned long crc, const unsigned char *buf, int len); static int swap_words = -1; static int verbose = 0; static bool guess_es = false; static bool keep_unlinked = true; static CLzmaEncHandle *p; static uint8_t propsEncoded[LZMA_PROPS_SIZE]; static size_t propsSize = sizeof(propsEncoded); unsigned short fix16(unsigned short c) { if (swap_words) return bswap_16(c); else return c; } unsigned long fix32(unsigned long c) { if (swap_words) return bswap_32(c); else return c; } typedef __u32 u32; void lzma_free_workspace(void) { LzmaEnc_Destroy(p, &lzma_alloc, &lzma_alloc); } int lzma_alloc_workspace(CLzmaEncProps *props) { if ((p = (CLzmaEncHandle *)LzmaEnc_Create(&lzma_alloc)) == NULL) { PRINT_ERROR("Failed to allocate lzma deflate workspace\n"); return -ENOMEM; } if (LzmaEnc_SetProps(p, props) != SZ_OK) { lzma_free_workspace(); return -1; } if (LzmaEnc_WriteProperties(p, propsEncoded, &propsSize) != SZ_OK) { lzma_free_workspace(); return -1; } return 0; } void rubin_do_decompress(unsigned char *bits, unsigned char *in, unsigned char *page_out, __u32 destlen) { register unsigned char *curr = page_out; unsigned char *end = page_out + destlen; register unsigned long temp; register unsigned long result; register unsigned long p; register unsigned long q; register unsigned long rec_q; register unsigned long bit; register long i0; unsigned long i; /* init_pushpull */ temp = *(u32 *) in; bit = 16; /* init_rubin */ q = 0; p = (long)(2 * UPPER_BIT_RUBIN); /* init_decode */ rec_q = (in[0] << 8) | in[1]; while (curr < end) { /* in byte */ result = 0; for (i = 0; i < 8; i++) { /* decode */ while ((q & UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN)) { q &= ~UPPER_BIT_RUBIN; q <<= 1; p <<= 1; rec_q &= ~UPPER_BIT_RUBIN; rec_q <<= 1; rec_q |= (temp >> (bit++ ^ 7)) & 1; if (bit > 31) { bit = 0; temp = *(u32 *) in; in += 4; } } i0 = (bits[i] * p) >> 8; if (i0 <= 0) i0 = 1; /* if it fails, it fails, we have our crc if (i0 >= p) i0 = p - 1; */ result >>= 1; if (rec_q < q + i0) { /* result |= 0x00; */ p = i0; } else { result |= 0x80; p -= i0; q += i0; } } *(curr++) = result; } } void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, unsigned long sourcelen, unsigned long dstlen) { unsigned char bits[8]; int c; for (c = 0; c < 8; c++) bits[c] = (256 - data_in[c]); rubin_do_decompress(bits, data_in + 8, cpage_out, dstlen); } void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen) { int positions[256]; int outpos; int pos; int i; outpos = pos = 0; for (i = 0; i < 256; positions[i++] = 0) ; while (outpos < destlen) { unsigned char value; int backoffs; int repeat; value = data_in[pos++]; cpage_out[outpos++] = value; /* first the verbatim copied byte */ repeat = data_in[pos++]; backoffs = positions[value]; positions[value] = outpos; if (repeat) { if (backoffs + repeat >= outpos) { while (repeat) { cpage_out[outpos++] = cpage_out[backoffs++]; repeat--; } } else { for (i = 0; i < repeat; i++) *(cpage_out + outpos + i) = *(cpage_out + backoffs + i); outpos += repeat; } } } } long zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen) { return (decompress_block(cpage_out, data_in + 2, memcpy)); } long lzma_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { int ret; size_t dl = (size_t)destlen; size_t sl = (size_t)srclen; ELzmaStatus status; ret = LzmaDecode(cpage_out, &dl, data_in, &sl, propsEncoded, propsSize, LZMA_FINISH_ANY, &status, &lzma_alloc); if (ret != SZ_OK || status == LZMA_STATUS_NOT_FINISHED || dl != (size_t)destlen) return -1; return destlen; } long lzo_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { size_t dl = destlen; int ret; ret = lzo1x_decompress_safe(data_in, srclen, cpage_out, &dl, NULL); if (ret != LZO_E_OK || dl != destlen) return -1; return dl; } int do_uncompress(void *dst, int dstlen, void *src, int srclen, int type) { switch (type) { case JFFS2_COMPR_NONE: memcpy(dst, src, dstlen); return dstlen; case JFFS2_COMPR_ZERO: memset(dst, 0, dstlen); return dstlen; case JFFS2_COMPR_RTIME: rtime_decompress((unsigned char *)src, (unsigned char *)dst, srclen, dstlen); return dstlen; case JFFS2_COMPR_RUBINMIPS: break; case JFFS2_COMPR_COPY: break; case JFFS2_COMPR_DYNRUBIN: dynrubin_decompress((unsigned char *)src, (unsigned char *)dst, srclen, dstlen); return dstlen; case JFFS2_COMPR_ZLIB: return zlib_decompress((unsigned char *)src, (unsigned char *)dst, srclen, dstlen); case JFFS2_COMPR_LZO: return lzo_decompress((unsigned char *)src, (unsigned char *)dst, srclen, dstlen); case JFFS2_COMPR_LZMA: return lzma_decompress((unsigned char *)src, (unsigned char *)dst, srclen, dstlen); } printf(" ** unknown compression type %d!\n", type); return -1; } std::map inodes; std::map node_type; std::map > childs; struct nodedata_s { unsigned char *data; int size; int offset; int isize, gid, uid, mode; nodedata_s(unsigned char *_data, int _size, int _offset, int _isize, int _gid, int _uid, int _mode) { data = (unsigned char *)malloc(_size); size = _size; offset = _offset; memcpy(data, _data, size); isize = _isize; gid = _gid; uid = _uid; mode = _mode; } nodedata_s() { data = 0; size = 0; offset = 0; isize = 0; gid = 0; uid = 0; mode = 0; } }; std::map > nodedata; int whine = 0; std::string prefix; FILE *devtab; void do_list(int inode, std::string root = "") { std::string pathname = prefix + root + inodes[inode]; std::map &data = nodedata[inode]; //printf("inode %d -> %s\n", inode, inodes[inode].c_str()); int max_size = 0, gid = 0, uid = 0, mode = 0755; if (!data.empty()) { std::map ::iterator last = data.end(); --last; max_size = last->second.isize; mode = last->second.mode; gid = last->second.gid; uid = last->second.uid; } if ((node_type[inode] == DT_BLK) || (node_type[inode] == DT_CHR)) max_size = 2; unsigned char *merged_data = (unsigned char *)calloc(1, max_size + 1); int devtab_type = 0, major = 0, minor = 0; for (auto i : data) { int size = i.second.size; int offset = i.second.offset; if (offset + size > max_size) size = max_size - offset; if (size > 0) memcpy(merged_data + i.second.offset, i.second.data, i.second.size); } switch (node_type[inode]) { case DT_DIR: if (mkdir(pathname.c_str(), mode & 0777)){ fprintf(stderr, "mkdir '%s' failed (%s)\n", pathname.c_str(), strerror(errno)); } devtab_type = 'd'; break; case DT_REG: { FILE *f = fopen(pathname.c_str(), "wb"); if (!f){ fprintf(stderr, "fopen '%s' failed (%s)\n", pathname.c_str(), strerror(errno)); } else { fwrite(merged_data, max_size, 1, f); fclose(f); } devtab_type = 'f'; break; } case DT_LNK: { symlink((char *)merged_data, pathname.c_str()); break; } case DT_CHR: case DT_BLK: { major = merged_data[1]; minor = merged_data[0]; if (mknod(pathname.c_str(), ((node_type[inode] == DT_BLK) ? S_IFBLK : S_IFCHR) | (mode & 07777), makedev(major, minor))) { if (!whine++){ fprintf(stderr, "mknod '%s' failed (%s)\n", pathname.c_str(), strerror(errno)); } } if (node_type[inode] == DT_BLK) devtab_type = 'b'; else devtab_type = 'c'; break; } case DT_FIFO: { if (mkfifo(pathname.c_str(), mode) < 0) fprintf(stderr, "failed to create FIFO(%s) (%s)\n", pathname.c_str(), strerror(errno)); break; } case DT_SOCK: { // create and close a TCP Unix Socket int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0); const char *cpath = pathname.c_str(); if(sock_fd < 0){ fprintf(stderr, "failed to create unix socket '%s' (%s)\n", cpath, strerror(errno)); break; } close(sock_fd); break; } case DT_WHT: goto node_warn_uhnandled; case DT_UNKNOWN: //deletion node if(inode == 0){ const char *cpath = pathname.c_str(); if(keep_unlinked){ int nidx = 0; std::string suffix = ""; while(access((pathname + suffix).c_str(), F_OK ) != -1){ suffix = std::to_string(nidx++); } std::string new_name = pathname + suffix; MFILE *f_src = mopen(cpath, O_RDONLY); MFILE *f_dst = mfopen(new_name.c_str(), "w+"); if(!f_src || !f_dst){ fprintf(stderr, "failed to copy '%s' to '%s'\n", cpath, new_name.c_str()); if(f_src) mclose(f_src); if(f_dst) mclose(f_dst); } else { mfile_map(f_dst, msize(f_src)); memcpy( mdata(f_dst, void), mdata(f_src, void), msize(f_src) ); mclose(f_dst); mclose(f_src); } } } else { node_warn_uhnandled: printf("warning:unhandled inode type(%d) for inode %d\n", node_type[inode], inode); } break; } free(merged_data); if (devtab_type && devtab && (inode != 1)){ fprintf(devtab, "%s %c %o %d %d %d %d - - -\n", (root + inodes[inode]).c_str(), devtab_type, mode & 07777, uid, gid, major, minor ); } if (node_type[inode] != DT_LNK) { if (chmod(pathname.c_str(), mode)) if (!whine++){ fprintf(stderr, "chmod failed for '%s' (%s)\n", pathname.c_str(), strerror(errno)); } if (chown(pathname.c_str(), uid, gid)) { #ifndef __CYGWIN__ if (!whine++) fprintf(stderr, "chown failed for '%s' (%s)\n", pathname.c_str(), strerror(errno)); #endif } } // printf("%s (%d)\n", pathname.c_str(), max_size); std::list < int >&child = childs[inode]; for (auto i : child) do_list(i, root + inodes[inode].c_str() + "/"); } inline int is_jffs2_magic(uint16_t val){ if(val == KSAMTIB_CIGAM_2SFFJ){ fputs("invalid endianess detected\n", stderr); return -1; } return (val == JFFS2_MAGIC_BITMASK); } size_t contiguos_region_size(MFILE *mf, off_t offset, uint8_t match_pattern){ uint8_t *pStart = mdata(mf, uint8_t); uint8_t *cursor = pStart + offset; size_t fileSz = msize(mf); for(; moff(mf, cursor) < fileSz; cursor++){ if(*cursor != match_pattern) break; } return (cursor - pStart) - offset; } uint32_t try_guess_es(MFILE *mf, bool *is_reliable){ uint8_t *data = mdata(mf, uint8_t); size_t fileSz = msize(mf); *is_reliable = false; uint8_t blk16[16]; memset(&blk16, 0xFF, sizeof(blk16)); // find start of remaining data off_t off = 0; for(; off < fileSz; off += sizeof(blk16)){ if(!memcmp(data + off, &blk16, sizeof(blk16))) break; } if(off == fileSz) return 0; // align to 16 int remainder = off % 16; while(remainder > 0){ if(*(data + (off++)) != 0xFF) return off; } // find end for(; off < fileSz; off += sizeof(blk16)){ if(memcmp(data + off, &blk16, sizeof(blk16)) != 0) break; } // align to next JFFS2 header for(int i=0; i<=32; i++, off++){ union jffs2_node_union *hdr = (union jffs2_node_union *)(data + off); if((is_jffs2_magic(hdr->u.magic)) && crc32_no_comp(0, (uint8_t *)hdr, sizeof(hdr->u) - 4) == fix32(hdr->u.hdr_crc) ){ break; } } *is_reliable = true; return off; } union jffs2_node_union *find_next_node(MFILE *mf, off_t cur_off, int erase_size){ uint8_t *data = mdata(mf, uint8_t); size_t fileSz = msize(mf); // find empty FS data { size_t empty_fsdata_sz = contiguos_region_size(mf, cur_off, 0x0); if(empty_fsdata_sz != 0){ if(verbose) printf("region(0x00) = 0x%x\n", empty_fsdata_sz); } cur_off += empty_fsdata_sz; } if(erase_size > -1){ cur_off = PAD_X(cur_off, erase_size); goto find_jffs2; } // find empty eraseblocks { size_t empty_esblks_sz = contiguos_region_size(mf, cur_off, 0xFF); if(empty_esblks_sz != 0){ if(verbose) printf("region(0xFF) = 0x%x\n", empty_esblks_sz); } cur_off += empty_esblks_sz; } find_jffs2: off_t off; for(off = cur_off; off < fileSz;){ union jffs2_node_union *node = (union jffs2_node_union *)(data + off); int r; if((r=is_jffs2_magic(node->u.magic)) && crc32_no_comp(0, (uint8_t *)node, sizeof(node->u) - 4) == fix32(node->u.hdr_crc) ){ return node; } // if something unusual happened, stop search if(r < 0){ break; } if(erase_size > -1){ off += erase_size; } else { off += 4; } } return NULL; } extern "C" int jffs2extract(char *infile, char *outdir, struct jffs2_main_args args) { int errors = 0; verbose = args.verbose; keep_unlinked = args.keep_unlinked; MFILE *mf = mopen(infile, O_RDONLY); if (!mf) { fprintf(stderr, "Failed to open '%s'\n", infile); return 1; } union jffs2_node_union *node = mdata(mf, union jffs2_node_union); swap_words = (node->u.magic == KSAMTIB_CIGAM_2SFFJ); bool es_reliable = false; uint32_t es; if(args.erase_size > -1){ es = args.erase_size; } else if(guess_es){ es = try_guess_es(mf, &es_reliable); printf("> Guessed Erase Size: 0x%x (reliable=%d)\n", es, es_reliable); } uint8_t *data = mdata(mf, uint8_t); off_t off = moff(mf, node); while(off + sizeof(*node) < msize(mf)){ node = (union jffs2_node_union *)&data[off]; if(!is_jffs2_magic(node->u.magic) || node->u.totlen == 0){ printf("invalid node - scanning next node... (offset: %p)\n", off); int use_es = -1; if(es_reliable){ use_es = es; } node = find_next_node(mf, off, use_es); if(node == NULL){ // reached EOF break; } off_t prev_off = off; off = moff(mf, node); printf("found at %p, after 0x%x bytes\n", off, off - prev_off); } if(moff(mf, node) + sizeof(*node) >= msize(mf)){ continue; } off += PAD_U32(node->u.totlen); if (verbose) printf("at %08x: %04x | %04x (%lu bytes): ", off, fix16(node->u.magic), fix16(node->u.nodetype), fix32(node->u.totlen)); if (crc32_no_comp(0, (unsigned char *)node, sizeof(node->u) - 4) != fix32(node->u.hdr_crc)) { ++errors; printf(" ** wrong crc **\n"); continue; } switch (fix16(node->u.nodetype)) { case JFFS2_NODETYPE_DIRENT: { char name[node->d.nsize + 1]; strncpy(name, (char *)node->d.name, node->d.nsize); name[node->d.nsize] = 0; if (verbose) printf("DIRENT, ino %lu (%s), parent=%lu\n", fix32(node->d.ino), name, fix32(node->d.pino)); uint32_t ino = fix32(node->d.ino); uint32_t pino = fix32(node->d.pino); inodes[ino] = name; node_type[ino] = node->d.type; childs[pino].push_back(ino); break; } case JFFS2_NODETYPE_INODE: { if (verbose) printf("\n"); if (crc32_no_comp(0, (unsigned char *)&(node->i), sizeof(struct jffs2_raw_inode) - 8) != fix32(node->i.node_crc)) { errors++; printf(" ** wrong node crc **\n"); continue; } if (verbose) { printf(" INODE, ino %lu (version %lu) at %08lx\n", fix32(node->i.ino), fix32(node->i.version), fix32(node->i.offset)); printf(" compression: %d, user compression requested: %d\n", node->i.compr, node->i.usercompr); } int compr_size = fix32(node->i.csize); int uncompr_size = fix32(node->i.dsize); if (verbose) printf(" compr_size: %d, uncompr_size: %d\n", compr_size, uncompr_size); uint8_t *compr = node->i.data; uint8_t uncomp[uncompr_size]; int extracted_size; if (crc32_no_comp(0, compr, compr_size) != fix32(node->i.data_crc)) { errors++; printf(" ** wrong data crc **\n"); continue; } else { if (verbose) printf(" data crc ok\n"); if ((extracted_size=do_uncompress(uncomp, uncompr_size, compr, compr_size, node->i.compr)) != uncompr_size) { errors++; printf(" ** data uncompress failed! (%u =! %u)\n", extracted_size, uncompr_size); } else { nodedata[fix32(node->i.ino)][fix32(node->i.version)] = nodedata_s( uncomp, uncompr_size, fix32(node->i.offset), fix32(node->i.isize), fix32(node->i.gid), fix32(node->i.uid), fix32(node->i.mode) ); #if 0 int i; for (i = 0; i < ((uncompr_size + 15) & ~15); ++i) { if ((i & 15) == 0) printf("%08x: ", fix32(node.i.offset) + i); if (i < uncompr_size) printf("%02x ", uncomp[i]); else printf(" "); if ((i & 15) == 15) printf("\n"); } #endif } } break; } case JFFS2_NODETYPE_CLEANMARKER: if (verbose) printf("CLEANMARKER\n"); break; case JFFS2_NODETYPE_PADDING: if (verbose) printf("PADDING\n"); break; case JFFS2_NODETYPE_SUMMARY: if (verbose) printf("SUMMARY\n"); break; default: errors++; printf(" ** INVALID ** - nodetype %04x (offset: %p)\n", fix16(node->u.nodetype), off); } } if (errors) { if (!inodes.empty()) printf("there were errors, but some valid stuff was detected. continuing.\n"); else { fprintf(stderr, "errors present and no valid data.\n"); mclose(mf); return 2; } } node_type[1] = DT_DIR; prefix = outdir; devtab = fopen((prefix + ".devtab").c_str(), "wb"); do_list(1); fclose(devtab); mclose(mf); return 0; } ================================================ FILE: src/jffs2/mini_inflate.cpp ================================================ /*------------------------------------------------------------------------- * Filename: mini_inflate.c * Version: $Id: mini_inflate.c,v 1.3 2002/01/24 22:58:42 rfeany Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill * Description: Mini inflate implementation (RFC 1951) *-----------------------------------------------------------------------*/ /* * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include /* The order that the code lengths in section 3.2.7 are in */ static unsigned char huffman_order[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; inline void cramfs_memset(int *s, const int c, size n) { n--; for (; n > 0; n--) s[n] = c; s[0] = c; } /* associate a stream with a block of data and reset the stream */ static void init_stream(struct bitstream *stream, unsigned char *data, void *(*inflate_memcpy) (void *, const void *, size)) { stream->error = NO_ERROR; stream->memcpy = inflate_memcpy; stream->decoded = 0; stream->data = data; stream->bit = 0; /* The first bit of the stream is the lsb of the * first byte */ /* really sorry about all this initialization, think of a better way, * let me know and it will get cleaned up */ stream->codes.bits = 8; stream->codes.num_symbols = 19; stream->codes.lengths = stream->code_lengths; stream->codes.symbols = stream->code_symbols; stream->codes.count = stream->code_count; stream->codes.first = stream->code_first; stream->codes.pos = stream->code_pos; stream->lengths.bits = 16; stream->lengths.num_symbols = 288; stream->lengths.lengths = stream->length_lengths; stream->lengths.symbols = stream->length_symbols; stream->lengths.count = stream->length_count; stream->lengths.first = stream->length_first; stream->lengths.pos = stream->length_pos; stream->distance.bits = 16; stream->distance.num_symbols = 32; stream->distance.lengths = stream->distance_lengths; stream->distance.symbols = stream->distance_symbols; stream->distance.count = stream->distance_count; stream->distance.first = stream->distance_first; stream->distance.pos = stream->distance_pos; } /* pull 'bits' bits out of the stream. The last bit pulled it returned as the * msb. (section 3.1.1) */ inline unsigned long pull_bits(struct bitstream *stream, const unsigned int bits) { unsigned long ret; unsigned int i; ret = 0; for (i = 0; i < bits; i++) { ret += ((*(stream->data) >> stream->bit) & 1) << i; /* if, before incrementing, we are on bit 7, * go to the lsb of the next byte */ if (stream->bit++ == 7) { stream->bit = 0; stream->data++; } } return ret; } inline int pull_bit(struct bitstream *stream) { int ret = ((*(stream->data) >> stream->bit) & 1); if (stream->bit++ == 7) { stream->bit = 0; stream->data++; } return ret; } /* discard bits up to the next whole byte */ static void discard_bits(struct bitstream *stream) { if (stream->bit != 0) { stream->bit = 0; stream->data++; } } /* No decompression, the data is all literals (section 3.2.4) */ static void decompress_none(struct bitstream *stream, unsigned char *dest) { unsigned int length; discard_bits(stream); length = *(stream->data++); length += *(stream->data++) << 8; pull_bits(stream, 16); /* throw away the inverse of the size */ stream->decoded += length; stream->memcpy(dest, stream->data, length); stream->data += length; } /* Read in a symbol from the stream (section 3.2.2) */ static int read_symbol(struct bitstream *stream, struct huffman_set *set) { int bits = 0; int code = 0; while (!(set->count[bits] && code < set->first[bits] + set->count[bits])) { code = (code << 1) + pull_bit(stream); if (++bits > set->bits) { /* error decoding (corrupted data?) */ stream->error = CODE_NOT_FOUND; return -1; } } return set->symbols[set->pos[bits] + code - set->first[bits]]; } /* decompress a stream of data encoded with the passed length and distance * huffman codes */ static void decompress_huffman(struct bitstream *stream, unsigned char *dest) { struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); int symbol, length, dist, i; do { if ((symbol = read_symbol(stream, lengths)) < 0) return; if (symbol < 256) { *(dest++) = symbol; /* symbol is a literal */ stream->decoded++; } else if (symbol > 256) { /* Determine the length of the repitition * (section 3.2.5) */ if (symbol < 265) length = symbol - 254; else if (symbol == 285) length = 258; else { length = pull_bits(stream, (symbol - 261) >> 2); length += (4 << ((symbol - 261) >> 2)) + 3; length += ((symbol - 1) % 4) << ((symbol - 261) >> 2); } /* Determine how far back to go */ if ((symbol = read_symbol(stream, distance)) < 0) return; if (symbol < 4) dist = symbol + 1; else { dist = pull_bits(stream, (symbol - 2) >> 1); dist += (2 << ((symbol - 2) >> 1)) + 1; dist += (symbol % 2) << ((symbol - 2) >> 1); } stream->decoded += length; for (i = 0; i < length; i++) { *dest = dest[-dist]; dest++; } } } while (symbol != 256); /* 256 is the end of the data block */ } /* Fill the lookup tables (section 3.2.2) */ static void fill_code_tables(struct huffman_set *set) { int code = 0, i, length; /* fill in the first code of each bit length, and the pos pointer */ set->pos[0] = 0; for (i = 1; i < set->bits; i++) { code = (code + set->count[i - 1]) << 1; set->first[i] = code; set->pos[i] = set->pos[i - 1] + set->count[i - 1]; } /* Fill in the table of symbols in order of their huffman code */ for (i = 0; i < set->num_symbols; i++) { if ((length = set->lengths[i])) set->symbols[set->pos[length]++] = i; } /* reset the pos pointer */ for (i = 1; i < set->bits; i++) set->pos[i] -= set->count[i]; } static void init_code_tables(struct huffman_set *set) { cramfs_memset(set->lengths, 0, set->num_symbols); cramfs_memset(set->count, 0, set->bits); cramfs_memset(set->first, 0, set->bits); } /* read in the huffman codes for dynamic decoding (section 3.2.7) */ static void decompress_dynamic(struct bitstream *stream, unsigned char *dest) { /* I tried my best to minimize the memory footprint here, while still * keeping up performance. I really dislike the _lengths[] tables, but * I see no way of eliminating them without a sizable performance * impact. The first struct table keeps track of stats on each bit * length. The _length table keeps a record of the bit length of each * symbol. The _symbols table is for looking up symbols by the huffman * code (the pos element points to the first place in the symbol table * where that bit length occurs). I also hate the initization of these * structs, if someone knows how to compact these, lemme know. */ struct huffman_set *codes = &(stream->codes); struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); int hlit = pull_bits(stream, 5) + 257; int hdist = pull_bits(stream, 5) + 1; int hclen = pull_bits(stream, 4) + 4; int length, curr_code, symbol, i, last_code; last_code = 0; init_code_tables(codes); init_code_tables(lengths); init_code_tables(distance); /* fill in the count of each bit length' as well as the lengths * table */ for (i = 0; i < hclen; i++) { length = pull_bits(stream, 3); codes->lengths[huffman_order[i]] = length; if (length) codes->count[length]++; } fill_code_tables(codes); /* Do the same for the length codes, being carefull of wrap through * to the distance table */ curr_code = 0; while (curr_code < hlit) { if ((symbol = read_symbol(stream, codes)) < 0) return; if (symbol == 0) { curr_code++; last_code = 0; } else if (symbol < 16) { /* Literal length */ lengths->lengths[curr_code] = last_code = symbol; lengths->count[symbol]++; curr_code++; } else if (symbol == 16) { /* repeat the last symbol 3 - 6 * times */ length = 3 + pull_bits(stream, 2); for (; length; length--, curr_code++) if (curr_code < hlit) { lengths->lengths[curr_code] = last_code; lengths->count[last_code]++; } else { /* wrap to the distance table */ distance->lengths[curr_code - hlit] = last_code; distance->count[last_code]++; } } else if (symbol == 17) { /* repeat a bit length 0 */ curr_code += 3 + pull_bits(stream, 3); last_code = 0; } else { /* same, but more times */ curr_code += 11 + pull_bits(stream, 7); last_code = 0; } } fill_code_tables(lengths); /* Fill the distance table, don't need to worry about wrapthrough * here */ curr_code -= hlit; while (curr_code < hdist) { if ((symbol = read_symbol(stream, codes)) < 0) return; if (symbol == 0) { curr_code++; last_code = 0; } else if (symbol < 16) { distance->lengths[curr_code] = last_code = symbol; distance->count[symbol]++; curr_code++; } else if (symbol == 16) { length = 3 + pull_bits(stream, 2); for (; length; length--, curr_code++) { distance->lengths[curr_code] = last_code; distance->count[last_code]++; } } else if (symbol == 17) { curr_code += 3 + pull_bits(stream, 3); last_code = 0; } else { curr_code += 11 + pull_bits(stream, 7); last_code = 0; } } fill_code_tables(distance); decompress_huffman(stream, dest); } /* fill in the length and distance huffman codes for fixed encoding * (section 3.2.6) */ static void decompress_fixed(struct bitstream *stream, unsigned char *dest) { /* let gcc fill in the initial values */ struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); cramfs_memset(lengths->count, 0, 16); cramfs_memset(lengths->first, 0, 16); cramfs_memset(lengths->lengths, 8, 144); cramfs_memset(lengths->lengths + 144, 9, 112); cramfs_memset(lengths->lengths + 256, 7, 24); cramfs_memset(lengths->lengths + 280, 8, 8); lengths->count[7] = 24; lengths->count[8] = 152; lengths->count[9] = 112; cramfs_memset(distance->count, 0, 16); cramfs_memset(distance->first, 0, 16); cramfs_memset(distance->lengths, 5, 32); distance->count[5] = 32; fill_code_tables(lengths); fill_code_tables(distance); decompress_huffman(stream, dest); } /* returns the number of bytes decoded, < 0 if there was an error. Note that * this function assumes that the block starts on a byte boundry * (non-compliant, but I don't see where this would happen). section 3.2.3 */ long decompress_block(unsigned char *dest, unsigned char *source, void *(*inflate_memcpy) (void *, const void *, size)) { int bfinal, btype; struct bitstream stream; init_stream(&stream, source, inflate_memcpy); do { bfinal = pull_bit(&stream); btype = pull_bits(&stream, 2); if (btype == NO_COMP) decompress_none(&stream, dest + stream.decoded); else if (btype == DYNAMIC_COMP) decompress_dynamic(&stream, dest + stream.decoded); else if (btype == FIXED_COMP) decompress_fixed(&stream, dest + stream.decoded); else stream.error = COMP_UNKNOWN; } while (!bfinal && !stream.error); #if 0 putstr("decompress_block start\r\n"); putLabeledWord("stream.error = ", stream.error); putLabeledWord("stream.decoded = ", stream.decoded); putLabeledWord("dest = ", dest); putstr("decompress_block end\r\n"); #endif return stream.error ? -stream.error : stream.decoded; } ================================================ FILE: src/lz4/CMakeLists.txt ================================================ add_library(lz4 lz4.c lz4hc.c lz4demo.c) target_include_directories(lz4 PUBLIC ${INC}/lz4) ================================================ FILE: src/lz4/bench.c ================================================ /* bench.c - Demo program to benchmark open-source compression algorithm Copyright (C) Yann Collet 2012 GPL v2 License 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ //************************************** // Compiler Options //************************************** // Visual warning messages #define _CRT_SECURE_NO_WARNINGS // Under Linux at least, pull in the *64 commands #define _LARGEFILE64_SOURCE // MSVC does not support S_ISREG #ifndef S_ISREG # define S_ISREG(x) (((x) & S_IFMT) == S_IFREG) #endif // GCC does not support _rotl outside of Windows #if !defined(_WIN32) # define _rotl(x,r) ((x << r) | (x >> (32 - r))) #endif //************************************** // Includes //************************************** #include // malloc #include // fprintf, fopen, ftello64 #include // timeb #include // stat64 #include // stat64 #include "lz4.h" #define COMPRESSOR0 LZ4_compress #include "lz4hc.h" #define COMPRESSOR1 LZ4_compressHC #define DEFAULTCOMPRESSOR LZ4_compress //************************************** // Basic Types //************************************** #if defined(_MSC_VER) // Visual Studio does not support 'stdint' natively # define BYTE unsigned __int8 # define U16 unsigned __int16 # define U32 unsigned __int32 # define S32 __int32 # define U64 unsigned __int64 #else # include # define BYTE uint8_t # define U16 uint16_t # define U32 uint32_t # define S32 int32_t # define U64 uint64_t #endif //************************************** // Constants //************************************** #define NBLOOPS 3 #define TIMELOOP 2000 #define KNUTH 2654435761U #define MAX_MEM (1984<<20) #define DEFAULT_CHUNKSIZE (8<<20) //************************************** // Local structures //************************************** struct chunkParameters { U32 id; char *inputBuffer; char *outputBuffer; int inputSize; int outputSize; }; struct compressionParameters { int (*compressionFunction) (const char *, char *, int); int (*decompressionFunction) (const char *, char *, int); }; //************************************** // MACRO //************************************** #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) //************************************** // Benchmark Parameters //************************************** static int chunkSize = DEFAULT_CHUNKSIZE; static int nbIterations = NBLOOPS; void BMK_SetBlocksize(int bsize) { chunkSize = bsize; DISPLAY("-Using Block Size of %i KB-", chunkSize >> 10); } void BMK_SetNbIterations(int nbLoops) { nbIterations = nbLoops; DISPLAY("- %i iterations-", nbIterations); } //********************************************************* // Private functions //********************************************************* static int BMK_GetMilliStart() { // Supposed to be portable // Rolls over every ~ 12.1 days (0x100000/24/60/60) // Use GetMilliSpan to correct for rollover struct timeb tb; int nCount; ftime(&tb); nCount = tb.millitm + (tb.time & 0xfffff) * 1000; return nCount; } static int BMK_GetMilliSpan(int nTimeStart) { int nSpan = BMK_GetMilliStart() - nTimeStart; if (nSpan < 0) nSpan += 0x100000 * 1000; return nSpan; } static U32 BMK_checksum_MMH3A(char *buff, U32 length) { const BYTE *data = (const BYTE *)buff; const int nblocks = length >> 2; U32 h1 = KNUTH; U32 c1 = 0xcc9e2d51; U32 c2 = 0x1b873593; const U32 *blocks = (const U32 *)(data + nblocks * 4); int i; for (i = -nblocks; i; i++) { U32 k1 = blocks[i]; k1 *= c1; k1 = _rotl(k1, 15); k1 *= c2; h1 ^= k1; h1 = _rotl(h1, 13); h1 = h1 * 5 + 0xe6546b64; } { const BYTE *tail = (const BYTE *)(data + nblocks * 4); U32 k1 = 0; switch (length & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; k1 *= c1; k1 = _rotl(k1, 15); k1 *= c2; h1 ^= k1; }; } h1 ^= length; h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1; } static size_t BMK_findMaxMem(U64 requiredMem) { size_t step = (64U << 20); // 64 MB BYTE *testmem = NULL; requiredMem = (((requiredMem >> 25) + 1) << 26); if (requiredMem > MAX_MEM) requiredMem = MAX_MEM; requiredMem += 2 * step; while (!testmem) { requiredMem -= step; testmem = malloc((size_t) requiredMem); } free(testmem); return (size_t) (requiredMem - step); } static U64 BMK_GetFileSize(char *infilename) { int r; #if defined(_MSC_VER) struct _stat64 statbuf; r = _stat64(infilename, &statbuf); #else struct stat statbuf; r = stat(infilename, &statbuf); #endif if (r || !S_ISREG(statbuf.st_mode)) return 0; // No good... return (U64) statbuf.st_size; } //********************************************************* // Public function //********************************************************* int BMK_benchFile(char **fileNamesTable, int nbFiles, int cLevel) { int fileIdx = 0; FILE *fileIn; char *infilename; U64 largefilesize; size_t benchedsize; int nbChunks; int maxCChunkSize; size_t readSize; char *in_buff; char *out_buff; int out_buff_size; struct chunkParameters *chunkP; U32 crcc, crcd = 0; struct compressionParameters compP; U64 totals = 0; U64 totalz = 0; double totalc = 0.; double totald = 0.; // Init switch (cLevel) { #ifdef COMPRESSOR0 case 0: compP.compressionFunction = COMPRESSOR0; break; #endif #ifdef COMPRESSOR1 case 1: compP.compressionFunction = COMPRESSOR1; break; #endif default: compP.compressionFunction = DEFAULTCOMPRESSOR; } compP.decompressionFunction = LZ4_uncompress; // Loop for each file while (fileIdx < nbFiles) { // Check file existence infilename = fileNamesTable[fileIdx++]; fileIn = fopen(infilename, "rb"); if (fileIn == NULL) { DISPLAY("Pb opening %s\n", infilename); return 11; } // Memory allocation & restrictions largefilesize = BMK_GetFileSize(infilename); benchedsize = (size_t) BMK_findMaxMem(largefilesize) / 2; if ((U64) benchedsize > largefilesize) benchedsize = (size_t) largefilesize; if (benchedsize < largefilesize) { DISPLAY("Not enough memory for '%s' full size; testing %i MB only...\n", infilename, (int)(benchedsize >> 20)); } // Alloc chunkP = (struct chunkParameters *)malloc(((benchedsize / chunkSize) + 1) * sizeof(struct chunkParameters)); in_buff = malloc((size_t) benchedsize); nbChunks = (benchedsize / chunkSize) + 1; maxCChunkSize = LZ4_compressBound(chunkSize); out_buff_size = nbChunks * maxCChunkSize; out_buff = malloc((size_t) out_buff_size); if (!in_buff || !out_buff) { DISPLAY("\nError: not enough memory!\n"); free(in_buff); free(out_buff); fclose(fileIn); return 12; } // Init chunks data { int i; size_t remaining = benchedsize; char *in = in_buff; char *out = out_buff; for (i = 0; i < nbChunks; i++) { chunkP[i].id = i; chunkP[i].inputBuffer = in; in += chunkSize; if ((int)remaining > chunkSize) { chunkP[i].inputSize = chunkSize; remaining -= chunkSize; } else { chunkP[i].inputSize = remaining; remaining = 0; } chunkP[i].outputBuffer = out; out += maxCChunkSize; chunkP[i].outputSize = 0; } } // Fill input buffer DISPLAY("Loading %s... \r", infilename); readSize = fread(in_buff, 1, benchedsize, fileIn); fclose(fileIn); if (readSize != benchedsize) { DISPLAY("\nError: problem reading file '%s' !! \n", infilename); free(in_buff); free(out_buff); return 13; } // Calculating input Checksum crcc = BMK_checksum_MMH3A(in_buff, benchedsize); // Bench { int loopNb, nb_loops, chunkNb; size_t cSize = 0; int milliTime; double fastestC = 100000000., fastestD = 100000000.; double ratio = 0.; DISPLAY("\r%79s\r", ""); for (loopNb = 1; loopNb <= nbIterations; loopNb++) { // Compression DISPLAY("%1i-%-14.14s : %9i ->\r", loopNb, infilename, (int)benchedsize); { size_t i; for (i = 0; i < benchedsize; i++) out_buff[i] = (char)i; } // warmimg up memory nb_loops = 0; milliTime = BMK_GetMilliStart(); while (BMK_GetMilliStart() == milliTime) ; milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { for (chunkNb = 0; chunkNb < nbChunks; chunkNb++) chunkP[chunkNb].outputSize = compP.compressionFunction(chunkP[chunkNb].inputBuffer, chunkP[chunkNb].outputBuffer, chunkP[chunkNb].inputSize); nb_loops++; } milliTime = BMK_GetMilliSpan(milliTime); if ((double)milliTime < fastestC * nb_loops) fastestC = (double)milliTime / nb_loops; cSize = 0; for (chunkNb = 0; chunkNb < nbChunks; chunkNb++) cSize += chunkP[chunkNb].outputSize; ratio = (double)cSize / (double)benchedsize *100.; DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%), %6.1f MB/s\r", loopNb, infilename, (int)benchedsize, (int)cSize, ratio, (double)benchedsize / fastestC / 1000.); // Decompression { size_t i; for (i = 0; i < benchedsize; i++) in_buff[i] = 0; } // zeroing area, for CRC checking nb_loops = 0; milliTime = BMK_GetMilliStart(); while (BMK_GetMilliStart() == milliTime) ; milliTime = BMK_GetMilliStart(); while (BMK_GetMilliSpan(milliTime) < TIMELOOP) { for (chunkNb = 0; chunkNb < nbChunks; chunkNb++) chunkP[chunkNb].outputSize = compP.decompressionFunction(chunkP[chunkNb].outputBuffer, chunkP[chunkNb].inputBuffer, chunkP[chunkNb].inputSize); nb_loops++; } milliTime = BMK_GetMilliSpan(milliTime); if ((double)milliTime < fastestD * nb_loops) fastestD = (double)milliTime / nb_loops; DISPLAY("%1i-%-14.14s : %9i -> %9i (%5.2f%%), %6.1f MB/s , %6.1f MB/s\r", loopNb, infilename, (int)benchedsize, (int)cSize, ratio, (double)benchedsize / fastestC / 1000., (double)benchedsize / fastestD / 1000.); // CRC Checking crcd = BMK_checksum_MMH3A(in_buff, benchedsize); if (crcc != crcd) { DISPLAY("\n!!! WARNING !!! %14s : Invalid Checksum : %x != %x\n", infilename, (unsigned)crcc, (unsigned)crcd); break; } } if (crcc == crcd) { if (ratio < 100.) DISPLAY("%-16.16s : %9i -> %9i (%5.2f%%), %6.1f MB/s , %6.1f MB/s\n", infilename, (int)benchedsize, (int)cSize, ratio, (double)benchedsize / fastestC / 1000., (double)benchedsize / fastestD / 1000.); else DISPLAY("%-16.16s : %9i -> %9i (%5.1f%%), %6.1f MB/s , %6.1f MB/s \n", infilename, (int)benchedsize, (int)cSize, ratio, (double)benchedsize / fastestC / 1000., (double)benchedsize / fastestD / 1000.); } totals += benchedsize; totalz += cSize; totalc += fastestC; totald += fastestD; } free(in_buff); free(out_buff); free(chunkP); } if (nbFiles > 1) printf("%-16.16s :%10llu ->%10llu (%5.2f%%), %6.1f MB/s , %6.1f MB/s\n", " TOTAL", (long long unsigned int)totals, (long long unsigned int)totalz, (double)totalz / (double)totals * 100., (double)totals / totalc / 1000., (double)totals / totald / 1000.); return 0; } ================================================ FILE: src/lz4/lz4.c ================================================ /* LZ4 - Fast LZ compression algorithm Copyright (C) 2011-2012, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ //************************************** // Tuning parameters //************************************** // COMPRESSIONLEVEL : // Increasing this value improves compression ratio // Lowering this value reduces memory usage // Reduced memory usage typically improves speed, due to cache effect (ex : L1 32KB for Intel, L1 64KB for AMD) // Memory usage formula : N->2^(N+2) Bytes (examples : 12 -> 16KB ; 17 -> 512KB) #define COMPRESSIONLEVEL 12 // NOTCOMPRESSIBLE_CONFIRMATION : // Decreasing this value will make the algorithm skip faster data segments considered "incompressible" // This may decrease compression ratio dramatically, but will be faster on incompressible data // Increasing this value will make the algorithm search more before declaring a segment "incompressible" // This could improve compression a bit, but will be slower on incompressible data // The default value (6) is recommended #define NOTCOMPRESSIBLE_CONFIRMATION 6 // LZ4_COMPRESSMIN : // Compression function will *fail* if it is not successful at compressing input by at least LZ4_COMPRESSMIN bytes // Since the compression function stops working prematurely, it results in a speed gain // The output however is unusable. Compression function result will be zero. // Default : 0 = disabled #define LZ4_COMPRESSMIN 0 // BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE : // This will provide a boost to performance for big endian cpu, but the resulting compressed stream will be incompatible with little-endian CPU. // You can set this option to 1 in situations where data will stay within closed environment // This option is useless on Little_Endian CPU (such as x86) //#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1 //************************************** // CPU Feature Detection //************************************** // 32 or 64 bits ? #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || defined(__LP64__) || defined(_LP64) ) // Detects 64 bits mode # define LZ4_ARCH64 1 #else # define LZ4_ARCH64 0 #endif // Little Endian or Big Endian ? // Note : overwrite the below #define if you know your architecture endianess #if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) || defined(PPC) || defined(__powerpc__) || defined(__powerpc) || defined(powerpc) || ((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) ) # define LZ4_BIG_ENDIAN 1 #else // Little Endian assumed. PDP Endian and other very rare endian format are unsupported. #endif // Unaligned memory access is automatically enabled for "common" CPU, such as x86. // For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected // If you know your target CPU supports unaligned memory access, you may want to force this option manually to improve performance #if defined(__ARM_FEATURE_UNALIGNED) # define LZ4_FORCE_UNALIGNED_ACCESS 1 #endif // Define this parameter if your target system or compiler does not support hardware bit count #if defined(_MSC_VER) && defined(_WIN32_WCE) // Visual Studio for Windows CE does not support Hardware bit count # define LZ4_FORCE_SW_BITCOUNT #endif //************************************** // Compiler Options //************************************** #if __STDC_VERSION__ >= 199901L // C99 /* "restrict" is a known keyword */ #else # define restrict // Disable restrict #endif #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #ifdef _MSC_VER // Visual Studio # define inline __forceinline// Visual is not C99, but supports some kind of inline # if LZ4_ARCH64 // 64-bit # pragma intrinsic(_BitScanForward64) // For Visual 2005 # pragma intrinsic(_BitScanReverse64) // For Visual 2005 # else # pragma intrinsic(_BitScanForward) // For Visual 2005 # pragma intrinsic(_BitScanReverse) // For Visual 2005 # endif #endif #ifdef _MSC_VER # define lz4_bswap16(x) _byteswap_ushort(x) #else # define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) #endif #if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) #endif #define likely(expr) expect((expr) != 0, 1) #define unlikely(expr) expect((expr) != 0, 0) //************************************** // Includes //************************************** #include // for malloc #include // for memset #include "lz4.h" //************************************** // Basic Types //************************************** #if defined(_MSC_VER) // Visual Studio does not support 'stdint' natively # define BYTE unsigned __int8 # define U16 unsigned __int16 # define U32 unsigned __int32 # define S32 __int32 # define U64 unsigned __int64 #else # include # define BYTE uint8_t # define U16 uint16_t # define U32 uint32_t # define S32 int32_t # define U64 uint64_t #endif #ifndef LZ4_FORCE_UNALIGNED_ACCESS # pragma pack(push, 1) #endif typedef struct _U16_S { U16 v; } U16_S; typedef struct _U32_S { U32 v; } U32_S; typedef struct _U64_S { U64 v; } U64_S; #ifndef LZ4_FORCE_UNALIGNED_ACCESS # pragma pack(pop) #endif #define A64(x) (((U64_S *)(x))->v) #define A32(x) (((U32_S *)(x))->v) #define A16(x) (((U16_S *)(x))->v) //************************************** // Constants //************************************** #define MINMATCH 4 #define HASH_LOG COMPRESSIONLEVEL #define HASHTABLESIZE (1 << HASH_LOG) #define HASH_MASK (HASHTABLESIZE - 1) #define SKIPSTRENGTH (NOTCOMPRESSIBLE_CONFIRMATION>2?NOTCOMPRESSIBLE_CONFIRMATION:2) #define STACKLIMIT 13 #define HEAPMODE (HASH_LOG>STACKLIMIT) // Defines if memory is allocated into the stack (local variable), or into the heap (malloc()). #define COPYLENGTH 8 #define LASTLITERALS 5 #define MFLIMIT (COPYLENGTH+MINMATCH) #define MINLENGTH (MFLIMIT+1) #define MAXD_LOG 16 #define MAX_DISTANCE ((1 << MAXD_LOG) - 1) #define ML_BITS 4 #define ML_MASK ((1U<> ((MINMATCH*8)-HASH_LOG)) #define LZ4_HASH_VALUE(p) LZ4_HASH_FUNCTION(A32(p)) #define LZ4_WILDCOPY(s,d,e) do { LZ4_COPYPACKET(s,d) } while (d> 3); # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clzll(val) >> 3); # else int r; if (!(val >> 32)) { r = 4; } else { r = 0; val >>= 32; } if (!(val >> 16)) { r += 2; val >>= 8; } else { val >>= 24; } r += (!val); return r; # endif # else # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward64(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctzll(val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >> 58]; # endif # endif } #else inline static int LZ4_NbCommonBytes(register U32 val) { # if defined(LZ4_BIG_ENDIAN) # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clz(val) >> 3); # else int r; if (!(val >> 16)) { r = 2; val >>= 8; } else { r = 0; val >>= 24; } r += (!val); return r; # endif # else # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctz(val) >> 3); # else static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; # endif # endif } #endif //**************************** // Public functions //**************************** int LZ4_compressBound(int isize) { return (isize + (isize / 255) + 16); } //****************************** // Compression functions //****************************** int LZ4_compressCtx(void **ctx, const char *source, char *dest, int isize) { #if HEAPMODE struct refTables *srt = (struct refTables *)(*ctx); HTYPE *HashTable; #else HTYPE HashTable[HASHTABLESIZE] = { 0 }; #endif const BYTE *ip = (BYTE *) source; INITBASE(base); const BYTE *anchor = ip; const BYTE *const iend = ip + isize; const BYTE *const mflimit = iend - MFLIMIT; #define matchlimit (iend - LASTLITERALS) BYTE *op = (BYTE *) dest; int len, length; const int skipStrength = SKIPSTRENGTH; U32 forwardH; // Init if (isize < MINLENGTH) goto _last_literals; #if HEAPMODE if (*ctx == NULL) { srt = (struct refTables *)malloc(sizeof(struct refTables)); *ctx = (void *)srt; } HashTable = (HTYPE *) (srt->hashTable); memset((void *)HashTable, 0, sizeof(srt->hashTable)); #else (void)ctx; #endif // First Byte HashTable[LZ4_HASH_VALUE(ip)] = ip - base; ip++; forwardH = LZ4_HASH_VALUE(ip); // Main Loop for (;;) { int findMatchAttempts = (1U << skipStrength) + 3; const BYTE *forwardIp = ip; const BYTE *ref; BYTE *token; // Find a match do { U32 h = forwardH; int step = findMatchAttempts++ >> skipStrength; ip = forwardIp; forwardIp = ip + step; if unlikely (forwardIp > mflimit) { goto _last_literals; } forwardH = LZ4_HASH_VALUE(forwardIp); ref = base + HashTable[h]; HashTable[h] = ip - base; } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); // Catch up while ((ip > anchor) && (ref > (BYTE *) source) && unlikely(ip[-1] == ref[-1])) { ip--; ref--; } // Encode Literal length length = ip - anchor; token = op++; if (length >= (int)RUN_MASK) { *token = (RUN_MASK << ML_BITS); len = length - RUN_MASK; for (; len > 254; len -= 255) *op++ = 255; *op++ = (BYTE) len; } else *token = (length << ML_BITS); // Copy Literals LZ4_BLINDCOPY(anchor, op, length); _next_match: // Encode Offset LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref); // Start Counting ip += MINMATCH; ref += MINMATCH; // MinMatch verified anchor = ip; while likely (ip < matchlimit - (STEPSIZE - 1)) { UARCH diff = AARCH(ref) ^ AARCH(ip); if (!diff) { ip += STEPSIZE; ref += STEPSIZE; continue; } ip += LZ4_NbCommonBytes(diff); goto _endCount; } if (LZ4_ARCH64) if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) { ip += 4; ref += 4; } if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) { ip += 2; ref += 2; } if ((ip < matchlimit) && (*ref == *ip)) ip++; _endCount: // Encode MatchLength len = (ip - anchor); if (len >= (int)ML_MASK) { *token += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { *op++ = 255; *op++ = 255; } if (len > 254) { len -= 255; *op++ = 255; } *op++ = (BYTE) len; } else *token += len; // Test end of chunk if (ip > mflimit) { anchor = ip; break; } // Fill table HashTable[LZ4_HASH_VALUE(ip - 2)] = ip - 2 - base; // Test next position ref = base + HashTable[LZ4_HASH_VALUE(ip)]; HashTable[LZ4_HASH_VALUE(ip)] = ip - base; if ((ref > ip - (MAX_DISTANCE + 1)) && (A32(ref) == A32(ip))) { token = op++; *token = 0; goto _next_match; } // Prepare next loop anchor = ip++; forwardH = LZ4_HASH_VALUE(ip); } _last_literals: // Encode Last Literals { int lastRun = iend - anchor; if ((LZ4_COMPRESSMIN > 0) && (((op - (BYTE *) dest) + lastRun + 1 + ((lastRun - 15) / 255)) > isize - LZ4_COMPRESSMIN)) return 0; if (lastRun >= (int)RUN_MASK) { *op++ = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) *op++ = 255; *op++ = (BYTE) lastRun; } else *op++ = (lastRun << ML_BITS); memcpy(op, anchor, iend - anchor); op += iend - anchor; } // End return (int)(((char *)op) - dest); } // Note : this function is valid only if isize < LZ4_64KLIMIT #define LZ4_64KLIMIT ((1<<16) + (MFLIMIT-1)) #define HASHLOG64K (HASH_LOG+1) #define HASH64KTABLESIZE (1U<> ((MINMATCH*8)-HASHLOG64K)) #define LZ4_HASH64K_VALUE(p) LZ4_HASH64K_FUNCTION(A32(p)) int LZ4_compress64kCtx(void **ctx, const char *source, char *dest, int isize) { #if HEAPMODE struct refTables *srt = (struct refTables *)(*ctx); U16 *HashTable; #else U16 HashTable[HASH64KTABLESIZE] = { 0 }; #endif const BYTE *ip = (BYTE *) source; const BYTE *anchor = ip; const BYTE *const base = ip; const BYTE *const iend = ip + isize; const BYTE *const mflimit = iend - MFLIMIT; #define matchlimit (iend - LASTLITERALS) BYTE *op = (BYTE *) dest; int len, length; const int skipStrength = SKIPSTRENGTH; U32 forwardH; // Init if (isize < MINLENGTH) goto _last_literals; #if HEAPMODE if (*ctx == NULL) { srt = (struct refTables *)malloc(sizeof(struct refTables)); *ctx = (void *)srt; } HashTable = (U16 *) (srt->hashTable); memset((void *)HashTable, 0, sizeof(srt->hashTable)); #else (void)ctx; #endif // First Byte ip++; forwardH = LZ4_HASH64K_VALUE(ip); // Main Loop for (;;) { int findMatchAttempts = (1U << skipStrength) + 3; const BYTE *forwardIp = ip; const BYTE *ref; BYTE *token; // Find a match do { U32 h = forwardH; int step = findMatchAttempts++ >> skipStrength; ip = forwardIp; forwardIp = ip + step; if (forwardIp > mflimit) { goto _last_literals; } forwardH = LZ4_HASH64K_VALUE(forwardIp); ref = base + HashTable[h]; HashTable[h] = ip - base; } while (A32(ref) != A32(ip)); // Catch up while ((ip > anchor) && (ref > (BYTE *) source) && (ip[-1] == ref[-1])) { ip--; ref--; } // Encode Literal length length = ip - anchor; token = op++; if (length >= (int)RUN_MASK) { *token = (RUN_MASK << ML_BITS); len = length - RUN_MASK; for (; len > 254; len -= 255) *op++ = 255; *op++ = (BYTE) len; } else *token = (length << ML_BITS); // Copy Literals LZ4_BLINDCOPY(anchor, op, length); _next_match: // Encode Offset LZ4_WRITE_LITTLEENDIAN_16(op, ip - ref); // Start Counting ip += MINMATCH; ref += MINMATCH; // MinMatch verified anchor = ip; while (ip < matchlimit - (STEPSIZE - 1)) { UARCH diff = AARCH(ref) ^ AARCH(ip); if (!diff) { ip += STEPSIZE; ref += STEPSIZE; continue; } ip += LZ4_NbCommonBytes(diff); goto _endCount; } if (LZ4_ARCH64) if ((ip < (matchlimit - 3)) && (A32(ref) == A32(ip))) { ip += 4; ref += 4; } if ((ip < (matchlimit - 1)) && (A16(ref) == A16(ip))) { ip += 2; ref += 2; } if ((ip < matchlimit) && (*ref == *ip)) ip++; _endCount: // Encode MatchLength len = (ip - anchor); if (len >= (int)ML_MASK) { *token += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { *op++ = 255; *op++ = 255; } if (len > 254) { len -= 255; *op++ = 255; } *op++ = (BYTE) len; } else *token += len; // Test end of chunk if (ip > mflimit) { anchor = ip; break; } // Fill table HashTable[LZ4_HASH64K_VALUE(ip - 2)] = ip - 2 - base; // Test next position ref = base + HashTable[LZ4_HASH64K_VALUE(ip)]; HashTable[LZ4_HASH64K_VALUE(ip)] = ip - base; if (A32(ref) == A32(ip)) { token = op++; *token = 0; goto _next_match; } // Prepare next loop anchor = ip++; forwardH = LZ4_HASH64K_VALUE(ip); } _last_literals: // Encode Last Literals { int lastRun = iend - anchor; if ((LZ4_COMPRESSMIN > 0) && (((op - (BYTE *) dest) + lastRun + 1 + ((lastRun - 15) / 255)) > isize - LZ4_COMPRESSMIN)) return 0; if (lastRun >= (int)RUN_MASK) { *op++ = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) *op++ = 255; *op++ = (BYTE) lastRun; } else *op++ = (lastRun << ML_BITS); memcpy(op, anchor, iend - anchor); op += iend - anchor; } // End return (int)(((char *)op) - dest); } int LZ4_compress(const char *source, char *dest, int isize) { #if HEAPMODE void *ctx = malloc(sizeof(struct refTables)); int result; if (isize < LZ4_64KLIMIT) result = LZ4_compress64kCtx(&ctx, source, dest, isize); else result = LZ4_compressCtx(&ctx, source, dest, isize); free(ctx); return result; #else if (isize < (int)LZ4_64KLIMIT) return LZ4_compress64kCtx(NULL, source, dest, isize); return LZ4_compressCtx(NULL, source, dest, isize); #endif } //**************************** // Decompression functions //**************************** // Note : The decoding functions LZ4_uncompress() and LZ4_uncompress_unknownOutputSize() // are safe against "buffer overflow" attack type. // They will never write nor read outside of the provided output buffers. // LZ4_uncompress_unknownOutputSize() also insures that it will never read outside of the input buffer. // A corrupted input will produce an error result, a negative int, indicating the position of the error within input stream. int LZ4_uncompress(const char *source, char *dest, int osize) { // Local Variables const BYTE *restrict ip = (const BYTE *)source; const BYTE *restrict ref; BYTE *restrict op = (BYTE *) dest; BYTE *const oend = op + osize; BYTE *cpy; BYTE token; int len, length; size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 }; // Main Loop while (1) { // get runlength token = *ip++; if ((length = (token >> ML_BITS)) == RUN_MASK) { for (; (len = *ip++) == 255; length += 255) { } length += len; } // copy literals cpy = op + length; if unlikely (cpy > oend - COPYLENGTH) { if (cpy > oend) goto _output_error; // Error : request to write beyond destination buffer memcpy(op, ip, length); ip += length; break; // Necessarily EOF } LZ4_WILDCOPY(ip, op, cpy); ip -= (op - cpy); op = cpy; // get offset LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); ip += 2; if (ref < (BYTE * const)dest) goto _output_error; // Error : offset create reference outside destination buffer // get matchlength if ((length = (token & ML_MASK)) == ML_MASK) { for (; *ip == 255; length += 255) { ip++; } length += *ip++; } // copy repeated sequence if unlikely (op - ref < STEPSIZE) { #if LZ4_ARCH64 size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; size_t dec2 = dec2table[op - ref]; #else const int dec2 = 0; #endif *op++ = *ref++; *op++ = *ref++; *op++ = *ref++; *op++ = *ref++; ref -= dec[op - ref]; A32(op) = A32(ref); op += STEPSIZE - 4; ref -= dec2; } else { LZ4_COPYSTEP(ref, op); } cpy = op + length - (STEPSIZE - 4); if (cpy > oend - COPYLENGTH) { if (cpy > oend) goto _output_error; // Error : request to write beyond destination buffer LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); while (op < cpy) *op++ = *ref++; op = cpy; if (op == oend) break; // Check EOF (should never happen, since last 5 bytes are supposed to be literals) continue; } LZ4_SECURECOPY(ref, op, cpy); op = cpy; // correction } // end of decoding return (int)(((char *)ip) - source); // write overflow error detected _output_error: return (int)(-(((char *)ip) - source)); } int LZ4_uncompress_unknownOutputSize(const char *source, char *dest, int isize, int maxOutputSize) { // Local Variables const BYTE *restrict ip = (const BYTE *)source; const BYTE *const iend = ip + isize; const BYTE *restrict ref; BYTE *restrict op = (BYTE *) dest; BYTE *const oend = op + maxOutputSize; BYTE *cpy; size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 }; // Main Loop while (ip < iend) { BYTE token; int length; // get runlength token = *ip++; if ((length = (token >> ML_BITS)) == RUN_MASK) { int s = 255; while ((ip < iend) && (s == 255)) { s = *ip++; length += s; } } // copy literals cpy = op + length; if ((cpy > oend - COPYLENGTH) || (ip + length > iend - COPYLENGTH)) { if (cpy > oend) goto _output_error; // Error : request to write beyond destination buffer if (ip + length > iend) goto _output_error; // Error : request to read beyond source buffer memcpy(op, ip, length); op += length; ip += length; if (ip < iend) goto _output_error; // Error : LZ4 format violation break; // Necessarily EOF, due to parsing restrictions } LZ4_WILDCOPY(ip, op, cpy); ip -= (op - cpy); op = cpy; // get offset LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip); ip += 2; if (ref < (BYTE * const)dest) goto _output_error; // Error : offset creates reference outside of destination buffer // get matchlength if ((length = (token & ML_MASK)) == ML_MASK) { while (ip < iend) { int s = *ip++; length += s; if (s == 255) continue; break; } } // copy repeated sequence if unlikely (op - ref < STEPSIZE) { #if LZ4_ARCH64 size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 }; size_t dec2 = dec2table[op - ref]; #else const int dec2 = 0; #endif *op++ = *ref++; *op++ = *ref++; *op++ = *ref++; *op++ = *ref++; ref -= dec[op - ref]; A32(op) = A32(ref); op += STEPSIZE - 4; ref -= dec2; } else { LZ4_COPYSTEP(ref, op); } cpy = op + length - (STEPSIZE - 4); if (cpy > oend - COPYLENGTH) { if (cpy > oend) goto _output_error; // Error : request to write outside of destination buffer LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH)); while (op < cpy) *op++ = *ref++; op = cpy; if (op == oend) break; // Check EOF (should never happen, since last 5 bytes are supposed to be literals) continue; } LZ4_SECURECOPY(ref, op, cpy); op = cpy; // correction } // end of decoding return (int)(((char *)op) - dest); // write overflow error detected _output_error: return (int)(-(((char *)ip) - source)); } ================================================ FILE: src/lz4/lz4_format_description.txt ================================================ LZ4 Format Description Last revised: 2012-02-27 Author : Y. Collet This small specification intents to provide enough information to anyone willing to produce LZ4-compatible compressed streams using any programming language. LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding. The most important design principle behind LZ4 is simplicity. It helps to create an easy to read and maintain source code. It also helps later on for optimisations, compactness, and speed. There is no entropy encoder backend nor framing layer. The latter is assumed to be handled by other parts of the system. This document only describes the format, not how the LZ4 compressor nor decompressor actually work. The correctness of the decompressor should not depend on implementation details of the compressor, and vice versa. -- Compressed stream format -- An LZ4 compressed stream is composed of sequences. Schematically, a sequence is a suite of literals, followed by a match copy. Each sequence starts with a token. The token is a one byte value, separated into two 4-bits fields. Therefore each field ranges from 0 to 15. The first field uses the 4 high-bits of the token. It provides the length of literals to follow. (Note : a literal is a not-compressed byte). If the field value is 0, then there is no literal. If it is 15, then we need to add some more bytes to indicate the full length. Each additionnal byte then represent a value from 0 to 255, which is added to the previous value to produce a total length. When the byte value is 255, another byte is output. There can be any number of bytes following the token. There is no "size limit". (Sidenote this is why a not-compressible input stream is expanded by 0.4%). Example 1 : A length of 48 will be represented as : - 15 : value for the 4-bits High field - 33 : (=48-15) remaining length to reach 48 Example 2 : A length of 280 will be represented as : - 15 : value for the 4-bits High field - 255 : following byte is maxed, since 280-15 >= 255 - 10 : (=280 - 15 - 255) ) remaining length to reach 280 Example 3 : A length of 15 will be represented as : - 15 : value for the 4-bits High field - 0 : (=15-15) yes, the zero must be output Following the token and optional length bytes, are the literals themselves. They are exactly as numerous as previously decoded (length of literals). It's possible that there are zero literal. Following the literals is the match copy operation. It starts by the offset. This is a 2 bytes value, in little endian format : the lower byte is the first one in the stream. The offset represents the position of the match to be copied from. 1 means "current position - 1 byte". The maximum offset value is 65535, 65536 cannot be coded. Note that 0 is an invalid value, not used. Then we need to extract the match length. For this, we use the second token field, the low 4-bits. Value, obviously, ranges from 0 to 15. However here, 0 means that the copy operation will be minimal. The minimum length of a match, called minmatch, is 4. As a consequence, a 0 value means 4 bytes, and a value of 15 means 19+ bytes. Similar to literal length, on reaching the highest possible value (15), we output additional bytes, one at a time, with values ranging from 0 to 255. They are added to total to provide the final match length. A 255 value means there is another byte to read and add. There is no limit to the number of optional bytes that can be output this way. (This points towards a maximum achievable compression ratio of ~250). With the offset and the matchlength, the decoder can now proceed to copy the data from the already decoded buffer. On decoding the matchlength, we reach the end of the compressed sequence, and therefore start another one. -- Parsing restrictions -- There are specific parsing rules to respect in order to remain compatible with assumptions made by the decoder : 1) The last 5 bytes are always literals 2) The last match must start at least 12 bytes before end of stream Consequently, a file with less than 13 bytes cannot be compressed. These rules are in place to ensure that the decoder will never read beyond the input buffer, nor write beyond the output buffer. Note that the last sequence is also incomplete, and stops right after literals. -- Additional notes -- There is no assumption nor limits to the way the compressor searches and selects matches within the source stream. It could be a fast scan, a multi-probe, a full search using BST, standard hash chains or MMC, well whatever. Advanced parsing strategies can also be implemented, such as lazy match, or full optimal parsing. All these trade-off offer distinctive speed/memory/compression advantages. Whatever the method used by the compressor, its result will be decodable by any LZ4 decoder if it follows the format specification described above. ================================================ FILE: src/lz4/lz4demo.c ================================================ /* LZ4Demo - Demo CLI program using LZ4 compression Copyright (C) Yann Collet 2011-2012 GPL v2 License 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ /* Note : this is *only* a demo program, an example to show how LZ4 can be used. It is not considered part of LZ4 compression library. The license of LZ4 is BSD. The license of the demo program is GPL. */ //**************************** // Warning messages //**************************** #define _CRT_SECURE_NO_WARNINGS // Visual (must be first line) //**************************** // Includes //**************************** #include // fprintf, fopen, fread, _fileno(?) #include // malloc #include // strcmp #include // clock #include // uint32_t #ifdef _WIN32 # include // _setmode # include // _O_BINARY #endif #include "lz4.h" #include "lz4hc.h" #include "bench.h" //************************************** // Compiler functions //************************************** #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #if defined(_MSC_VER) // Visual Studio # define swap32 _byteswap_ulong #elif GCC_VERSION >= 430 # define swap32 __builtin_bswap32 #else static inline unsigned int swap32(unsigned int x) { return ((x << 24) & 0xff000000) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff); } #endif //**************************** // Constants //**************************** #define COMPRESSOR_NAME "Compression CLI using LZ4 algorithm" #define COMPRESSOR_VERSION "" #define COMPILED __DATE__ #define AUTHOR "Yann Collet" #define EXTENSION ".lz4" #define WELCOME_MESSAGE "*** %s %s, by %s (%s) ***\n", COMPRESSOR_NAME, COMPRESSOR_VERSION, AUTHOR, COMPILED unsigned int CHUNKSIZE = 8 << 20; // 8 MB #define CACHELINE 64 //#define ARCHIVE_MAGICNUMBER 0x184C2102 #define ARCHIVE_MAGICNUMBER 0x50345A4C //#define ARCHIVE_MAGICNUMBER_SIZE 4 #define ARCHIVE_MAGICNUMBER_SIZE 0x20 //************************************** // Architecture Macros //************************************** static const int one = 1; #define CPU_LITTLE_ENDIAN (*(char*)(&one)) #define CPU_BIG_ENDIAN (!CPU_LITTLE_ENDIAN) #define LITTLE_ENDIAN32(i) if (CPU_BIG_ENDIAN) { i = swap32(i); } //************************************** // Macros //************************************** #define DISPLAY(...) fprintf(stderr, __VA_ARGS__) //**************************** // Functions //**************************** int usage(char *exename) { DISPLAY("Usage :\n"); DISPLAY(" %s [arg] input output\n", exename); DISPLAY("Arguments :\n"); DISPLAY(" -c0: Fast compression (default) \n"); DISPLAY(" -c1: High compression \n"); DISPLAY(" -d : decompression \n"); DISPLAY(" -b#: Benchmark files, using # compression level\n"); DISPLAY(" -t : check compressed file \n"); DISPLAY(" -h : help (this text)\n"); DISPLAY("input : can be 'stdin' (pipe) or a filename\n"); DISPLAY("output : can be 'stdout'(pipe) or a filename or 'null'\n"); return 0; } int badusage(char *exename) { DISPLAY("Wrong parameters\n"); usage(exename); return 0; } int get_fileHandle(const char *input_filename, const char *output_filename, FILE ** pfinput, FILE ** pfoutput) { char stdinmark[] = "stdin"; char stdoutmark[] = "stdout"; if (!strcmp(input_filename, stdinmark)) { DISPLAY("Using stdin for input\n"); *pfinput = stdin; #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows _setmode(_fileno(stdin), _O_BINARY); #endif } else { *pfinput = fopen(input_filename, "rb"); } if (!strcmp(output_filename, stdoutmark)) { DISPLAY("Using stdout for output\n"); *pfoutput = stdout; #ifdef _WIN32 // Need to set stdin/stdout to binary mode specifically for windows _setmode(_fileno(stdout), _O_BINARY); #endif } else { *pfoutput = fopen(output_filename, "wb"); } if (*pfinput == 0) { DISPLAY("Pb opening %s\n", input_filename); return 2; } if (*pfoutput == 0) { DISPLAY("Pb opening %s\n", output_filename); return 3; } return 0; } int compress_file(char *input_filename, char *output_filename, int compressionlevel) { int (*compressionFunction) (const char *, char *, int); unsigned long long filesize = 0; unsigned long long compressedfilesize = ARCHIVE_MAGICNUMBER_SIZE; unsigned int u32var; char *in_buff; char *out_buff; FILE *finput; FILE *foutput; int r; int displayLevel = (compressionlevel > 0); clock_t start, end; // Init switch (compressionlevel) { case 0: compressionFunction = LZ4_compress; break; case 1: compressionFunction = LZ4_compressHC; break; default: compressionFunction = LZ4_compress; } start = clock(); r = get_fileHandle(input_filename, output_filename, &finput, &foutput); if (r) return r; // Allocate Memory in_buff = (char *)malloc(CHUNKSIZE); out_buff = (char *)malloc(LZ4_compressBound(CHUNKSIZE)); if (!in_buff || !out_buff) { DISPLAY("Allocation error : not enough memory\n"); return 8; } // Write Archive Header u32var = ARCHIVE_MAGICNUMBER; LITTLE_ENDIAN32(u32var); *(unsigned int *)out_buff = u32var; fwrite(out_buff, 1, ARCHIVE_MAGICNUMBER_SIZE, foutput); // Main Loop while (1) { int outSize; // Read Block int inSize = fread(in_buff, 1, CHUNKSIZE, finput); if (inSize <= 0) break; filesize += inSize; if (displayLevel) DISPLAY("Read : %i MB \r", (int)(filesize >> 20)); // Compress Block outSize = compressionFunction(in_buff, out_buff + 4, inSize); compressedfilesize += outSize + 4; if (displayLevel) DISPLAY("Read : %i MB ==> %.2f%%\r", (int)(filesize >> 20), (double)compressedfilesize / filesize * 100); // Write Block LITTLE_ENDIAN32(outSize); *(unsigned int *)out_buff = outSize; LITTLE_ENDIAN32(outSize); fwrite(out_buff, 1, outSize + 4, foutput); } // Status end = clock(); DISPLAY("Compressed %llu bytes into %llu bytes ==> %.2f%%\n", (unsigned long long)filesize, (unsigned long long)compressedfilesize, (double)compressedfilesize / filesize * 100); { double seconds = (double)(end - start) / CLOCKS_PER_SEC; DISPLAY("Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024); } // Close & Free free(in_buff); free(out_buff); fclose(finput); fclose(foutput); return 0; } int LZ4_decode_file(const char *input_filename, const char *output_filename) { unsigned long long filesize = 0; char *in_buff; char *out_buff; size_t uselessRet; int sinkint; uint32_t chunkSize[ARCHIVE_MAGICNUMBER_SIZE / 4]; FILE *finput; FILE *foutput; clock_t start, end; int r; // Init start = clock(); r = get_fileHandle(input_filename, output_filename, &finput, &foutput); if (r) return r; // Check Archive Header uselessRet = fread(chunkSize, 1, ARCHIVE_MAGICNUMBER_SIZE, finput); if (!uselessRet) { DISPLAY("Cannot read header\n"); return -1; } //LITTLE_ENDIAN32(chunkSize); if (chunkSize[0] != ARCHIVE_MAGICNUMBER) { DISPLAY("Unrecognized header : file cannot be decoded\n"); return 6; } // Allocate Memory CHUNKSIZE = (uint32_t) chunkSize[3]; in_buff = (char *)malloc(CHUNKSIZE + CHUNKSIZE / 0xFF + 64); out_buff = (char *)malloc(CHUNKSIZE); if (!in_buff || !out_buff) { DISPLAY("Allocation error : not enough memory\n"); return 7; } uint32_t n = 0; uint32_t nextSize; uint32_t numOfSizes = chunkSize[4]; uint32_t *sizesTable = (uint32_t *) malloc(4 * numOfSizes); uselessRet = fread(sizesTable, 4, numOfSizes, finput); if (!uselessRet) { DISPLAY("Cannot read sizes table\n"); return -1; } filesize = 0LL; while (1) { // Main Loop nextSize = sizesTable[n]; uselessRet = fread(in_buff, 1, nextSize, finput); if (!uselessRet) { DISPLAY("Cannot read header\n"); return -1; } if (n >= numOfSizes - 1) { // Decode Block sinkint = LZ4_uncompress_unknownOutputSize(in_buff, out_buff, nextSize, CHUNKSIZE); if (sinkint < 0) { DISPLAY("Decoding Failed ! Corrupted input !\n"); return 9; } filesize += sinkint; // Write Block fwrite(out_buff, 1, sinkint, foutput); break; } uint32_t res = LZ4_uncompress(in_buff, out_buff, CHUNKSIZE); if (nextSize != res) { printf("Uncompress error. n:%d, res:%X, nextSize:%X\n", n, res, nextSize); return 8; } filesize += CHUNKSIZE; ++n; fwrite(out_buff, 1, CHUNKSIZE, foutput); if (n >= numOfSizes) break; } // Status end = clock(); DISPLAY("Successfully decoded %llu bytes. ", (unsigned long long)filesize); { double seconds = (double)(end - start) / CLOCKS_PER_SEC; DISPLAY("Done in %.2f s ==> %.2f MB/s\n", seconds, (double)filesize / seconds / 1024 / 1024); } // Close & Free free(sizesTable); free(in_buff); free(out_buff); fclose(finput); fclose(foutput); return 0; } //int main(int argc, char** argv) //{ //int i, //cLevel=0, //decode=0, //bench=0, //filenamesStart=2; //char* exename=argv[0]; //char* input_filename=0; //char* output_filename=0; //#ifdef _WIN32 //char nulmark[] = "nul"; //#else //char nulmark[] = "/dev/null"; //#endif //char nullinput[] = "null"; // Welcome message //DISPLAY( WELCOME_MESSAGE); //if (argc<2) { badusage(exename); return 1; } //for(i=1; i='0') cLevel=argument[1] - '0'; continue; } // Decoding //if ( argument[0] =='d' ) { decode=1; continue; } // Bench //if ( argument[0] =='b' ) { bench=1; if (argument[1] >= '0') cLevel=argument[1] - '0'; continue; } // Modify Block Size (benchmark only) //if ( argument[0] =='B' ) { int B = argument[1] - '0'; int S = 1 << (10 + 2*B); BMK_SetBlocksize(S); continue; } // Modify Nb Iterations (benchmark only) //if ( argument[0] =='i' ) { int iters = argument[1] - '0'; BMK_SetNbIterations(iters); continue; } // Test //if ( argument[0] =='t' ) { decode=1; output_filename=nulmark; continue; } //} // first provided filename is input //if (!input_filename) { input_filename=argument; filenamesStart=i; continue; } // second provided filename is output //if (!output_filename) //{ //output_filename=argument; //if (!strcmp (output_filename, nullinput)) output_filename = nulmark; //continue; //} //} // No input filename ==> Error //if(!input_filename) { badusage(exename); return 1; } //if (bench) return BMK_benchFile(argv+filenamesStart, argc-filenamesStart, cLevel); // No output filename ==> Error //if (!output_filename) { badusage(exename); return 1; } //if (decode) return decode_file(input_filename, output_filename); //return compress_file(input_filename, output_filename, cLevel); // Compression is 'default' action //} ================================================ FILE: src/lz4/lz4hc.c ================================================ /* LZ4 HC - High Compression Mode of LZ4 Copyright (C) 2011-2012, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ //************************************** // CPU Feature Detection //************************************** // 32 or 64 bits ? #if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || defined(__LP64__) || defined(_LP64) ) // Detects 64 bits mode # define LZ4_ARCH64 1 #else # define LZ4_ARCH64 0 #endif // Little Endian or Big Endian ? #if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || defined(__PPC) || defined(PPC) || defined(__powerpc__) || defined(__powerpc) || defined(powerpc) || ((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))) ) # define LZ4_BIG_ENDIAN 1 #else // Little Endian assumed. PDP Endian and other very rare endian format are unsupported. #endif // Unaligned memory access is automatically enabled for "common" CPU, such as x86. // For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected // If you know your target CPU supports unaligned memory access, you may want to force this option manually to improve performance #if defined(__ARM_FEATURE_UNALIGNED) # define LZ4_FORCE_UNALIGNED_ACCESS 1 #endif //************************************** // Compiler Options //************************************** #if __STDC_VERSION__ >= 199901L // C99 /* "restrict" is a known keyword */ #else # define restrict // Disable restrict #endif #ifdef _MSC_VER # define inline __forceinline// Visual is not C99, but supports some kind of inline #endif #ifdef _MSC_VER // Visual Studio # define bswap16(x) _byteswap_ushort(x) #else # define bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8))) #endif //************************************** // Includes //************************************** #include // calloc, free #include // memset, memcpy #include "lz4hc.h" #define ALLOCATOR(s) calloc(1,s) #define FREEMEM free #define MEM_INIT memset //************************************** // Basic Types //************************************** #if defined(_MSC_VER) // Visual Studio does not support 'stdint' natively # define BYTE unsigned __int8 # define U16 unsigned __int16 # define U32 unsigned __int32 # define S32 __int32 # define U64 unsigned __int64 #else # include # define BYTE uint8_t # define U16 uint16_t # define U32 uint32_t # define S32 int32_t # define U64 uint64_t #endif #ifndef LZ4_FORCE_UNALIGNED_ACCESS # pragma pack(push, 1) #endif typedef struct _U16_S { U16 v; } U16_S; typedef struct _U32_S { U32 v; } U32_S; typedef struct _U64_S { U64 v; } U64_S; #ifndef LZ4_FORCE_UNALIGNED_ACCESS # pragma pack(pop) #endif #define A64(x) (((U64_S *)(x))->v) #define A32(x) (((U32_S *)(x))->v) #define A16(x) (((U16_S *)(x))->v) //************************************** // Constants //************************************** #define MINMATCH 4 #define DICTIONARY_LOGSIZE 16 #define MAXD (1<> ((MINMATCH*8)-HASH_LOG)) #define HASH_VALUE(p) HASH_FUNCTION(*(U32*)(p)) #define HASH_POINTER(p) (HashTable[HASH_VALUE(p)] + base) #define DELTANEXT(p) chainTable[(size_t)(p) & MAXD_MASK] #define GETNEXT(p) ((p) - (size_t)DELTANEXT(p)) #define ADD_HASH(p) { size_t delta = (p) - HASH_POINTER(p); if (delta>MAX_DISTANCE) delta = MAX_DISTANCE; DELTANEXT(p) = (U16)delta; HashTable[HASH_VALUE(p)] = (p) - base; } //************************************** // Private functions //************************************** #if LZ4_ARCH64 inline static int LZ4_NbCommonBytes(register U64 val) { # if defined(LZ4_BIG_ENDIAN) # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse64(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clzll(val) >> 3); # else int r; if (!(val >> 32)) { r = 4; } else { r = 0; val >>= 32; } if (!(val >> 16)) { r += 2; val >>= 8; } else { val >>= 24; } r += (!val); return r; # endif # else # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward64(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctzll(val) >> 3); # else static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; return DeBruijnBytePos[((U64) ((val & -val) * 0x0218A392CDABBD3F)) >> 58]; # endif # endif } #else inline static int LZ4_NbCommonBytes(register U32 val) { # if defined(LZ4_BIG_ENDIAN) # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanReverse(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_clz(val) >> 3); # else int r; if (!(val >> 16)) { r = 2; val >>= 8; } else { r = 0; val >>= 24; } r += (!val); return r; # endif # else # if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward(&r, val); return (int)(r >> 3); # elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT) return (__builtin_ctz(val) >> 3); # else static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; return DeBruijnBytePos[((U32) ((val & -(S32) val) * 0x077CB531U)) >> 27]; # endif # endif } #endif inline static int LZ4HC_Init(LZ4HC_Data_Structure * hc4, const BYTE * base) { MEM_INIT((void *)hc4->hashTable, 0, sizeof(hc4->hashTable)); MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); hc4->nextToUpdate = base + LZ4_ARCH64; hc4->base = base; return 1; } inline static void *LZ4HC_Create(const BYTE * base) { void *hc4 = ALLOCATOR(sizeof(LZ4HC_Data_Structure)); LZ4HC_Init(hc4, base); return hc4; } inline static int LZ4HC_Free(void **LZ4HC_Data) { FREEMEM(*LZ4HC_Data); *LZ4HC_Data = NULL; return (1); } inline static void LZ4HC_Insert(LZ4HC_Data_Structure * hc4, const BYTE * ip) { U16 *chainTable = hc4->chainTable; HTYPE *HashTable = hc4->hashTable; INITBASE(base, hc4->base); while (hc4->nextToUpdate < ip) { ADD_HASH(hc4->nextToUpdate); hc4->nextToUpdate++; } } inline static int LZ4HC_InsertAndFindBestMatch(LZ4HC_Data_Structure * hc4, const BYTE * ip, const BYTE * const matchlimit, const BYTE ** matchpos) { U16 *const chainTable = hc4->chainTable; HTYPE *const HashTable = hc4->hashTable; const BYTE *ref; INITBASE(base, hc4->base); int nbAttempts = MAX_NB_ATTEMPTS; int ml = 0; // HC4 match finder LZ4HC_Insert(hc4, ip); ref = HASH_POINTER(ip); while ((ref > (ip - MAX_DISTANCE)) && (nbAttempts)) { nbAttempts--; if (*(ref + ml) == *(ip + ml)) if (*(U32 *) ref == *(U32 *) ip) { const BYTE *reft = ref + MINMATCH; const BYTE *ipt = ip + MINMATCH; while (ipt < matchlimit - (STEPSIZE - 1)) { UARCH diff = AARCH(reft) ^ AARCH(ipt); if (!diff) { ipt += STEPSIZE; reft += STEPSIZE; continue; } ipt += LZ4_NbCommonBytes(diff); goto _endCount; } if (LZ4_ARCH64) if ((ipt < (matchlimit - 3)) && (A32(reft) == A32(ipt))) { ipt += 4; reft += 4; } if ((ipt < (matchlimit - 1)) && (A16(reft) == A16(ipt))) { ipt += 2; reft += 2; } if ((ipt < matchlimit) && (*reft == *ipt)) ipt++; _endCount: if (ipt - ip > ml) { ml = ipt - ip; *matchpos = ref; } } ref = GETNEXT(ref); } return ml; } inline static int LZ4HC_InsertAndGetWiderMatch(LZ4HC_Data_Structure * hc4, const BYTE * ip, const BYTE * startLimit, const BYTE * matchlimit, int longest, const BYTE ** matchpos, const BYTE ** startpos) { U16 *const chainTable = hc4->chainTable; HTYPE *const HashTable = hc4->hashTable; INITBASE(base, hc4->base); const BYTE *ref; int nbAttempts = MAX_NB_ATTEMPTS; int delta = ip - startLimit; // First Match LZ4HC_Insert(hc4, ip); ref = HASH_POINTER(ip); while ((ref > ip - MAX_DISTANCE) && (ref >= hc4->base) && (nbAttempts)) { nbAttempts--; if (*(startLimit + longest) == *(ref - delta + longest)) if (*(U32 *) ref == *(U32 *) ip) { const BYTE *reft = ref + MINMATCH; const BYTE *ipt = ip + MINMATCH; const BYTE *startt = ip; while (ipt < matchlimit - (STEPSIZE - 1)) { UARCH diff = AARCH(reft) ^ AARCH(ipt); if (!diff) { ipt += STEPSIZE; reft += STEPSIZE; continue; } ipt += LZ4_NbCommonBytes(diff); goto _endCount; } if (LZ4_ARCH64) if ((ipt < (matchlimit - 3)) && (A32(reft) == A32(ipt))) { ipt += 4; reft += 4; } if ((ipt < (matchlimit - 1)) && (A16(reft) == A16(ipt))) { ipt += 2; reft += 2; } if ((ipt < matchlimit) && (*reft == *ipt)) ipt++; _endCount: reft = ref; while ((startt > startLimit) && (reft > hc4->base) && (startt[-1] == reft[-1])) { startt--; reft--; } if ((ipt - startt) > longest) { longest = ipt - startt; *matchpos = reft; *startpos = startt; } } ref = GETNEXT(ref); } return longest; } inline static int LZ4_encodeSequence(const BYTE ** ip, BYTE ** op, const BYTE ** anchor, int ml, const BYTE * ref) { int length, len; BYTE *token; // Encode Literal length length = *ip - *anchor; token = (*op)++; if (length >= (int)RUN_MASK) { *token = (RUN_MASK << ML_BITS); len = length - RUN_MASK; for (; len > 254; len -= 255) *(*op)++ = 255; *(*op)++ = (BYTE) len; } else *token = (length << ML_BITS); // Copy Literals LZ4_BLINDCOPY(*anchor, *op, length); // Encode Offset LZ4_WRITE_LITTLEENDIAN_16(*op, *ip - ref); // Encode MatchLength len = (int)(ml - MINMATCH); if (len >= (int)ML_MASK) { *token += ML_MASK; len -= ML_MASK; for (; len > 509; len -= 510) { *(*op)++ = 255; *(*op)++ = 255; } if (len > 254) { len -= 255; *(*op)++ = 255; } *(*op)++ = (BYTE) len; } else *token += len; // Prepare next loop *ip += ml; *anchor = *ip; return 0; } //**************************** // Compression CODE //**************************** int LZ4_compressHCCtx(LZ4HC_Data_Structure * ctx, const char *source, char *dest, int isize) { const BYTE *ip = (const BYTE *)source; const BYTE *anchor = ip; const BYTE *const iend = ip + isize; const BYTE *const mflimit = iend - MFLIMIT; const BYTE *const matchlimit = (iend - LASTLITERALS); BYTE *op = (BYTE *) dest; int ml, ml2, ml3, ml0; const BYTE *ref = NULL; const BYTE *start2 = NULL; const BYTE *ref2 = NULL; const BYTE *start3 = NULL; const BYTE *ref3 = NULL; const BYTE *start0; const BYTE *ref0; ip++; // Main Loop while (ip < mflimit) { ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, (&ref)); if (!ml) { ip++; continue; } // saved, in case we would skip too much start0 = ip; ref0 = ref; ml0 = ml; _Search2: if (ip + ml < mflimit) ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, &ref2, &start2); else ml2 = ml; if (ml2 == ml) // No better match { LZ4_encodeSequence(&ip, &op, &anchor, ml, ref); continue; } if (start0 < ip) { if (start2 < ip + ml0) // empirical { ip = start0; ref = ref0; ml = ml0; } } // Here, start0==ip if ((start2 - ip) < 3) // First Match too small : removed { ml = ml2; ip = start2; ref = ref2; goto _Search2; } _Search3: // Currently we have : // ml2 > ml1, and // ip1+3 <= ip2 (usually < ip1+ml1) if ((start2 - ip) < OPTIMAL_ML) { int correction; int new_ml = ml; if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; if (ip + new_ml > start2 + ml2 - MINMATCH) new_ml = start2 - ip + ml2 - MINMATCH; correction = new_ml - (start2 - ip); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } // Now, we have start2 = ip+new_ml, with new_ml=min(ml, OPTIMAL_ML=18) if (start2 + ml2 < mflimit) ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3); else ml3 = ml2; if (ml3 == ml2) // No better match : 2 sequences to encode { // ip & ref are known; Now for ml if (start2 < ip + ml) { if ((start2 - ip) < OPTIMAL_ML) { int correction; if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; if (ip + ml > start2 + ml2 - MINMATCH) ml = start2 - ip + ml2 - MINMATCH; correction = ml - (start2 - ip); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = start2 - ip; } } // Now, encode 2 sequences LZ4_encodeSequence(&ip, &op, &anchor, ml, ref); ip = start2; LZ4_encodeSequence(&ip, &op, &anchor, ml2, ref2); continue; } if (start3 < ip + ml + 3) // Not enough space for match 2 : remove it { if (start3 >= (ip + ml)) // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 { if (start2 < ip + ml) { int correction = (ip + ml) - start2; start2 += correction; ref2 += correction; ml2 -= correction; if (ml2 < MINMATCH) { start2 = start3; ref2 = ref3; ml2 = ml3; } } LZ4_encodeSequence(&ip, &op, &anchor, ml, ref); ip = start3; ref = ref3; ml = ml3; start0 = start2; ref0 = ref2; ml0 = ml2; goto _Search2; } start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // OK, now we have 3 ascending matches; let's write at least the first one // ip & ref are known; Now for ml if (start2 < ip + ml) { if ((start2 - ip) < (int)ML_MASK) { int correction; if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; if (ip + ml > start2 + ml2 - MINMATCH) ml = start2 - ip + ml2 - MINMATCH; correction = ml - (start2 - ip); if (correction > 0) { start2 += correction; ref2 += correction; ml2 -= correction; } } else { ml = start2 - ip; } } LZ4_encodeSequence(&ip, &op, &anchor, ml, ref); ip = start2; ref = ref2; ml = ml2; start2 = start3; ref2 = ref3; ml2 = ml3; goto _Search3; } // Encode Last Literals { int lastRun = iend - anchor; if (lastRun >= (int)RUN_MASK) { *op++ = (RUN_MASK << ML_BITS); lastRun -= RUN_MASK; for (; lastRun > 254; lastRun -= 255) *op++ = 255; *op++ = (BYTE) lastRun; } else *op++ = (lastRun << ML_BITS); memcpy(op, anchor, iend - anchor); op += iend - anchor; } // End return (int)(((char *)op) - dest); } int LZ4_compressHC(const char *source, char *dest, int isize) { void *ctx = LZ4HC_Create((const BYTE *)source); int result = LZ4_compressHCCtx(ctx, source, dest, isize); LZ4HC_Free(&ctx); return result; } ================================================ FILE: src/lzhs/CMakeLists.txt ================================================ add_library(lzhs lzhs.c lzhs_lib.c) target_link_libraries(lzhs utils) ================================================ FILE: src/lzhs/lzhs.c ================================================ /** * LZHS Encoder * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ /************************************************************** LZSS.C -- A Data Compression Program (tab = 4 spaces) *************************************************************** 4/6/1989 Haruhiko Okumura Use, distribute, and modify this program freely. Please send me your improved versions. PC-VAN SCIENCE NIFTY-Serve PAF01022 CompuServe 74050,1022 **************************************************************/ #include #include #include #include "common.h" #include "util.h" #include "lzhs/lzhs.h" #include "lzhs/tables.h" /*** Huffman decoding tables ***/ static t_code(*huff_charlen)[1] = (void *)&charlen_table; // Raw LZSS Characters + Length of LZSS match static t_code(*huff_pos)[1] = (void *)&pos_table; // Position of LZSS match /*** Huffman lookup tables ***/ // indices 0-287 for charlen, 0-31 for charpos // signed -1 is used as the invalid/unpopulated index static int16_t lookup_charlen[131072]; //2^(13 + 4 bits for key_charlen) static int16_t lookup_charpos[512]; //2^( 6 + 3 bits for key_charpos) /* * Pack together length and code to create a key for the lookup table * [length][code] */ static inline uint32_t key_charlen(uint32_t code, uint32_t len){ return ((len & 0xF) << 13) | (code & 0x1FFF); } static inline uint16_t key_charpos(uint32_t code, uint32_t len){ return ((len & 0x7) << 6) | (code & 0x3F); } void lzhs_init_lookup(){ memset(&lookup_charlen, 0xFF, sizeof(lookup_charlen)); memset(&lookup_charpos, 0xFF, sizeof(lookup_charpos)); } struct lzhs_ctx *lzhs_ctx_new(){ struct lzhs_ctx *ctx = calloc(1, sizeof(struct lzhs_ctx)); ctx->bitno = 8; return ctx; } ///////////// LZSS ALGO ///////////// static void InitTree(struct lzhs_ctx *ctx) { int i; for (i = N + 1; i <= N + 256; i++) ctx->rson[i] = N; for (i = 0; i < N; i++) ctx->dad[i] = N; } static void lazy_match(struct lzhs_ctx *ctx, int r) { unsigned char *key; int i, p, cmp = 1, tmp = 0; if (ctx->match_length <= F - THRESHOLD) { key = &ctx->text_buf[r + 1]; p = key[0] + N + 1; while (1) { if (cmp >= 0) { if (ctx->rson[p] != N) p = ctx->rson[p]; else break; } else { if (ctx->lson[p] != N) p = ctx->lson[p]; else break; } for (i = 1; i <= F - 1; i++) { cmp = key[i] - ctx->text_buf[p + i]; if (key[i] != ctx->text_buf[p + i]) break; } if (i > tmp) if ((tmp = i) > F - 1) break; } } if (tmp > ctx->match_length) ctx->match_length = 0; } static void InsertNode(struct lzhs_ctx *ctx, int r) { unsigned char *key = &ctx->text_buf[r]; int tmp, p, i, cmp = 1; p = ctx->text_buf[r] + N + 1; ctx->lson[r] = ctx->rson[r] = N; ctx->match_length = 0; while (1) { if (cmp < 0) { if (ctx->lson[p] == N) { ctx->lson[p] = r; ctx->dad[r] = p; return lazy_match(ctx, r); } p = ctx->lson[p]; } else { if (ctx->rson[p] == N) { ctx->rson[p] = r; ctx->dad[r] = p; return lazy_match(ctx, r); } p = ctx->rson[p]; } for (i = 1;; ++i) { if (i < F) { cmp = key[i] - ctx->text_buf[p + i]; if (key[i] == ctx->text_buf[p + i]) continue; } break; } if (i >= ctx->match_length) { if (r < p) tmp = r - p + N; else tmp = r - p; } if (i >= ctx->match_length) { if (i == ctx->match_length) { if (tmp < ctx->match_position) ctx->match_position = tmp; } else ctx->match_position = tmp; if ((ctx->match_length = i) > F - 1) break; } } ctx->dad[r] = ctx->dad[p]; ctx->lson[r] = ctx->lson[p]; ctx->rson[r] = ctx->rson[p]; ctx->dad[ctx->lson[p]] = ctx->dad[ctx->rson[p]] = r; if (ctx->rson[ctx->dad[p]] == p) ctx->rson[ctx->dad[p]] = r; else ctx->lson[ctx->dad[p]] = r; ctx->dad[p] = N; } static void DeleteNode(struct lzhs_ctx *ctx, int p) { int q; if (ctx->dad[p] == N) return; if (ctx->rson[p] == N) q = ctx->lson[p]; else if (ctx->lson[p] == N) q = ctx->rson[p]; else { q = ctx->lson[p]; if (ctx->rson[q] != N) { do { q = ctx->rson[q]; } while (ctx->rson[q] != N); ctx->rson[ctx->dad[q]] = ctx->lson[q]; ctx->dad[ctx->lson[q]] = ctx->dad[q]; ctx->lson[q] = ctx->lson[p]; ctx->dad[ctx->lson[p]] = q; } ctx->rson[q] = ctx->rson[p]; ctx->dad[ctx->rson[p]] = q; } ctx->dad[q] = ctx->dad[p]; if (ctx->rson[ctx->dad[p]] == p) ctx->rson[ctx->dad[p]] = q; else ctx->lson[ctx->dad[p]] = q; ctx->dad[p] = N; } ///////////// HUFFMAN ALGO ///////////// static void InitHuffman(struct lzhs_ctx *ctx) { ctx->code = ctx->len = 0; ctx->preno = ctx->precode = 0; // Clear the huffman code buffer memset(&ctx->code_buf, 0x00, sizeof(ctx->code_buf)); // Initial bit no (to fetch next byte at first iteration) ctx->bitno = 8; } static void putChar(struct lzhs_ctx *ctx, uint32_t code, uint32_t no, FILE *out) { uint32_t tmpno, tmpcode; if (ctx->preno + no > 7) { do { no -= tmpno = 8 - ctx->preno; tmpcode = ctx->code >> no; fputc(tmpcode | (ctx->precode << tmpno), out); ctx->code -= tmpcode << no; ctx->preno = ctx->precode = 0; } while (no > 7); ctx->preno = no; ctx->precode = code; } else { ctx->preno += no; ctx->precode = code | (ctx->precode << no); } } static inline int getData(struct lzhs_ctx *ctx, cursor_t *in) { if (ctx->bitno > 7) { ctx->bitno = 0; if((ctx->c = cgetc(in)) == EOF){ return 0; } } ctx->code = (ctx->code << 1) | ((ctx->c >> (7 - ctx->bitno++)) & 1); // get bit msb - index ctx->len++; return 1; } ///////////// EXPORTS ///////////// /* * Huffman encodes the specified stream */ void huff(struct lzhs_ctx *ctx, FILE * in, FILE * out, unsigned long int *p_textsize, unsigned long int *p_codesize) { ctx->textsize = ctx->codesize; ctx->codesize = 0; int c, i, j, m, flags = 0; while (1) { if (((flags >>= 1) & 256) == 0) { if ((c = getc(in)) == EOF) break; flags = c | 0xFF00; } if (flags & 1) { if ((c = getc(in)) == EOF) break; putChar(ctx, huff_charlen[c]->code, huff_charlen[c]->len, out); // lookup in char table } else { if ((j = getc(in)) == EOF) break; // match length if ((i = getc(in)) == EOF) break; // byte1 of match position if ((m = getc(in)) == EOF) break; // byte0 of match position putChar(ctx, huff_charlen[256 + j]->code, huff_charlen[256 + j]->len, out); // lookup in len table i = m | (i << 8); putChar(ctx, huff_pos[(i >> 7)]->code, huff_pos[(i >> 7)]->len, out); // lookup in pos table putChar(ctx, i - (i >> 7 << 7), 7, out); } } putc(ctx->precode << (8 - ctx->preno), out); ctx->codesize = ftell(out) - sizeof(struct lzhs_header); if(p_textsize) *p_textsize = ctx->textsize; if(p_codesize) *p_codesize = ctx->codesize; printf("LZHS Out(%ld)/In(%ld): %.4f\n", ctx->codesize, ctx->textsize, (double)ctx->codesize / ctx->textsize); } /* * Huffman decodes the specified stream */ void unhuff(struct lzhs_ctx *ctx, cursor_t *in, cursor_t *out) { InitHuffman(ctx); ctx->code_buf[0] = 0; ctx->code_buf_ptr = ctx->mask = 1; while (1) { if (UNLIKELY(!getData(ctx, in))) goto flush_ret; if (ctx->len < 4) continue; // len in code_len table should be min 4 uint32_t key = key_charlen(ctx->code, ctx->len); ctx->i = lookup_charlen[key]; if(ctx->i == -2) continue; if(ctx->i == -1){ bool found = false; for (ctx->i = 0; ctx->i < 288; ctx->i++) { if (huff_charlen[ctx->i]->len == ctx->len && huff_charlen[ctx->i]->code == ctx->code ){ lookup_charlen[key] = ctx->i; found = true; break; } } if(!found){ lookup_charlen[key] = -2; continue; } } if(ctx->i > 255){ ctx->code_buf[ctx->code_buf_ptr++] = ctx->i - 256; ctx->code = ctx->len = 0; while (1) { if (UNLIKELY(!getData(ctx, in))) goto flush_ret; if (ctx->len < 2) continue; // len in pos table should be min 2 uint32_t key = key_charpos(ctx->code, ctx->len); ctx->j = lookup_charpos[key]; if(ctx->j == -2) continue; if(ctx->j == -1){ bool found = false; for (ctx->j = 0; ctx->j < 32; ctx->j++) { if (huff_pos[ctx->j]->len == ctx->len && huff_pos[ctx->j]->code == ctx->code ){ lookup_charpos[key] = ctx->j; found = 1; break; } } if(!found){ lookup_charpos[key] = -2; continue; } } ctx->code_buf[ctx->code_buf_ptr++] = ctx->j >> 1; ctx->k = -1; break; } ctx->code = 0; for (ctx->k = 0; ctx->k < 7; ctx->k++) if (UNLIKELY(!getData(ctx, in))) goto flush_ret; ctx->code_buf[ctx->code_buf_ptr++] = ctx->code | (ctx->j << 7); ctx->code = ctx->len = 0; } else { ctx->code_buf[0] |= ctx->mask; ctx->code_buf[ctx->code_buf_ptr++] = ctx->i; ctx->code = ctx->len = 0; } if ((ctx->mask <<= 1) == 0) { for (ctx->j = 0; ctx->j < ctx->code_buf_ptr; ctx->j++){ if(UNLIKELY(cputc(ctx->code_buf[ctx->j], out) == EOF)) return; } ctx->code_buf[0] = 0; ctx->code_buf_ptr = ctx->mask = 1; } } flush_ret: if (ctx->code_buf_ptr > 1) // flushing buffer for (ctx->i = 0; ctx->i < ctx->code_buf_ptr; ctx->i++){ if(UNLIKELY(cputc(ctx->code_buf[ctx->i], out) == EOF)) return; } return; } /* * LZSS encodes the specified stream */ void lzss(struct lzhs_ctx *ctx, FILE * infile, FILE * outfile, unsigned long int *p_textsize, unsigned long int *p_codesize) { int c, i, len, r, s, last_match_length, code_buf_ptr; unsigned char code_buf[32], mask; InitTree(ctx); code_buf[0] = 0; code_buf_ptr = mask = 1; s = ctx->codesize = 0; r = N - F; for (len = 0; len < F && (c = getc(infile)) != EOF; len++) ctx->text_buf[r + len] = c; if ((ctx->textsize = len) == 0) return; InsertNode(ctx, r); do { if (ctx->match_length > len) ctx->match_length = len; if (ctx->match_length <= THRESHOLD) { ctx->match_length = 1; code_buf[0] |= mask; code_buf[code_buf_ptr++] = ctx->text_buf[r]; } else { code_buf[code_buf_ptr++] = ctx->match_length - THRESHOLD - 1; code_buf[code_buf_ptr++] = (ctx->match_position >> 8) & 0xff; code_buf[code_buf_ptr++] = ctx->match_position; } if ((mask <<= 1) == 0) { for (i = 0; i < code_buf_ptr; i++) { putc(code_buf[i], outfile); ctx->codesize++; } code_buf[0] = 0; code_buf_ptr = mask = 1; } last_match_length = ctx->match_length; for (i = 0; i < last_match_length && (c = getc(infile)) != EOF; i++) { DeleteNode(ctx, s); ctx->text_buf[s] = c; if (s < F - 1) ctx->text_buf[s + N] = c; s = (s + 1) & (N - 1); r = (r + 1) & (N - 1); InsertNode(ctx, r); } ctx->textsize += i; while (i++ < last_match_length) { DeleteNode(ctx, s); s = (s + 1) & (N - 1); r = (r + 1) & (N - 1); if (--len) InsertNode(ctx, r); } } while (len > 0); if (code_buf_ptr > 1) { for (i = 0; i < code_buf_ptr; i++) { putc(code_buf[i], outfile); ctx->codesize++; } } if(p_textsize) *p_textsize = ctx->textsize; if(p_codesize) *p_codesize = ctx->codesize; printf("LZSS Out(%ld)/In(%ld): %.3f\n", ctx->codesize, ctx->textsize, (double)ctx->codesize / ctx->textsize); } /* * LZSS decodes the specified stream */ void unlzss(struct lzhs_ctx *ctx, cursor_t *in, cursor_t *out) { int c, i, j, k, m, r = 0, flags = 0; while (1) { if (((flags >>= 1) & 256) == 0) { if ((c = cgetc(in)) == EOF) break; flags = c | 0xff00; } if (flags & 1) { if((c = cgetc(in)) == EOF) break; if(cputc((ctx->text_buf[r++] = c), out) == EOF) return; r &= (N - 1); } else { if((j = cgetc(in)) == EOF) // match length break; if((i = cgetc(in)) == EOF) // byte1 of match position break; if((m = cgetc(in)) == EOF) // byte0 of match position break; i = (i << 8) | m; for (k = 0; k <= j + THRESHOLD; k++) { m = ctx->text_buf[(r - i) & (N - 1)]; if(cputc((ctx->text_buf[r++] = m), out) == EOF) return; r &= (N - 1); } } } } ================================================ FILE: src/lzhs/lzhs_lib.c ================================================ /** * LZHS Encoder * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #include #include #include #include #include #include "config.h" #include "mfile.h" #include "lzhs/lzhs.h" #include "mediatek.h" #include "util.h" #define LZHS_SIZE_THRESHOLD (20 * 1024 * 1024) //20 MB (a random sane value) static bool lzhs_lookup_initialized = false; bool _is_lzhs_mem(struct lzhs_header *header){ if ( !memcmp(header->spare, "\0\0\0\0\0\0\0", sizeof(header->spare)) && header->compressedSize > 0 && header->compressedSize <= LZHS_SIZE_THRESHOLD && header->uncompressedSize > 0 && header->uncompressedSize <= LZHS_SIZE_THRESHOLD ){ return true; } return false; } bool is_lzhs_mem(MFILE *file, off_t offset){ struct lzhs_header *header = (struct lzhs_header *)(mdata(file, uint8_t) + offset); if(msize(file) < offset + sizeof(struct lzhs_header)){ return false; } return _is_lzhs_mem(header); } MFILE *is_lzhs(const char *filename) { MFILE *file = mopen(filename, O_RDONLY); if (file == NULL) { err_exit("Can't open file %s\n", filename); } if(is_lzhs_mem(file, 0)) return file; mclose(file); return NULL; } static void ARMThumb_Convert(unsigned char *data, uint32_t size, uint32_t nowPos, int encoding) { uint32_t i; for (i = 0; i + 4 <= size; i += 2) { if ((data[i + 1] & 0xF8) == 0xF0 && (data[i + 3] & 0xF8) == 0xF8) { uint32_t src = ((data[i + 1] & 0x7) << 19) | (data[i + 0] << 11) | ((data[i + 3] & 0x7) << 8) | (data[i + 2]); src <<= 1; uint32_t dest; if (encoding) dest = nowPos + i + 4 + src; else dest = src - (nowPos + i + 4); dest >>= 1; data[i + 1] = 0xF0 | ((dest >> 19) & 0x7); data[i + 0] = (dest >> 11); data[i + 3] = 0xF8 | ((dest >> 8) & 0x7); data[i + 2] = (dest); i += 2; } } } static int lzhs_pad_file(const char *filename, const char *outfilename) { int input_filesize; size_t n; char *ptr; FILE *infile, *outfile; infile = fopen(filename, "rb"); if (infile) { outfile = fopen(outfilename, "wb"); if (outfile) { fseek(infile, 0, SEEK_END); size_t filesize = ftell(infile); rewind(infile); ptr = malloc(sizeof(char) * filesize); int extrabytes = 0; for (input_filesize = 0;; input_filesize += n) { //start a loop. add read elements every iteration n = fread(ptr, 1u, 0x200u, infile); //read 512 bytes from input into ptr if (n <= 0) break; if (n % 16 != 0) { unsigned int x = (n / 8) * 8; //it will be truncated, so we get next multiple if (x < n) x += 8; x = x - n; //how many bytes we need to add extrabytes += x; //add the bytes to the counter } fwrite(ptr, 1u, n, outfile); //write read bytes to output } printf("We need to fill extra %d bytes\n", extrabytes); int i; for (i = 1; i <= extrabytes; i++) putc(0xff, outfile); fclose(infile); fclose(outfile); return 0; } else { printf("Open file %s failed.\n", outfilename); return 1; } } else { printf("open file %s fail \n", filename); return 1; } return 0; } unsigned char lzhs_calc_checksum(unsigned char *buf, int fsize) { unsigned char checksum = 0; int i; for (i = 0; i < fsize; ++i) checksum += buf[i]; return checksum; } void lzhs_encode(const char *infile, const char *outfile) { struct lzhs_header header; FILE *in, *out; unsigned char *buf; size_t fsize; char *outpath; unsigned long int textsize, codesize; struct lzhs_ctx *ctx = lzhs_ctx_new(); #if 1 //// PADDING printf("\n[LZHS] Padding...\n"); asprintf(&outpath, "%s.tmp", infile); lzhs_pad_file(infile, outpath); in = fopen(outpath, "rb"); if (!in) { err_exit("Cannot open file %s\n", outpath); } free(outpath); #else in = fopen(infile, "rb"); #endif //// ARM 2 THUMB asprintf(&outpath, "%s.conv", infile); out = fopen(outpath, "wb"); if (!out) { err_exit("Cannot open file conv\n"); } fseek(in, 0, SEEK_END); fsize = ftell(in); rewind(in); buf = calloc(1, fsize); fread(buf, 1, fsize, in); rewind(in); printf("[LZHS] Calculating checksum...\n"); header.checksum = lzhs_calc_checksum(buf, fsize); memset(&header.spare, 0, sizeof(header.spare)); printf("Checksum = %x\n", header.checksum); printf("[LZHS] Converting ARM => Thumb...\n"); ARMThumb_Convert(buf, fsize, 0, 1); fwrite(buf, 1, fsize, out); free(buf); ////LZSS freopen(outpath, "rb", in); if (!in) { err_exit("Cannot open file conv\n"); } free(outpath); asprintf(&outpath, "%s.lzs", infile); freopen(outpath, "wb", out); printf("[LZHS] Encoding with LZSS...\n"); lzss(ctx, in, out, &textsize, &codesize); if (!out) { err_exit("Cannot open tmp.lzs\n"); } ////HUFFMAN freopen(outpath, "rb", in); if (!in) { err_exit("Cannot open file tmp.lzs\n"); } freopen(outfile, "wb", out); if (!out) { err_exit("Cannot open file %s\n", outfile); } header.uncompressedSize = fsize; fwrite(&header, 1, sizeof(header), out); printf("[LZHS] Encoding with Huffman...\n"); huff(ctx, in, out, &textsize, &codesize); header.compressedSize = codesize; printf("[LZHS] Writing Header...\n"); rewind(out); fwrite(&header, 1, sizeof(header), out); printf("[LZHS] Done!\n"); free(outpath); fclose(in); fclose(out); free(ctx); } cursor_t *lzhs_decode(MFILE *in_file, off_t offset, const char *out_path, uint8_t *out_checksum){ if(!lzhs_lookup_initialized){ lzhs_init_lookup(); lzhs_lookup_initialized = true; } struct lzhs_header *header = (struct lzhs_header *)(mdata(in_file, uint8_t) + offset); printf("\n---LZHS details---\n"); printf("Compressed:\t%u\n", header->compressedSize); printf("Uncompressed:\t%u\n", header->uncompressedSize); printf("Checksum:\t0x%x\n\n", header->checksum); /* * There are a few cases where the huffman data can result in a bigger LZSS set than the final output size. * To work around this problem, we set temp memory to twice the uncompressedSize. */ size_t tempSize = header->uncompressedSize * 2; void *tmp = MFILE_ANON(tempSize); if(tmp == MAP_FAILED){ perror("mmap tmp for lzhs\n"); return (cursor_t *)-1; } memset(tmp, 0x00, tempSize); MFILE *out_file = NULL; uint8_t *out_bytes = NULL; if(out_path == NULL){ out_bytes = MFILE_ANON(header->uncompressedSize); if(out_bytes == MAP_FAILED){ perror("mmap out for lzhs\n"); return (cursor_t *)-1; } } else { out_file = mfopen(out_path, "w+"); if(!out_file){ fprintf(stderr, "Cannot open output file %s\n", out_path); return (cursor_t *)-1; } mfile_map(out_file, header->uncompressedSize); out_bytes = mdata(out_file, uint8_t); } uint8_t *in_bytes = mdata(in_file, uint8_t); /* Input file */ cursor_t in_cur = { .ptr = in_bytes + offset + sizeof(*header), .size = header->compressedSize, .offset = 0 }; /* Temp memory */ cursor_t out_cur = { .ptr = tmp, .size = tempSize, .offset = 0 }; struct lzhs_ctx *ctx = lzhs_ctx_new(); printf("[LZHS] Decoding Huffman...\n"); // Input file -> Temp memory unhuff(ctx, &in_cur, &out_cur); printf("[LZHS] Decoding LZSS...\n"); // Rewind the huffman cursor and change ends out_cur.offset = 0; memcpy((void *)&in_cur, (void *)&out_cur, sizeof(cursor_t)); // Setup output cursor for the final file out_cur.ptr = out_bytes; out_cur.size = header->uncompressedSize; // Temp memory -> Output file unlzss(ctx, &in_cur, &out_cur); free(ctx); // We don't need the temp memory anymore munmap(tmp, tempSize); printf("[LZHS] Converting Thumb => ARM...\n"); ARMThumb_Convert(out_bytes, out_cur.size, 0, 0); printf("[LZHS] Calculating checksum...\n"); uint8_t checksum = lzhs_calc_checksum(out_bytes, out_cur.size); if(out_checksum != NULL){ *out_checksum = checksum; } printf("Calculated checksum = 0x%x\n", checksum); if (checksum != header->checksum) printf("[LZHS] WARNING: Checksum mismatch (got 0x%x, expected 0x%x)!!\n", checksum, header->checksum); if (out_cur.size != header->uncompressedSize) printf("[LZHS] WARNING: Size mismatch (got %zu, expected %u)!!\n", out_cur.size, header->uncompressedSize); if(out_file != NULL){ mclose(out_file); return NULL; } else { cursor_t *cpy = calloc(1, sizeof(out_cur)); memcpy(cpy, &out_cur, sizeof(out_cur)); return cpy; } } int process_lzhs_segment(MFILE *in_file, off_t offset, const char *name) { int r = 0; char *file_dir = my_dirname(in_file->path); char *out_path; asprintf(&out_path, "%s/%s.lzhs", file_dir, name); printf("[MTK] Extracting %s to %s...\n", name, out_path); MFILE *out_file = mfopen(out_path, "w+"); if (!out_file) { fprintf(stderr, "Cannot open file %s for writing\n", out_path); r = -1; goto exit; } uint8_t *bytes = &(mdata(in_file, uint8_t))[offset]; struct lzhs_header *lzhs_hdr = (struct lzhs_header *)bytes; /* Allocate file */ mfile_map(out_file, sizeof(*lzhs_hdr) + lzhs_hdr->compressedSize ); /* Copy compressed file */ memcpy( (void *)(mdata(out_file, uint8_t)), (void *)bytes, lzhs_hdr->compressedSize + sizeof(*lzhs_hdr) ); printf("[MTK] UnLZHS %s\n", out_path); asprintf(&out_path, "%s/%s.unlzhs", file_dir, name); // Decode the file we just wrote lzhs_decode(out_file, 0, out_path, NULL); mclose(out_file); exit: free(out_path); free(file_dir); return r; } int extract_lzhs(MFILE *in_file) { int r; if(is_lzhs_mem(in_file, MTK_LOADER_OFF) && (r=process_lzhs_segment(in_file, MTK_LOADER_OFF, "mtkloader")) < 0){ return r; } else if(is_lzhs_mem(in_file, MTK_LOADER_OFF1) && (r=process_lzhs_segment(in_file, MTK_LOADER_OFF1, "mtkloader")) < 0){ return r; } if(is_lzhs_mem(in_file, MTK_UBOOT_OFF) && (r=process_lzhs_segment(in_file, MTK_UBOOT_OFF, "uboot")) < 0) return r; if(is_lzhs_mem(in_file, MTK_HISENSE_UBOOT_OFF) && (r=process_lzhs_segment(in_file, MTK_HISENSE_UBOOT_OFF, "uboot")) < 0) return r; if(msize(in_file) < MTK_UBOOT_OFF){ return 0; } struct lzhs_header *uboot_hdr = (struct lzhs_header *)(&(mdata(in_file, uint8_t))[MTK_UBOOT_OFF]); uint pad; pad = (pad = (uboot_hdr->compressedSize % 16)) == 0 ? 0 : (16 - pad); off_t mtk_tz = ( //Offset of uboot MTK_UBOOT_OFF + //Size of its lzhs header sizeof(struct lzhs_header) + //uboot compressed size uboot_hdr->compressedSize + //Align to the next "line" pad + //TZ relative offset MTK_TZ_OFF ); /* Do we have the TZ segment? (mtk5369 only) */ if(mtk_tz < msize(in_file)){ if(is_lzhs_mem(in_file, mtk_tz) && (r=process_lzhs_segment(in_file, mtk_tz, "boot_tz")) < 0) return r; } return 0; } ================================================ FILE: src/lzma/CMakeLists.txt ================================================ add_library(lzma LzFind.c LzmaDec.c LzmaEnc.c) target_include_directories(lzma PUBLIC ${INC}) ================================================ FILE: src/lzma/LzFind.c ================================================ /* LzFind.c -- Match finder for LZ algorithms 2009-04-22 : Igor Pavlov : Public domain */ #include #include "lzma/LzFind.h" #include "lzma/LzHash.h" #define kEmptyHashValue 0 #define kMaxValForNormalize ((UInt32)0xFFFFFFFF) #define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ #define kNormalizeMask (~(kNormalizeStepMin - 1)) #define kMaxHistorySize ((UInt32)3 << 30) #define kStartMaxLen 3 static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) { if (!p->directInput) { alloc->Free(alloc, p->bufferBase); p->bufferBase = 0; } } /* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) { UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; if (p->directInput) { p->blockSize = blockSize; return 1; } if (p->bufferBase == 0 || p->blockSize != blockSize) { LzInWindow_Free(p, alloc); p->blockSize = blockSize; p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); } return (p->bufferBase != 0); } Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) { p->posLimit -= subValue; p->pos -= subValue; p->streamPos -= subValue; } static void MatchFinder_ReadBlock(CMatchFinder *p) { if (p->streamEndWasReached || p->result != SZ_OK) return; if (p->directInput) { UInt32 curSize = 0xFFFFFFFF - p->streamPos; if (curSize > p->directInputRem) curSize = (UInt32)p->directInputRem; p->directInputRem -= curSize; p->streamPos += curSize; if (p->directInputRem == 0) p->streamEndWasReached = 1; return; } for (;;) { Byte *dest = p->buffer + (p->streamPos - p->pos); size_t size = (p->bufferBase + p->blockSize - dest); if (size == 0) return; p->result = p->stream->Read(p->stream, dest, &size); if (p->result != SZ_OK) return; if (size == 0) { p->streamEndWasReached = 1; return; } p->streamPos += (UInt32)size; if (p->streamPos - p->pos > p->keepSizeAfter) return; } } void MatchFinder_MoveBlock(CMatchFinder *p) { memmove(p->bufferBase, p->buffer - p->keepSizeBefore, (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); p->buffer = p->bufferBase + p->keepSizeBefore; } int MatchFinder_NeedMove(CMatchFinder *p) { if (p->directInput) return 0; /* if (p->streamEndWasReached) return 0; */ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); } void MatchFinder_ReadIfRequired(CMatchFinder *p) { if (p->streamEndWasReached) return; if (p->keepSizeAfter >= p->streamPos - p->pos) MatchFinder_ReadBlock(p); } static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) { if (MatchFinder_NeedMove(p)) MatchFinder_MoveBlock(p); MatchFinder_ReadBlock(p); } static void MatchFinder_SetDefaultSettings(CMatchFinder *p) { p->cutValue = 32; p->btMode = 1; p->numHashBytes = 4; p->bigHash = 0; } #define kCrcPoly 0xEDB88320 void MatchFinder_Construct(CMatchFinder *p) { UInt32 i; p->bufferBase = 0; p->directInput = 0; p->hash = 0; MatchFinder_SetDefaultSettings(p); for (i = 0; i < 256; i++) { UInt32 r = i; int j; for (j = 0; j < 8; j++) r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); p->crc[i] = r; } } static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) { alloc->Free(alloc, p->hash); p->hash = 0; } void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) { MatchFinder_FreeThisClassMemory(p, alloc); LzInWindow_Free(p, alloc); } static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) { size_t sizeInBytes = (size_t)num * sizeof(CLzRef); if (sizeInBytes / sizeof(CLzRef) != num) return 0; return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); } int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) { UInt32 sizeReserv; if (historySize > kMaxHistorySize) { MatchFinder_Free(p, alloc); return 0; } sizeReserv = historySize >> 1; if (historySize > ((UInt32)2 << 30)) sizeReserv = historySize >> 2; sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); p->keepSizeBefore = historySize + keepAddBufferBefore + 1; p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ if (LzInWindow_Create(p, sizeReserv, alloc)) { UInt32 newCyclicBufferSize = historySize + 1; UInt32 hs; p->matchMaxLen = matchMaxLen; { p->fixedHashSize = 0; if (p->numHashBytes == 2) hs = (1 << 16) - 1; else { hs = historySize - 1; hs |= (hs >> 1); hs |= (hs >> 2); hs |= (hs >> 4); hs |= (hs >> 8); hs >>= 1; hs |= 0xFFFF; /* don't change it! It's required for Deflate */ if (hs > (1 << 24)) { if (p->numHashBytes == 3) hs = (1 << 24) - 1; else hs >>= 1; } } p->hashMask = hs; hs++; if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; hs += p->fixedHashSize; } { UInt32 prevSize = p->hashSizeSum + p->numSons; UInt32 newSize; p->historySize = historySize; p->hashSizeSum = hs; p->cyclicBufferSize = newCyclicBufferSize; p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); newSize = p->hashSizeSum + p->numSons; if (p->hash != 0 && prevSize == newSize) return 1; MatchFinder_FreeThisClassMemory(p, alloc); p->hash = AllocRefs(newSize, alloc); if (p->hash != 0) { p->son = p->hash + p->hashSizeSum; return 1; } } } MatchFinder_Free(p, alloc); return 0; } static void MatchFinder_SetLimits(CMatchFinder *p) { UInt32 limit = kMaxValForNormalize - p->pos; UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; if (limit2 < limit) limit = limit2; limit2 = p->streamPos - p->pos; if (limit2 <= p->keepSizeAfter) { if (limit2 > 0) limit2 = 1; } else limit2 -= p->keepSizeAfter; if (limit2 < limit) limit = limit2; { UInt32 lenLimit = p->streamPos - p->pos; if (lenLimit > p->matchMaxLen) lenLimit = p->matchMaxLen; p->lenLimit = lenLimit; } p->posLimit = p->pos + limit; } void MatchFinder_Init(CMatchFinder *p) { UInt32 i; for (i = 0; i < p->hashSizeSum; i++) p->hash[i] = kEmptyHashValue; p->cyclicBufferPos = 0; p->buffer = p->bufferBase; p->pos = p->streamPos = p->cyclicBufferSize; p->result = SZ_OK; p->streamEndWasReached = 0; MatchFinder_ReadBlock(p); MatchFinder_SetLimits(p); } static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) { return (p->pos - p->historySize - 1) & kNormalizeMask; } void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) { UInt32 i; for (i = 0; i < numItems; i++) { UInt32 value = items[i]; if (value <= subValue) value = kEmptyHashValue; else value -= subValue; items[i] = value; } } static void MatchFinder_Normalize(CMatchFinder *p) { UInt32 subValue = MatchFinder_GetSubValue(p); MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); MatchFinder_ReduceOffsets(p, subValue); } static void MatchFinder_CheckLimits(CMatchFinder *p) { if (p->pos == kMaxValForNormalize) MatchFinder_Normalize(p); if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) MatchFinder_CheckAndMoveAndRead(p); if (p->cyclicBufferPos == p->cyclicBufferSize) p->cyclicBufferPos = 0; MatchFinder_SetLimits(p); } static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { son[_cyclicBufferPos] = curMatch; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) return distances; { const Byte *pb = cur - delta; curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; if (pb[maxLen] == cur[maxLen] && *pb == *cur) { UInt32 len = 0; while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) return distances; } } } } } UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, UInt32 *distances, UInt32 maxLen) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return distances; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { if (++len != lenLimit && pb[len] == cur[len]) while (++len != lenLimit) if (pb[len] != cur[len]) break; if (maxLen < len) { *distances++ = maxLen = len; *distances++ = delta - 1; if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return distances; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) { CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; CLzRef *ptr1 = son + (_cyclicBufferPos << 1); UInt32 len0 = 0, len1 = 0; for (;;) { UInt32 delta = pos - curMatch; if (cutValue-- == 0 || delta >= _cyclicBufferSize) { *ptr0 = *ptr1 = kEmptyHashValue; return; } { CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); const Byte *pb = cur - delta; UInt32 len = (len0 < len1 ? len0 : len1); if (pb[len] == cur[len]) { while (++len != lenLimit) if (pb[len] != cur[len]) break; { if (len == lenLimit) { *ptr1 = pair[0]; *ptr0 = pair[1]; return; } } } if (pb[len] < cur[len]) { *ptr1 = curMatch; ptr1 = pair + 1; curMatch = *ptr1; len1 = len; } else { *ptr0 = curMatch; ptr0 = pair; curMatch = *ptr0; len0 = len; } } } } #define MOVE_POS \ ++p->cyclicBufferPos; \ p->buffer++; \ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); #define MOVE_POS_RET MOVE_POS return offset; static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } #define GET_MATCHES_HEADER2(minLen, ret_op) \ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ cur = p->buffer; #define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) #define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) #define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue #define GET_MATCHES_FOOTER(offset, maxLen) \ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ distances + offset, maxLen) - distances); MOVE_POS_RET; #define SKIP_FOOTER \ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 1) } UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = 0; GET_MATCHES_FOOTER(offset, 2) } static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, delta2, maxLen, offset; GET_MATCHES_HEADER(3) HASH3_CALC; delta2 = p->pos - p->hash[hash2Value]; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; maxLen = 2; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[0] = maxLen; distances[1] = delta2 - 1; offset = 2; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; GET_MATCHES_FOOTER(offset, maxLen) } static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; GET_MATCHES_HEADER(4) HASH4_CALC; delta2 = p->pos - p->hash[ hash2Value]; delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; maxLen = 1; offset = 0; if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) { distances[0] = maxLen = 2; distances[1] = delta2 - 1; offset = 2; } if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) { maxLen = 3; distances[offset + 1] = delta3 - 1; offset += 2; delta2 = delta3; } if (offset != 0) { for (; maxLen != lenLimit; maxLen++) if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) break; distances[offset - 2] = maxLen; if (maxLen == lenLimit) { p->son[p->cyclicBufferPos] = curMatch; MOVE_POS_RET; } } if (maxLen < 3) maxLen = 3; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances + offset, maxLen) - (distances)); MOVE_POS_RET } UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) { UInt32 offset; GET_MATCHES_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), distances, 2) - (distances)); MOVE_POS_RET } static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(2) HASH2_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value; SKIP_HEADER(3) HASH3_CALC; curMatch = p->hash[kFix3HashSize + hashValue]; p->hash[hash2Value] = p->hash[kFix3HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->pos; p->hash[kFix4HashSize + hashValue] = p->pos; SKIP_FOOTER } while (--num != 0); } static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { UInt32 hash2Value, hash3Value; SKIP_HEADER(4) HASH4_CALC; curMatch = p->hash[kFix4HashSize + hashValue]; p->hash[ hash2Value] = p->hash[kFix3HashSize + hash3Value] = p->hash[kFix4HashSize + hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) { do { SKIP_HEADER(3) HASH_ZIP_CALC; curMatch = p->hash[hashValue]; p->hash[hashValue] = p->pos; p->son[p->cyclicBufferPos] = curMatch; MOVE_POS } while (--num != 0); } void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) { vTable->Init = (Mf_Init_Func)MatchFinder_Init; vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; if (!p->btMode) { vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; } else if (p->numHashBytes == 2) { vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; } else if (p->numHashBytes == 3) { vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; } else { vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; } } ================================================ FILE: src/lzma/LzmaDec.c ================================================ /* LzmaDec.c -- LZMA Decoder 2009-09-20 : Igor Pavlov : Public domain */ #include "lzma/LzmaDec.h" #include #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define RC_INIT_SIZE 5 #define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); #define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); #define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ { UPDATE_0(p); i = (i + i); A0; } else \ { UPDATE_1(p); i = (i + i) + 1; A1; } #define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) #define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } #define TREE_DECODE(probs, limit, i) \ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } /* #define _LZMA_SIZE_OPT */ #ifdef _LZMA_SIZE_OPT #define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) #else #define TREE_6_DECODE(probs, i) \ { i = 1; \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ TREE_GET_BIT(probs, i); \ i -= 0x40; } #endif #define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } #define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) #define UPDATE_0_CHECK range = bound; #define UPDATE_1_CHECK range -= bound; code -= bound; #define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ { UPDATE_0_CHECK; i = (i + i); A0; } else \ { UPDATE_1_CHECK; i = (i + i) + 1; A1; } #define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) #define TREE_DECODE_CHECK(probs, limit, i) \ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } #define kNumPosBitsMax 4 #define kNumPosStatesMax (1 << kNumPosBitsMax) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define LenChoice 0 #define LenChoice2 (LenChoice + 1) #define LenLow (LenChoice2 + 1) #define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) #define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) #define kNumLenProbs (LenHigh + kLenNumHighSymbols) #define kNumStates 12 #define kNumLitStates 7 #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #define kNumPosSlotBits 6 #define kNumLenToPosStates 4 #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kMatchMinLen 2 #define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define IsMatch 0 #define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) #define IsRepG0 (IsRep + kNumStates) #define IsRepG1 (IsRepG0 + kNumStates) #define IsRepG2 (IsRepG1 + kNumStates) #define IsRep0Long (IsRepG2 + kNumStates) #define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) #define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) #define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) #define LenCoder (Align + kAlignTableSize) #define RepLenCoder (LenCoder + kNumLenProbs) #define Literal (RepLenCoder + kNumLenProbs) #define LZMA_BASE_SIZE 1846 #define LZMA_LIT_SIZE 768 #define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) #if Literal != LZMA_BASE_SIZE StopCompilingDueBUG #endif #define LZMA_DIC_MIN (1 << 12) /* First LZMA-symbol is always decoded. And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization Out: Result: SZ_OK - OK SZ_ERROR_DATA - Error p->remainLen: < kMatchSpecLenStart : normal remain = kMatchSpecLenStart : finished = kMatchSpecLenStart + 1 : Flush marker = kMatchSpecLenStart + 2 : State Init Marker */ static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { CLzmaProb *probs = p->probs; unsigned state = p->state; UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; unsigned lc = p->prop.lc; Byte *dic = p->dic; SizeT dicBufSize = p->dicBufSize; SizeT dicPos = p->dicPos; UInt32 processedPos = p->processedPos; UInt32 checkDicSize = p->checkDicSize; unsigned len = 0; const Byte *buf = p->buf; UInt32 range = p->range; UInt32 code = p->code; do { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = processedPos & pbMask; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { unsigned symbol; UPDATE_0(prob); prob = probs + Literal; if (checkDicSize != 0 || processedPos != 0) prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); if (state < kNumLitStates) { state -= (state < 4) ? state : 3; symbol = 1; do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); } else { unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; unsigned offs = 0x100; state -= (state < 10) ? 3 : 6; symbol = 1; do { unsigned bit; CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) } while (symbol < 0x100); } dic[dicPos++] = (Byte)symbol; processedPos++; continue; } else { UPDATE_1(prob); prob = probs + IsRep + state; IF_BIT_0(prob) { UPDATE_0(prob); state += kNumStates; prob = probs + LenCoder; } else { UPDATE_1(prob); if (checkDicSize == 0 && processedPos == 0) return SZ_ERROR_DATA; prob = probs + IsRepG0 + state; IF_BIT_0(prob) { UPDATE_0(prob); prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0(prob) { UPDATE_0(prob); dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; processedPos++; state = state < kNumLitStates ? 9 : 11; continue; } UPDATE_1(prob); } else { UInt32 distance; UPDATE_1(prob); prob = probs + IsRepG1 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep1; } else { UPDATE_1(prob); prob = probs + IsRepG2 + state; IF_BIT_0(prob) { UPDATE_0(prob); distance = rep2; } else { UPDATE_1(prob); distance = rep3; rep3 = rep2; } rep2 = rep1; } rep1 = rep0; rep0 = distance; } state = state < kNumLitStates ? 8 : 11; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = (1 << kLenNumLowBits); } else { UPDATE_1(probLen); probLen = prob + LenChoice2; IF_BIT_0(probLen) { UPDATE_0(probLen); probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = (1 << kLenNumMidBits); } else { UPDATE_1(probLen); probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = (1 << kLenNumHighBits); } } TREE_DECODE(probLen, limit, len); len += offset; } if (state >= kNumStates) { UInt32 distance; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_6_DECODE(prob, distance); if (distance >= kStartPosModelIndex) { unsigned posSlot = (unsigned)distance; int numDirectBits = (int)(((distance >> 1) - 1)); distance = (2 | (distance & 1)); if (posSlot < kEndPosModelIndex) { distance <<= numDirectBits; prob = probs + SpecPos + distance - posSlot - 1; { UInt32 mask = 1; unsigned i = 1; do { GET_BIT2(prob + i, i, ; , distance |= mask); mask <<= 1; } while (--numDirectBits != 0); } } else { numDirectBits -= kNumAlignBits; do { NORMALIZE range >>= 1; { UInt32 t; code -= range; t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ distance = (distance << 1) + (t + 1); code += range & t; } /* distance <<= 1; if (code >= range) { code -= range; distance |= 1; } */ } while (--numDirectBits != 0); prob = probs + Align; distance <<= kNumAlignBits; { unsigned i = 1; GET_BIT2(prob + i, i, ; , distance |= 1); GET_BIT2(prob + i, i, ; , distance |= 2); GET_BIT2(prob + i, i, ; , distance |= 4); GET_BIT2(prob + i, i, ; , distance |= 8); } if (distance == (UInt32)0xFFFFFFFF) { len += kMatchSpecLenStart; state -= kNumStates; break; } } } rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance + 1; if (checkDicSize == 0) { if (distance >= processedPos) return SZ_ERROR_DATA; } else if (distance >= checkDicSize) return SZ_ERROR_DATA; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; } len += kMatchMinLen; if (limit == dicPos) return SZ_ERROR_DATA; { SizeT rem = limit - dicPos; unsigned curLen = ((rem < len) ? (unsigned)rem : len); SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); processedPos += curLen; len -= curLen; if (pos + curLen <= dicBufSize) { Byte *dest = dic + dicPos; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; const Byte *lim = dest + curLen; dicPos += curLen; do *(dest) = (Byte)*(dest + src); while (++dest != lim); } else { do { dic[dicPos++] = dic[pos]; if (++pos == dicBufSize) pos = 0; } while (--curLen != 0); } } } } while (dicPos < limit && buf < bufLimit); NORMALIZE; p->buf = buf; p->range = range; p->code = code; p->remainLen = len; p->dicPos = dicPos; p->processedPos = processedPos; p->reps[0] = rep0; p->reps[1] = rep1; p->reps[2] = rep2; p->reps[3] = rep3; p->state = state; return SZ_OK; } static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) { if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) { Byte *dic = p->dic; SizeT dicPos = p->dicPos; SizeT dicBufSize = p->dicBufSize; unsigned len = p->remainLen; UInt32 rep0 = p->reps[0]; if (limit - dicPos < len) len = (unsigned)(limit - dicPos); if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) p->checkDicSize = p->prop.dicSize; p->processedPos += len; p->remainLen -= len; while (len-- != 0) { dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; dicPos++; } p->dicPos = dicPos; } } static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) { do { SizeT limit2 = limit; if (p->checkDicSize == 0) { UInt32 rem = p->prop.dicSize - p->processedPos; if (limit - p->dicPos > rem) limit2 = p->dicPos + rem; } RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); if (p->processedPos >= p->prop.dicSize) p->checkDicSize = p->prop.dicSize; LzmaDec_WriteRem(p, limit); } while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); if (p->remainLen > kMatchSpecLenStart) { p->remainLen = kMatchSpecLenStart; } return 0; } typedef enum { DUMMY_ERROR, /* unexpected end of input stream */ DUMMY_LIT, DUMMY_MATCH, DUMMY_REP } ELzmaDummy; static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) { UInt32 range = p->range; UInt32 code = p->code; const Byte *bufLimit = buf + inSize; CLzmaProb *probs = p->probs; unsigned state = p->state; ELzmaDummy res; { CLzmaProb *prob; UInt32 bound; unsigned ttt; unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ prob = probs + Literal; if (p->checkDicSize != 0 || p->processedPos != 0) prob += (LZMA_LIT_SIZE * ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); if (state < kNumLitStates) { unsigned symbol = 1; do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); } else { unsigned matchByte = p->dic[p->dicPos - p->reps[0] + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; unsigned offs = 0x100; unsigned symbol = 1; do { unsigned bit; CLzmaProb *probLit; matchByte <<= 1; bit = (matchByte & offs); probLit = prob + offs + bit + symbol; GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) } while (symbol < 0x100); } res = DUMMY_LIT; } else { unsigned len; UPDATE_1_CHECK; prob = probs + IsRep + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; state = 0; prob = probs + LenCoder; res = DUMMY_MATCH; } else { UPDATE_1_CHECK; res = DUMMY_REP; prob = probs + IsRepG0 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; NORMALIZE_CHECK; return DUMMY_REP; } else { UPDATE_1_CHECK; } } else { UPDATE_1_CHECK; prob = probs + IsRepG1 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; prob = probs + IsRepG2 + state; IF_BIT_0_CHECK(prob) { UPDATE_0_CHECK; } else { UPDATE_1_CHECK; } } } state = kNumStates; prob = probs + RepLenCoder; } { unsigned limit, offset; CLzmaProb *probLen = prob + LenChoice; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenLow + (posState << kLenNumLowBits); offset = 0; limit = 1 << kLenNumLowBits; } else { UPDATE_1_CHECK; probLen = prob + LenChoice2; IF_BIT_0_CHECK(probLen) { UPDATE_0_CHECK; probLen = prob + LenMid + (posState << kLenNumMidBits); offset = kLenNumLowSymbols; limit = 1 << kLenNumMidBits; } else { UPDATE_1_CHECK; probLen = prob + LenHigh; offset = kLenNumLowSymbols + kLenNumMidSymbols; limit = 1 << kLenNumHighBits; } } TREE_DECODE_CHECK(probLen, limit, len); len += offset; } if (state < 4) { unsigned posSlot; prob = probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { int numDirectBits = ((posSlot >> 1) - 1); /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ if (posSlot < kEndPosModelIndex) { prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; } else { numDirectBits -= kNumAlignBits; do { NORMALIZE_CHECK range >>= 1; code -= range & (((code - range) >> 31) - 1); /* if (code >= range) code -= range; */ } while (--numDirectBits != 0); prob = probs + Align; numDirectBits = kNumAlignBits; } { unsigned i = 1; do { GET_BIT_CHECK(prob + i, i); } while (--numDirectBits != 0); } } } } } NORMALIZE_CHECK; return res; } static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) { p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); p->range = 0xFFFFFFFF; p->needFlush = 0; } void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) { p->needFlush = 1; p->remainLen = 0; p->tempBufSize = 0; if (initDic) { p->processedPos = 0; p->checkDicSize = 0; p->needInitState = 1; } if (initState) p->needInitState = 1; } void LzmaDec_Init(CLzmaDec *p) { p->dicPos = 0; LzmaDec_InitDicAndState(p, True, True); } static void LzmaDec_InitStateReal(CLzmaDec *p) { UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); UInt32 i; CLzmaProb *probs = p->probs; for (i = 0; i < numProbs; i++) probs[i] = kBitModelTotal >> 1; p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; p->state = 0; p->needInitState = 0; } SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT inSize = *srcLen; (*srcLen) = 0; LzmaDec_WriteRem(p, dicLimit); *status = LZMA_STATUS_NOT_SPECIFIED; while (p->remainLen != kMatchSpecLenStart) { int checkEndMarkNow; if (p->needFlush != 0) { for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) p->tempBuf[p->tempBufSize++] = *src++; if (p->tempBufSize < RC_INIT_SIZE) { *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (p->tempBuf[0] != 0) return SZ_ERROR_DATA; LzmaDec_InitRc(p, p->tempBuf); p->tempBufSize = 0; } checkEndMarkNow = 0; if (p->dicPos >= dicLimit) { if (p->remainLen == 0 && p->code == 0) { *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; return SZ_OK; } if (finishMode == LZMA_FINISH_ANY) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_OK; } if (p->remainLen != 0) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } checkEndMarkNow = 1; } if (p->needInitState) LzmaDec_InitStateReal(p); if (p->tempBufSize == 0) { SizeT processed; const Byte *bufLimit; if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, src, inSize); if (dummyRes == DUMMY_ERROR) { memcpy(p->tempBuf, src, inSize); p->tempBufSize = (unsigned)inSize; (*srcLen) += inSize; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } bufLimit = src; } else bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; p->buf = src; if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) return SZ_ERROR_DATA; processed = (SizeT)(p->buf - src); (*srcLen) += processed; src += processed; inSize -= processed; } else { unsigned rem = p->tempBufSize, lookAhead = 0; while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) p->tempBuf[rem++] = src[lookAhead++]; p->tempBufSize = rem; if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) { int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); if (dummyRes == DUMMY_ERROR) { (*srcLen) += lookAhead; *status = LZMA_STATUS_NEEDS_MORE_INPUT; return SZ_OK; } if (checkEndMarkNow && dummyRes != DUMMY_MATCH) { *status = LZMA_STATUS_NOT_FINISHED; return SZ_ERROR_DATA; } } p->buf = p->tempBuf; if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) return SZ_ERROR_DATA; lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); (*srcLen) += lookAhead; src += lookAhead; inSize -= lookAhead; p->tempBufSize = 0; } } if (p->code == 0) *status = LZMA_STATUS_FINISHED_WITH_MARK; return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; } SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) { SizeT outSize = *destLen; SizeT inSize = *srcLen; *srcLen = *destLen = 0; for (;;) { SizeT inSizeCur = inSize, outSizeCur, dicPos; ELzmaFinishMode curFinishMode; SRes res; if (p->dicPos == p->dicBufSize) p->dicPos = 0; dicPos = p->dicPos; if (outSize > p->dicBufSize - dicPos) { outSizeCur = p->dicBufSize; curFinishMode = LZMA_FINISH_ANY; } else { outSizeCur = dicPos + outSize; curFinishMode = finishMode; } res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); src += inSizeCur; inSize -= inSizeCur; *srcLen += inSizeCur; outSizeCur = p->dicPos - dicPos; memcpy(dest, p->dic + dicPos, outSizeCur); dest += outSizeCur; outSize -= outSizeCur; *destLen += outSizeCur; if (res != 0) return res; if (outSizeCur == 0 || outSize == 0) return SZ_OK; } } void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->probs); p->probs = 0; } static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) { alloc->Free(alloc, p->dic); p->dic = 0; } void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) { LzmaDec_FreeProbs(p, alloc); LzmaDec_FreeDict(p, alloc); } SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) { UInt32 dicSize; Byte d; if (size < LZMA_PROPS_SIZE) return SZ_ERROR_UNSUPPORTED; else dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); if (dicSize < LZMA_DIC_MIN) dicSize = LZMA_DIC_MIN; p->dicSize = dicSize; d = data[0]; if (d >= (9 * 5 * 5)) return SZ_ERROR_UNSUPPORTED; p->lc = d % 9; d /= 9; p->pb = d / 5; p->lp = d % 5; return SZ_OK; } static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) { UInt32 numProbs = LzmaProps_GetNumProbs(propNew); if (p->probs == 0 || numProbs != p->numProbs) { LzmaDec_FreeProbs(p, alloc); p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); p->numProbs = numProbs; if (p->probs == 0) return SZ_ERROR_MEM; } return SZ_OK; } SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); p->prop = propNew; return SZ_OK; } SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) { CLzmaProps propNew; SizeT dicBufSize; RINOK(LzmaProps_Decode(&propNew, props, propsSize)); RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); dicBufSize = propNew.dicSize; if (p->dic == 0 || dicBufSize != p->dicBufSize) { LzmaDec_FreeDict(p, alloc); p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); if (p->dic == 0) { LzmaDec_FreeProbs(p, alloc); return SZ_ERROR_MEM; } } p->dicBufSize = dicBufSize; p->prop = propNew; return SZ_OK; } SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) { CLzmaDec p; SRes res; SizeT inSize = *srcLen; SizeT outSize = *destLen; *srcLen = *destLen = 0; if (inSize < RC_INIT_SIZE) return SZ_ERROR_INPUT_EOF; LzmaDec_Construct(&p); res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); if (res != 0) return res; p.dic = dest; p.dicBufSize = outSize; LzmaDec_Init(&p); *srcLen = inSize; res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) res = SZ_ERROR_INPUT_EOF; (*destLen) = p.dicPos; LzmaDec_FreeProbs(&p, alloc); return res; } ================================================ FILE: src/lzma/LzmaEnc.c ================================================ /* LzmaEnc.c -- LZMA Encoder 2009-11-24 : Igor Pavlov : Public domain */ #include /* #define SHOW_STAT */ /* #define SHOW_STAT2 */ #if defined(SHOW_STAT) || defined(SHOW_STAT2) #include #endif #include "lzma/LzmaEnc.h" /* disable MT */ #define _7ZIP_ST #include "lzma/LzFind.h" #ifndef _7ZIP_ST #include "LzFindMt.h" #endif #ifdef SHOW_STAT static int ttt = 0; #endif #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) #define kBlockSize (9 << 10) #define kUnpackBlockSize (1 << 18) #define kMatchArraySize (1 << 21) #define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) #define kNumMaxDirectBits (31) #define kNumTopBits 24 #define kTopValue ((UInt32)1 << kNumTopBits) #define kNumBitModelTotalBits 11 #define kBitModelTotal (1 << kNumBitModelTotalBits) #define kNumMoveBits 5 #define kProbInitValue (kBitModelTotal >> 1) #define kNumMoveReducingBits 4 #define kNumBitPriceShiftBits 4 #define kBitPrice (1 << kNumBitPriceShiftBits) void LzmaEncProps_Init(CLzmaEncProps *p) { p->level = 5; p->dictSize = p->mc = 0; p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; p->writeEndMark = 0; } void LzmaEncProps_Normalize(CLzmaEncProps *p) { int level = p->level; if (level < 0) level = 5; p->level = level; if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); if (p->lc < 0) p->lc = 3; if (p->lp < 0) p->lp = 0; if (p->pb < 0) p->pb = 2; if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); if (p->numHashBytes < 0) p->numHashBytes = 4; if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); if (p->numThreads < 0) p->numThreads = #ifndef _7ZIP_ST ((p->btMode && p->algo) ? 2 : 1); #else 1; #endif } UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) { CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); return props.dictSize; } /* #define LZMA_LOG_BSR */ /* Define it for Intel's CPU */ #ifdef LZMA_LOG_BSR #define kDicLogSizeMaxCompress 30 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } UInt32 GetPosSlot1(UInt32 pos) { UInt32 res; BSR2_RET(pos, res); return res; } #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } #else #define kNumLogBits (9 + (int)sizeof(size_t) / 2) #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) void LzmaEnc_FastPosInit(Byte *g_FastPos) { int c = 2, slotFast; g_FastPos[0] = 0; g_FastPos[1] = 1; for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) { UInt32 k = (1 << ((slotFast >> 1) - 1)); UInt32 j; for (j = 0; j < k; j++, c++) g_FastPos[c] = (Byte)slotFast; } } #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ res = p->g_FastPos[pos >> i] + (i * 2); } /* #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ p->g_FastPos[pos >> 6] + 12 : \ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } */ #define GetPosSlot1(pos) p->g_FastPos[pos] #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } #endif #define LZMA_NUM_REPS 4 typedef unsigned CState; typedef struct { UInt32 price; CState state; int prev1IsChar; int prev2; UInt32 posPrev2; UInt32 backPrev2; UInt32 posPrev; UInt32 backPrev; UInt32 backs[LZMA_NUM_REPS]; } COptimal; #define kNumOpts (1 << 12) #define kNumLenToPosStates 4 #define kNumPosSlotBits 6 #define kDicLogSizeMin 0 #define kDicLogSizeMax 32 #define kDistTableSizeMax (kDicLogSizeMax * 2) #define kNumAlignBits 4 #define kAlignTableSize (1 << kNumAlignBits) #define kAlignMask (kAlignTableSize - 1) #define kStartPosModelIndex 4 #define kEndPosModelIndex 14 #define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) #define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) #ifdef _LZMA_PROB32 #define CLzmaProb UInt32 #else #define CLzmaProb UInt16 #endif #define LZMA_PB_MAX 4 #define LZMA_LC_MAX 8 #define LZMA_LP_MAX 4 #define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) #define kLenNumLowBits 3 #define kLenNumLowSymbols (1 << kLenNumLowBits) #define kLenNumMidBits 3 #define kLenNumMidSymbols (1 << kLenNumMidBits) #define kLenNumHighBits 8 #define kLenNumHighSymbols (1 << kLenNumHighBits) #define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) #define LZMA_MATCH_LEN_MIN 2 #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) #define kNumStates 12 typedef struct { CLzmaProb choice; CLzmaProb choice2; CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; CLzmaProb high[kLenNumHighSymbols]; } CLenEnc; typedef struct { CLenEnc p; UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; UInt32 tableSize; UInt32 counters[LZMA_NUM_PB_STATES_MAX]; } CLenPriceEnc; typedef struct { UInt32 range; Byte cache; UInt64 low; UInt64 cacheSize; Byte *buf; Byte *bufLim; Byte *bufBase; ISeqOutStream *outStream; UInt64 processed; SRes res; } CRangeEnc; typedef struct { CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; } CSaveState; typedef struct { IMatchFinder matchFinder; void *matchFinderObj; #ifndef _7ZIP_ST Bool mtMode; CMatchFinderMt matchFinderMt; #endif CMatchFinder matchFinderBase; #ifndef _7ZIP_ST Byte pad[128]; #endif UInt32 optimumEndIndex; UInt32 optimumCurrentIndex; UInt32 longestMatchLength; UInt32 numPairs; UInt32 numAvail; COptimal opt[kNumOpts]; #ifndef LZMA_LOG_BSR Byte g_FastPos[1 << kNumLogBits]; #endif UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; UInt32 numFastBytes; UInt32 additionalOffset; UInt32 reps[LZMA_NUM_REPS]; UInt32 state; UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; UInt32 alignPrices[kAlignTableSize]; UInt32 alignPriceCount; UInt32 distTableSize; unsigned lc, lp, pb; unsigned lpMask, pbMask; CLzmaProb *litProbs; CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb isRep[kNumStates]; CLzmaProb isRepG0[kNumStates]; CLzmaProb isRepG1[kNumStates]; CLzmaProb isRepG2[kNumStates]; CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; CLzmaProb posAlignEncoder[1 << kNumAlignBits]; CLenPriceEnc lenEnc; CLenPriceEnc repLenEnc; unsigned lclp; Bool fastMode; CRangeEnc rc; Bool writeEndMark; UInt64 nowPos64; UInt32 matchPriceCount; Bool finished; Bool multiThread; SRes result; UInt32 dictSize; UInt32 matchFinderCycles; int needInit; CSaveState saveState; } CLzmaEnc; void LzmaEnc_SaveState(CLzmaEncHandle pp) { CLzmaEnc *p = (CLzmaEnc *)pp; CSaveState *dest = &p->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); } void LzmaEnc_RestoreState(CLzmaEncHandle pp) { CLzmaEnc *dest = (CLzmaEnc *)pp; const CSaveState *p = &dest->saveState; int i; dest->lenEnc = p->lenEnc; dest->repLenEnc = p->repLenEnc; dest->state = p->state; for (i = 0; i < kNumStates; i++) { memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); } for (i = 0; i < kNumLenToPosStates; i++) memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); memcpy(dest->reps, p->reps, sizeof(p->reps)); memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); } SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) { CLzmaEnc *p = (CLzmaEnc *)pp; CLzmaEncProps props = *props2; LzmaEncProps_Normalize(&props); if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) return SZ_ERROR_PARAM; p->dictSize = props.dictSize; p->matchFinderCycles = props.mc; { unsigned fb = props.fb; if (fb < 5) fb = 5; if (fb > LZMA_MATCH_LEN_MAX) fb = LZMA_MATCH_LEN_MAX; p->numFastBytes = fb; } p->lc = props.lc; p->lp = props.lp; p->pb = props.pb; p->fastMode = (props.algo == 0); p->matchFinderBase.btMode = props.btMode; { UInt32 numHashBytes = 4; if (props.btMode) { if (props.numHashBytes < 2) numHashBytes = 2; else if (props.numHashBytes < 4) numHashBytes = props.numHashBytes; } p->matchFinderBase.numHashBytes = numHashBytes; } p->matchFinderBase.cutValue = props.mc; p->writeEndMark = props.writeEndMark; #ifndef _7ZIP_ST /* if (newMultiThread != _multiThread) { ReleaseMatchFinder(); _multiThread = newMultiThread; } */ p->multiThread = (props.numThreads > 1); #endif return SZ_OK; } static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; #define IsCharState(s) ((s) < 7) #define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) #define kInfinityPrice (1 << 30) static void RangeEnc_Construct(CRangeEnc *p) { p->outStream = 0; p->bufBase = 0; } #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) #define RC_BUF_SIZE (1 << 16) static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) { if (p->bufBase == 0) { p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); if (p->bufBase == 0) return 0; p->bufLim = p->bufBase + RC_BUF_SIZE; } return 1; } static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->bufBase); p->bufBase = 0; } static void RangeEnc_Init(CRangeEnc *p) { /* Stream.Init(); */ p->low = 0; p->range = 0xFFFFFFFF; p->cacheSize = 1; p->cache = 0; p->buf = p->bufBase; p->processed = 0; p->res = SZ_OK; } static void RangeEnc_FlushStream(CRangeEnc *p) { size_t num; if (p->res != SZ_OK) return; num = p->buf - p->bufBase; if (num != p->outStream->Write(p->outStream, p->bufBase, num)) p->res = SZ_ERROR_WRITE; p->processed += num; p->buf = p->bufBase; } static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) { if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) { Byte temp = p->cache; do { Byte *buf = p->buf; *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); p->buf = buf; if (buf == p->bufLim) RangeEnc_FlushStream(p); temp = 0xFF; } while (--p->cacheSize != 0); p->cache = (Byte)((UInt32)p->low >> 24); } p->cacheSize++; p->low = (UInt32)p->low << 8; } static void RangeEnc_FlushData(CRangeEnc *p) { int i; for (i = 0; i < 5; i++) RangeEnc_ShiftLow(p); } static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) { do { p->range >>= 1; p->low += p->range & (0 - ((value >> --numBits) & 1)); if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } while (numBits != 0); } static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) { UInt32 ttt = *prob; UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; if (symbol == 0) { p->range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } else { p->low += newBound; p->range -= newBound; ttt -= ttt >> kNumMoveBits; } *prob = (CLzmaProb)ttt; if (p->range < kTopValue) { p->range <<= 8; RangeEnc_ShiftLow(p); } } static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) { symbol |= 0x100; do { RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); } static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) { UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); } void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) { UInt32 i; for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) { const int kCyclesBits = kNumBitPriceShiftBits; UInt32 w = i; UInt32 bitCount = 0; int j; for (j = 0; j < kCyclesBits; j++) { w = w * w; bitCount <<= 1; while (w >= ((UInt32)1 << 16)) { w >>= 1; bitCount++; } } ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); } } #define GET_PRICE(prob, symbol) \ p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICEa(prob, symbol) \ ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= 0x100; do { price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); symbol <<= 1; } while (symbol < 0x10000); return price; } static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 offs = 0x100; symbol |= 0x100; do { matchByte <<= 1; price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); symbol <<= 1; offs &= ~(matchByte ^ symbol); } while (symbol < 0x10000); return price; } static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = numBitLevels; i != 0;) { UInt32 bit; i--; bit = (symbol >> i) & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; } } static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) { UInt32 m = 1; int i; for (i = 0; i < numBitLevels; i++) { UInt32 bit = symbol & 1; RangeEnc_EncodeBit(rc, probs + m, bit); m = (m << 1) | bit; symbol >>= 1; } } static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; symbol |= (1 << numBitLevels); while (symbol != 1) { price += GET_PRICEa(probs[symbol >> 1], symbol & 1); symbol >>= 1; } return price; } static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) { UInt32 price = 0; UInt32 m = 1; int i; for (i = numBitLevels; i != 0; i--) { UInt32 bit = symbol & 1; symbol >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) | bit; } return price; } static void LenEnc_Init(CLenEnc *p) { unsigned i; p->choice = p->choice2 = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) p->low[i] = kProbInitValue; for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) p->mid[i] = kProbInitValue; for (i = 0; i < kLenNumHighSymbols; i++) p->high[i] = kProbInitValue; } static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) { if (symbol < kLenNumLowSymbols) { RangeEnc_EncodeBit(rc, &p->choice, 0); RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); } else { RangeEnc_EncodeBit(rc, &p->choice, 1); if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) { RangeEnc_EncodeBit(rc, &p->choice2, 0); RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); } else { RangeEnc_EncodeBit(rc, &p->choice2, 1); RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); } } } static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) { UInt32 a0 = GET_PRICE_0a(p->choice); UInt32 a1 = GET_PRICE_1a(p->choice); UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); UInt32 i = 0; for (i = 0; i < kLenNumLowSymbols; i++) { if (i >= numSymbols) return; prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); } for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) { if (i >= numSymbols) return; prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); } for (; i < numSymbols; i++) prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); } static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) { LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); p->counters[posState] = p->tableSize; } static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) { UInt32 posState; for (posState = 0; posState < numPosStates; posState++) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) { LenEnc_Encode(&p->p, rc, symbol, posState); if (updatePrice) if (--p->counters[posState] == 0) LenPriceEnc_UpdateTable(p, posState, ProbPrices); } static void MovePos(CLzmaEnc *p, UInt32 num) { #ifdef SHOW_STAT ttt += num; printf("\n MovePos %d", num); #endif if (num != 0) { p->additionalOffset += num; p->matchFinder.Skip(p->matchFinderObj, num); } } static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) { UInt32 lenRes = 0, numPairs; p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); #ifdef SHOW_STAT printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); ttt++; { UInt32 i; for (i = 0; i < numPairs; i += 2) printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); } #endif if (numPairs > 0) { lenRes = p->matches[numPairs - 2]; if (lenRes == p->numFastBytes) { const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; UInt32 distance = p->matches[numPairs - 1] + 1; UInt32 numAvail = p->numAvail; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; { const Byte *pby2 = pby - distance; for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); } } } p->additionalOffset++; *numDistancePairsRes = numPairs; return lenRes; } #define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; #define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; #define IsShortRep(p) ((p)->backPrev == 0) static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) { return GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]); } static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) { UInt32 price; if (repIndex == 0) { price = GET_PRICE_0(p->isRepG0[state]); price += GET_PRICE_1(p->isRep0Long[state][posState]); } else { price = GET_PRICE_1(p->isRepG0[state]); if (repIndex == 1) price += GET_PRICE_0(p->isRepG1[state]); else { price += GET_PRICE_1(p->isRepG1[state]); price += GET_PRICE(p->isRepG2[state], repIndex - 2); } } return price; } static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) { return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + GetPureRepPrice(p, repIndex, state, posState); } static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) { UInt32 posMem = p->opt[cur].posPrev; UInt32 backMem = p->opt[cur].backPrev; p->optimumEndIndex = cur; do { if (p->opt[cur].prev1IsChar) { MakeAsChar(&p->opt[posMem]) p->opt[posMem].posPrev = posMem - 1; if (p->opt[cur].prev2) { p->opt[posMem - 1].prev1IsChar = False; p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; } } { UInt32 posPrev = posMem; UInt32 backCur = backMem; backMem = p->opt[posPrev].backPrev; posMem = p->opt[posPrev].posPrev; p->opt[posPrev].backPrev = backCur; p->opt[posPrev].posPrev = cur; cur = posPrev; } } while (cur != 0); *backRes = p->opt[0].backPrev; p->optimumCurrentIndex = p->opt[0].posPrev; return p->optimumCurrentIndex; } #define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) { UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; UInt32 matchPrice, repMatchPrice, normalMatchPrice; UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; UInt32 *matches; const Byte *data; Byte curByte, matchByte; if (p->optimumEndIndex != p->optimumCurrentIndex) { const COptimal *opt = &p->opt[p->optimumCurrentIndex]; UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; *backRes = opt->backPrev; p->optimumCurrentIndex = opt->posPrev; return lenRes; } p->optimumCurrentIndex = p->optimumEndIndex = 0; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; if (numAvail < 2) { *backRes = (UInt32)(-1); return 1; } if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repMaxIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 lenTest; const Byte *data2; reps[i] = p->reps[i]; data2 = data - (reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) { repLens[i] = 0; continue; } for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); repLens[i] = lenTest; if (lenTest > repLens[repMaxIndex]) repMaxIndex = i; } if (repLens[repMaxIndex] >= p->numFastBytes) { UInt32 lenRes; *backRes = repMaxIndex; lenRes = repLens[repMaxIndex]; MovePos(p, lenRes - 1); return lenRes; } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } curByte = *data; matchByte = *(data - (reps[0] + 1)); if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) { *backRes = (UInt32)-1; return 1; } p->opt[0].state = (CState)p->state; posState = (position & p->pbMask); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + (!IsCharState(p->state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } MakeAsChar(&p->opt[1]); matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); if (matchByte == curByte) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); if (shortRepPrice < p->opt[1].price) { p->opt[1].price = shortRepPrice; MakeAsShortRep(&p->opt[1]); } } lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); if (lenEnd < 2) { *backRes = p->opt[1].backPrev; return 1; } p->opt[1].posPrev = 0; for (i = 0; i < LZMA_NUM_REPS; i++) p->opt[0].backs[i] = reps[i]; len = lenEnd; do p->opt[len--].price = kInfinityPrice; while (len >= 2); for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 repLen = repLens[i]; UInt32 price; if (repLen < 2) continue; price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; COptimal *opt = &p->opt[repLen]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = i; opt->prev1IsChar = False; } } while (--repLen >= 2); } normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); if (len <= mainLen) { UInt32 offs = 0; while (len > matches[offs]) offs += 2; for (; ; len++) { COptimal *opt; UInt32 distance = matches[offs + 1]; UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(len); if (distance < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][distance]; else { UInt32 slot; GetPosSlot2(distance, slot); curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; } opt = &p->opt[len]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = 0; opt->backPrev = distance + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (len == matches[offs]) { offs += 2; if (offs == numPairs) break; } } } cur = 0; #ifdef SHOW_STAT2 if (position >= 0) { unsigned i; printf("\n pos = %4X", position); for (i = cur; i <= lenEnd; i++) printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); } #endif for (;;) { UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; Bool nextIsChar; Byte curByte, matchByte; const Byte *data; COptimal *curOpt; COptimal *nextOpt; cur++; if (cur == lenEnd) return Backward(p, backRes, cur); newLen = ReadMatchDistances(p, &numPairs); if (newLen >= p->numFastBytes) { p->numPairs = numPairs; p->longestMatchLength = newLen; return Backward(p, backRes, cur); } position++; curOpt = &p->opt[cur]; posPrev = curOpt->posPrev; if (curOpt->prev1IsChar) { posPrev--; if (curOpt->prev2) { state = p->opt[curOpt->posPrev2].state; if (curOpt->backPrev2 < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } else state = p->opt[posPrev].state; state = kLiteralNextStates[state]; } else state = p->opt[posPrev].state; if (posPrev == cur - 1) { if (IsShortRep(curOpt)) state = kShortRepNextStates[state]; else state = kLiteralNextStates[state]; } else { UInt32 pos; const COptimal *prevOpt; if (curOpt->prev1IsChar && curOpt->prev2) { posPrev = curOpt->posPrev2; pos = curOpt->backPrev2; state = kRepNextStates[state]; } else { pos = curOpt->backPrev; if (pos < LZMA_NUM_REPS) state = kRepNextStates[state]; else state = kMatchNextStates[state]; } prevOpt = &p->opt[posPrev]; if (pos < LZMA_NUM_REPS) { UInt32 i; reps[0] = prevOpt->backs[pos]; for (i = 1; i <= pos; i++) reps[i] = prevOpt->backs[i - 1]; for (; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i]; } else { UInt32 i; reps[0] = (pos - LZMA_NUM_REPS); for (i = 1; i < LZMA_NUM_REPS; i++) reps[i] = prevOpt->backs[i - 1]; } } curOpt->state = (CState)state; curOpt->backs[0] = reps[0]; curOpt->backs[1] = reps[1]; curOpt->backs[2] = reps[2]; curOpt->backs[3] = reps[3]; curPrice = curOpt->price; nextIsChar = False; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; curByte = *data; matchByte = *(data - (reps[0] + 1)); posState = (position & p->pbMask); curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); { const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); curAnd1Price += (!IsCharState(state) ? LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : LitEnc_GetPrice(probs, curByte, p->ProbPrices)); } nextOpt = &p->opt[cur + 1]; if (curAnd1Price < nextOpt->price) { nextOpt->price = curAnd1Price; nextOpt->posPrev = cur; MakeAsChar(nextOpt); nextIsChar = True; } matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) { UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); if (shortRepPrice <= nextOpt->price) { nextOpt->price = shortRepPrice; nextOpt->posPrev = cur; MakeAsShortRep(nextOpt); nextIsChar = True; } } numAvailFull = p->numAvail; { UInt32 temp = kNumOpts - 1 - cur; if (temp < numAvailFull) numAvailFull = temp; } if (numAvailFull < 2) continue; numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); if (!nextIsChar && matchByte != curByte) /* speed optimization */ { /* try Literal + rep0 */ UInt32 temp; UInt32 lenTest2; const Byte *data2 = data - (reps[0] + 1); UInt32 limit = p->numFastBytes + 1; if (limit > numAvailFull) limit = numAvailFull; for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); lenTest2 = temp - 1; if (lenTest2 >= 2) { UInt32 state2 = kLiteralNextStates[state]; UInt32 posStateNext = (position + 1) & p->pbMask; UInt32 nextRepMatchPrice = curAnd1Price + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = False; } } } } startLen = 2; /* speed optimization */ { UInt32 repIndex; for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) { UInt32 lenTest; UInt32 lenTestTemp; UInt32 price; const Byte *data2 = data - (reps[repIndex] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); while (lenEnd < cur + lenTest) p->opt[++lenEnd].price = kInfinityPrice; lenTestTemp = lenTest; price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); do { UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; COptimal *opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = repIndex; opt->prev1IsChar = False; } } while (--lenTest >= 2); lenTest = lenTestTemp; if (repIndex == 0) startLen = lenTest + 1; /* if (_maxMode) */ { UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kRepNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = price + p->repLenEnc.prices[posState][lenTest - 2] + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (position + lenTest + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 curAndLenPrice; COptimal *opt; UInt32 offset = cur + lenTest + 1 + lenTest2; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = repIndex; } } } } } } /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ if (newLen > numAvail) { newLen = numAvail; for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); matches[numPairs] = newLen; numPairs += 2; } if (newLen >= startLen) { UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); UInt32 offs, curBack, posSlot; UInt32 lenTest; while (lenEnd < cur + newLen) p->opt[++lenEnd].price = kInfinityPrice; offs = 0; while (startLen > matches[offs]) offs += 2; curBack = matches[offs + 1]; GetPosSlot2(curBack, posSlot); for (lenTest = /*2*/ startLen; ; lenTest++) { UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; UInt32 lenToPosState = GetLenToPosState(lenTest); COptimal *opt; if (curBack < kNumFullDistances) curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; else curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; opt = &p->opt[cur + lenTest]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur; opt->backPrev = curBack + LZMA_NUM_REPS; opt->prev1IsChar = False; } if (/*_maxMode && */lenTest == matches[offs]) { /* Try Match + Literal + Rep0 */ const Byte *data2 = data - (curBack + 1); UInt32 lenTest2 = lenTest + 1; UInt32 limit = lenTest2 + p->numFastBytes; UInt32 nextRepMatchPrice; if (limit > numAvailFull) limit = numAvailFull; for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); lenTest2 -= lenTest + 1; if (lenTest2 >= 2) { UInt32 state2 = kMatchNextStates[state]; UInt32 posStateNext = (position + lenTest) & p->pbMask; UInt32 curAndLenCharPrice = curAndLenPrice + GET_PRICE_0(p->isMatch[state2][posStateNext]) + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), data[lenTest], data2[lenTest], p->ProbPrices); state2 = kLiteralNextStates[state2]; posStateNext = (posStateNext + 1) & p->pbMask; nextRepMatchPrice = curAndLenCharPrice + GET_PRICE_1(p->isMatch[state2][posStateNext]) + GET_PRICE_1(p->isRep[state2]); /* for (; lenTest2 >= 2; lenTest2--) */ { UInt32 offset = cur + lenTest + 1 + lenTest2; UInt32 curAndLenPrice; COptimal *opt; while (lenEnd < offset) p->opt[++lenEnd].price = kInfinityPrice; curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); opt = &p->opt[offset]; if (curAndLenPrice < opt->price) { opt->price = curAndLenPrice; opt->posPrev = cur + lenTest + 1; opt->backPrev = 0; opt->prev1IsChar = True; opt->prev2 = True; opt->posPrev2 = cur; opt->backPrev2 = curBack + LZMA_NUM_REPS; } } } offs += 2; if (offs == numPairs) break; curBack = matches[offs + 1]; if (curBack >= kNumFullDistances) GetPosSlot2(curBack, posSlot); } } } } } #define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) { UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; const Byte *data; const UInt32 *matches; if (p->additionalOffset == 0) mainLen = ReadMatchDistances(p, &numPairs); else { mainLen = p->longestMatchLength; numPairs = p->numPairs; } numAvail = p->numAvail; *backRes = (UInt32)-1; if (numAvail < 2) return 1; if (numAvail > LZMA_MATCH_LEN_MAX) numAvail = LZMA_MATCH_LEN_MAX; data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; repLen = repIndex = 0; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; for (len = 2; len < numAvail && data[len] == data2[len]; len++); if (len >= p->numFastBytes) { *backRes = i; MovePos(p, len - 1); return len; } if (len > repLen) { repIndex = i; repLen = len; } } matches = p->matches; if (mainLen >= p->numFastBytes) { *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; MovePos(p, mainLen - 1); return mainLen; } mainDist = 0; /* for GCC */ if (mainLen >= 2) { mainDist = matches[numPairs - 1]; while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) { if (!ChangePair(matches[numPairs - 3], mainDist)) break; numPairs -= 2; mainLen = matches[numPairs - 2]; mainDist = matches[numPairs - 1]; } if (mainLen == 2 && mainDist >= 0x80) mainLen = 1; } if (repLen >= 2 && ( (repLen + 1 >= mainLen) || (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) { *backRes = repIndex; MovePos(p, repLen - 1); return repLen; } if (mainLen < 2 || numAvail <= 2) return 1; p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); if (p->longestMatchLength >= 2) { UInt32 newDistance = matches[p->numPairs - 1]; if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || (p->longestMatchLength > mainLen + 1) || (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) return 1; } data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; for (i = 0; i < LZMA_NUM_REPS; i++) { UInt32 len, limit; const Byte *data2 = data - (p->reps[i] + 1); if (data[0] != data2[0] || data[1] != data2[1]) continue; limit = mainLen - 1; for (len = 2; len < limit && data[len] == data2[len]; len++); if (len >= limit) return 1; } *backRes = mainDist + LZMA_NUM_REPS; MovePos(p, mainLen - 2); return mainLen; } static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) { UInt32 len; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; len = LZMA_MATCH_LEN_MIN; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); } static SRes CheckErrors(CLzmaEnc *p) { if (p->result != SZ_OK) return p->result; if (p->rc.res != SZ_OK) p->result = SZ_ERROR_WRITE; if (p->matchFinderBase.result != SZ_OK) p->result = SZ_ERROR_READ; if (p->result != SZ_OK) p->finished = True; return p->result; } static SRes Flush(CLzmaEnc *p, UInt32 nowPos) { /* ReleaseMFStream(); */ p->finished = True; if (p->writeEndMark) WriteEndMarker(p, nowPos & p->pbMask); RangeEnc_FlushData(&p->rc); RangeEnc_FlushStream(&p->rc); return CheckErrors(p); } static void FillAlignPrices(CLzmaEnc *p) { UInt32 i; for (i = 0; i < kAlignTableSize; i++) p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); p->alignPriceCount = 0; } static void FillDistancesPrices(CLzmaEnc *p) { UInt32 tempPrices[kNumFullDistances]; UInt32 i, lenToPosState; for (i = kStartPosModelIndex; i < kNumFullDistances; i++) { UInt32 posSlot = GetPosSlot1(i); UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); } for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) { UInt32 posSlot; const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; for (posSlot = 0; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); { UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; UInt32 i; for (i = 0; i < kStartPosModelIndex; i++) distancesPrices[i] = posSlotPrices[i]; for (; i < kNumFullDistances; i++) distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; } } p->matchPriceCount = 0; } void LzmaEnc_Construct(CLzmaEnc *p) { RangeEnc_Construct(&p->rc); MatchFinder_Construct(&p->matchFinderBase); #ifndef _7ZIP_ST MatchFinderMt_Construct(&p->matchFinderMt); p->matchFinderMt.MatchFinder = &p->matchFinderBase; #endif { CLzmaEncProps props; LzmaEncProps_Init(&props); LzmaEnc_SetProps(p, &props); } #ifndef LZMA_LOG_BSR LzmaEnc_FastPosInit(p->g_FastPos); #endif LzmaEnc_InitPriceTables(p->ProbPrices); p->litProbs = 0; p->saveState.litProbs = 0; } CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) { void *p; p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); if (p != 0) LzmaEnc_Construct((CLzmaEnc *)p); return p; } void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) { alloc->Free(alloc, p->litProbs); alloc->Free(alloc, p->saveState.litProbs); p->litProbs = 0; p->saveState.litProbs = 0; } void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) { #ifndef _7ZIP_ST MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); #endif MatchFinder_Free(&p->matchFinderBase, allocBig); LzmaEnc_FreeLits(p, alloc); RangeEnc_Free(&p->rc, alloc); } void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) { LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); alloc->Free(alloc, p); } static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) { UInt32 nowPos32, startPos32; if (p->needInit) { p->matchFinder.Init(p->matchFinderObj); p->needInit = 0; } if (p->finished) return p->result; RINOK(CheckErrors(p)); nowPos32 = (UInt32)p->nowPos64; startPos32 = nowPos32; if (p->nowPos64 == 0) { UInt32 numPairs; Byte curByte; if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) return Flush(p, nowPos32); ReadMatchDistances(p, &numPairs); RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); p->state = kLiteralNextStates[p->state]; curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); LitEnc_Encode(&p->rc, p->litProbs, curByte); p->additionalOffset--; nowPos32++; } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) for (;;) { UInt32 pos, len, posState; if (p->fastMode) len = GetOptimumFast(p, &pos); else len = GetOptimum(p, nowPos32, &pos); #ifdef SHOW_STAT2 printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); #endif posState = nowPos32 & p->pbMask; if (len == 1 && pos == (UInt32)-1) { Byte curByte; CLzmaProb *probs; const Byte *data; RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; curByte = *data; probs = LIT_PROBS(nowPos32, *(data - 1)); if (IsCharState(p->state)) LitEnc_Encode(&p->rc, probs, curByte); else LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); p->state = kLiteralNextStates[p->state]; } else { RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); if (pos < LZMA_NUM_REPS) { RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); if (pos == 0) { RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); } else { UInt32 distance = p->reps[pos]; RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); if (pos == 1) RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); else { RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); if (pos == 3) p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; } p->reps[1] = p->reps[0]; p->reps[0] = distance; } if (len == 1) p->state = kShortRepNextStates[p->state]; else { LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); p->state = kRepNextStates[p->state]; } } else { UInt32 posSlot; RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); p->state = kMatchNextStates[p->state]; LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); pos -= LZMA_NUM_REPS; GetPosSlot(pos, posSlot); RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); if (posSlot >= kStartPosModelIndex) { UInt32 footerBits = ((posSlot >> 1) - 1); UInt32 base = ((2 | (posSlot & 1)) << footerBits); UInt32 posReduced = pos - base; if (posSlot < kEndPosModelIndex) RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); else { RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); p->alignPriceCount++; } } p->reps[3] = p->reps[2]; p->reps[2] = p->reps[1]; p->reps[1] = p->reps[0]; p->reps[0] = pos; p->matchPriceCount++; } } p->additionalOffset -= len; nowPos32 += len; if (p->additionalOffset == 0) { UInt32 processed; if (!p->fastMode) { if (p->matchPriceCount >= (1 << 7)) FillDistancesPrices(p); if (p->alignPriceCount >= kAlignTableSize) FillAlignPrices(p); } if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) break; processed = nowPos32 - startPos32; if (useLimits) { if (processed + kNumOpts + 300 >= maxUnpackSize || RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) break; } else if (processed >= (1 << 15)) { p->nowPos64 += nowPos32 - startPos32; return CheckErrors(p); } } } p->nowPos64 += nowPos32 - startPos32; return Flush(p, nowPos32); } #define kBigHashDicLimit ((UInt32)1 << 24) static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 beforeSize = kNumOpts; Bool btMode; if (!RangeEnc_Alloc(&p->rc, alloc)) return SZ_ERROR_MEM; btMode = (p->matchFinderBase.btMode != 0); #ifndef _7ZIP_ST p->mtMode = (p->multiThread && !p->fastMode && btMode); #endif { unsigned lclp = p->lc + p->lp; if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) { LzmaEnc_FreeLits(p, alloc); p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); if (p->litProbs == 0 || p->saveState.litProbs == 0) { LzmaEnc_FreeLits(p, alloc); return SZ_ERROR_MEM; } p->lclp = lclp; } } p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); if (beforeSize + p->dictSize < keepWindowSize) beforeSize = keepWindowSize - p->dictSize; #ifndef _7ZIP_ST if (p->mtMode) { RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); p->matchFinderObj = &p->matchFinderMt; MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); } else #endif { if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) return SZ_ERROR_MEM; p->matchFinderObj = &p->matchFinderBase; MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); } return SZ_OK; } void LzmaEnc_Init(CLzmaEnc *p) { UInt32 i; p->state = 0; for (i = 0 ; i < LZMA_NUM_REPS; i++) p->reps[i] = 0; RangeEnc_Init(&p->rc); for (i = 0; i < kNumStates; i++) { UInt32 j; for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) { p->isMatch[i][j] = kProbInitValue; p->isRep0Long[i][j] = kProbInitValue; } p->isRep[i] = kProbInitValue; p->isRepG0[i] = kProbInitValue; p->isRepG1[i] = kProbInitValue; p->isRepG2[i] = kProbInitValue; } { UInt32 num = 0x300 << (p->lp + p->lc); for (i = 0; i < num; i++) p->litProbs[i] = kProbInitValue; } { for (i = 0; i < kNumLenToPosStates; i++) { CLzmaProb *probs = p->posSlotEncoder[i]; UInt32 j; for (j = 0; j < (1 << kNumPosSlotBits); j++) probs[j] = kProbInitValue; } } { for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) p->posEncoders[i] = kProbInitValue; } LenEnc_Init(&p->lenEnc.p); LenEnc_Init(&p->repLenEnc.p); for (i = 0; i < (1 << kNumAlignBits); i++) p->posAlignEncoder[i] = kProbInitValue; p->optimumEndIndex = 0; p->optimumCurrentIndex = 0; p->additionalOffset = 0; p->pbMask = (1 << p->pb) - 1; p->lpMask = (1 << p->lp) - 1; } void LzmaEnc_InitPrices(CLzmaEnc *p) { if (!p->fastMode) { FillDistancesPrices(p); FillAlignPrices(p); } p->lenEnc.tableSize = p->repLenEnc.tableSize = p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); } static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { UInt32 i; for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) if (p->dictSize <= ((UInt32)1 << i)) break; p->distTableSize = i * 2; p->finished = False; p->result = SZ_OK; RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); LzmaEnc_Init(p); LzmaEnc_InitPrices(p); p->nowPos64 = 0; return SZ_OK; } static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; p->rc.outStream = outStream; return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); } SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; p->matchFinderBase.stream = inStream; p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) { p->matchFinderBase.directInput = 1; p->matchFinderBase.bufferBase = (Byte *)src; p->matchFinderBase.directInputRem = srcLen; } SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)pp; LzmaEnc_SetInputBuf(p, src, srcLen); p->needInit = 1; return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); } void LzmaEnc_Finish(CLzmaEncHandle pp) { #ifndef _7ZIP_ST CLzmaEnc *p = (CLzmaEnc *)pp; if (p->mtMode) MatchFinderMt_ReleaseStream(&p->matchFinderMt); #else pp = pp; #endif } typedef struct { ISeqOutStream funcTable; Byte *data; SizeT rem; Bool overflow; } CSeqOutStreamBuf; static size_t MyWrite(void *pp, const void *data, size_t size) { CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; if (p->rem < size) { size = p->rem; p->overflow = True; } memcpy(p->data, data, size); p->rem -= size; p->data += size; return size; } UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); } const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) { const CLzmaEnc *p = (CLzmaEnc *)pp; return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; } SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) { CLzmaEnc *p = (CLzmaEnc *)pp; UInt64 nowPos64; SRes res; CSeqOutStreamBuf outStream; outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = False; p->finished = False; p->result = SZ_OK; if (reInit) LzmaEnc_Init(p); LzmaEnc_InitPrices(p); nowPos64 = p->nowPos64; RangeEnc_Init(&p->rc); p->rc.outStream = &outStream.funcTable; res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); *unpackSize = (UInt32)(p->nowPos64 - nowPos64); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) { SRes res = SZ_OK; #ifndef _7ZIP_ST Byte allocaDummy[0x300]; int i = 0; for (i = 0; i < 16; i++) allocaDummy[i] = (Byte)i; #endif for (;;) { res = LzmaEnc_CodeOneBlock(p, False, 0, 0); if (res != SZ_OK || p->finished != 0) break; if (progress != 0) { res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); if (res != SZ_OK) { res = SZ_ERROR_PROGRESS; break; } } } LzmaEnc_Finish(p); return res; } SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); } SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) { CLzmaEnc *p = (CLzmaEnc *)pp; int i; UInt32 dictSize = p->dictSize; if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM; *size = LZMA_PROPS_SIZE; props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); for (i = 11; i <= 30; i++) { if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; } if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; } } for (i = 0; i < 4; i++) props[1 + i] = (Byte)(dictSize >> (8 * i)); return SZ_OK; } SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { SRes res; CLzmaEnc *p = (CLzmaEnc *)pp; CSeqOutStreamBuf outStream; LzmaEnc_SetInputBuf(p, src, srcLen); outStream.funcTable.Write = MyWrite; outStream.data = dest; outStream.rem = *destLen; outStream.overflow = False; p->writeEndMark = writeEndMark; p->rc.outStream = &outStream.funcTable; res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); if (res == SZ_OK) res = LzmaEnc_Encode2(p, progress); *destLen -= outStream.rem; if (outStream.overflow) return SZ_ERROR_OUTPUT_EOF; return res; } SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) { CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); SRes res; if (p == 0) return SZ_ERROR_MEM; res = LzmaEnc_SetProps(p, props); if (res == SZ_OK) { res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); if (res == SZ_OK) res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, writeEndMark, progress, alloc, allocBig); } LzmaEnc_Destroy(p, alloc, allocBig); return res; } ================================================ FILE: src/lzo-lg.c ================================================ /* lzopack.c -- LZO example program: a simple file packer This file is part of the LZO real-time data compression library. Copyright (C) 1996-2008 Markus Franz Xaver Johannes Oberhumer All Rights Reserved. Patched by Arno1 (http://lg-hack.info) for LG digital tv firmware The LZO library 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 2 of the License, or (at your option) any later version. The LZO library 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 the LZO library; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Markus F.X.J. Oberhumer http://www.oberhumer.com/opensource/lzo/ */ /************************************************************************* // NOTE: this is an example program, so do not use to backup your data. // // This program lacks things like sophisticated file handling but is // pretty complete regarding compression - it should provide a good // starting point for adaption for your applications. // // Please study LZO.FAQ and simple.c first. **************************************************************************/ #include "common.h" #include "lzo/lzoconf.h" #include "lzo/lzo1x.h" /* portability layer */ #define WANT_LZO_MALLOC 1 #define WANT_LZO_FREAD 1 #define WANT_LZO_WILDARGV 1 #include "lzo/portab.h" static unsigned long total_in = 0; static unsigned long total_out = 0; static lzo_bool opt_debug = 0; lzo_uint32 fi_size = 0; /* magic file header for lzopack-compressed files */ static const unsigned char magic[8] = { 0x00, 0xe9, 0x4c, 0x5a, 0x4f, 0xff, 0x1a, 0x00 }; /************************************************************************* // file IO **************************************************************************/ lzo_uint xread(FILE * fp, lzo_voidp buf, lzo_uint len, lzo_bool allow_eof) { lzo_uint l; l = (lzo_uint) lzo_fread(fp, buf, len); if (l > len) { fprintf(stderr, "\nsomething's wrong with your C library !!!\n"); exit(1); } if (l != len && !allow_eof) { fprintf(stderr, "\nread error - premature end of file\n"); exit(1); } total_in += (unsigned long)l; return l; } lzo_uint xwrite(FILE * fp, const lzo_voidp buf, lzo_uint len) { if (fp != NULL && lzo_fwrite(fp, buf, len) != len) { fprintf(stderr, "\nwrite error (disk full ?)\n"); exit(1); } total_out += (unsigned long)len; return len; } int xgetc(FILE * fp) { unsigned char c; xread(fp, (lzo_voidp) & c, 1, 0); return c; } void xputc(FILE * fp, int c) { unsigned char cc = (unsigned char)(c & 0xff); xwrite(fp, (const lzo_voidp)&cc, 1); } /* read and write portable 32-bit integers */ lzo_uint32 xread32(FILE * fp) { unsigned char b[4]; lzo_uint32 v; xread(fp, b, 4, 0); v = (lzo_uint32) b[3] << 0; v |= (lzo_uint32) b[2] << 8; v |= (lzo_uint32) b[1] << 16; v |= (lzo_uint32) b[0] << 24; return v; } void xwrite32(FILE * fp, lzo_xint v) { unsigned char b[4]; b[3] = (unsigned char)((v >> 0) & 0xff); b[2] = (unsigned char)((v >> 8) & 0xff); b[1] = (unsigned char)((v >> 16) & 0xff); b[0] = (unsigned char)((v >> 24) & 0xff); xwrite(fp, b, 4); } /************************************************************************* // compress // // possible improvement: we could use overlapping compression to // save some memory - see overlap.c. This would require some minor // changes in the decompression code as well, because if a block // turns out to be incompressible we would still have to store it in its // "compressed" (i.e. then slightly enlarged) form because the original // (uncompressed) data would have been lost during the overlapping // compression. **************************************************************************/ int do_compress(FILE * fi, FILE * fo, int level, lzo_uint block_size) { int r = 0; lzo_bytep in = NULL; lzo_bytep out = NULL; lzo_bytep wrkmem = NULL; lzo_uint in_len; lzo_uint out_len; lzo_uint32 wrk_len = 0; lzo_uint32 flags = 1; /* do compute a checksum */ int method = 1; /* compression method: LZO1X */ lzo_uint32 checksum; total_in = total_out = 0; /* * Step 1: write magic header, flags & block size, init checksum */ xwrite(fo, magic, sizeof(magic)); xwrite32(fo, fi_size); printf("Decompressed size : %d\n", fi_size); xwrite32(fo, flags); xputc(fo, method); /* compression method */ xputc(fo, level); /* compression level */ xwrite32(fo, block_size); checksum = lzo_adler32(0, NULL, 0); /* * Step 2: allocate compression buffers and work-memory */ in = (lzo_bytep) lzo_malloc(block_size); out = (lzo_bytep) lzo_malloc(block_size + block_size / 16 + 64 + 3); if (level == 9) wrk_len = LZO1X_999_MEM_COMPRESS; else wrk_len = LZO1X_1_MEM_COMPRESS; wrkmem = (lzo_bytep) lzo_malloc(wrk_len); if (in == NULL || out == NULL || wrkmem == NULL) { printf("out of memory\n"); r = 1; goto err; } /* * Step 3: process blocks */ for (;;) { /* read block */ in_len = xread(fi, in, block_size, 1); if (in_len <= 0) break; /* update checksum */ if (flags & 1) checksum = lzo_adler32(checksum, in, in_len); /* clear wrkmem (not needed, only for debug/benchmark purposes) */ if (opt_debug) lzo_memset(wrkmem, 0xff, wrk_len); /* compress block */ if (level == 9) r = lzo1x_999_compress(in, in_len, out, &out_len, wrkmem); else r = lzo1x_1_compress(in, in_len, out, &out_len, wrkmem); if (r != LZO_E_OK || out_len > in_len + in_len / 16 + 64 + 3) { /* this should NEVER happen */ printf("internal error - compression failed: %d\n", r); r = 2; goto err; } /* write uncompressed block size */ xwrite32(fo, in_len); if (out_len < in_len) { /* write compressed block */ xwrite32(fo, out_len); xwrite(fo, out, out_len); } else { /* not compressible - write uncompressed block */ xwrite32(fo, in_len); xwrite(fo, in, in_len); } } /* write EOF marker */ xwrite32(fo, 0); /* write checksum */ if (flags & 1) xwrite32(fo, checksum); r = 0; err:lzo_free(wrkmem); lzo_free(out); lzo_free(in); return r; } /************************************************************************* // decompress / test // // We are using overlapping (in-place) decompression to save some // memory - see overlap.c. **************************************************************************/ int do_decompress(FILE * fi, FILE * fo) { unsigned int r = 0; lzo_bytep buf = NULL; lzo_uint buf_len; unsigned char m[sizeof(magic)]; lzo_uint32 flags, UNUSED(decomp_size); int method; int level; lzo_uint block_size; lzo_uint32 checksum; total_in = total_out = 0; /* * Step 1: check magic header, read flags & block size, init checksum */ if (xread(fi, m, sizeof(magic), 1) != sizeof(magic) || memcmp(m, magic, sizeof(magic)) != 0) { //printf("header error - this file is not compressed by lzopack\n"); r = 1; goto err; } //decomp_size = xread32(fi); flags = xread32(fi); method = xgetc(fi); if (method != 1) { // check for different LZO header including version // TODO: convert this to structs with MFILE fseek(fi, -1, SEEK_CUR); uint32_t version = xread32(fi); if(version != 1){ header_error: printf("header error - invalid method %d (version: %d)\n", method, version); r = 2; goto err; } method = xgetc(fi); if(method != 1){ goto header_error; } } level = xgetc(fi); block_size = xread32(fi); if (block_size < 1024 || block_size > 8 * 1024 * 1024L) { printf("header error - invalid block size %ld\n", (long)block_size); r = 3; goto err; } checksum = lzo_adler32(0, NULL, 0); /* * Step 2: allocate buffer for in-place decompression */ buf_len = block_size + block_size / 16 + 64 + 3; buf = (lzo_bytep) lzo_malloc(buf_len); if (buf == NULL) { printf("out of memory\n"); r = 4; goto err; } /* * Step 3: process blocks */ for (;;) { lzo_bytep in; lzo_bytep out; lzo_uint in_len; lzo_uint out_len; /* read uncompressed size */ out_len = xread32(fi); /* exit if last block (EOF marker) */ if (out_len == 0) break; /* read compressed size */ in_len = xread32(fi); /* sanity check of the size values */ if (in_len > block_size || out_len > block_size || in_len == 0 || in_len > out_len) { printf("block size error - data corrupted\n"); r = 5; goto err; } /* place compressed block at the top of the buffer */ in = buf + buf_len - in_len; out = buf; /* read compressed block data */ xread(fi, in, in_len, 0); if (in_len < out_len) { /* decompress - use safe decompressor as data might be corrupted * during a file transfer */ lzo_uint new_len = out_len; r = lzo1x_decompress_safe(in, in_len, out, &new_len, NULL); if (r != LZO_E_OK || new_len != out_len) { printf("compressed data violation: %u\n", r); r = 6; goto err; } /* write decompressed block */ xwrite(fo, out, out_len); /* update checksum */ if (flags & 1) checksum = lzo_adler32(checksum, out, out_len); } else { /* write original (incompressible) block */ xwrite(fo, in, in_len); /* update checksum */ if (flags & 1) checksum = lzo_adler32(checksum, in, in_len); } } /* read and verify checksum */ if (flags & 1) { lzo_uint32 c = xread32(fi); if (c != checksum) { printf("checksum error - data corrupted\n"); r = 7; goto err; } } r = 0; err:lzo_free(buf); return r; } /************************************************************************* // **************************************************************************/ /* open input file */ static FILE *xopen_fi(const char *name) { FILE *fp; fp = fopen(name, "rb"); if (fp == NULL) { printf("cannot open input file %s\n", name); exit(1); } else { struct stat st; int is_regular = 1; if (stat(name, &st) != 0 || !S_ISREG(st.st_mode)) is_regular = 0; else fi_size = (lzo_uint32) st.st_size; if (!is_regular) { printf("%s is not a regular file\n", name); fclose(fp); fp = NULL; exit(1); } } return fp; } /* open output file */ static FILE *xopen_fo(const char *name) { FILE *fp; #if 0 /* this is an example program, so make sure we don't overwrite a file */ fp = fopen(name, "rb"); if (fp != NULL) { printf("%s: file %s already exists -- not overwritten\n", progname, name); fclose(fp); fp = NULL; exit(1); } #endif fp = fopen(name, "wb"); if (fp == NULL) { printf("cannot open output file %s\n", name); exit(1); } return fp; } /* close file */ static void xclose(FILE * fp) { if (fp) { int err; err = ferror(fp); if (fclose(fp) != 0) err = 1; if (err) { printf("error while closing file\n"); exit(1); } } } int check_lzo_header(const char *name) { FILE *fi = xopen_fi(name); unsigned char m[sizeof(magic)]; int result = (xread(fi, m, sizeof(magic), 1) != sizeof(magic) || memcmp(m, magic, sizeof(magic)) != 0); xclose(fi); return !result; } /************************************************************************* // **************************************************************************/ int __lzo_cdecl_main lzo_unpack(const char *in_name, const char *out_name) { int r = 0; FILE *fi = NULL; FILE *fo = NULL; lzo_uint UNUSED(opt_block_size); /* * Step 1: initialize the LZO library */ if (lzo_init() != LZO_E_OK) { printf("internal error - lzo_init() failed !!!\n"); printf("(this usually indicates a compiler bug - try recompiling\nwithout optimizations, and enable `-DLZO_DEBUG' for diagnostics)\n"); exit(1); } #if 0 /* * Step 2: setup memory */ opt_block_size = 256 * 1024L; #if defined(ACC_MM_AHSHIFT) /* reduce memory requirements for ancient 16-bit DOS 640kB real-mode */ if (ACC_MM_AHSHIFT != 3) opt_block_size = 16 * 1024L; #endif #endif /* * Step 4: process file(s) */ fi = xopen_fi(in_name); fo = xopen_fo(out_name); r = do_decompress(fi, fo); // if (r == 0) printf("decompressed %lu into %lu bytes\n", total_in, total_out); xclose(fi); fi = NULL; xclose(fo); fo = NULL; return r; } /* vi:ts=4:et */ ================================================ FILE: src/main.c ================================================ /** * Copyright 2016 Smx * Copyright 2016 lprot * Copyright 20?? sirius * All right reserved */ #include #include #include #include #include #include #include #include #include #ifdef __CYGWIN__ # include #endif #include "config.h" #include "mfile.h" #include "epk.h" #include "epk1.h" /* EPK v1 */ #include "epk2.h" /* EPK v2 */ #include "epk3.h" /* EPK v3 */ #include "cramfs/cramfs.h" /* CRAMFS */ #include "cramfs/cramfsswap.h" #include "lz4/lz4.h" /* LZ4 */ #include "lzo/lzo.h" /* LZO */ #include "lzhs/lzhs.h" /* LZHS */ #include "jffs2/jffs2.h" /* JFFS2 */ #include "squashfs/unsquashfs.h" /* SQUASHFS */ #include "minigzip.h" /* GZIP */ #include "symfile.h" /* SYM */ #include "stream/tsfile.h" /* STR and PIF */ #include "mediatek.h" /* MTK Boot */ #include "mediatek_pkg.h" /* MTK UPG */ #include "realtek.h" #include "philips.h" #include "u-boot/partinfo.h" /* PARTINFO */ #include "util.h" #ifdef __APPLE__ #include #endif static int print_usage(void); config_opts_t config_opts; int handle_file(char *file, config_opts_t *config_opts) { char *dest_dir = config_opts->dest_dir; char *file_name = my_basename(file); char *file_base = remove_ext(file_name); //const char *file_ext = get_ext(strdup(file_name)); char *dest_file = NULL; int result = EXIT_SUCCESS; MFILE *mf = NULL; if (isFileEPK1(file)) { if (config_opts->signatureOnly) { printf("EPK1 is not signed; nothing to do\n"); } else { extract_epk1_file(file, config_opts); } } else if (isFileEPK2(file) || isFileEPK3(file)) { extractEPKfile(file, config_opts); } else if (config_opts->signatureOnly) { /* none of the following file types have signatures */ printf("Only EPKs supported in signature-only mode\n"); result = EXIT_FAILURE; } else if((mf=is_mtk_pkg(file))){ extract_mtk_pkg(file, config_opts); } else if((mf=is_firm_image(file))){ extract_firm_image(mf); } else if((mf=is_philips_fusion1(file))){ extract_philips_fusion1(mf, config_opts); } else if((mf=is_lzhs_fs(file))){ asprintf(&dest_file, "%s/%s.ext4", dest_dir, file_name); extract_lzhs_fs(mf, dest_file, config_opts); /* LZ4 */ } else if ((mf=is_lz4(file))) { asprintf(&dest_file, "%s/%s.unlz4", dest_dir, file_name); printf("UnLZ4 file to: %s\n", dest_file); if (!LZ4_decode_file(file, dest_file)) handle_file(dest_file, config_opts); /* LZO */ } else if (check_lzo_header(file)) { if (!strcmp(file_name, "logo.pak")) asprintf(&dest_file, "%s/%s.bmp", dest_dir, file_name); else asprintf(&dest_file, "%s/%s.unlzo", dest_dir, file_name); printf("UnLZO file to: %s\n", dest_file); if (!lzo_unpack(file, dest_file)) handle_file(dest_file, config_opts); /* NFSB */ } else if ((mf=is_nfsb(file))) { asprintf(&dest_file, "%s/%s.unnfsb", dest_dir, file_name); printf("UnNFSB file to: %s\n", dest_file); unnfsb(file, dest_file); handle_file(dest_file, config_opts); /* SQUASHFS */ } else if (is_squashfs(file)) { if (!config_opts->noAutoUnsquashfs) { asprintf(&dest_file, "%s/%s.unsquashfs", dest_dir, file_name); printf("UnSQUASHFS file to: %s\n", dest_file); rmrf(dest_file); unsquashfs(file, dest_file); } else { puts("Not UnSQUASHFSing"); } /* GZIP */ } else if ((mf=is_gzip(file))) { asprintf(&dest_file, "%s/", dest_dir); printf("UnGZIP %s to folder %s\n", file, dest_file); char *gz_name = file_uncompress_origname(file, dest_file); handle_file(gz_name, config_opts); free(gz_name); /* MTK boot partition */ } else if ((mf=is_mtk_boot(file))) { asprintf(&dest_file, "%s/mtk_1bl.bin", dest_dir); printf("[MTK] Extracting 1BL to mtk_1bl.bin...\n"); extract_mtk_1bl(mf, dest_file); printf("[MTK] Extracting embedded LZHS files...\n"); extract_lzhs(mf); /* Realtek BSPFW partition */ } else if ((mf=is_rtk_bspfw(file))) { printf("[RTK] Splitting bspfw.pak...\n"); split_rtk_bspfw(mf, dest_dir); /* CRAMFS Big Endian */ } else if (is_cramfs_image(file, "be")) { asprintf(&dest_file, "%s/%s.cramswap", dest_dir, file_name); printf("Swapping cramfs endian for file %s\n", file); cramswap(file, dest_file); handle_file(dest_file, config_opts); /* CRAMFS Little Endian */ } else if (is_cramfs_image(file, "le")) { asprintf(&dest_file, "%s/%s.uncramfs", dest_dir, file_name); printf("UnCRAMFS %s to folder %s\n", file, dest_file); rmrf(dest_file); uncramfs(dest_file, file); /* Kernel uImage */ } else if (is_kernel(file)) { asprintf(&dest_file, "%s/%s.unpaked", dest_dir, file_name); printf("Extracting boot image (kernel) to: %s\n", dest_file); extract_kernel(file, dest_file); handle_file(dest_file, config_opts); /* Partition Table (partinfo) */ } else if (isPartPakfile(file)) { asprintf(&dest_file, "%s/%s.txt", dest_dir, file_base); printf("Saving partition info to: %s\n", dest_file); dump_partinfo(file, dest_file); /* JFFS2 */ } else if (is_jffs2(file)) { asprintf(&dest_file, "%s/%s.unjffs2", dest_dir, file_name); printf("UnJFFS2 file %s to folder %s\n", file, dest_file); rmrf(dest_file); struct jffs2_main_args args = { .erase_size = -1, .keep_unlinked = false, .verbose = 0 }; jffs2extract(file, dest_file, args); /* PVR STR (ts/m2ts video) */ } else if (isSTRfile(file)) { asprintf(&dest_file, "%s/%s.ts", dest_dir, file_name); printf("\nConverting %s file to TS\n", file); struct tsfile_options opts = { .video_stream_type = -1, .audio_stream_type = -1, .append = 0 }; convertSTR2TS(file, &opts); /* PVR PIF (Program Information File) */ } else if (!strncasecmp(&file[strlen(file) - 3], "PIF", 3)) { asprintf(&dest_file, "%s/%s.ts", dest_dir, file_name); printf("\nProcessing PIF file: %s\n", file); processPIF(file, dest_file); /* SYM File (Debugging information) */ } else if (symfile_load(file) == 0) { asprintf(&dest_file, "%s/%s.idc", dest_dir, file_name); printf("Converting SYM file to IDC script: %s\n", dest_file); symfile_write_idc(dest_file); /* MTK LZHS (Modified LZSS + Huffman) */ } else if ((mf=is_lzhs(file))) { asprintf(&dest_file, "%s/%s.unlzhs", dest_dir, file_name); printf("UnLZHS %s to %s\n", file, dest_file); lzhs_decode(mf, 0, dest_file, NULL); /* MTK TZFW (TrustZone Firmware) */ } else if (!strcmp(file_name, "tzfw.pak") && (mf=is_elf(file))) { printf("Splitting mtk tzfw...\n"); split_mtk_tz(mf, dest_dir); } else { result = EXIT_FAILURE; } if(mf != NULL) mclose(mf); free(file_name); free(file_base); if(dest_file != NULL) free(dest_file); return result; } int main(int argc, char *argv[]) { printf("\nLG Electronics digital TV firmware package (EPK) extractor version 4.8 (http://openlgtv.org.ru)\n\n"); if (argc < 2) { return print_usage(); } char *exe_dir = calloc(1, PATH_MAX); char *current_dir = calloc(1, PATH_MAX); #ifdef __APPLE__ uint32_t pathsz = PATH_MAX; if (_NSGetExecutablePath(exe_dir, &pathsz) == 0){ printf("Executable path is %s\n", exe_dir); } else { printf("Buffer too small; need size %u\n", PATH_MAX); return EXIT_FAILURE; } config_opts.config_dir = my_dirname(exe_dir); #else getcwd(current_dir, PATH_MAX); printf("Current directory: %s\n", current_dir); readlink("/proc/self/exe", exe_dir, PATH_MAX); #endif config_opts.config_dir = my_dirname(exe_dir); config_opts.dest_dir = calloc(1, PATH_MAX); config_opts.enableSignatureChecking = 0; config_opts.noAutoUnsquashfs = false; config_opts.signatureOnly = false; int opt; while ((opt = getopt(argc, argv, "csnS")) != -1) { switch (opt) { case 's':{ config_opts.enableSignatureChecking = 1; break; } case 'c':{ strcpy(config_opts.dest_dir, current_dir); break; } case 'n':{ config_opts.noAutoUnsquashfs = true; break; } case 'S':{ config_opts.signatureOnly = true; config_opts.enableSignatureChecking = 1; break; } case ':':{ printf("Option `%c' needs a value\n\n", optopt); exit(1); break; } case '?':{ printf("Unknown option: `%c'\n\n", optopt); return 1; } } } if (optind == argc) { /* no non-option args */ return print_usage(); } #ifdef __CYGWIN__ char posix[PATH_MAX]; cygwin_conv_path(CCP_WIN_A_TO_POSIX, argv[optind], posix, PATH_MAX); char *input_file = posix; #else char *input_file = argv[optind]; #endif printf("Input file: %s\n", input_file); char *dname = NULL; if (strlen(config_opts.dest_dir) == 0){ dname = my_dirname(input_file); strcpy(config_opts.dest_dir, dname); } if (strlen(config_opts.dest_dir) == 0 && config_opts.dest_dir[0] == '.'){ dname = my_dirname(exe_dir); strcpy(config_opts.dest_dir, dname); } free(dname); printf("Destination directory: %s\n", config_opts.dest_dir); free(exe_dir); free(current_dir); int exit_code = handle_file(input_file, &config_opts); if (exit_code == EXIT_FAILURE) { return err_ret("Unsupported input file format: %s\n\n", input_file); } (void) err_ret("\nExtraction is finished.\n\n"); return EXIT_SUCCESS; } static int print_usage(void) { printf("Usage: epk2extract [-options] FILENAME\n\n"); printf("Options:\n"); printf(" -c : extract to current directory instead of source file directory\n"); printf(" -s : enable signature checking for EPK files\n"); printf(" -S : only check signature (implies -s)\n"); printf(" -n : no automatic unsquashfs\n\n"); return err_ret(NULL); } ================================================ FILE: src/mediatek.c ================================================ /** * Mediatek bootloader handling * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include "mfile.h" #include "mediatek.h" #include "util.h" //lzhs //#include "lzhs/lzhs.h" //boot and tzfw #include void extract_mtk_1bl(MFILE *in, const char *outname) { MFILE *out = mfopen(outname, "w+"); if (out == NULL){ err_exit("Can't open file %s for writing (%s)\n", outname, strerror(errno)); } size_t pbl_size = 0; uint8_t *data = mdata(in, uint8_t); if(memcmp(data + 0x100, MTK_PBL_MAGIC, strlen(MTK_PBL_MAGIC)) == 0) pbl_size = MTK_PBL_SIZE; else if(memcmp(data + 0x100, MTK_ROM_MAGIC, strlen(MTK_ROM_MAGIC)) == 0) pbl_size = MTK_ROM_SIZE; else err_exit("Cannot detect PBL size\n"); printf("[MTK] PBL Size: 0x%08X\n", pbl_size); mfile_map(out, pbl_size); memcpy( mdata(out, uint8_t), mdata(in, uint8_t), pbl_size ); mclose(out); } void split_mtk_tz(MFILE *tz, const char *destdir) { size_t tz_size; char *dest; asprintf(&dest, "%s/env.o", destdir); MFILE *out = mfopen(dest, "w+"); if (out == NULL) err_exit("Can't open file %s for writing\n", dest); tz_size = msize(tz) - MTK_ENV_SIZE; printf("Extracting env.o... (%d bytes)\n", MTK_ENV_SIZE); uint8_t *data = mdata(tz, uint8_t); mfile_map(out, MTK_ENV_SIZE); memcpy(mdata(out, void), data, MTK_ENV_SIZE); free(dest); mclose(out); asprintf(&dest, "%s/tz.bin", destdir); out = mfopen(dest, "w+"); if (out == NULL) err_exit("Can't open file %s for writing\n", dest); mfile_map(out, tz_size); printf("Extracting tz.bin... (%zu bytes)\n", tz_size); memcpy(mdata(out, void), data + MTK_ENV_SIZE, tz_size); free(dest); mclose(out); } MFILE *is_mtk_boot(const char *filename) { MFILE *file = mopen(filename, O_RDONLY); uint8_t *data = mdata(file, uint8_t); if (file == NULL) { err_exit("Can't open file %s\n", filename); } if ( (msize(file) >= MTK_PBL_SIZE) && (memcmp(data + 0x100, MTK_PBL_MAGIC, strlen(MTK_PBL_MAGIC)) == 0) ){ printf("Found valid PBL magic: "MTK_PBL_MAGIC"\n"); } else if ( (msize(file) >= MTK_ROM_SIZE) && (memcmp(data + 0x100, MTK_ROM_MAGIC, strlen(MTK_ROM_MAGIC)) == 0) ){ printf("Found valid PBL/ROM magic: "MTK_ROM_MAGIC"\n"); } else { mclose(file); return NULL; } return file; } int is_elf_mem(Elf32_Ehdr * header) { if (!memcmp(&header->e_ident, ELFMAG, 4)) return 1; return 0; } MFILE *is_elf(const char *filename) { MFILE *file = mopen(filename, O_RDONLY); if (file == NULL) { err_exit("Can't open file %s\n", filename); } Elf32_Ehdr *elfHdr = mdata(file, Elf32_Ehdr); if (!memcmp(&(elfHdr->e_ident), ELFMAG, 4)) return file; mclose(file); return NULL; } ================================================ FILE: src/mediatek_pkg.c ================================================ /** * Mediatek PKG Handling * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include "main.h" //for handle_file #include "mfile.h" #include "mediatek_pkg.h" #include "lzhs/lzhs.h" #include "util.h" #include "util_crypto.h" #include "thpool.h" enum mtkpkg_variant { OLD = 1 << 0, NEW = 1 << 1, THOMPSON = 1 << 2, PHILIPS = 1 << 3, SHARP = 1 << 4 }; #define SIZEOF_THOMPSON_HEADER 0x170 #define SIZEOF_OLD_HEADER 0x98 static int mtkpkg_variant_flags = NEW; static struct mtkupg_header packageHeader; static bool was_decrypted = false; int compare_pkg_header(uint8_t *header, size_t headerSize){ struct mtkupg_header *hdr = (struct mtkupg_header *)header; if( !strncmp(hdr->vendor_magic, HISENSE_PKG_MAGIC, strlen(HISENSE_PKG_MAGIC)) ){ printf("[+] Found HISENSE Package\n"); return 1; } if( !strncmp(hdr->vendor_magic, SHARP_PKG_MAGIC, strlen(SHARP_PKG_MAGIC)) ){ printf("[+] Found SHARP Package\n"); mtkpkg_variant_flags |= SHARP; return 1; } if( !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC, strlen(TPV_PKG_MAGIC)) || !strncmp(hdr->vendor_magic, TPV_PKG_MAGIC2,strlen(TPV_PKG_MAGIC2)) ){ printf("[+] Found PHILIPS(TPV) Package\n"); return 1; } if( !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC, strlen(PHILIPS_PKG_MAGIC)) || !strncmp(hdr->vendor_magic, PHILIPS_PKG_MAGIC2, strlen(PHILIPS_PKG_MAGIC2)) ){ printf("[+] Found PHILIPS Package\n"); return 1; } if( !strncmp(hdr->mtk_magic, MTK_FIRMWARE_MAGIC, strlen(MTK_FIRMWARE_MAGIC)) ){ printf("[+] Found UNKNOWN Package (Magic: '%.*s')\n", member_size(struct mtkupg_header, vendor_magic), hdr->vendor_magic ); return 1; } return 0; } int compare_content_header(uint8_t *header, size_t headerSize){ struct mtkpkg_data *data = (struct mtkpkg_data *)header; if ( !strncmp(data->header.mtk_reserved, MTK_RESERVED_MAGIC, strlen(MTK_RESERVED_MAGIC)) ){ return 1; } return 0; } bool is_known_partition(struct mtkpkg *pak){ const char *likelyPartitionNames[] = { "cfig", "ixml", "tzbp", NULL }; const char **curPartName = likelyPartitionNames; for(int nameIndex=0; *curPartName != NULL; nameIndex++){ if(!strncmp(pak->header.pakName, *curPartName, sizeof(pak->header.pakName))){ return true; } curPartName++; } return false; } MFILE *is_mtk_pkg(const char *pkgfile){ setKeyFile_MTK(); MFILE *mf = mopen(pkgfile, O_RDONLY); if(!mf){ err_exit("Cannot open file %s\n", pkgfile); } uint8_t *data = mdata(mf, uint8_t); void *decryptedHeader = NULL; KeyPair *headerKey = NULL; do { if((headerKey = find_AES_key(data, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){ break; } /* It failed, but we want to check for Philips. * Philips has an additional 0x80 header before the normal PKG one */ if((headerKey = find_AES_key(data + PHILIPS_HEADER_SIZE, UPG_HEADER_SIZE, compare_pkg_header, KEY_CBC, (void **)&decryptedHeader, 0)) != NULL){ mtkpkg_variant_flags |= PHILIPS; } } while(0); if(headerKey != NULL){ was_decrypted = true; memcpy(&packageHeader, decryptedHeader, sizeof(packageHeader)); free(headerKey); return mf; } /* No AES key found to decrypt the header. Try to check if it's a MTK PKG anyways * This method can return false for valid packages as the order of partitions isn't fixed */ /* First pak doesn't have extended fields */ struct mtkpkg *firstPak = (struct mtkpkg *)(data + sizeof(struct mtkupg_header)); if(is_known_partition(firstPak)) return mf; firstPak = (struct mtkpkg *)(data + SIZEOF_OLD_HEADER); if(is_known_partition(firstPak)){ mtkpkg_variant_flags = OLD; return mf; } firstPak = (struct mtkpkg *)(data + SIZEOF_OLD_HEADER + PHILIPS_HEADER_SIZE); if(is_known_partition(firstPak)){ mtkpkg_variant_flags = OLD | PHILIPS; return mf; } firstPak = (struct mtkpkg *)(data + SIZEOF_THOMPSON_HEADER); if(is_known_partition(firstPak)){ mtkpkg_variant_flags = NEW | THOMPSON; return mf; } mclose(mf); return NULL; } #define SIZEOF_FIRM_HEADERS 0x90 MFILE *is_firm_image(const char *pkg){ MFILE *mf = mopen(pkg, O_RDONLY); if(!mf){ err_exit("Cannot open file %s\n", pkg); } if(msize(mf) < (SIZEOF_FIRM_HEADERS + 16)){ mclose(mf); return NULL; } if(is_lzhs_mem(mf, SIZEOF_FIRM_HEADERS)){ return mf; } mclose(mf); return NULL; } int extract_firm_image(MFILE *mf){ return process_lzhs_segment(mf, SIZEOF_FIRM_HEADERS, "firm"); } MFILE *is_lzhs_fs(const char *pkg){ MFILE *mf = mopen(pkg, O_RDONLY); if(!mf){ err_exit("Cannot open file %s\n", pkg); } uint8_t *data = mdata(mf, uint8_t); off_t start = MTK_EXT_LZHS_OFFSET; if(is_nfsb_mem(mf, SHARP_PKG_HEADER_SIZE)){ start += SHARP_PKG_HEADER_SIZE; } if(msize(mf) < (start + sizeof(struct lzhs_header))){ goto fail; } if( is_lzhs_mem(mf, start) && is_lzhs_mem(mf, start + sizeof(struct lzhs_header)) && // First LZHS header contains number of segment in checksum. Make sure that it is the first segment ((struct lzhs_header *)&data[start])->checksum == 1 ){ return mf; } fail: mclose(mf); return NULL; } /* Arguments passed to the thread function */ struct thread_arg { MFILE *mf; off_t offset; char *filename; uint blockNo; }; void process_block(struct thread_arg *arg){ printf("[+] Extracting %u...\n", arg->blockNo); uint8_t out_checksum = 0x00; cursor_t *out_cur = lzhs_decode(arg->mf, arg->offset, NULL, &out_checksum); if(out_cur == NULL || (intptr_t)out_cur < 0){ err_exit("LZHS decode failed\n"); } MFILE *out = mfopen(arg->filename, "w+"); if(!out){ err_exit("mfopen failed for file '%s'\n", arg->filename); } mfile_map(out, out_cur->size); memcpy( mdata(out, void), out_cur->ptr, out_cur->size ); mclose(out); munmap(out_cur->ptr, out_cur->size); free(out_cur); free(arg->filename); free(arg); } /* * Hisense (or Mediatek?) uses an ext4 filesystem splitted in chunks, compressed with LZHS * They use 2 LZHS header for each chunk * The first header contains the chunk number, and the compressed size includes the outer lzhs header (+16) * The second header contains the actual data */ void extract_lzhs_fs(MFILE *mf, const char *dest_file, config_opts_t *config_opts){ int is_sharp = 0; uint8_t *data = mdata(mf, uint8_t); if(is_nfsb_mem(mf, SHARP_PKG_HEADER_SIZE)){ data += SHARP_PKG_HEADER_SIZE; is_sharp = 1; } FILE *out_file = fopen(dest_file, "w+"); if(!out_file){ err_exit("Cannot open %s for writing\n", dest_file); } char *dir = my_dirname(dest_file); char *file = my_basename(dest_file); char *base = remove_ext(file); char *tmpdir; asprintf(&tmpdir, "%s/tmp", dir); createFolder(tmpdir); printf("Copying 0x%08X bytes\n", MTK_EXT_LZHS_OFFSET); /* Copy first MB as-is (uncompressed) */ fwrite ( data, MTK_EXT_LZHS_OFFSET, 1, out_file ); data += MTK_EXT_LZHS_OFFSET; int nThreads = sysconf(_SC_NPROCESSORS_ONLN); printf("[+] Max threads: %d\n", nThreads); threadpool thpool = thpool_init(nThreads); uint segNo = 0; while(moff(mf, data) < msize(mf)){ struct lzhs_header *main_hdr = (struct lzhs_header *)data; struct lzhs_header *seg_hdr = (struct lzhs_header *)(data + sizeof(*main_hdr)); printf("\n[0x%08X] segment #%u (compressed='%u bytes', uncompressed='%u bytes')\n", moff(mf, main_hdr), main_hdr->checksum, seg_hdr->compressedSize, seg_hdr->uncompressedSize); char *outSeg; asprintf(&outSeg, "%s/%s.%d", tmpdir, base, (segNo++) + 1); struct thread_arg *arg = calloc(1, sizeof(struct thread_arg)); arg->mf = mf; arg->offset = moff(mf, seg_hdr); arg->filename = outSeg; arg->blockNo = main_hdr->checksum; thpool_add_work(thpool, (void *)process_block, arg); uint pad; pad = (pad = (seg_hdr->compressedSize % 16)) == 0 ? 0 : (16 - pad); data += ( sizeof(*main_hdr) + sizeof(*seg_hdr) + seg_hdr->compressedSize + pad ); } thpool_wait(thpool); thpool_destroy(thpool); uint i; for(i=1; i<=segNo; i++){ printf("[+] Joining Segment %u\n", i); char *outSeg; asprintf(&outSeg, "%s/%s.%u", tmpdir, base, i); MFILE *seg = mopen(outSeg, O_RDONLY); if(seg) { fwrite(mdata(seg, void), msize(seg), 1, out_file); mclose(seg); } else { printf("A package wasn't written to disk because of a memory allocation failure\n"); } unlink(outSeg); free(outSeg); } rmrf(tmpdir); free(tmpdir); fclose(out_file); free(dir); free(file); free(base); if(is_sharp){ handle_file(dest_file, config_opts); } } void print_pkg_header(struct mtkupg_header *hdr){ hexdump(hdr, sizeof(*hdr)); printf("======== Firmware Info ========\n"); printf("| Product Name: %s\n", hdr->product_name); printf("| Firmware ID : %.*s\n", member_size(struct mtkupg_header, vendor_magic) + member_size(struct mtkupg_header, mtk_magic) + member_size(struct mtkupg_header, vendor_info), hdr->vendor_magic ); printf("| File Size: %u bytes\n", hdr->fileSize); printf("| Platform Type: 0x%02X\n", hdr->platform); printf("======== Firmware Info ========\n"); } static off_t get_mtkpkg_offset(){ if((mtkpkg_variant_flags & THOMPSON) == THOMPSON){ return SIZEOF_THOMPSON_HEADER; } off_t offset = 0; if((mtkpkg_variant_flags & NEW) == NEW){ offset += sizeof(struct mtkupg_header); } else if((mtkpkg_variant_flags & OLD) == OLD){ offset += SIZEOF_OLD_HEADER; } if((mtkpkg_variant_flags & PHILIPS) == PHILIPS){ offset += PHILIPS_HEADER_SIZE; } return offset; } void extract_mtk_pkg(const char *pkgFile, config_opts_t *config_opts){ MFILE *mf = mopen_private(pkgFile, O_RDONLY); mprotect(mf->pMem, msize(mf), PROT_READ | PROT_WRITE); off_t offset = get_mtkpkg_offset(); uint8_t *data = mdata(mf, uint8_t) + offset; char *file_name = my_basename(mf->path); char *file_base = remove_ext(file_name); struct mtkupg_header *hdr = (was_decrypted) ? &packageHeader : NULL; if(hdr != NULL) print_pkg_header(hdr); if(hdr != NULL){ // Use product name for now (version would be better) asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, hdr->product_name); } else { asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, file_base); } createFolder(config_opts->dest_dir); KeyPair *dataKey = NULL; int pakNo; for(pakNo=0; moff(mf, data) < msize(mf); pakNo++){ struct mtkpkg *pak = (struct mtkpkg *)data; if((mtkpkg_variant_flags & PHILIPS) == PHILIPS && moff(mf, data) + PHILIPS_SIGNATURE_SIZE == msize(mf)){ printf("-- RSA 2048 Signature --\n"); hexdump(data, PHILIPS_SIGNATURE_SIZE); //Philips RSA-2048 signature break; } size_t cryptedHeaderSize = ((mtkpkg_variant_flags & NEW) == NEW) ? sizeof(pak->content.header) : 0; /* Skip pak header and crypted header */ data += sizeof(pak->header) + cryptedHeaderSize; uint8_t *pkgData = (uint8_t *)&(pak->content.header); size_t dataSize = sizeof(pak->content.header); size_t pkgSize = pak->header.pakSize; if(pkgSize == 0){ goto save_file; } if((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED){ dataSize += pak->header.pakSize; } #pragma region FindAesKey uint8_t *decryptedPkgData = NULL; if(was_decrypted){ if(dataKey == NULL){ dataKey = find_AES_key( pkgData, dataSize, compare_content_header, KEY_CBC, (void **)&decryptedPkgData, 1 ); int success = dataKey != NULL; if(success){ /* Copy decrypted data */ memcpy(pkgData, decryptedPkgData, dataSize); free(decryptedPkgData); } else if(was_decrypted) { /* Try to decrypt by using vendorMagic repeated 4 times, ivec 0 */ do { AES_KEY aesKey; uint8_t keybuf[16]; uint i; for(i=0; i<4; i++){ memcpy(&keybuf[4 * i], hdr->vendor_magic, sizeof(uint32_t)); } AES_set_decrypt_key((uint8_t *)&keybuf, 128, &aesKey); dataKey = calloc(1, sizeof(KeyPair)); //also fills ivec with zeros memcpy(&(dataKey->key), &aesKey, sizeof(aesKey)); uint8_t iv_tmp[16]; memcpy(&iv_tmp, &(dataKey->ivec), sizeof(iv_tmp)); AES_cbc_encrypt( pkgData, pkgData, dataSize, &(dataKey->key), (void *)&iv_tmp, AES_DECRYPT ); success = compare_content_header(pkgData, sizeof(struct mtkpkg_data)); } while(0); } if(!success){ if((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED){ printf("[-] Couldn't decrypt data!\n"); } else { printf("[-] Couldn't decrypt header!\n"); } } } else { #pragma endregion uint8_t iv_tmp[16]; memcpy(&iv_tmp, &(dataKey->ivec), sizeof(iv_tmp)); AES_cbc_encrypt( pkgData, pkgData, dataSize, &(dataKey->key), (void *)&iv_tmp, AES_DECRYPT ); int success = compare_content_header(pkgData, sizeof(struct mtkpkg_data)); if(!success){ fprintf(stderr, "[!] WARNING: MTK Crypted header not found, continuing anyways...\n"); } } } if((mtkpkg_variant_flags & NEW) == NEW){ // Skip the mtk header (reserved inc) pkgData += sizeof(struct mtkpkg_crypted_header); } printf("\nPAK #%u %s (name='%s', offset='0x%lx', size='%u bytes'", pakNo + 1, ((pak->header.flags & PAK_FLAG_ENCRYPTED) == PAK_FLAG_ENCRYPTED) ? "[ENCRYPTED]" : "", pak->header.pakName, moff(mf, data), pak->header.pakSize ); struct mtkpkg_plat *ext = (struct mtkpkg_plat *)pkgData; /* Parse the fields at the start of pkgData, and skip them */ if(!strncmp(ext->platform, MTK_PAK_MAGIC, strlen(MTK_PAK_MAGIC))){ uint8_t *extData = (uint8_t *)&(ext->otaID_len); /* otaID is optional. if we have it, it's preceded by its length. If we don't have it, we have the iPAD magic instead */ int has_otaID = strncmp(extData, MTK_PAD_MAGIC, strlen(MTK_PAD_MAGIC)) != 0; if(has_otaID){ printf(", platform='%s', otaid='%s'", ext->platform, ext->otaID); if(pakNo == 1 && hdr == NULL){ asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, ext->otaID); createFolder(config_opts->dest_dir); } } else if(pakNo == 1 && hdr == NULL){ asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, file_base); createFolder(config_opts->dest_dir); } /* Skip the headers to get to the data */ uint skip = sizeof(*ext); if(has_otaID){ skip += ext->otaID_len; } if(skip < MTK_EXTHDR_SIZE){ skip += (MTK_EXTHDR_SIZE - skip); } pkgData += skip; pkgSize -= skip; } save_file: printf(")\n"); char *dest_path = NULL; asprintf(&dest_path, "%s/%.*s.pak", config_opts->dest_dir, member_size(struct mtkpkg_header, pakName), pak->header.pakName ); MFILE *out = mfopen(dest_path, "w+"); if(!out){ err_exit("Cannot open %s for writing\n", dest_path); } printf("Saving partition (%s) to file %s\n\n", pak->header.pakName, dest_path); if(pkgSize == 0) goto saved_file; mfile_map(out, pkgSize); mwrite(pkgData, pkgSize, 1, out); saved_file: mclose(out); if(dest_path != NULL && pkgSize != 0){ handle_file(dest_path, config_opts); } if(dest_path != NULL){ free(dest_path); } data += pak->header.pakSize; } if(dataKey != NULL){ free(dataKey); } free(file_name); free(file_base); mclose(mf); } ================================================ FILE: src/mfile.c ================================================ /** * mmap file wrapper * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include #include #include #include #include "mfile.h" #include "common.h" #include "util.h" #define PERMS_DEFAULT (mode_t)0666 /* * Creates a new mfile structure */ inline MFILE *mfile_new(){ MFILE *mem = calloc(1, sizeof(MFILE)); return mem; } /* * Updates size and path to a file */ int _mfile_update_info(MFILE *file, const char *path){ if(path){ if(file->path) free(file->path); file->path = strdup(path); } if(stat(file->path, &(file->statBuf)) < 0) return -1; return 0; } void mfile_flush(void *mem, size_t length){ msync(mem, length, MS_INVALIDATE); //madvise(mem, length, MADV_REMOVE); } /* * Wrapper to mmap */ void *_mfile_map(MFILE *file, size_t mapSize, int mapFlags){ if(msize(file) < mapSize){ lseek(file->fd, mapSize-1, SEEK_SET); uint8_t buf = 0x00; write(file->fd, &buf, 1); lseek(file->fd, 0, SEEK_SET); _mfile_update_info(file, NULL); } file->pMem = mmap(0, mapSize, file->prot, mapFlags, file->fd, 0); if(file->pMem == MAP_FAILED){ err_exit("mmap failed: %s (%d)\n", strerror(errno), errno); return NULL; } // enable read ahead and trash previously read pages madvise(file->pMem, mapSize, MADV_SEQUENTIAL); return file->pMem; } inline void *mfile_map(MFILE *file, size_t mapSize){ return _mfile_map(file, mapSize, MAP_SHARED); } inline void *mfile_map_private(MFILE *file, size_t mapSize){ return _mfile_map(file, mapSize, MAP_PRIVATE); } /* * Opens and maps a file with open */ MFILE *_mopen(const char *path, int oflags, int mapFlags){ MFILE *file = mfile_new(); file->fd = open(path, oflags, PERMS_DEFAULT); if(file->fd < 0){ goto e0_ret; } if(_mfile_update_info(file, path) < 0) goto e1_ret; if((oflags & O_ACCMODE) == O_RDONLY) { file->prot = PROT_READ; } else if((oflags & O_ACCMODE) == O_WRONLY) { file->prot = PROT_WRITE; } else if((oflags & O_ACCMODE) == O_RDWR) { file->prot = PROT_READ | PROT_WRITE; } size_t fileSz = msize(file); if(fileSz > 0){ if(_mfile_map(file, fileSz, mapFlags) == MAP_FAILED){ goto e1_ret; } } return file; e1_ret: close(file->fd); e0_ret: if(file->path) free(file->path); free(file); return NULL; } inline MFILE *mopen(const char *path, int oflags){ return _mopen(path, oflags, MAP_SHARED); } inline MFILE *mopen_private(const char *path, int oflags){ return _mopen(path, oflags, MAP_PRIVATE); } int mgetc(MFILE *stream){ if(UNLIKELY(stream->offset >= msize(stream))) return EOF; return (unsigned int)(*(&((uint8_t *)(stream->pMem))[stream->offset++])); } int mputc(int c, MFILE *stream){ if(UNLIKELY(stream->offset >= msize(stream))) return EOF; ((uint8_t *)(stream->pMem))[stream->offset] = (uint8_t)c; stream->offset++; return c; } inline int cgetc(cursor_t *stream){ if(UNLIKELY(stream->offset >= stream->size)) return EOF; return (unsigned int)( *(&( ((unsigned char *)(stream->ptr))[stream->offset++] )) ); } int cputc(int c, cursor_t *stream){ if(UNLIKELY(stream->offset >= stream->size)) return EOF; ((unsigned char *)(stream->ptr))[stream->offset++] = (unsigned char)c; return c; } /* * Closes an opened file and frees the structure */ int mclose(MFILE *mfile){ if(!mfile || mfile->fd < 0 || !mfile->pMem || mfile->statBuf.st_size <= 0) return -1; if(munmap(mfile->pMem, mfile->statBuf.st_size) < 0) return -2; free(mfile->path); if(mfile->fh != NULL){ fclose(mfile->fh); mfile->fd = 0; } else { close(mfile->fd); } free(mfile); mfile = NULL; return 0; } /* * Opens and maps a file with fopen */ MFILE *_mfopen(const char *path, const char *mode, int mapFlags){ MFILE *file = mfile_new(); file->fh = fopen(path, mode); if(file->fh == NULL){ goto e0_ret; } file->fd = fileno(file->fh); if(_mfile_update_info(file, path) < 0) goto e1_ret; if(strstr(mode, "r") != NULL || strstr(mode, "+") != NULL){ file->prot |= PROT_READ; } if(strstr(mode, "w") != NULL){ file->prot |= PROT_WRITE; } size_t fileSz = msize(file); if(fileSz > 0){ if(_mfile_map(file, fileSz, mapFlags) == MAP_FAILED){ goto e1_ret; } } return file; e1_ret: fclose(file->fh); e0_ret: free(file); return NULL; } inline MFILE *mfopen(const char *path, const char *mode){ return _mfopen(path, mode, MAP_SHARED); } inline MFILE *mfopen_private(const char *path, const char *mode){ return _mfopen(path, mode, MAP_PRIVATE); } ================================================ FILE: src/minigzip.c ================================================ /* minigzip.c -- simulate gzip using the zlib compression library * Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* * minigzip is a minimal implementation of the gzip utility. This is * only an example of using zlib and isn't meant to replace the * full-featured gzip. No attempt is made to deal with file systems * limiting names to 14 or 8+3 characters, etc... Error checking is * very limited. So use minigzip only for testing; use gzip for the * real thing. On MSDOS, use only on file names without extension * or in pipe mode. */ /* @(#) $Id$ */ #include "zlib.h" #include #ifdef STDC # include # include #endif #ifdef USE_MMAP # include # include # include #endif #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) # include # include # ifdef UNDER_CE # include # endif # define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) #else # define SET_BINARY_MODE(file) #endif #ifdef _MSC_VER # define snprintf _snprintf #endif #ifdef VMS # define unlink delete # define GZ_SUFFIX "-gz" #endif #ifdef RISCOS # define unlink remove # define GZ_SUFFIX "-gz" # define fileno(file) file->__file #endif #if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fileno */ #endif #if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) #ifndef WIN32 /* unlink already in stdio.h for WIN32 */ extern int unlink OF((const char *)); #endif #endif #if defined(UNDER_CE) # include # define perror(s) pwinerror(s) /* Map the Windows error number in ERROR to a locale-dependent error message string and return a pointer to it. Typically, the values for ERROR come from GetLastError. The string pointed to shall not be modified by the application, but may be overwritten by a subsequent call to strwinerror The strwinerror function does not change the current setting of GetLastError. */ static char *strwinerror (error) DWORD error; { static char buf[1024]; wchar_t *msgbuf; DWORD lasterr = GetLastError(); DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, error, 0, /* Default language */ (LPVOID)&msgbuf, 0, NULL); if (chars != 0) { /* If there is an \r\n appended, zap it. */ if (chars >= 2 && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { chars -= 2; msgbuf[chars] = 0; } if (chars > sizeof (buf) - 1) { chars = sizeof (buf) - 1; msgbuf[chars] = 0; } wcstombs(buf, msgbuf, chars + 1); LocalFree(msgbuf); } else { sprintf(buf, "unknown win32 error (%ld)", error); } SetLastError(lasterr); return buf; } static void pwinerror (s) const char *s; { if (s && *s) fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); else fprintf(stderr, "%s\n", strwinerror(GetLastError ())); } #endif /* UNDER_CE */ #ifndef GZ_SUFFIX # define GZ_SUFFIX ".gz" #endif #define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) #define BUFLEN 16384 #define MAX_NAME_LEN 1024 #ifdef MAXSEG_64K # define local static /* Needed for systems with limitation on stack size. */ #else # define local #endif #ifdef Z_SOLO /* for Z_SOLO, create simplified gz* functions using deflate and inflate */ #if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) # include /* for unlink() */ #endif void *myalloc OF((void *, unsigned, unsigned)); void myfree OF((void *, void *)); void *myalloc(q, n, m) void *q; unsigned n, m; { q = Z_NULL; return calloc(n, m); } void myfree(q, p) void *q, *p; { q = Z_NULL; free(p); } typedef struct gzFile_s { FILE *file; int write; int err; char *msg; z_stream strm; } *gzFile; gzFile gzopen OF((const char *, const char *)); gzFile gzdopen OF((int, const char *)); gzFile gz_open OF((const char *, int, const char *)); gzFile gzopen(path, mode) const char *path; const char *mode; { return gz_open(path, -1, mode); } gzFile gzdopen(fd, mode) int fd; const char *mode; { return gz_open(NULL, fd, mode); } gzFile gz_open(path, fd, mode) const char *path; int fd; const char *mode; { gzFile gz; int ret; gz = malloc(sizeof(struct gzFile_s)); if (gz == NULL) return NULL; gz->write = strchr(mode, 'w') != NULL; gz->strm.zalloc = myalloc; gz->strm.zfree = myfree; gz->strm.opaque = Z_NULL; if (gz->write) ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); else { gz->strm.next_in = 0; gz->strm.avail_in = Z_NULL; ret = inflateInit2(&(gz->strm), 15 + 16); } if (ret != Z_OK) { free(gz); return NULL; } gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : fopen(path, gz->write ? "wb" : "rb"); if (gz->file == NULL) { gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); free(gz); return NULL; } gz->err = 0; gz->msg = ""; return gz; } int gzwrite OF((gzFile, const void *, unsigned)); int gzwrite(gz, buf, len) gzFile gz; const void *buf; unsigned len; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL || !gz->write) return 0; strm = &(gz->strm); strm->next_in = (void *)buf; strm->avail_in = len; do { strm->next_out = out; strm->avail_out = BUFLEN; (void)deflate(strm, Z_NO_FLUSH); fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); } while (strm->avail_out == 0); return len; } int gzread OF((gzFile, void *, unsigned)); int gzread(gz, buf, len) gzFile gz; void *buf; unsigned len; { int ret; unsigned got; unsigned char in[1]; z_stream *strm; if (gz == NULL || gz->write) return 0; if (gz->err) return 0; strm = &(gz->strm); strm->next_out = (void *)buf; strm->avail_out = len; do { got = fread(in, 1, 1, gz->file); if (got == 0) break; strm->next_in = in; strm->avail_in = 1; ret = inflate(strm, Z_NO_FLUSH); if (ret == Z_DATA_ERROR) { gz->err = Z_DATA_ERROR; gz->msg = strm->msg; return 0; } if (ret == Z_STREAM_END) inflateReset(strm); } while (strm->avail_out); return len - strm->avail_out; } int gzclose OF((gzFile)); int gzclose(gz) gzFile gz; { z_stream *strm; unsigned char out[BUFLEN]; if (gz == NULL) return Z_STREAM_ERROR; strm = &(gz->strm); if (gz->write) { strm->next_in = Z_NULL; strm->avail_in = 0; do { strm->next_out = out; strm->avail_out = BUFLEN; (void)deflate(strm, Z_FINISH); fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); } while (strm->avail_out == 0); deflateEnd(strm); } else inflateEnd(strm); fclose(gz->file); free(gz); return Z_OK; } const char *gzerror OF((gzFile, int *)); const char *gzerror(gz, err) gzFile gz; int *err; { *err = gz->err; return gz->msg; } #endif char *prog; void error OF((const char *msg)); void gz_compress OF((FILE *in, gzFile out)); #ifdef USE_MMAP int gz_compress_mmap OF((FILE *in, gzFile out)); #endif void gz_uncompress OF((gzFile in, FILE *out)); void file_compress OF((char *file, char *mode)); void file_uncompress OF((char *file)); /* =========================================================================== * Display error message and exit */ void error(msg) const char *msg; { fprintf(stderr, "%s: %s\n", prog, msg); exit(1); } /* =========================================================================== * Compress input to output then close both files. */ void gz_compress(in, out) FILE *in; gzFile out; { local char buf[BUFLEN]; int len; int err; #ifdef USE_MMAP /* Try first compressing with mmap. If mmap fails (minigzip used in a * pipe), use the normal fread loop. */ if (gz_compress_mmap(in, out) == Z_OK) return; #endif for (;;) { len = (int)fread(buf, 1, sizeof(buf), in); if (ferror(in)) { perror("fread"); exit(1); } if (len == 0) break; if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); } fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); } #ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ /* Try compressing the input file at once using mmap. Return Z_OK if * if success, Z_ERRNO otherwise. */ int gz_compress_mmap(in, out) FILE *in; gzFile out; { int len; int err; int ifd = fileno(in); caddr_t buf; /* mmap'ed buffer for the entire input file */ off_t buf_len; /* length of the input file */ struct stat sb; /* Determine the size of the file, needed for mmap: */ if (fstat(ifd, &sb) < 0) return Z_ERRNO; buf_len = sb.st_size; if (buf_len <= 0) return Z_ERRNO; /* Now do the actual mmap: */ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); if (buf == (caddr_t)(-1)) return Z_ERRNO; /* Compress the whole file at once: */ len = gzwrite(out, (char *)buf, (unsigned)buf_len); if (len != (int)buf_len) error(gzerror(out, &err)); munmap(buf, buf_len); fclose(in); if (gzclose(out) != Z_OK) error("failed gzclose"); return Z_OK; } #endif /* USE_MMAP */ /* =========================================================================== * Uncompress input to output then close both files. */ void gz_uncompress(in, out) gzFile in; FILE *out; { local char buf[BUFLEN]; int len; int err; for (;;) { len = gzread(in, buf, sizeof(buf)); if (len < 0) error (gzerror(in, &err)); if (len == 0) break; if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { error("failed fwrite"); } } if (fclose(out)) error("failed fclose"); if (gzclose(in) != Z_OK) error("failed gzclose"); } /* =========================================================================== * Compress the given file: create a corresponding .gz file and remove the * original. */ void file_compress(file, mode) char *file; char *mode; { local char outfile[MAX_NAME_LEN]; FILE *in; gzFile out; if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); #else strcpy(outfile, file); strcat(outfile, GZ_SUFFIX); #endif in = fopen(file, "rb"); if (in == NULL) { perror(file); exit(1); } out = gzopen(outfile, mode); if (out == NULL) { fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); exit(1); } gz_compress(in, out); unlink(file); } /* =========================================================================== * Uncompress the given file and remove the original. */ void file_uncompress(file) char *file; { local char buf[MAX_NAME_LEN]; char *infile, *outfile; FILE *out; gzFile in; size_t len = strlen(file); if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { fprintf(stderr, "%s: filename too long\n", prog); exit(1); } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(buf, sizeof(buf), "%s", file); #else strcpy(buf, file); #endif if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { infile = file; outfile = buf; outfile[len-3] = '\0'; } else { outfile = file; infile = buf; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); #else strcat(infile, GZ_SUFFIX); #endif } in = gzopen(infile, "rb"); if (in == NULL) { fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); exit(1); } out = fopen(outfile, "wb"); if (out == NULL) { perror(file); exit(1); } gz_uncompress(in, out); unlink(infile); } char *file_uncompress_origname(char *infile, char *path) { FILE *in, *out; gzFile gzin; char *filename; int len = 0; in = fopen(infile, "rb"); if (in == NULL) { printf("Can't open %s\n", infile); exit(1); } fseek(in, 10, SEEK_SET); char c; do { c = getc(in); len++; } while (c != '\x00'); //calculate string length char *dest = malloc(len + strlen(path)); //allocate space for path+name memset(dest, 0x0, strlen(dest)); filename = malloc(len); //allocate space for name fseek(in, 10, SEEK_SET); fread(filename, 1, len, in); //read filename printf("Ungzipping file: %s\n", filename); fclose(in); strcat(dest, path); strcat(dest, filename); gzin = gzopen(infile, "rb"); if (in == NULL) { fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); exit(1); } out = fopen(dest, "wb"); if (out == NULL) { perror(infile); exit(1); } gz_uncompress(gzin, out); //unlink(infile); return dest; } ================================================ FILE: src/partinfo.c ================================================ /** * LG partition table decoder * Original code from u-boot GPL package * Copyright 2016 Smx * Copyright 20?? ??? */ #include #include #include #include #include #include "partinfo.h" #include "util.h" #ifdef __CYGWIN__ # define lne "\r\n" #else # define lne "\n" #endif #define println() fprintf(destfile,lne) #include extern int errno; FILE *destfile; //structs struct m_partmap_info m_partinfo; struct p1_partmap_info p1_partinfo; struct p2_partmap_info p2_partinfo; const char *m_menu_partition_str[] = { "MTD Partition Information ---------------------------------------------------------------------------------", "index[%d] - ", "cur epk ver : 0x%06x", "old epk ver : 0x%06x", "\t name = %s", "\t offset = 0x%08x", "\t size = 0x%08x", "\t sw_ver = %d", "\t filename = %s", "\t MTD flags = %s\n" }; const char *m_menu_partition_info[] = { "[%2d] \"%-12s\" : 0x%08x-0x%08x (0x%08x)", " %c%c%c%c", " : \"%-20s\"[%d] - 0x%06x : (%c/%c)", "[%2d] Empty\n" }; static const char *p_menu_partition_str[] = { "Partition Information ---------------------------------------------------------------------------------", "index[%d] - ", "cur epk ver : 0x%06x", "old epk ver : 0x%06x", "\t name = %s", "\t offset = 0x%08x", "\t size = 0x%08x", "\t sw_ver = %d", "\t filename = %s", "\t flags = %s\n", "\t used = %c", "\t valid = %c" }; static const char *p1_menu_partition_info[] = { "[%2d] \"%-12s\" : 0x%08x-0x%08x (0x%08x)", " %c%c%c%c%c", " : \"%-20s\"[%d] - 0x%06x : (%c/%c)", "[%2d] Empty\n" }; static const char *p2_menu_partition_info[] = { "[%2d] \"%-12s\" : 0x%01x%08x-0x%01x%08x (0x%01x%08x)", " %c%c%c%c%c", " : \"%-20s\"[%d] - 0x%06x : (%c/%c) [%3d\%]", "[%2d] Empty\n" }; void print_size(unsigned int devsize) { if (devsize % (1024 * 1024 * 1024) == 0) { //Gigabytes fprintf(destfile, "\tSize: %dGB", (devsize / 1024 / 1024 / 1024)); } else { //Small MTD, use Megabytes fprintf(destfile, "\tSize: %dMB", (devsize / 1024 / 1024)); } } unsigned int print_minfo(void) { int i = 0; struct m_partition_info *bi = NULL; struct m_device_info *mtdi = NULL; mtdi = M_GET_DEV_INFO(0); fprintf(destfile, "MTD Name: %s", mtdi->name); unsigned int devsize = mtdi->size; print_size(devsize); println(); println(); fprintf(destfile, "%s", m_menu_partition_str[0]); println(); println(); fprintf(destfile, "magic : %08x", m_partinfo.magic); println(); println(); fprintf(destfile, m_menu_partition_str[2], m_partinfo.cur_epk_ver); println(); fprintf(destfile, m_menu_partition_str[3], m_partinfo.old_epk_ver); println(); println(); for (i = 0; i < (m_partinfo.npartition); i++) { bi = M_GET_PART_INFO(i); fprintf(destfile, m_menu_partition_info[0], i, bi->name, bi->offset, (bi->offset + bi->size), bi->size); fprintf(destfile, m_menu_partition_info[1], (bi->mask_flags & PART_FLG_FIXED) ? 'F' : '-', (bi->mask_flags & PART_FLG_MASTER) ? 'M' : '-', (bi->mask_flags & PART_FLG_IDKEY) ? 'I' : '-', (bi->mask_flags & PART_FLG_CACHE) ? 'C' : '-'); if (strlen(bi->filename)) { fprintf(destfile, m_menu_partition_info[2], bi->filename, bi->filesize, bi->sw_ver, bi->used ? 'U' : 'u', bi->valid ? 'V' : 'v'); println(); } else println(); } return 0; } unsigned int print_p1info(void) { int i = 0; struct p1_partition_info *p1i = NULL; struct p1_device_info *p1di = NULL; p1di = P1_GET_DEV_INFO(); fprintf(destfile, "Flash Name: %s", p1di->name); unsigned int devsize = p1di->size; print_size(devsize); println(); println(); fprintf(destfile, "%s", p_menu_partition_str[0]); println(); println(); fprintf(destfile, "magic : %08x", p1_partinfo.magic); println(); println(); fprintf(destfile, p_menu_partition_str[2], p1_partinfo.cur_epk_ver); println(); fprintf(destfile, p_menu_partition_str[3], p1_partinfo.old_epk_ver); println(); println(); if (p1_partinfo.npartition > PM_PARTITION_MAX) { printf("[ERROR] Number of partition is %d\n", p1_partinfo.npartition); return (unsigned int)-1; } for (i = 0; i < (p1_partinfo.npartition); i++) { p1i = P1_GET_PART_INFO(i); fprintf(destfile, p1_menu_partition_info[0], i, p1i->name, p1i->offset, (p1i->offset + p1i->size), p1i->size); fprintf(destfile, p1_menu_partition_info[1], (p1i->mask_flags & PART_FLG_FIXED) ? 'F' : '-', (p1i->mask_flags & PART_FLG_MASTER) ? 'M' : '-', (p1i->mask_flags & PART_FLG_SECURED) ? 'S' : '-', (p1i->mask_flags & PART_FLG_IDKEY) ? 'I' : '-', (p1i->mask_flags & PART_FLG_CACHE) ? 'C' : ((p1i->mask_flags & PART_FLG_DATA) ? 'D' : '-') ); if (p1i->mask_flags & PART_FLG_ERASE) fprintf(destfile, "*"); if (strlen(p1i->filename)) { fprintf(destfile, p1_menu_partition_info[2], p1i->filename, p1i->filesize, p1i->sw_ver, p1i->used ? 'U' : 'u', p1i->valid ? 'V' : 'v'); println(); } else println(); } return 0; } unsigned int print_p2info(void) { int i = 0; struct p2_partition_info *p2i = NULL; struct p2_device_info *p2di = NULL; p2di = P2_GET_DEV_INFO(); fprintf(destfile, "Flash Name: %s", p2di->name); unsigned int devsize = p2di->size; print_size(devsize); println(); println(); fprintf(destfile, "%s", p_menu_partition_str[0]); println(); println(); fprintf(destfile, "magic : %08x", p2_partinfo.magic); println(); println(); fprintf(destfile, p_menu_partition_str[2], p2_partinfo.cur_epk_ver); println(); fprintf(destfile, p_menu_partition_str[3], p2_partinfo.old_epk_ver); println(); println(); if (p2_partinfo.npartition > P2_PARTITION_MAX) { printf("[ERROR] Number of partition is %d\n", p2_partinfo.npartition); return (unsigned int)-1; } for (i = 0; i < (p2_partinfo.npartition); i++) { p2i = P2_GET_PART_INFO(i); fprintf(destfile, p2_menu_partition_info[0], i, p2i->name, U64_UPPER(p2i->offset), U64_LOWER(p2i->offset), U64_UPPER(p2i->offset + p2i->size), U64_LOWER(p2i->offset + p2i->size), U64_UPPER(p2i->size), U64_LOWER(p2i->size)); fprintf(destfile, p2_menu_partition_info[1], (p2i->mask_flags & PART_FLG_FIXED) ? 'F' : '-', (p2i->mask_flags & PART_FLG_MASTER) ? 'M' : '-', (p2i->mask_flags & PART_FLG_SECURED) ? 'S' : '-', (p2i->mask_flags & PART_FLG_IDKEY) ? 'I' : '-', (p2i->mask_flags & PART_FLG_CACHE) ? 'C' : ((p2i->mask_flags & PART_FLG_DATA) ? 'D' : '-') ); if (p2i->mask_flags & PART_FLG_ERASE) fprintf(destfile, "*"); if (strlen(p2i->filename)) { fprintf(destfile, p2_menu_partition_info[2], p2i->filename, p2i->filesize, p2i->sw_ver, p2i->used ? 'U' : 'u', p2i->valid ? 'V' : 'v', (unsigned long)((double)p2i->filesize / p2i->size * 100)); println(); } else println(); } return 0; } unsigned int do_partinfo(void) { fprintf(destfile, "%s Detected", modelname); println(); println(); switch (part_type) { case STRUCT_PARTINFOv2: print_p2info(); break; case STRUCT_PARTINFOv1: print_p1info(); break; case STRUCT_MTDINFO: print_minfo(); break; default: err_exit("Unhandled partition table structure\n"); break; } println(); char buf[256]; rewind(destfile); printf("\n"); while (fgets(buf, sizeof buf, destfile)) { //print file we just wrote to stdout printf("%s", buf); } fclose(destfile); return 0; } unsigned int load_partinfo(const char *filename) { FILE *file; file = fopen(filename, "rb"); if (file == NULL) { err_exit("Can't open file %s\n", filename); } size_t size = 0; switch (part_type) { case STRUCT_PARTINFOv2: size = sizeof(struct p2_partmap_info); fread(&p2_partinfo, 1, size, file); break; case STRUCT_PARTINFOv1: size = sizeof(struct p1_partmap_info); fread(&p1_partinfo, 1, size, file); break; case STRUCT_MTDINFO: size = sizeof(struct m_partmap_info); fread(&m_partinfo, 1, size, file); break; default: fclose(file); err_exit("Unhandled partition table structure\n"); break; } return 0; } unsigned int dump_partinfo(const char *filename, const char *outfile) { destfile = fopen(outfile, "w+"); if (destfile == NULL) err_exit("Can't open file %s for writing. Error is: %s\n", outfile, strerror(errno)); load_partinfo(filename); do_partinfo(); return 0; } ================================================ FILE: src/philips.c ================================================ /** * Copyright 2016 Smx * All right reserved */ #include #include #include #include "config.h" #include "mfile.h" #include "util.h" #include "philips.h" #include "main.h" #define PHILIPS_DEBUG MFILE *is_philips_fusion1(const char *filename){ MFILE *mf = mopen(filename, O_RDONLY); if(!mf){ err_exit("mfopen failed for %s\n", filename); } uint8_t *data = mdata(mf, uint8_t); if(!memcmp(data, PHILIPS_FUSION1_MAGIC, strlen(PHILIPS_FUSION1_MAGIC))){ return mf; } mclose(mf); return NULL; } void extract_philips_fusion1(MFILE *mf, config_opts_t *config_opts){ char *basename = my_basename(mf->path); char *name = remove_ext(basename); asprintf_inplace(&config_opts->dest_dir, "%s/%s", config_opts->dest_dir, name); createFolder(config_opts->dest_dir); uint8_t *data = mdata(mf, uint8_t); struct philips_fusion1_upg *upg = mdata(mf, struct philips_fusion1_upg); struct philips_fusion1_part *part_table = (struct philips_fusion1_part *)&data[0xB0]; printf("Fusion1 firmware contains %u partitions (first at 0x%08X)\n", upg->numPartitions, upg->firstPartition ); uint i; for(i=0; inumPartitions; i++){ struct philips_fusion1_part *part = &part_table[i]; printf("[Part %u] Index: %02u - 0x%08X (0x%08X bytes)\n", i, part->index, part->offset, part->size ); #ifdef PHILIPS_DEBUG printf("UNK0: 0x%08X\n", part->unk0); printf("UNK1: 0x%08X\n", part->unk1); printf("UNK2: 0x%08X\n", part->unk2); printf("UNK3: 0x%08X\n\n", part->unk3); #endif char *path; asprintf(&path, "%s/part_%d.pak", config_opts->dest_dir, i); printf(" Writing partition to %s\n", path); MFILE *out = mfopen(path, "w+"); if(out) { mfile_map(out, part->size); memcpy( mdata(out, void), &data[part->offset], part->size ); mclose(out); handle_file(path, config_opts); } else { printf("A package wasn't written to disk because of a memory allocation failure\n"); } free(path); } free(name); free(basename); } ================================================ FILE: src/realtek.c ================================================ #include #include #include #include #include #include "mfile.h" #include "realtek/rtsplit.h" #include "util.h" MFILE *is_rtk_bspfw(const char *filename){ MFILE *mf = mopen(filename, O_RDONLY); if(mf == NULL){ err_exit("Can't open file %s\n", filename); } kernel_image_header *hdr = mdata(mf, kernel_image_header); int zero_size = member_size(kernel_image_header, reserved); uint8_t reserved[zero_size]; memset(&reserved, 0x00, zero_size); int matches = 0; for(; moff(mf, hdr) < msize(mf); hdr++){ int stop = 0; switch(hdr->magic){ case HEADER_AUDIO1_IMAGE: case HEADER_AUDIO2_IMAGE: case HEADER_VIDEO1_IMAGE: case HEADER_VIDEO2_IMAGE: if(memcmp(&hdr->reserved, &reserved, zero_size) != 0){ break; } if(hdr->offset > msize(mf) || (hdr->offset + hdr->size) > msize(mf)){ break; } matches++; break; default: stop = 1; break; } if(stop){ break; } } if(matches < 1){ mclose(mf); return NULL; } return mf; } void split_rtk_bspfw(MFILE *mf, const char *destdir) { char *innerDirectory; asprintf(&innerDirectory, "%s/bspfw.pak.split", destdir); createFolder(innerDirectory); kernel_image_header *hdr = mdata(mf, kernel_image_header); for(; moff(mf, hdr) < msize(mf); hdr++){ char *filepath = NULL; switch(hdr->magic){ case HEADER_AUDIO1_IMAGE: case HEADER_AUDIO2_IMAGE: case HEADER_VIDEO1_IMAGE: case HEADER_VIDEO2_IMAGE: { char *filename = (hdr->magic == HEADER_AUDIO1_IMAGE) ? "ACPU1" : ( (hdr->magic == HEADER_AUDIO2_IMAGE) ? "ACPU2" : ( (hdr->magic == HEADER_VIDEO1_IMAGE) ? "VCPU1" : "VCPU2" ) ); printf("Found %s firmware (offset='0x%x', size='0x%x')\n", filename, hdr->offset, hdr->size); asprintf(&filepath, "%s/%s.bin", innerDirectory, filename); printf(" == Saving to %s\n", filepath); MFILE *out = mfopen(filepath, "w+"); if(out == NULL){ err_exit("Cannot open '%s' for writing\n", filepath); } mfile_map(out, hdr->size); memcpy( mdata(out, void), mdata(mf, uint8_t) + hdr->offset, hdr->size ); mclose(out); break; } } if(filepath != NULL){ free(filepath); } } free(innerDirectory); } ================================================ FILE: src/squashfs/CMakeLists.txt ================================================ add_library(squashfs compressor.c gzip_wrapper.c lzo_wrapper.c swap.c read_xattrs.c unsquash-1.c unsquash-2.c unsquash-3.c unsquash-4.c unsquashfs.c unsquashfs_info.c unsquashfs_xattr.c) target_include_directories(squashfs PUBLIC ${INC}/squashfs ${LZO_INCLUDE_DIR} ) target_compile_definitions(squashfs PRIVATE -DGZIP_SUPPORT -DLZO_SUPPORT -DCOMP_DEFAULT=\"gzip\" -DXATTR_SUPPORT -DXATTR_DEFAULT ) ================================================ FILE: src/squashfs/action.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2011, 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * action.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "squashfs_fs.h" #include "mksquashfs.h" #include "action.h" #include "error.h" /* * code to parse actions */ static char *cur_ptr, *source; static struct action *fragment_spec = NULL; static struct action *exclude_spec = NULL; static struct action *empty_spec = NULL; static struct action *move_spec = NULL; static struct action *other_spec = NULL; static int fragment_count = 0; static int exclude_count = 0; static int empty_count = 0; static int move_count = 0; static int other_count = 0; static struct file_buffer *def_fragment = NULL; static struct token_entry token_table[] = { {"(", TOK_OPEN_BRACKET, 1,}, {")", TOK_CLOSE_BRACKET, 1}, {"&&", TOK_AND, 2}, {"||", TOK_OR, 2}, {"!", TOK_NOT, 1}, {",", TOK_COMMA, 1}, {"@", TOK_AT, 1}, {" ", TOK_WHITE_SPACE, 1}, {"\t ", TOK_WHITE_SPACE, 1}, {"", -1, 0} }; static struct test_entry test_table[]; static struct action_entry action_table[]; static struct expr *parse_expr(int subexp); extern char *pathname(struct dir_ent *); extern char *subpathname(struct dir_ent *); extern int read_file(char *filename, char *type, int (parse_line) (char *)); /* * Lexical analyser */ #define STR_SIZE 256 static int get_token(char **string) { /* string buffer */ static char *str = NULL; static int size = 0; char *str_ptr; int cur_size, i, quoted; while (1) { if (*cur_ptr == '\0') return TOK_EOF; for (i = 0; token_table[i].token != -1; i++) if (strncmp(cur_ptr, token_table[i].string, token_table[i].size) == 0) break; if (token_table[i].token != TOK_WHITE_SPACE) break; cur_ptr++; } if (token_table[i].token != -1) { cur_ptr += token_table[i].size; return token_table[i].token; } /* string */ if (str == NULL) { str = malloc(STR_SIZE); if (str == NULL) MEM_ERROR(); size = STR_SIZE; } /* Initialise string being read */ str_ptr = str; cur_size = 0; quoted = 0; while (1) { while (*cur_ptr == '"') { cur_ptr++; quoted = !quoted; } if (*cur_ptr == '\0') { /* inside quoted string EOF, otherwise end of string */ if (quoted) return TOK_EOF; else break; } if (!quoted) { for (i = 0; token_table[i].token != -1; i++) if (strncmp(cur_ptr, token_table[i].string, token_table[i].size) == 0) break; if (token_table[i].token != -1) break; } if (*cur_ptr == '\\') { cur_ptr++; if (*cur_ptr == '\0') return TOK_EOF; } if (cur_size + 2 > size) { char *tmp; size = (cur_size + 1 + STR_SIZE) & ~(STR_SIZE - 1); tmp = realloc(str, size); if (tmp == NULL) MEM_ERROR(); str_ptr = str_ptr - str + tmp; str = tmp; } *str_ptr++ = *cur_ptr++; cur_size++; } *str_ptr = '\0'; *string = str; return TOK_STRING; } static int peek_token(char **string) { char *saved = cur_ptr; int token = get_token(string); cur_ptr = saved; return token; } /* * Expression parser */ static void free_parse_tree(struct expr *expr) { if (expr->type == ATOM_TYPE) { int i; for (i = 0; i < expr->atom.test->args; i++) free(expr->atom.argv[i]); free(expr->atom.argv); } else if (expr->type == UNARY_TYPE) free_parse_tree(expr->unary_op.expr); else { free_parse_tree(expr->expr_op.lhs); free_parse_tree(expr->expr_op.rhs); } free(expr); } static struct expr *create_expr(struct expr *lhs, int op, struct expr *rhs) { struct expr *expr; if (rhs == NULL) { free_parse_tree(lhs); return NULL; } expr = malloc(sizeof(*expr)); if (expr == NULL) MEM_ERROR(); expr->type = OP_TYPE; expr->expr_op.lhs = lhs; expr->expr_op.rhs = rhs; expr->expr_op.op = op; return expr; } static struct expr *create_unary_op(struct expr *lhs, int op) { struct expr *expr; if (lhs == NULL) return NULL; expr = malloc(sizeof(*expr)); if (expr == NULL) MEM_ERROR(); expr->type = UNARY_TYPE; expr->unary_op.expr = lhs; expr->unary_op.op = op; return expr; } static struct expr *parse_test(char *name) { char *string; int token; int i; struct test_entry *test; struct expr *expr; for (i = 0; test_table[i].args != -1; i++) if (strcmp(name, test_table[i].name) == 0) break; if (test_table[i].args == -1) { SYNTAX_ERROR("Non-existent test \"%s\"\n", name); return NULL; } test = &test_table[i]; expr = malloc(sizeof(*expr)); if (expr == NULL) MEM_ERROR(); expr->type = ATOM_TYPE; expr->atom.argv = malloc(test->args * sizeof(char *)); if (expr->atom.argv == NULL) MEM_ERROR(); expr->atom.test = test; expr->atom.data = NULL; /* * If the test has no arguments, allow it to be typed * without brackets */ if (test->args == 0) { token = peek_token(&string); if (token != TOK_OPEN_BRACKET) goto skip_args; } token = get_token(&string); if (token != TOK_OPEN_BRACKET) { SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n", TOK_TO_STR(token, string)); goto failed; } for (i = 0; i < test->args; i++) { token = get_token(&string); if (token != TOK_STRING) { SYNTAX_ERROR("Unexpected token \"%s\", expected " "argument\n", TOK_TO_STR(token, string)); goto failed; } expr->atom.argv[i] = strdup(string); if (i + 1 < test->args) { token = get_token(&string); if (token != TOK_COMMA) { SYNTAX_ERROR("Unexpected token \"%s\", " "expected \",\"\n", TOK_TO_STR(token, string)); goto failed; } } } if (test->parse_args) { int res = test->parse_args(test, &expr->atom); if (res == 0) goto failed; } token = get_token(&string); if (token != TOK_CLOSE_BRACKET) { SYNTAX_ERROR("Unexpected token \"%s\", expected \")\"\n", TOK_TO_STR(token, string)); goto failed; } skip_args: return expr; failed: free(expr->atom.argv); free(expr); return NULL; } static struct expr *get_atom() { char *string; int token = get_token(&string); switch (token) { case TOK_NOT: return create_unary_op(get_atom(), token); case TOK_OPEN_BRACKET: return parse_expr(1); case TOK_STRING: return parse_test(string); default: SYNTAX_ERROR("Unexpected token \"%s\", expected test " "operation, \"!\", or \"(\"\n", TOK_TO_STR(token, string)); return NULL; } } static struct expr *parse_expr(int subexp) { struct expr *expr = get_atom(); while (expr) { char *string; int op = get_token(&string); if (op == TOK_EOF) { if (subexp) { free_parse_tree(expr); SYNTAX_ERROR("Expected \"&&\", \"||\" or " "\")\", got EOF\n"); return NULL; } break; } if (op == TOK_CLOSE_BRACKET) { if (!subexp) { free_parse_tree(expr); SYNTAX_ERROR("Unexpected \")\", expected " "\"&&\", \"!!\" or EOF\n"); return NULL; } break; } if (op != TOK_AND && op != TOK_OR) { free_parse_tree(expr); SYNTAX_ERROR("Unexpected token \"%s\", expected " "\"&&\" or \"||\"\n", TOK_TO_STR(op, string)); return NULL; } expr = create_expr(expr, op, get_atom()); } return expr; } /* * Action parser */ int parse_action(char *s) { char *string, **argv = NULL; int i, token, args = 0; struct expr *expr; struct action_entry *action; void *data = NULL; struct action **spec_list; int spec_count; cur_ptr = source = s; token = get_token(&string); if (token != TOK_STRING) { SYNTAX_ERROR("Unexpected token \"%s\", expected name\n", TOK_TO_STR(token, string)); return 0; } for (i = 0; action_table[i].args != -1; i++) if (strcmp(string, action_table[i].name) == 0) break; if (action_table[i].args == -1) { SYNTAX_ERROR("Non-existent action \"%s\"\n", string); return 0; } action = &action_table[i]; token = get_token(&string); if (token == TOK_AT) goto skip_args; if (token != TOK_OPEN_BRACKET) { SYNTAX_ERROR("Unexpected token \"%s\", expected \"(\"\n", TOK_TO_STR(token, string)); goto failed; } /* * speculatively read all the arguments, and then see if the * number of arguments read is the number expected, this handles * actions with a variable number of arguments */ token = get_token(&string); if (token == TOK_CLOSE_BRACKET) goto skip_args; while (1) { if (token != TOK_STRING) { SYNTAX_ERROR("Unexpected token \"%s\", expected " "argument\n", TOK_TO_STR(token, string)); goto failed; } argv = realloc(argv, (args + 1) * sizeof(char *)); if (argv == NULL) MEM_ERROR(); argv[args++] = strdup(string); token = get_token(&string); if (token == TOK_CLOSE_BRACKET) break; if (token != TOK_COMMA) { SYNTAX_ERROR("Unexpected token \"%s\", expected " "\",\" or \")\"\n", TOK_TO_STR(token, string)); goto failed; } token = get_token(&string); } skip_args: /* * expected number of arguments? */ if (action->args != -2 && args != action->args) { SYNTAX_ERROR("Unexpected number of arguments, expected %d, " "got %d\n", action->args, args); goto failed; } if (action->parse_args) { int res = action->parse_args(action, args, argv, &data); if (res == 0) goto failed; } if (token == TOK_CLOSE_BRACKET) token = get_token(&string); if (token != TOK_AT) { SYNTAX_ERROR("Unexpected token \"%s\", expected \"@\"\n", TOK_TO_STR(token, string)); goto failed; } expr = parse_expr(0); if (expr == NULL) goto failed; /* * choose action list and increment action counter */ switch (action->type) { case FRAGMENT_ACTION: spec_count = fragment_count++; spec_list = &fragment_spec; break; case EXCLUDE_ACTION: spec_count = exclude_count++; spec_list = &exclude_spec; break; case EMPTY_ACTION: spec_count = empty_count++; spec_list = &empty_spec; break; case MOVE_ACTION: spec_count = move_count++; spec_list = &move_spec; break; default: spec_count = other_count++; spec_list = &other_spec; } *spec_list = realloc(*spec_list, (spec_count + 1) * sizeof(struct action)); if (*spec_list == NULL) MEM_ERROR(); (*spec_list)[spec_count].type = action->type; (*spec_list)[spec_count].action = action; (*spec_list)[spec_count].args = args; (*spec_list)[spec_count].argv = argv; (*spec_list)[spec_count].expr = expr; (*spec_list)[spec_count].data = data; return 1; failed: free(argv); return 0; } /* * Evaluate expressions */ static int eval_expr(struct expr *expr, struct action_data *action_data) { int match; switch (expr->type) { case ATOM_TYPE: match = expr->atom.test->fn(&expr->atom, action_data); break; case UNARY_TYPE: match = !eval_expr(expr->unary_op.expr, action_data); break; default: match = eval_expr(expr->expr_op.lhs, action_data); if ((expr->expr_op.op == TOK_AND && match) || (expr->expr_op.op == TOK_OR && !match)) match = eval_expr(expr->expr_op.rhs, action_data); break; } return match; } /* * Read action file, passing each line to parse_action() for * parsing. * * One action per line, of the form * action(arg1,arg2)@expr(arg1,arg2).... * * Actions can be split across multiple lines using "\". * * Blank lines and comment lines indicated by # are supported. */ int read_action_file(char *filename) { return read_file(filename, "action", parse_action); } /* * General action evaluation code */ int actions() { return other_count; } void eval_actions(struct dir_ent *dir_ent) { int i, match; struct action_data action_data; int file_type = dir_ent->inode->buf.st_mode & S_IFMT; action_data.name = dir_ent->name; action_data.pathname = pathname(dir_ent); action_data.subpath = subpathname(dir_ent); action_data.buf = &dir_ent->inode->buf; action_data.depth = dir_ent->our_dir->depth; for (i = 0; i < other_count; i++) { struct action *action = &other_spec[i]; if ((action->action->file_types & file_type) == 0) /* action does not operate on this file type */ continue; match = eval_expr(action->expr, &action_data); if (match) action->action->run_action(action, dir_ent); } } /* * Fragment specific action code */ void *eval_frag_actions(struct dir_ent *dir_ent) { int i, match; struct action_data action_data; action_data.name = dir_ent->name; action_data.pathname = pathname(dir_ent); action_data.subpath = subpathname(dir_ent); action_data.buf = &dir_ent->inode->buf; action_data.depth = dir_ent->our_dir->depth; for (i = 0; i < fragment_count; i++) { match = eval_expr(fragment_spec[i].expr, &action_data); if (match) return &fragment_spec[i].data; } return &def_fragment; } void *get_frag_action(void *fragment) { struct action *spec_list_end = &fragment_spec[fragment_count]; struct action *action; if (fragment == NULL) return &def_fragment; if (fragment_count == 0) return NULL; if (fragment == &def_fragment) action = &fragment_spec[0] - 1; else action = fragment - offsetof(struct action, data); if (++action == spec_list_end) return NULL; return &action->data; } /* * Exclude specific action code */ int exclude_actions() { return exclude_count; } int eval_exclude_actions(char *name, char *pathname, char *subpath, struct stat *buf, int depth) { int i, match = 0; struct action_data action_data; action_data.name = name; action_data.pathname = pathname; action_data.subpath = subpath; action_data.buf = buf; action_data.depth = depth; for (i = 0; i < exclude_count && !match; i++) match = eval_expr(exclude_spec[i].expr, &action_data); return match; } /* * Fragment specific action code */ static void frag_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->no_fragments = 0; } static void no_frag_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->no_fragments = 1; } static void always_frag_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->always_use_fragments = 1; } static void no_always_frag_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->always_use_fragments = 0; } /* * Compression specific action code */ static void comp_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->noD = inode->noF = 0; } static void uncomp_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; inode->noD = inode->noF = 1; } /* * Uid/gid specific action code */ static long long parse_uid(char *arg) { char *b; long long uid = strtoll(arg, &b, 10); if (*b == '\0') { if (uid < 0 || uid >= (1LL << 32)) { SYNTAX_ERROR("action: uid out of range\n"); return -1; } } else { struct passwd *passwd = getpwnam(arg); if (passwd) uid = passwd->pw_uid; else { SYNTAX_ERROR("action: invalid uid or unknown user\n"); return -1; } } return uid; } static long long parse_gid(char *arg) { char *b; long long gid = strtoll(arg, &b, 10); if (*b == '\0') { if (gid < 0 || gid >= (1LL << 32)) { SYNTAX_ERROR("action: gid out of range\n"); return -1; } } else { struct group *group = getgrnam(arg); if (group) gid = group->gr_gid; else { SYNTAX_ERROR("action: invalid gid or unknown user\n"); return -1; } } return gid; } static int parse_uid_args(struct action_entry *action, int args, char **argv, void **data) { long long uid; struct uid_info *uid_info; uid = parse_uid(argv[0]); if (uid == -1) return 0; uid_info = malloc(sizeof(struct uid_info)); if (uid_info == NULL) MEM_ERROR(); uid_info->uid = uid; *data = uid_info; return 1; } static int parse_gid_args(struct action_entry *action, int args, char **argv, void **data) { long long gid; struct gid_info *gid_info; gid = parse_gid(argv[0]); if (gid == -1) return 0; gid_info = malloc(sizeof(struct gid_info)); if (gid_info == NULL) MEM_ERROR(); gid_info->gid = gid; *data = gid_info; return 1; } static int parse_guid_args(struct action_entry *action, int args, char **argv, void **data) { long long uid, gid; struct guid_info *guid_info; uid = parse_uid(argv[0]); if (uid == -1) return 0; gid = parse_gid(argv[1]); if (gid == -1) return 0; guid_info = malloc(sizeof(struct guid_info)); if (guid_info == NULL) MEM_ERROR(); guid_info->uid = uid; guid_info->gid = gid; *data = guid_info; return 1; } static void uid_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; struct uid_info *uid_info = action->data; inode->buf.st_uid = uid_info->uid; } static void gid_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; struct gid_info *gid_info = action->data; inode->buf.st_gid = gid_info->gid; } static void guid_action(struct action *action, struct dir_ent *dir_ent) { struct inode_info *inode = dir_ent->inode; struct guid_info *guid_info = action->data; inode->buf.st_uid = guid_info->uid; inode->buf.st_gid = guid_info->gid; } /* * Mode specific action code */ static int parse_octal_mode_args(unsigned int mode, int bytes, int args, char **argv, void **data) { struct mode_data *mode_data; /* check there's no trailing junk */ if (argv[0][bytes] != '\0') { SYNTAX_ERROR("Unexpected trailing bytes after octal " "mode number\n"); return 0; } /* check there's only one argument */ if (args > 1) { SYNTAX_ERROR("Octal mode number is first argument, " "expected one argument, got %d\n", args); return 0; } /* check mode is within range */ if (mode > 07777) { SYNTAX_ERROR("Octal mode %o is out of range\n", mode); return 0; } mode_data = malloc(sizeof(struct mode_data)); if (mode_data == NULL) MEM_ERROR(); mode_data->operation = ACTION_MODE_OCT; mode_data->mode = mode; mode_data->next = NULL; *data = mode_data; return 1; } /* * Parse symbolic mode of format [ugoa]+[+-=]PERMS * PERMS = [rwxXst]+ or [ugo] */ static struct mode_data *parse_sym_mode_arg(char *arg) { struct mode_data *mode_data = malloc(sizeof(*mode_data)); int mode = 0; int mask = 0; int op; char X = 0; if (mode_data == NULL) MEM_ERROR(); if (arg[0] != 'u' && arg[0] != 'g' && arg[0] != 'o' && arg[0] != 'a') { /* no ownership specifiers, default to a */ mask = 0777; goto parse_operation; } /* parse ownership specifiers */ while (1) { switch (*arg) { case 'u': mask |= 04700; break; case 'g': mask |= 02070; break; case 'o': mask |= 01007; break; case 'a': mask = 07777; break; default: goto parse_operation; } arg++; } parse_operation: switch (*arg) { case '+': op = ACTION_MODE_ADD; break; case '-': op = ACTION_MODE_REM; break; case '=': op = ACTION_MODE_SET; break; default: SYNTAX_ERROR("Action mode: Expected one of '+', '-' or '=', " "got '%c'\n", *arg); goto failed; } arg++; /* Parse PERMS */ if (*arg == 'u' || *arg == 'g' || *arg == 'o') { /* PERMS = [ugo] */ mode = -*arg; if (*++arg != '\0') { SYNTAX_ERROR("Action mode: permission 'u', 'g' or 'o' " "has trailing characters\n"); goto failed; } } else { /* PERMS = [rwxXst]+ */ while (*arg != '\0') { switch (*arg) { case 'r': mode |= 0444; break; case 'w': mode |= 0222; break; case 'x': mode |= 0111; break; case 's': mode |= 06000; break; case 't': mode |= 01000; break; case 'X': X = 1; break; default: SYNTAX_ERROR("Action mode: unrecognised " "permission '%c'\n", *arg); goto failed; } arg++; } mode &= mask; } mode_data->operation = op; mode_data->mode = mode; mode_data->mask = mask; mode_data->X = X; mode_data->next = NULL; return mode_data; failed: free(mode_data); return NULL; } static int parse_sym_mode_args(struct action_entry *action, int args, char **argv, void **data) { int i; struct mode_data *head = NULL, *cur = NULL; for (i = 0; i < args; i++) { struct mode_data *entry = parse_sym_mode_arg(argv[i]); if (entry == NULL) return 0; if (cur) { cur->next = entry; cur = entry; } else head = cur = entry; } *data = head; return 1; } static int parse_mode_args(struct action_entry *action, int args, char **argv, void **data) { int n, bytes; unsigned int mode; if (args == 0) { SYNTAX_ERROR("Mode action expects one or more arguments\n"); return 0; } /* octal mode number? */ n = sscanf(argv[0], "%o%n", &mode, &bytes); if (n >= 1) return parse_octal_mode_args(mode, bytes, args, argv, data); else return parse_sym_mode_args(action, args, argv, data); } static void mode_action(struct action *action, struct dir_ent *dir_ent) { struct stat *buf = &dir_ent->inode->buf; struct mode_data *mode_data = action->data; int mode = 0; for (; mode_data; mode_data = mode_data->next) { if (mode_data->mode < 0) { /* 'u', 'g' or 'o' */ switch (-mode_data->mode) { case 'u': mode = (buf->st_mode >> 6) & 07; break; case 'g': mode = (buf->st_mode >> 3) & 07; break; case 'o': mode = buf->st_mode & 07; break; } mode = ((mode << 6) | (mode << 3) | mode) & mode_data->mask; } else if (mode_data->X && ((buf->st_mode & S_IFMT) == S_IFDIR || (buf->st_mode & 0111))) /* X permission, only takes effect if inode is a * directory or x is set for some owner */ mode = mode_data->mode | (0111 & mode_data->mask); else mode = mode_data->mode; switch (mode_data->operation) { case ACTION_MODE_OCT: buf->st_mode = (buf->st_mode & ~S_IFMT) | mode; break; case ACTION_MODE_SET: buf->st_mode = (buf->st_mode & ~mode_data->mask) | mode; break; case ACTION_MODE_ADD: buf->st_mode |= mode; break; case ACTION_MODE_REM: buf->st_mode &= ~mode; } } } /* * Empty specific action code */ int empty_actions() { return empty_count; } static int parse_empty_args(struct action_entry *action, int args, char **argv, void **data) { struct empty_data *empty_data; int val; if (args >= 2) { SYNTAX_ERROR("Empty action expects zero or one argument\n"); return 0; } if (args == 0 || strcmp(argv[0], "all") == 0) val = EMPTY_ALL; else if (strcmp(argv[0], "source") == 0) val = EMPTY_SOURCE; else if (strcmp(argv[0], "excluded") == 0) val = EMPTY_EXCLUDED; else { SYNTAX_ERROR("Empty action expects zero arguments, or one" "argument containing \"all\", \"source\", or \"excluded\"" "\n"); return 0; } empty_data = malloc(sizeof(*empty_data)); if (empty_data == NULL) MEM_ERROR(); empty_data->val = val; *data = empty_data; return 1; } int eval_empty_actions(struct dir_ent *dir_ent) { int i, match = 0; struct action_data action_data; struct empty_data *data; struct dir_info *dir = dir_ent->dir; /* * Empty action only works on empty directories */ if (dir->count != 0) return 0; action_data.name = dir_ent->name; action_data.pathname = pathname(dir_ent); action_data.subpath = subpathname(dir_ent); action_data.buf = &dir_ent->inode->buf; action_data.depth = dir_ent->our_dir->depth; for (i = 0; i < empty_count && !match; i++) { data = empty_spec[i].data; /* * determine the cause of the empty directory and evaluate * the empty action specified. Three empty actions: * - EMPTY_SOURCE: empty action triggers only if the directory * was originally empty, i.e directories that are empty * only due to excluding are ignored. * - EMPTY_EXCLUDED: empty action triggers only if the directory * is empty because of excluding, i.e. directories that * were originally empty are ignored. * - EMPTY_ALL (the default): empty action triggers if the * directory is empty, irrespective of the reason, i.e. * the directory could have been originally empty or could * be empty due to excluding. */ if ((data->val == EMPTY_EXCLUDED && !dir->excluded) || (data->val == EMPTY_SOURCE && dir->excluded)) continue; match = eval_expr(empty_spec[i].expr, &action_data); } return match; } /* * Move specific action code */ static struct move_ent *move_list = NULL; int move_actions() { return move_count; } static char *move_pathname(struct move_ent *move) { struct dir_info *dest; char *name, *pathname; int res; dest = (move->ops & ACTION_MOVE_MOVE) ? move->dest : move->dir_ent->our_dir; name = (move->ops & ACTION_MOVE_RENAME) ? move->name : move->dir_ent->name; if (dest->subpath[0] != '\0') res = asprintf(&pathname, "%s/%s", dest->subpath, name); else res = asprintf(&pathname, "/%s", name); if (res == -1) BAD_ERROR("asprintf failed in move_pathname\n"); return pathname; } static char *get_comp(char **pathname) { char *path = *pathname, *start; while (*path == '/') path++; if (*path == '\0') return NULL; start = path; while (*path != '/' && *path != '\0') path++; *pathname = path; return strndup(start, path - start); } static struct dir_ent *lookup_comp(char *comp, struct dir_info *dest) { struct dir_ent *dir_ent; for (dir_ent = dest->list; dir_ent; dir_ent = dir_ent->next) if (strcmp(comp, dir_ent->name) == 0) break; return dir_ent; } void eval_move(struct action_data *action_data, struct move_ent *move, struct dir_info *root, struct dir_ent *dir_ent, char *pathname) { struct dir_info *dest, *source = dir_ent->our_dir; struct dir_ent *comp_ent; char *comp, *path = pathname; /* * Walk pathname to get the destination directory * * Like the mv command, if the last component exists and it * is a directory, then move the file into that directory, * otherwise, move the file into parent directory of the last * component and rename to the last component. */ if (pathname[0] == '/') /* absolute pathname, walk from root directory */ dest = root; else /* relative pathname, walk from current directory */ dest = source; for (comp = get_comp(&pathname); comp; free(comp), comp = get_comp(&pathname)) { if (strcmp(comp, ".") == 0) continue; if (strcmp(comp, "..") == 0) { /* if we're in the root directory then ignore */ if (dest->depth > 1) dest = dest->dir_ent->our_dir; continue; } /* * Look up comp in current directory, if it exists and it is a * directory continue walking the pathname, otherwise exit, * we've walked as far as we can go, normally this is because * we've arrived at the leaf component which we are going to * rename source to */ comp_ent = lookup_comp(comp, dest); if (comp_ent == NULL || (comp_ent->inode->buf.st_mode & S_IFMT) != S_IFDIR) break; dest = comp_ent->dir; } if (comp) { /* Leaf component? If so we're renaming to this */ char *remainder = get_comp(&pathname); free(remainder); if (remainder) { /* * trying to move source to a subdirectory of * comp, but comp either doesn't exist, or it isn't * a directory, which is impossible */ if (comp_ent == NULL) ERROR("Move action: cannot move %s to %s, no " "such directory %s\n", action_data->subpath, path, comp); else ERROR("Move action: cannot move %s to %s, %s " "is not a directory\n", action_data->subpath, path, comp); free(comp); return; } /* * Multiple move actions triggering on one file can be merged * if one is a RENAME and the other is a MOVE. Multiple RENAMEs * can only merge if they're doing the same thing */ if (move->ops & ACTION_MOVE_RENAME) { if (strcmp(comp, move->name) != 0) { char *conf_path = move_pathname(move); ERROR("Move action: Cannot move %s to %s, " "conflicting move, already moving " "to %s via another move action!\n", action_data->subpath, path, conf_path); free(conf_path); free(comp); return; } free(comp); } else { move->name = comp; move->ops |= ACTION_MOVE_RENAME; } } if (dest != source) { /* * Multiple move actions triggering on one file can be merged * if one is a RENAME and the other is a MOVE. Multiple MOVEs * can only merge if they're doing the same thing */ if (move->ops & ACTION_MOVE_MOVE) { if (dest != move->dest) { char *conf_path = move_pathname(move); ERROR("Move action: Cannot move %s to %s, " "conflicting move, already moving " "to %s via another move action!\n", action_data->subpath, path, conf_path); free(conf_path); return; } } else { move->dest = dest; move->ops |= ACTION_MOVE_MOVE; } } } static int subdirectory(struct dir_info *source, struct dir_info *dest) { if (source == NULL) return 0; return strlen(source->subpath) <= strlen(dest->subpath) && (dest->subpath[strlen(source->subpath)] == '/' || dest->subpath[strlen(source->subpath)] == '\0') && strncmp(source->subpath, dest->subpath, strlen(source->subpath)) == 0; } void eval_move_actions(struct dir_info *root, struct dir_ent *dir_ent) { int i; struct action_data action_data; struct move_ent *move = NULL; action_data.name = dir_ent->name; action_data.pathname = pathname(dir_ent); action_data.subpath = subpathname(dir_ent); action_data.buf = &dir_ent->inode->buf; action_data.depth = dir_ent->our_dir->depth; /* * Evaluate each move action against the current file. For any * move actions that match don't actually perform the move now, but, * store it, and execute all the stored move actions together once the * directory scan is complete. This is done to ensure each separate * move action does not nondeterministically interfere with other move * actions. Each move action is considered to act independently, and * each move action sees the directory tree in the same state. */ for (i = 0; i < move_count; i++) { struct action *action = &move_spec[i]; int match = eval_expr(action->expr, &action_data); if (match) { if (move == NULL) { move = malloc(sizeof(*move)); if (move == NULL) MEM_ERROR(); move->ops = 0; move->dir_ent = dir_ent; } eval_move(&action_data, move, root, dir_ent, action->argv[0]); } } if (move) { struct dir_ent *comp_ent; struct dir_info *dest; char *name; /* * Move contains the result of all triggered move actions. * Check the destination doesn't already exist */ if (move->ops == 0) { free(move); return; } dest = (move->ops & ACTION_MOVE_MOVE) ? move->dest : dir_ent->our_dir; name = (move->ops & ACTION_MOVE_RENAME) ? move->name : dir_ent->name; comp_ent = lookup_comp(name, dest); if (comp_ent) { char *conf_path = move_pathname(move); ERROR("Move action: Cannot move %s to %s, " "destination already exists\n", action_data.subpath, conf_path); free(conf_path); free(move); return; } /* * If we're moving a directory, check we're not moving it to a * subdirectory of itself */ if (subdirectory(dir_ent->dir, dest)) { char *conf_path = move_pathname(move); ERROR("Move action: Cannot move %s to %s, this is a " "subdirectory of itself\n", action_data.subpath, conf_path); free(conf_path); free(move); return; } move->next = move_list; move_list = move; } } static void move_dir(struct dir_ent *dir_ent) { struct dir_info *dir = dir_ent->dir; struct dir_ent *comp_ent; /* update our directory's subpath name */ free(dir->subpath); dir->subpath = strdup(subpathname(dir_ent)); /* recursively update the subpaths of any sub-directories */ for (comp_ent = dir->list; comp_ent; comp_ent = comp_ent->next) if (comp_ent->dir) move_dir(comp_ent); } static void move_file(struct move_ent *move_ent) { struct dir_ent *dir_ent = move_ent->dir_ent; if (move_ent->ops & ACTION_MOVE_MOVE) { struct dir_ent *comp_ent, *prev = NULL; struct dir_info *source = dir_ent->our_dir, *dest = move_ent->dest; char *filename = pathname(dir_ent); /* * If we're moving a directory, check we're not moving it to a * subdirectory of itself */ if (subdirectory(dir_ent->dir, dest)) { char *conf_path = move_pathname(move_ent); ERROR("Move action: Cannot move %s to %s, this is a " "subdirectory of itself\n", subpathname(dir_ent), conf_path); free(conf_path); return; } /* Remove the file from source directory */ for (comp_ent = source->list; comp_ent != dir_ent; prev = comp_ent, comp_ent = comp_ent->next) ; if (prev) prev->next = comp_ent->next; else source->list = comp_ent->next; source->count--; if ((comp_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) source->directory_count--; /* Add the file to dest directory */ comp_ent->next = dest->list; dest->list = comp_ent; comp_ent->our_dir = dest; dest->count++; if ((comp_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) dest->directory_count++; /* * We've moved the file, and so we can't now use the * parent directory's pathname to calculate the pathname */ if (dir_ent->nonstandard_pathname == NULL) { dir_ent->nonstandard_pathname = strdup(filename); if (dir_ent->source_name) { free(dir_ent->source_name); dir_ent->source_name = NULL; } } } if (move_ent->ops & ACTION_MOVE_RENAME) { /* * If we're using name in conjunction with the parent * directory's pathname to calculate the pathname, we need * to use source_name to override. Otherwise it's already being * over-ridden */ if (dir_ent->nonstandard_pathname == NULL && dir_ent->source_name == NULL) dir_ent->source_name = dir_ent->name; else free(dir_ent->name); dir_ent->name = move_ent->name; } if (dir_ent->dir) /* * dir_ent is a directory, and we have to recursively fix-up * its subpath, and the subpaths of all of its sub-directories */ move_dir(dir_ent); } void do_move_actions() { while (move_list) { struct move_ent *temp = move_list; struct dir_info *dest = (move_list->ops & ACTION_MOVE_MOVE) ? move_list->dest : move_list->dir_ent->our_dir; char *name = (move_list->ops & ACTION_MOVE_RENAME) ? move_list->name : move_list->dir_ent->name; struct dir_ent *comp_ent = lookup_comp(name, dest); if (comp_ent) { char *conf_path = move_pathname(move_list); ERROR("Move action: Cannot move %s to %s, " "destination already exists\n", subpathname(move_list->dir_ent), conf_path); free(conf_path); } else move_file(move_list); move_list = move_list->next; free(temp); } } /* * General test evaluation code */ /* * A number can be of the form [range]number[size] * [range] is either: * '<' or '-', match on less than number * '>' or '+', match on greater than number * '' (nothing), match on exactly number * [size] is either: * '' (nothing), number * 'k' or 'K', number * 2^10 * 'm' or 'M', number * 2^20 * 'g' or 'G', number * 2^30 */ static int parse_number(char *start, long long *size, int *range, char **error) { char *end; long long number; if (*start == '>' || *start == '+') { *range = NUM_GREATER; start++; } else if (*start == '<' || *start == '-') { *range = NUM_LESS; start++; } else *range = NUM_EQ; errno = 0; /* To enable failure after call to be determined */ number = strtoll(start, &end, 10); if ((errno == ERANGE && (number == LLONG_MAX || number == LLONG_MIN)) || (errno != 0 && number == 0)) { /* long long underflow or overflow in conversion, or other * conversion error. * Note: we don't check for LLONG_MIN and LLONG_MAX only * because strtoll can validly return that if the * user used these values */ *error = "Long long underflow, overflow or other conversion " "error"; return 0; } if (end == start) { /* Couldn't read any number */ *error = "Number expected"; return 0; } switch (end[0]) { case 'g': case 'G': number *= 1024; case 'm': case 'M': number *= 1024; case 'k': case 'K': number *= 1024; if (end[1] != '\0') { *error = "Trailing junk after size specifier"; return 0; } break; case '\0': break; default: *error = "Trailing junk after number"; return 0; } *size = number; return 1; } static int parse_number_arg(struct test_entry *test, struct atom *atom) { struct test_number_arg *number; long long size; int range; char *error; int res = parse_number(atom->argv[0], &size, &range, &error); if (res == 0) { TEST_SYNTAX_ERROR(test, 0, "%s\n", error); return 0; } number = malloc(sizeof(*number)); if (number == NULL) MEM_ERROR(); number->range = range; number->size = size; atom->data = number; return 1; } static int parse_range_args(struct test_entry *test, struct atom *atom) { struct test_range_args *range; long long start, end; int type; int res; char *error; res = parse_number(atom->argv[0], &start, &type, &error); if (res == 0) { TEST_SYNTAX_ERROR(test, 0, "%s\n", error); return 0; } if (type != NUM_EQ) { TEST_SYNTAX_ERROR(test, 0, "Range specifier (<, >, -, +) not " "expected\n"); return 0; } res = parse_number(atom->argv[1], &end, &type, &error); if (res == 0) { TEST_SYNTAX_ERROR(test, 1, "%s\n", error); return 0; } if (type != NUM_EQ) { TEST_SYNTAX_ERROR(test, 1, "Range specifier (<, >, -, +) not " "expected\n"); return 0; } range = malloc(sizeof(*range)); if (range == NULL) MEM_ERROR(); range->start = start; range->end = end; atom->data = range; return 1; } /* * Generic test code macro */ #define TEST_FN(NAME, MATCH, CODE) \ static int NAME##_fn(struct atom *atom, struct action_data *action_data) \ { \ /* test operates on MATCH file types only */ \ if (!(action_data->buf->st_mode & MATCH)) \ return 0; \ \ CODE \ } /* * Generic test code macro testing VAR for size (eq, less than, greater than) */ #define TEST_VAR_FN(NAME, MATCH, VAR) TEST_FN(NAME, MATCH, \ { \ int match = 0; \ struct test_number_arg *number = atom->data; \ \ switch (number->range) { \ case NUM_EQ: \ match = VAR == number->size; \ break; \ case NUM_LESS: \ match = VAR < number->size; \ break; \ case NUM_GREATER: \ match = VAR > number->size; \ break; \ } \ \ return match; \ }) /* * Generic test code macro testing VAR for range [x, y] (value between x and y * inclusive). */ #define TEST_VAR_RANGE_FN(NAME, MATCH, VAR) TEST_FN(NAME##_range, MATCH, \ { \ struct test_range_args *range = atom->data; \ \ return range->start <= VAR && VAR <= range->end; \ }) /* * Name, Pathname and Subpathname test specific code */ /* * Add a leading "/" if subpathname and pathname lacks it */ static int check_pathname(struct test_entry *test, struct atom *atom) { int res; char *name; if (atom->argv[0][0] != '/') { res = asprintf(&name, "/%s", atom->argv[0]); if (res == -1) BAD_ERROR("asprintf failed in check_pathname\n"); free(atom->argv[0]); atom->argv[0] = name; } return 1; } TEST_FN(name, ACTION_ALL_LNK, return fnmatch(atom->argv[0], action_data->name, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0;) TEST_FN(pathname, ACTION_ALL_LNK, return fnmatch(atom->argv[0], action_data->subpath, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0;) static int count_components(char *path) { int count; for (count = 0; *path != '\0'; count++) { while (*path == '/') path++; while (*path != '\0' && *path != '/') path++; } return count; } static char *get_start(char *s, int n) { int count; char *path = s; for (count = 0; *path != '\0' && count < n; count++) { while (*path == '/') path++; while (*path != '\0' && *path != '/') path++; } if (count == n) *path = '\0'; return s; } static int subpathname_fn(struct atom *atom, struct action_data *action_data) { return fnmatch(atom->argv[0], get_start(strdupa(action_data->subpath), count_components(atom->argv[0])), FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0; } TEST_VAR_FN(filesize, ACTION_REG, action_data->buf->st_size) TEST_VAR_FN(dirsize, ACTION_DIR, action_data->buf->st_size) TEST_VAR_FN(size, ACTION_ALL_LNK, action_data->buf->st_size) TEST_VAR_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino) TEST_VAR_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink) TEST_VAR_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks) TEST_VAR_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks) TEST_VAR_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks) TEST_VAR_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid) TEST_VAR_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid) TEST_VAR_FN(depth, ACTION_ALL_LNK, action_data->depth) TEST_VAR_RANGE_FN(filesize, ACTION_REG, action_data->buf->st_size) TEST_VAR_RANGE_FN(dirsize, ACTION_DIR, action_data->buf->st_size) TEST_VAR_RANGE_FN(size, ACTION_ALL_LNK, action_data->buf->st_size) TEST_VAR_RANGE_FN(inode, ACTION_ALL_LNK, action_data->buf->st_ino) TEST_VAR_RANGE_FN(nlink, ACTION_ALL_LNK, action_data->buf->st_nlink) TEST_VAR_RANGE_FN(fileblocks, ACTION_REG, action_data->buf->st_blocks) TEST_VAR_RANGE_FN(dirblocks, ACTION_DIR, action_data->buf->st_blocks) TEST_VAR_RANGE_FN(blocks, ACTION_ALL_LNK, action_data->buf->st_blocks) TEST_VAR_RANGE_FN(gid, ACTION_ALL_LNK, action_data->buf->st_gid) TEST_VAR_RANGE_FN(uid, ACTION_ALL_LNK, action_data->buf->st_uid) TEST_VAR_RANGE_FN(depth, ACTION_ALL_LNK, action_data->depth) /* * Type test specific code */ struct type_entry type_table[] = { {S_IFSOCK, 's'}, {S_IFLNK, 'l'}, {S_IFREG, 'f'}, {S_IFBLK, 'b'}, {S_IFDIR, 'd'}, {S_IFCHR, 'c'}, {S_IFIFO, 'p'}, {0, 0}, }; static int parse_type_arg(struct test_entry *test, struct atom *atom) { int i; if (strlen(atom->argv[0]) != 1) goto failed; for (i = 0; type_table[i].type != 0; i++) if (type_table[i].type == atom->argv[0][0]) break; atom->data = &type_table[i]; if (type_table[i].type != 0) return 1; failed: TEST_SYNTAX_ERROR(test, 0, "Unexpected file type, expected 'f', 'd', " "'c', 'b', 'l', 's' or 'p'\n"); return 0; } static int type_fn(struct atom *atom, struct action_data *action_data) { struct type_entry *type = atom->data; return (action_data->buf->st_mode & S_IFMT) == type->value; } /* * True test specific code */ static int true_fn(struct atom *atom, struct action_data *action_data) { return 1; } /* * False test specific code */ static int false_fn(struct atom *atom, struct action_data *action_data) { return 0; } /* * File test specific code */ static int parse_file_arg(struct test_entry *test, struct atom *atom) { int res; regex_t *preg = malloc(sizeof(regex_t)); if (preg == NULL) MEM_ERROR(); res = regcomp(preg, atom->argv[0], REG_EXTENDED); if (res) { char str[1024]; /* overflow safe */ regerror(res, preg, str, 1024); free(preg); TEST_SYNTAX_ERROR(test, 0, "invalid regex \"%s\" because " "\"%s\"\n", atom->argv[0], str); return 0; } atom->data = preg; return 1; } static int file_fn(struct atom *atom, struct action_data *action_data) { int child, res, size = 0, status; int pipefd[2]; char *buffer = NULL; regex_t *preg = atom->data; res = pipe(pipefd); if (res == -1) BAD_ERROR("file_fn pipe failed\n"); child = fork(); if (child == -1) BAD_ERROR("file_fn fork_failed\n"); if (child == 0) { /* * Child process * Connect stdout to pipefd[1] and execute file command */ close(STDOUT_FILENO); res = dup(pipefd[1]); if (res == -1) exit(EXIT_FAILURE); execlp("file", "file", "-b", action_data->pathname, (char *)NULL); exit(EXIT_FAILURE); } /* * Parent process. Read stdout from file command */ close(pipefd[1]); do { buffer = realloc(buffer, size + 512); if (buffer == NULL) MEM_ERROR(); res = read_bytes(pipefd[0], buffer + size, 512); if (res == -1) BAD_ERROR("file_fn pipe read error\n"); size += 512; } while (res == 512); size = size + res - 512; buffer[size] = '\0'; res = waitpid(child, &status, 0); if (res == -1) BAD_ERROR("file_fn waitpid failed\n"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) BAD_ERROR("file_fn file returned error\n"); close(pipefd[0]); res = regexec(preg, buffer, (size_t) 0, NULL, 0); free(buffer); return res == 0; } /* * Exec test specific code */ static int exec_fn(struct atom *atom, struct action_data *action_data) { int child, i, res, status; child = fork(); if (child == -1) BAD_ERROR("exec_fn fork_failed\n"); if (child == 0) { /* * Child process * redirect stdin, stdout & stderr to /dev/null and * execute atom->argv[0] */ int fd = open("/dev/null", O_RDWR); if (fd == -1) exit(EXIT_FAILURE); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); for (i = 0; i < 3; i++) { res = dup(fd); if (res == -1) exit(EXIT_FAILURE); } close(fd); /* * Create environment variables * NAME: name of file * PATHNAME: pathname of file relative to squashfs root * SOURCE_PATHNAME: the pathname of the file in the source * directory */ res = setenv("NAME", action_data->name, 1); if (res == -1) exit(EXIT_FAILURE); res = setenv("PATHNAME", action_data->subpath, 1); if (res == -1) exit(EXIT_FAILURE); res = setenv("SOURCE_PATHNAME", action_data->pathname, 1); if (res == -1) exit(EXIT_FAILURE); execl("/bin/sh", "sh", "-c", atom->argv[0], (char *)NULL); exit(EXIT_FAILURE); } /* * Parent process. */ res = waitpid(child, &status, 0); if (res == -1) BAD_ERROR("exec_fn waitpid failed\n"); return WIFEXITED(status) ? WEXITSTATUS(status) == 0 : 0; } #ifdef SQUASHFS_TRACE static void dump_parse_tree(struct expr *expr) { if (expr->type == ATOM_TYPE) { int i; printf("%s(", expr->atom.test->name); for (i = 0; i < expr->atom.test->args; i++) { printf("%s", expr->atom.argv[i]); if (i + 1 < expr->atom.test->args) printf(","); } printf(")"); } else if (expr->type == UNARY_TYPE) { printf("%s", token_table[expr->unary_op.op].string); dump_parse_tree(expr->unary_op.expr); } else { printf("("); dump_parse_tree(expr->expr_op.lhs); printf("%s", token_table[expr->expr_op.op].string); dump_parse_tree(expr->expr_op.rhs); printf(")"); } } void dump_action_list(struct action *spec_list, int spec_count) { int i; for (i = 0; i < spec_count; i++) { printf("%s", spec_list[i].action->name); if (spec_list[i].action->args) { int n; printf("("); for (n = 0; n < spec_list[i].action->args; n++) { printf("%s", spec_list[i].argv[n]); if (n + 1 < spec_list[i].action->args) printf(","); } printf(")"); } printf("="); dump_parse_tree(spec_list[i].expr); printf("\n"); } } void dump_actions() { dump_action_list(exclude_spec, exclude_count); dump_action_list(fragment_spec, fragment_count); dump_action_list(other_spec, other_count); dump_action_list(move_spec, move_count); dump_action_list(empty_spec, empty_count); } #else void dump_actions() { } #endif static struct test_entry test_table[] = { {"name", 1, name_fn}, {"pathname", 1, pathname_fn, check_pathname}, {"subpathname", 1, subpathname_fn, check_pathname}, {"filesize", 1, filesize_fn, parse_number_arg}, {"dirsize", 1, dirsize_fn, parse_number_arg}, {"size", 1, size_fn, parse_number_arg}, {"inode", 1, inode_fn, parse_number_arg}, {"nlink", 1, nlink_fn, parse_number_arg}, {"fileblocks", 1, fileblocks_fn, parse_number_arg}, {"dirblocks", 1, dirblocks_fn, parse_number_arg}, {"blocks", 1, blocks_fn, parse_number_arg}, {"gid", 1, gid_fn, parse_number_arg}, {"uid", 1, uid_fn, parse_number_arg}, {"depth", 1, depth_fn, parse_number_arg}, {"filesize_range", 2, filesize_range_fn, parse_range_args}, {"dirsize_range", 2, dirsize_range_fn, parse_range_args}, {"size_range", 2, size_range_fn, parse_range_args}, {"inode_range", 2, inode_range_fn, parse_range_args}, {"nlink_range", 2, nlink_range_fn, parse_range_args}, {"fileblocks_range", 2, fileblocks_range_fn, parse_range_args}, {"dirblocks_range", 2, dirblocks_range_fn, parse_range_args}, {"blocks_range", 2, blocks_range_fn, parse_range_args}, {"gid_range", 2, gid_range_fn, parse_range_args}, {"uid_range", 2, uid_range_fn, parse_range_args}, {"depth_range", 2, depth_range_fn, parse_range_args}, {"type", 1, type_fn, parse_type_arg}, {"true", 0, true_fn, NULL}, {"false", 0, false_fn, NULL}, {"file", 1, file_fn, parse_file_arg}, {"exec", 1, exec_fn, NULL}, {"", -1} }; static struct action_entry action_table[] = { {"fragment", FRAGMENT_ACTION, 1, ACTION_REG, NULL, NULL}, {"exclude", EXCLUDE_ACTION, 0, ACTION_ALL_LNK, NULL, NULL}, {"fragments", FRAGMENTS_ACTION, 0, ACTION_REG, NULL, frag_action}, {"no-fragments", NO_FRAGMENTS_ACTION, 0, ACTION_REG, NULL, no_frag_action}, {"always-use-fragments", ALWAYS_FRAGS_ACTION, 0, ACTION_REG, NULL, always_frag_action}, {"dont-always-use-fragments", NO_ALWAYS_FRAGS_ACTION, 0, ACTION_REG, NULL, no_always_frag_action}, {"compressed", COMPRESSED_ACTION, 0, ACTION_REG, NULL, comp_action}, {"uncompressed", UNCOMPRESSED_ACTION, 0, ACTION_REG, NULL, uncomp_action}, {"uid", UID_ACTION, 1, ACTION_ALL_LNK, parse_uid_args, uid_action}, {"gid", GID_ACTION, 1, ACTION_ALL_LNK, parse_gid_args, gid_action}, {"guid", GUID_ACTION, 2, ACTION_ALL_LNK, parse_guid_args, guid_action}, {"mode", MODE_ACTION, -2, ACTION_ALL, parse_mode_args, mode_action}, {"empty", EMPTY_ACTION, -2, ACTION_DIR, parse_empty_args, NULL}, {"move", MOVE_ACTION, -2, ACTION_ALL_LNK, NULL, NULL}, {"", 0, -1, 0, NULL, NULL} }; ================================================ FILE: src/squashfs/caches-queues-lists.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * caches-queues-lists.c */ #include #include #include #include #include "error.h" #include "caches-queues-lists.h" extern int add_overflow(int, int); extern int multiply_overflow(int, int); #define TRUE 1 #define FALSE 0 struct queue *queue_init(int size) { struct queue *queue = malloc(sizeof(struct queue)); if (queue == NULL) MEM_ERROR(); if (add_overflow(size, 1) || multiply_overflow(size + 1, sizeof(void *))) BAD_ERROR("Size too large in queue_init\n"); queue->data = malloc(sizeof(void *) * (size + 1)); if (queue->data == NULL) MEM_ERROR(); queue->size = size + 1; queue->readp = queue->writep = 0; pthread_mutex_init(&queue->mutex, NULL); pthread_cond_init(&queue->empty, NULL); pthread_cond_init(&queue->full, NULL); return queue; } void queue_put(struct queue *queue, void *data) { int nextp; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); while ((nextp = (queue->writep + 1) % queue->size) == queue->readp) pthread_cond_wait(&queue->full, &queue->mutex); queue->data[queue->writep] = data; queue->writep = nextp; pthread_cond_signal(&queue->empty); pthread_cleanup_pop(1); } void *queue_get(struct queue *queue) { void *data; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); while (queue->readp == queue->writep) pthread_cond_wait(&queue->empty, &queue->mutex); data = queue->data[queue->readp]; queue->readp = (queue->readp + 1) % queue->size; pthread_cond_signal(&queue->full); pthread_cleanup_pop(1); return data; } int queue_empty(struct queue *queue) { int empty; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); empty = queue->readp == queue->writep; pthread_cleanup_pop(1); return empty; } void queue_flush(struct queue *queue) { pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); queue->readp = queue->writep; pthread_cleanup_pop(1); } void dump_queue(struct queue *queue) { pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); printf("\tMax size %d, size %d%s\n", queue->size - 1, queue->readp <= queue->writep ? queue->writep - queue->readp : queue->size - queue->readp + queue->writep, queue->readp == queue->writep ? " (EMPTY)" : ((queue->writep + 1) % queue->size) == queue->readp ? " (FULL)" : ""); pthread_cleanup_pop(1); } /* define seq queue hash tables */ #define CALCULATE_SEQ_HASH(N) CALCULATE_HASH(N) /* Called with the seq queue mutex held */ INSERT_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq) /* Called with the cache mutex held */ REMOVE_HASH_TABLE(seq, struct seq_queue, CALCULATE_SEQ_HASH, sequence, seq); static unsigned int sequence = 0; struct seq_queue *seq_queue_init() { struct seq_queue *queue = malloc(sizeof(struct seq_queue)); if (queue == NULL) MEM_ERROR(); memset(queue, 0, sizeof(struct seq_queue)); pthread_mutex_init(&queue->mutex, NULL); pthread_cond_init(&queue->wait, NULL); return queue; } void seq_queue_put(struct seq_queue *queue, struct file_buffer *entry) { pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); insert_seq_hash_table(queue, entry); if (entry->fragment) queue->fragment_count++; else queue->block_count++; if (entry->sequence == sequence) pthread_cond_signal(&queue->wait); pthread_cleanup_pop(1); } struct file_buffer *seq_queue_get(struct seq_queue *queue) { /* * Look-up buffer matching sequence in the queue, if found return * it, otherwise wait until it arrives */ int hash = CALCULATE_SEQ_HASH(sequence); struct file_buffer *entry; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); while (1) { for (entry = queue->hash_table[hash]; entry; entry = entry->seq_next) if (entry->sequence == sequence) break; if (entry) { /* * found the buffer in the queue, decrement the * appropriate count, and remove from hash list */ if (entry->fragment) queue->fragment_count--; else queue->block_count--; remove_seq_hash_table(queue, entry); sequence++; break; } /* entry not found, wait for it to arrive */ pthread_cond_wait(&queue->wait, &queue->mutex); } pthread_cleanup_pop(1); return entry; } void seq_queue_flush(struct seq_queue *queue) { int i; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); for (i = 0; i < HASH_SIZE; i++) queue->hash_table[i] = NULL; queue->fragment_count = queue->block_count = 0; pthread_cleanup_pop(1); } void dump_seq_queue(struct seq_queue *queue, int fragment_queue) { int size; pthread_cleanup_push((void *)pthread_mutex_unlock, &queue->mutex); pthread_mutex_lock(&queue->mutex); size = fragment_queue ? queue->fragment_count : queue->block_count; printf("\tMax size unlimited, size %d%s\n", size, size == 0 ? " (EMPTY)" : ""); pthread_cleanup_pop(1); } /* define cache hash tables */ #define CALCULATE_CACHE_HASH(N) CALCULATE_HASH(llabs(N)) /* Called with the cache mutex held */ INSERT_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash) /* Called with the cache mutex held */ REMOVE_HASH_TABLE(cache, struct cache, CALCULATE_CACHE_HASH, index, hash); /* define cache free list */ /* Called with the cache mutex held */ INSERT_LIST(free, struct file_buffer) /* Called with the cache mutex held */ REMOVE_LIST(free, struct file_buffer) struct cache *cache_init(int buffer_size, int max_buffers, int noshrink_lookup, int first_freelist) { struct cache *cache = malloc(sizeof(struct cache)); if (cache == NULL) MEM_ERROR(); cache->max_buffers = max_buffers; cache->buffer_size = buffer_size; cache->count = 0; cache->used = 0; cache->free_list = NULL; /* * The cache will grow up to max_buffers in size in response to * an increase in readhead/number of buffers in flight. But * once the outstanding buffers gets returned, we can either elect * to shrink the cache, or to put the freed blocks onto a free list. * * For the caches where we want to do lookup (fragment/writer), * a don't shrink policy is best, for the reader cache it * makes no sense to keep buffers around longer than necessary as * we don't do any lookup on those blocks. */ cache->noshrink_lookup = noshrink_lookup; /* * The default use freelist before growing cache policy behaves * poorly with appending - with many duplicates the caches * do not grow due to the fact that large queues of outstanding * fragments/writer blocks do not occur, leading to small caches * and un-uncessary performance loss to frequent cache * replacement in the small caches. Therefore with appending * change the policy to grow the caches before reusing blocks * from the freelist */ cache->first_freelist = first_freelist; memset(cache->hash_table, 0, sizeof(struct file_buffer *) * 65536); pthread_mutex_init(&cache->mutex, NULL); pthread_cond_init(&cache->wait_for_free, NULL); pthread_cond_init(&cache->wait_for_unlock, NULL); return cache; } struct file_buffer *cache_lookup(struct cache *cache, long long index) { /* Lookup block in the cache, if found return with usage count * incremented, if not found return NULL */ int hash = CALCULATE_CACHE_HASH(index); struct file_buffer *entry; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); for (entry = cache->hash_table[hash]; entry; entry = entry->hash_next) if (entry->index == index) break; if (entry) { /* found the block in the cache, increment used count and * if necessary remove from free list so it won't disappear */ if (entry->used == 0) { remove_free_list(&cache->free_list, entry); cache->used++; } entry->used++; } pthread_cleanup_pop(1); return entry; } static struct file_buffer *cache_freelist(struct cache *cache) { struct file_buffer *entry = cache->free_list; remove_free_list(&cache->free_list, entry); /* a block on the free_list is hashed */ remove_cache_hash_table(cache, entry); cache->used++; return entry; } static struct file_buffer *cache_alloc(struct cache *cache) { struct file_buffer *entry = malloc(sizeof(struct file_buffer) + cache->buffer_size); if (entry == NULL) MEM_ERROR(); entry->cache = cache; entry->free_prev = entry->free_next = NULL; cache->count++; return entry; } static struct file_buffer *_cache_get(struct cache *cache, long long index, int hash) { /* Get a free block out of the cache indexed on index. */ struct file_buffer *entry = NULL; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); while (1) { if (cache->noshrink_lookup) { /* first try to get a block from the free list */ if (cache->first_freelist && cache->free_list) entry = cache_freelist(cache); else if (cache->count < cache->max_buffers) { entry = cache_alloc(cache); cache->used++; } else if (!cache->first_freelist && cache->free_list) entry = cache_freelist(cache); } else { /* shrinking non-lookup cache */ if (cache->count < cache->max_buffers) { entry = cache_alloc(cache); if (cache->count > cache->max_count) cache->max_count = cache->count; } } if (entry) break; /* wait for a block */ pthread_cond_wait(&cache->wait_for_free, &cache->mutex); } /* initialise block and if hash is set insert into the hash table */ entry->used = 1; entry->locked = FALSE; entry->wait_on_unlock = FALSE; entry->error = FALSE; if (hash) { entry->index = index; insert_cache_hash_table(cache, entry); } pthread_cleanup_pop(1); return entry; } struct file_buffer *cache_get(struct cache *cache, long long index) { return _cache_get(cache, index, 1); } struct file_buffer *cache_get_nohash(struct cache *cache) { return _cache_get(cache, 0, 0); } void cache_hash(struct file_buffer *entry, long long index) { struct cache *cache = entry->cache; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); entry->index = index; insert_cache_hash_table(cache, entry); pthread_cleanup_pop(1); } void cache_block_put(struct file_buffer *entry) { struct cache *cache; /* * Finished with this cache entry, once the usage count reaches zero it * can be reused. * * If noshrink_lookup is set, put the block onto the free list. * As blocks remain accessible via the hash table they can be found * getting a new lease of life before they are reused. * * if noshrink_lookup is not set then shrink the cache. */ if (entry == NULL) return; cache = entry->cache; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); entry->used--; if (entry->used == 0) { if (cache->noshrink_lookup) { insert_free_list(&cache->free_list, entry); cache->used--; } else { free(entry); cache->count--; } /* One or more threads may be waiting on this block */ pthread_cond_signal(&cache->wait_for_free); } pthread_cleanup_pop(1); } void dump_cache(struct cache *cache) { pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); if (cache->noshrink_lookup) printf("\tMax buffers %d, Current size %d, Used %d, %s\n", cache->max_buffers, cache->count, cache->used, cache->free_list ? "Free buffers" : "No free buffers"); else printf("\tMax buffers %d, Current size %d, Maximum historical " "size %d\n", cache->max_buffers, cache->count, cache->max_count); pthread_cleanup_pop(1); } struct file_buffer *cache_get_nowait(struct cache *cache, long long index) { struct file_buffer *entry = NULL; /* * block doesn't exist, create it, but return it with the * locked flag set, so nothing tries to use it while it doesn't * contain data. * * If there's no space in the cache then return NULL. */ pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); /* first try to get a block from the free list */ if (cache->first_freelist && cache->free_list) entry = cache_freelist(cache); else if (cache->count < cache->max_buffers) { entry = cache_alloc(cache); cache->used++; } else if (!cache->first_freelist && cache->free_list) entry = cache_freelist(cache); if (entry) { /* initialise block and insert into the hash table */ entry->used = 1; entry->locked = TRUE; entry->wait_on_unlock = FALSE; entry->error = FALSE; entry->index = index; insert_cache_hash_table(cache, entry); } pthread_cleanup_pop(1); return entry; } struct file_buffer *cache_lookup_nowait(struct cache *cache, long long index, char *locked) { /* * Lookup block in the cache, if found return it with the locked flag * indicating whether it is currently locked. In both cases increment * the used count. * * If it doesn't exist in the cache return NULL; */ int hash = CALCULATE_CACHE_HASH(index); struct file_buffer *entry; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); /* first check if the entry already exists */ for (entry = cache->hash_table[hash]; entry; entry = entry->hash_next) if (entry->index == index) break; if (entry) { if (entry->used == 0) { remove_free_list(&cache->free_list, entry); cache->used++; } entry->used++; *locked = entry->locked; } pthread_cleanup_pop(1); return entry; } void cache_wait_unlock(struct file_buffer *buffer) { struct cache *cache = buffer->cache; pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); while (buffer->locked) { /* * another thread is filling this in, wait until it * becomes unlocked. Used has been incremented to ensure it * doesn't get reused. By definition a block can't be * locked and unused, and so we don't need to worry * about it being on the freelist now, but, it may * become unused when unlocked unless used is * incremented */ buffer->wait_on_unlock = TRUE; pthread_cond_wait(&cache->wait_for_unlock, &cache->mutex); } pthread_cleanup_pop(1); } void cache_unlock(struct file_buffer *entry) { struct cache *cache = entry->cache; /* * Unlock this locked cache entry. If anything is waiting for this * to become unlocked, wake it up. */ pthread_cleanup_push((void *)pthread_mutex_unlock, &cache->mutex); pthread_mutex_lock(&cache->mutex); entry->locked = FALSE; if (entry->wait_on_unlock) { entry->wait_on_unlock = FALSE; pthread_cond_broadcast(&cache->wait_for_unlock); } pthread_cleanup_pop(1); } ================================================ FILE: src/squashfs/compressor.c ================================================ /* * * Copyright (c) 2009, 2010, 2011 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * compressor.c */ #include #include #include "compressor.h" #include "squashfs_fs.h" #ifndef GZIP_SUPPORT static struct compressor gzip_comp_ops = { ZLIB_COMPRESSION, "gzip" }; #else extern struct compressor gzip_comp_ops; #endif #ifndef LZMA_SUPPORT static struct compressor lzma_comp_ops = { LZMA_COMPRESSION, "lzma" }; #else extern struct compressor lzma_comp_ops; #endif #ifndef LZO_SUPPORT static struct compressor lzo_comp_ops = { LZO_COMPRESSION, "lzo" }; #else extern struct compressor lzo_comp_ops; #endif #ifndef LZ4_SUPPORT static struct compressor lz4_comp_ops = { LZ4_COMPRESSION, "lz4" }; #else extern struct compressor lz4_comp_ops; #endif #ifndef XZ_SUPPORT static struct compressor xz_comp_ops = { XZ_COMPRESSION, "xz" }; #else extern struct compressor xz_comp_ops; #endif static struct compressor unknown_comp_ops = { 0, "unknown" }; struct compressor *compressor[] = { &gzip_comp_ops, &lzma_comp_ops, &lzo_comp_ops, &lz4_comp_ops, &xz_comp_ops, &unknown_comp_ops }; struct compressor *lookup_compressor(char *name) { int i; for (i = 0; compressor[i]->id; i++) if (strcmp(compressor[i]->name, name) == 0) break; return compressor[i]; } struct compressor *lookup_compressor_id(int id) { int i; for (i = 0; compressor[i]->id; i++) if (id == compressor[i]->id) break; return compressor[i]; } void display_compressors(char *indent, char *def_comp) { int i; for (i = 0; compressor[i]->id; i++) if (compressor[i]->supported) fprintf(stderr, "%s\t%s%s\n", indent, compressor[i]->name, strcmp(compressor[i]->name, def_comp) == 0 ? " (default)" : ""); } void display_compressor_usage(char *def_comp) { int i; for (i = 0; compressor[i]->id; i++) if (compressor[i]->supported) { char *str = strcmp(compressor[i]->name, def_comp) == 0 ? " (default)" : ""; if (compressor[i]->usage) { fprintf(stderr, "\t%s%s\n", compressor[i]->name, str); compressor[i]->usage(); } else fprintf(stderr, "\t%s (no options)%s\n", compressor[i]->name, str); } } ================================================ FILE: src/squashfs/gzip_wrapper.c ================================================ /* * Copyright (c) 2009, 2010, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * gzip_wrapper.c * * Support for ZLIB compression http://www.zlib.net */ #include #include #include #include #include "squashfs_fs.h" #include "gzip_wrapper.h" #include "compressor.h" static struct strategy strategy[] = { {"default", Z_DEFAULT_STRATEGY, 0}, {"filtered", Z_FILTERED, 0}, {"huffman_only", Z_HUFFMAN_ONLY, 0}, {"run_length_encoded", Z_RLE, 0}, {"fixed", Z_FIXED, 0}, {NULL, 0, 0} }; static int strategy_count = 0; /* default compression level */ static int compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL; /* default window size */ static int window_size = GZIP_DEFAULT_WINDOW_SIZE; /* * This function is called by the options parsing code in mksquashfs.c * to parse any -X compressor option. * * This function returns: * >=0 (number of additional args parsed) on success * -1 if the option was unrecognised, or * -2 if the option was recognised, but otherwise bad in * some way (e.g. invalid parameter) * * Note: this function sets internal compressor state, but does not * pass back the results of the parsing other than success/failure. * The gzip_dump_options() function is called later to get the options in * a format suitable for writing to the filesystem. */ static int gzip_options(char *argv[], int argc) { if (strcmp(argv[0], "-Xcompression-level") == 0) { if (argc < 2) { fprintf(stderr, "gzip: -Xcompression-level missing " "compression level\n"); fprintf(stderr, "gzip: -Xcompression-level it " "should be 1 >= n <= 9\n"); goto failed; } compression_level = atoi(argv[1]); if (compression_level < 1 || compression_level > 9) { fprintf(stderr, "gzip: -Xcompression-level invalid, it " "should be 1 >= n <= 9\n"); goto failed; } return 1; } else if (strcmp(argv[0], "-Xwindow-size") == 0) { if (argc < 2) { fprintf(stderr, "gzip: -Xwindow-size missing window " " size\n"); fprintf(stderr, "gzip: -Xwindow-size \n"); goto failed; } window_size = atoi(argv[1]); if (window_size < 8 || window_size > 15) { fprintf(stderr, "gzip: -Xwindow-size invalid, it " "should be 8 >= n <= 15\n"); goto failed; } return 1; } else if (strcmp(argv[0], "-Xstrategy") == 0) { char *name; int i; if (argc < 2) { fprintf(stderr, "gzip: -Xstrategy missing " "strategies\n"); goto failed; } name = argv[1]; while (name[0] != '\0') { for (i = 0; strategy[i].name; i++) { int n = strlen(strategy[i].name); if ((strncmp(name, strategy[i].name, n) == 0) && (name[n] == '\0' || name[n] == ',')) { if (strategy[i].selected == 0) { strategy[i].selected = 1; strategy_count++; } name += name[n] == ',' ? n + 1 : n; break; } } if (strategy[i].name == NULL) { fprintf(stderr, "gzip: -Xstrategy unrecognised " "strategy\n"); goto failed; } } return 1; } return -1; failed: return -2; } /* * This function is called after all options have been parsed. * It is used to do post-processing on the compressor options using * values that were not expected to be known at option parse time. * * This function returns 0 on successful post processing, or * -1 on error */ static int gzip_options_post(int block_size) { if (strategy_count == 1 && strategy[0].selected) { strategy_count = 0; strategy[0].selected = 0; } return 0; } /* * This function is called by mksquashfs to dump the parsed * compressor options in a format suitable for writing to the * compressor options field in the filesystem (stored immediately * after the superblock). * * This function returns a pointer to the compression options structure * to be stored (and the size), or NULL if there are no compression * options * */ static void *gzip_dump_options(int block_size, int *size) { static struct gzip_comp_opts comp_opts; int i, strategies = 0; /* * If default compression options of: * compression-level: 8 and * window-size: 15 and * strategy_count == 0 then * don't store a compression options structure (this is compatible * with the legacy implementation of GZIP for Squashfs) */ if (compression_level == GZIP_DEFAULT_COMPRESSION_LEVEL && window_size == GZIP_DEFAULT_WINDOW_SIZE && strategy_count == 0) return NULL; for (i = 0; strategy[i].name; i++) strategies |= strategy[i].selected << i; comp_opts.compression_level = compression_level; comp_opts.window_size = window_size; comp_opts.strategy = strategies; SQUASHFS_INSWAP_COMP_OPTS(&comp_opts); *size = sizeof(comp_opts); return &comp_opts; } /* * This function is a helper specifically for the append mode of * mksquashfs. Its purpose is to set the internal compressor state * to the stored compressor options in the passed compressor options * structure. * * In effect this function sets up the compressor options * to the same state they were when the filesystem was originally * generated, this is to ensure on appending, the compressor uses * the same compression options that were used to generate the * original filesystem. * * Note, even if there are no compressor options, this function is still * called with an empty compressor structure (size == 0), to explicitly * set the default options, this is to ensure any user supplied * -X options on the appending mksquashfs command line are over-ridden * * This function returns 0 on sucessful extraction of options, and * -1 on error */ static int gzip_extract_options(int block_size, void *buffer, int size) { struct gzip_comp_opts *comp_opts = buffer; int i; if (size == 0) { /* Set default values */ compression_level = GZIP_DEFAULT_COMPRESSION_LEVEL; window_size = GZIP_DEFAULT_WINDOW_SIZE; strategy_count = 0; return 0; } /* we expect a comp_opts structure of sufficient size to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* Check comp_opts structure for correctness */ if (comp_opts->compression_level < 1 || comp_opts->compression_level > 9) { fprintf(stderr, "gzip: bad compression level in " "compression options structure\n"); goto failed; } compression_level = comp_opts->compression_level; if (comp_opts->window_size < 8 || comp_opts->window_size > 15) { fprintf(stderr, "gzip: bad window size in " "compression options structure\n"); goto failed; } window_size = comp_opts->window_size; strategy_count = 0; for (i = 0; strategy[i].name; i++) { if ((comp_opts->strategy >> i) & 1) { strategy[i].selected = 1; strategy_count++; } else strategy[i].selected = 0; } return 0; failed: fprintf(stderr, "gzip: error reading stored compressor options from " "filesystem!\n"); return -1; } void gzip_display_options(void *buffer, int size) { struct gzip_comp_opts *comp_opts = buffer; int i, printed; /* we expect a comp_opts structure of sufficient size to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* Check comp_opts structure for correctness */ if (comp_opts->compression_level < 1 || comp_opts->compression_level > 9) { fprintf(stderr, "gzip: bad compression level in " "compression options structure\n"); goto failed; } printf("\tcompression-level %d\n", comp_opts->compression_level); if (comp_opts->window_size < 8 || comp_opts->window_size > 15) { fprintf(stderr, "gzip: bad window size in " "compression options structure\n"); goto failed; } printf("\twindow-size %d\n", comp_opts->window_size); for (i = 0, printed = 0; strategy[i].name; i++) { if ((comp_opts->strategy >> i) & 1) { if (printed) printf(", "); else printf("\tStrategies selected: "); printf("%s", strategy[i].name); printed = 1; } } if (!printed) printf("\tStrategies selected: default\n"); else printf("\n"); return; failed: fprintf(stderr, "gzip: error reading stored compressor options from " "filesystem!\n"); } /* * This function is called by mksquashfs to initialise the * compressor, before compress() is called. * * This function returns 0 on success, and * -1 on error */ static int gzip_init(void **strm, int block_size, int datablock) { int i, j, res; struct gzip_stream *stream; if (!datablock || !strategy_count) { stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy)); if (stream == NULL) goto failed; stream->strategies = 1; stream->strategy[0].strategy = Z_DEFAULT_STRATEGY; } else { stream = malloc(sizeof(*stream) + sizeof(struct gzip_strategy) * strategy_count); if (stream == NULL) goto failed; memset(stream->strategy, 0, sizeof(struct gzip_strategy) * strategy_count); stream->strategies = strategy_count; for (i = 0, j = 0; strategy[i].name; i++) { if (!strategy[i].selected) continue; stream->strategy[j].strategy = strategy[i].strategy; if (j) { stream->strategy[j].buffer = malloc(block_size); if (stream->strategy[j].buffer == NULL) goto failed2; } j++; } } stream->stream.zalloc = Z_NULL; stream->stream.zfree = Z_NULL; stream->stream.opaque = 0; res = deflateInit2(&stream->stream, compression_level, Z_DEFLATED, window_size, 8, stream->strategy[0].strategy); if (res != Z_OK) goto failed2; *strm = stream; return 0; failed2: for (i = 1; i < stream->strategies; i++) free(stream->strategy[i].buffer); free(stream); failed: return -1; } static int gzip_compress(void *strm, void *d, void *s, int size, int block_size, int *error) { int i, res; struct gzip_stream *stream = strm; struct gzip_strategy *selected = NULL; stream->strategy[0].buffer = d; for (i = 0; i < stream->strategies; i++) { struct gzip_strategy *strategy = &stream->strategy[i]; res = deflateReset(&stream->stream); if (res != Z_OK) goto failed; stream->stream.next_in = s; stream->stream.avail_in = size; stream->stream.next_out = strategy->buffer; stream->stream.avail_out = block_size; if (stream->strategies > 1) { res = deflateParams(&stream->stream, compression_level, strategy->strategy); if (res != Z_OK) goto failed; } res = deflate(&stream->stream, Z_FINISH); strategy->length = stream->stream.total_out; if (res == Z_STREAM_END) { if (!selected || selected->length > strategy->length) selected = strategy; } else if (res != Z_OK) goto failed; } if (!selected) /* * Output buffer overflow. Return out of buffer space */ return 0; if (selected->buffer != d) memcpy(d, selected->buffer, selected->length); return (int)selected->length; failed: /* * All other errors return failure, with the compressor * specific error code in *error */ *error = res; return -1; } static int gzip_uncompress(void *d, void *s, int size, int outsize, int *error) { int res; unsigned long bytes = outsize; res = uncompress(d, &bytes, s, size); if (res == Z_OK) return (int)bytes; else { *error = res; return -1; } } void gzip_usage() { fprintf(stderr, "\t -Xcompression-level \n"); fprintf(stderr, "\t\t should be 1 .. 9 (default " "%d)\n", GZIP_DEFAULT_COMPRESSION_LEVEL); fprintf(stderr, "\t -Xwindow-size \n"); fprintf(stderr, "\t\t should be 8 .. 15 (default " "%d)\n", GZIP_DEFAULT_WINDOW_SIZE); fprintf(stderr, "\t -Xstrategy strategy1,strategy2,...,strategyN\n"); fprintf(stderr, "\t\tCompress using strategy1,strategy2,...,strategyN" " in turn\n"); fprintf(stderr, "\t\tand choose the best compression.\n"); fprintf(stderr, "\t\tAvailable strategies: default, filtered, " "huffman_only,\n\t\trun_length_encoded and fixed\n"); } struct compressor gzip_comp_ops = { .init = gzip_init, .compress = gzip_compress, .uncompress = gzip_uncompress, .options = gzip_options, .options_post = gzip_options_post, .dump_options = gzip_dump_options, .extract_options = gzip_extract_options, .display_options = gzip_display_options, .usage = gzip_usage, .id = ZLIB_COMPRESSION, .name = "gzip", .supported = 1 }; ================================================ FILE: src/squashfs/info.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * info.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "squashfs_fs.h" #include "mksquashfs.h" #include "error.h" #include "progressbar.h" #include "caches-queues-lists.h" static int silent = 0; static struct dir_ent *ent = NULL; pthread_t info_thread; void disable_info() { ent = NULL; } void update_info(struct dir_ent *dir_ent) { ent = dir_ent; } void print_filename() { struct dir_ent *dir_ent = ent; if (dir_ent == NULL) return; if (dir_ent->our_dir->subpath[0] != '\0') INFO("%s/%s\n", dir_ent->our_dir->subpath, dir_ent->name); else INFO("/%s\n", dir_ent->name); } void dump_state() { disable_progress_bar(); printf("Queue and Cache status dump\n"); printf("===========================\n"); printf("file buffer queue (reader thread -> deflate thread(s))\n"); dump_queue(to_deflate); printf("uncompressed fragment queue (reader thread -> fragment" " thread(s))\n"); dump_queue(to_process_frag); printf("processed fragment queue (fragment thread(s) -> main" " thread)\n"); dump_seq_queue(to_main, 1); printf("compressed block queue (deflate thread(s) -> main thread)\n"); dump_seq_queue(to_main, 0); printf("uncompressed packed fragment queue (main thread -> fragment" " deflate thread(s))\n"); dump_queue(to_frag); printf("locked frag queue (compressed frags waiting while multi-block" " file is written)\n"); dump_queue(locked_fragment); printf("compressed block queue (main & fragment deflate threads(s) ->" " writer thread)\n"); dump_queue(to_writer); printf("read cache (uncompressed blocks read by reader thread)\n"); dump_cache(reader_buffer); printf("block write cache (compressed blocks waiting for the writer" " thread)\n"); dump_cache(bwriter_buffer); printf("fragment write cache (compressed fragments waiting for the" " writer thread)\n"); dump_cache(fwriter_buffer); printf("fragment cache (frags waiting to be compressed by fragment" " deflate thread(s))\n"); dump_cache(fragment_buffer); printf("fragment reserve cache (avoids pipeline stall if frag cache" " full in dup check)\n"); dump_cache(reserve_cache); enable_progress_bar(); } void *info_thrd(void *arg) { sigset_t sigmask; struct timespec timespec = {.tv_sec = 1,.tv_nsec = 0 }; int sig, waiting = 0; sigemptyset(&sigmask); sigaddset(&sigmask, SIGQUIT); sigaddset(&sigmask, SIGHUP); while (1) { if (waiting) sig = sigtimedwait(&sigmask, NULL, ×pec); else sig = sigwaitinfo(&sigmask, NULL); if (sig == -1) { switch (errno) { case EAGAIN: /* interval timed out */ waiting = 0; /* FALLTHROUGH */ case EINTR: /* if waiting, the wait will be longer, but that's OK */ continue; default: BAD_ERROR("sigtimedwait/sigwaitinfo failed " "because %s\n", strerror(errno)); } } if (sig == SIGQUIT && !waiting) { print_filename(); /* set one second interval period, if ^\ received within then, dump queue and cache status */ waiting = 1; } else dump_state(); } } void init_info() { pthread_create(&info_thread, NULL, info_thrd, NULL); } ================================================ FILE: src/squashfs/lz4_wrapper.c ================================================ /* * Copyright (c) 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lz4_wrapper.c * * Support for LZ4 compression http://fastcompression.blogspot.com/p/lz4.html */ #include #include #include #include #include #include "squashfs_fs.h" #include "lz4_wrapper.h" #include "compressor.h" static int hc = 0; /* * This function is called by the options parsing code in mksquashfs.c * to parse any -X compressor option. * * This function returns: * >=0 (number of additional args parsed) on success * -1 if the option was unrecognised, or * -2 if the option was recognised, but otherwise bad in * some way (e.g. invalid parameter) * * Note: this function sets internal compressor state, but does not * pass back the results of the parsing other than success/failure. * The lz4_dump_options() function is called later to get the options in * a format suitable for writing to the filesystem. */ static int lz4_options(char *argv[], int argc) { if (strcmp(argv[0], "-Xhc") == 0) { hc = 1; return 0; } return -1; } /* * This function is called by mksquashfs to dump the parsed * compressor options in a format suitable for writing to the * compressor options field in the filesystem (stored immediately * after the superblock). * * This function returns a pointer to the compression options structure * to be stored (and the size), or NULL if there are no compression * options * * Currently LZ4 always returns a comp_opts structure, with * the version indicating LZ4_LEGACY stream fomat. This is to * easily accomodate changes in the kernel code to different * stream formats */ static void *lz4_dump_options(int block_size, int *size) { static struct lz4_comp_opts comp_opts; comp_opts.version = LZ4_LEGACY; comp_opts.flags = hc ? LZ4_HC : 0; SQUASHFS_INSWAP_COMP_OPTS(&comp_opts); *size = sizeof(comp_opts); return &comp_opts; } /* * This function is a helper specifically for the append mode of * mksquashfs. Its purpose is to set the internal compressor state * to the stored compressor options in the passed compressor options * structure. * * In effect this function sets up the compressor options * to the same state they were when the filesystem was originally * generated, this is to ensure on appending, the compressor uses * the same compression options that were used to generate the * original filesystem. * * Note, even if there are no compressor options, this function is still * called with an empty compressor structure (size == 0), to explicitly * set the default options, this is to ensure any user supplied * -X options on the appending mksquashfs command line are over-ridden * * This function returns 0 on sucessful extraction of options, and * -1 on error */ static int lz4_extract_options(int block_size, void *buffer, int size) { struct lz4_comp_opts *comp_opts = buffer; /* we expect a comp_opts structure to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* we expect the stream format to be LZ4_LEGACY */ if (comp_opts->version != LZ4_LEGACY) { fprintf(stderr, "lz4: unknown LZ4 version\n"); goto failed; } /* * Check compression flags, currently only LZ4_HC ("high compression") * can be set. */ if (comp_opts->flags == LZ4_HC) hc = 1; else if (comp_opts->flags != 0) { fprintf(stderr, "lz4: unknown LZ4 flags\n"); goto failed; } return 0; failed: fprintf(stderr, "lz4: error reading stored compressor options from " "filesystem!\n"); return -1; } /* * This function is a helper specifically for unsquashfs. * Its purpose is to check that the compression options are * understood by this version of LZ4. * * This is important for LZ4 because the format understood by the * Linux kernel may change from the already obsolete legacy format * currently supported. * * If this does happen, then this version of LZ4 will not be able to decode * the newer format. So we need to check for this. * * This function returns 0 on sucessful checking of options, and * -1 on error */ static int lz4_check_options(int block_size, void *buffer, int size) { struct lz4_comp_opts *comp_opts = buffer; /* we expect a comp_opts structure to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* we expect the stream format to be LZ4_LEGACY */ if (comp_opts->version != LZ4_LEGACY) { fprintf(stderr, "lz4: unknown LZ4 version\n"); goto failed; } return 0; failed: fprintf(stderr, "lz4: error reading stored compressor options from " "filesystem!\n"); return -1; } void lz4_display_options(void *buffer, int size) { struct lz4_comp_opts *comp_opts = buffer; /* check passed comp opts struct is of the correct length */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* we expect the stream format to be LZ4_LEGACY */ if (comp_opts->version != LZ4_LEGACY) { fprintf(stderr, "lz4: unknown LZ4 version\n"); goto failed; } /* * Check compression flags, currently only LZ4_HC ("high compression") * can be set. */ if (comp_opts->flags & ~LZ4_FLAGS_MASK) { fprintf(stderr, "lz4: unknown LZ4 flags\n"); goto failed; } if (comp_opts->flags & LZ4_HC) printf("\tHigh Compression option specified (-Xhc)\n"); return; failed: fprintf(stderr, "lz4: error reading stored compressor options from " "filesystem!\n"); } static int lz4_compress(void *strm, void *dest, void *src, int size, int block_size, int *error) { int res; if (hc) res = LZ4_compressHC_limitedOutput(src, dest, size, block_size); else res = LZ4_compress_limitedOutput(src, dest, size, block_size); if (res == 0) { /* * Output buffer overflow. Return out of buffer space */ return 0; } else if (res < 0) { /* * All other errors return failure, with the compressor * specific error code in *error */ *error = res; return -1; } return res; } static int lz4_uncompress(void *dest, void *src, int size, int outsize, int *error) { int res = LZ4_decompress_safe(src, dest, size, outsize); if (res < 0) { *error = res; return -1; } return res; } void lz4_usage() { fprintf(stderr, "\t -Xhc\n"); fprintf(stderr, "\t\tCompress using LZ4 High Compression\n"); } struct compressor lz4_comp_ops = { .compress = lz4_compress, .uncompress = lz4_uncompress, .options = lz4_options, .dump_options = lz4_dump_options, .extract_options = lz4_extract_options, .check_options = lz4_check_options, .display_options = lz4_display_options, .usage = lz4_usage, .id = LZ4_COMPRESSION, .name = "lz4", .supported = 1 }; ================================================ FILE: src/squashfs/lzma_wrapper.c ================================================ /* * Copyright (c) 2009, 2010, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lzma_wrapper.c * * Support for LZMA1 compression using LZMA SDK (4.65 used in * development, other versions may work) http://www.7-zip.org/sdk.html */ #include #include "squashfs_fs.h" #include "compressor.h" #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8) static int lzma_compress(void *strm, void *dest, void *src, int size, int block_size, int *error) { unsigned char *d = dest; size_t props_size = LZMA_PROPS_SIZE, outlen = block_size - LZMA_HEADER_SIZE; int res; res = LzmaCompress(dest + LZMA_HEADER_SIZE, &outlen, src, size, dest, &props_size, 5, block_size, 3, 0, 2, 32, 1); if (res == SZ_ERROR_OUTPUT_EOF) { /* * Output buffer overflow. Return out of buffer space error */ return 0; } if (res != SZ_OK) { /* * All other errors return failure, with the compressor * specific error code in *error */ *error = res; return -1; } /* * Fill in the 8 byte little endian uncompressed size field in the * LZMA header. 8 bytes is excessively large for squashfs but * this is the standard LZMA header and which is expected by the kernel * code */ d[LZMA_PROPS_SIZE] = size & 255; d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255; d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255; d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255; d[LZMA_PROPS_SIZE + 4] = 0; d[LZMA_PROPS_SIZE + 5] = 0; d[LZMA_PROPS_SIZE + 6] = 0; d[LZMA_PROPS_SIZE + 7] = 0; /* * Success, return the compressed size. Outlen returned by the LZMA * compressor does not include the LZMA header space */ return outlen + LZMA_HEADER_SIZE; } static int lzma_uncompress(void *dest, void *src, int size, int outsize, int *error) { unsigned char *s = src; size_t outlen, inlen = size - LZMA_HEADER_SIZE; int res; outlen = s[LZMA_PROPS_SIZE] | (s[LZMA_PROPS_SIZE + 1] << 8) | (s[LZMA_PROPS_SIZE + 2] << 16) | (s[LZMA_PROPS_SIZE + 3] << 24); if (outlen > outsize) { *error = 0; return -1; } res = LzmaUncompress(dest, &outlen, src + LZMA_HEADER_SIZE, &inlen, src, LZMA_PROPS_SIZE); if (res == SZ_OK) return outlen; else { *error = res; return -1; } } struct compressor lzma_comp_ops = { .init = NULL, .compress = lzma_compress, .uncompress = lzma_uncompress, .options = NULL, .usage = NULL, .id = LZMA_COMPRESSION, .name = "lzma", .supported = 1 }; ================================================ FILE: src/squashfs/lzma_xz_wrapper.c ================================================ /* * Copyright (c) 2010, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lzma_xz_wrapper.c * * Support for LZMA1 compression using XZ Utils liblzma http://tukaani.org/xz/ */ #include #include #include #include "squashfs_fs.h" #include "compressor.h" #define LZMA_PROPS_SIZE 5 #define LZMA_UNCOMP_SIZE 8 #define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMP_SIZE) #define LZMA_OPTIONS 5 #define MEMLIMIT (32 * 1024 * 1024) static int lzma_compress(void *dummy, void *dest, void *src, int size, int block_size, int *error) { unsigned char *d = (unsigned char *)dest; lzma_options_lzma opt; lzma_stream strm = LZMA_STREAM_INIT; int res; lzma_lzma_preset(&opt, LZMA_OPTIONS); opt.dict_size = block_size; res = lzma_alone_encoder(&strm, &opt); if (res != LZMA_OK) { lzma_end(&strm); goto failed; } strm.next_out = dest; strm.avail_out = block_size; strm.next_in = src; strm.avail_in = size; res = lzma_code(&strm, LZMA_FINISH); lzma_end(&strm); if (res == LZMA_STREAM_END) { /* * Fill in the 8 byte little endian uncompressed size field in * the LZMA header. 8 bytes is excessively large for squashfs * but this is the standard LZMA header and which is expected by * the kernel code */ d[LZMA_PROPS_SIZE] = size & 255; d[LZMA_PROPS_SIZE + 1] = (size >> 8) & 255; d[LZMA_PROPS_SIZE + 2] = (size >> 16) & 255; d[LZMA_PROPS_SIZE + 3] = (size >> 24) & 255; d[LZMA_PROPS_SIZE + 4] = 0; d[LZMA_PROPS_SIZE + 5] = 0; d[LZMA_PROPS_SIZE + 6] = 0; d[LZMA_PROPS_SIZE + 7] = 0; return (int)strm.total_out; } if (res == LZMA_OK) /* * Output buffer overflow. Return out of buffer space */ return 0; failed: /* * All other errors return failure, with the compressor * specific error code in *error */ *error = res; return -1; } static int lzma_uncompress(void *dest, void *src, int size, int outsize, int *error) { lzma_stream strm = LZMA_STREAM_INIT; int uncompressed_size = 0, res; unsigned char lzma_header[LZMA_HEADER_SIZE]; res = lzma_alone_decoder(&strm, MEMLIMIT); if (res != LZMA_OK) { lzma_end(&strm); goto failed; } memcpy(lzma_header, src, LZMA_HEADER_SIZE); uncompressed_size = lzma_header[LZMA_PROPS_SIZE] | (lzma_header[LZMA_PROPS_SIZE + 1] << 8) | (lzma_header[LZMA_PROPS_SIZE + 2] << 16) | (lzma_header[LZMA_PROPS_SIZE + 3] << 24); if (uncompressed_size > outsize) { res = 0; goto failed; } memset(lzma_header + LZMA_PROPS_SIZE, 255, LZMA_UNCOMP_SIZE); strm.next_out = dest; strm.avail_out = outsize; strm.next_in = lzma_header; strm.avail_in = LZMA_HEADER_SIZE; res = lzma_code(&strm, LZMA_RUN); if (res != LZMA_OK || strm.avail_in != 0) { lzma_end(&strm); goto failed; } strm.next_in = src + LZMA_HEADER_SIZE; strm.avail_in = size - LZMA_HEADER_SIZE; res = lzma_code(&strm, LZMA_FINISH); lzma_end(&strm); if (res == LZMA_STREAM_END || (res == LZMA_OK && strm.total_out >= uncompressed_size && strm.avail_in == 0)) return uncompressed_size; failed: *error = res; return -1; } struct compressor lzma_comp_ops = { .init = NULL, .compress = lzma_compress, .uncompress = lzma_uncompress, .options = NULL, .usage = NULL, .id = LZMA_COMPRESSION, .name = "lzma", .supported = 1 }; ================================================ FILE: src/squashfs/lzo_wrapper.c ================================================ /* * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * lzo_wrapper.c * * Support for LZO compression http://www.oberhumer.com/opensource/lzo */ #include #include #include #include #include #include "squashfs_fs.h" #include "lzo_wrapper.h" #include "compressor.h" static struct lzo_algorithm lzo[] = { {"lzo1x_1", LZO1X_1_MEM_COMPRESS, lzo1x_1_compress}, {"lzo1x_1_11", LZO1X_1_11_MEM_COMPRESS, lzo1x_1_11_compress}, {"lzo1x_1_12", LZO1X_1_12_MEM_COMPRESS, lzo1x_1_12_compress}, {"lzo1x_1_15", LZO1X_1_15_MEM_COMPRESS, lzo1x_1_15_compress}, {"lzo1x_999", LZO1X_999_MEM_COMPRESS, lzo1x_999_wrapper}, {NULL, 0, NULL} }; /* default LZO compression algorithm and compression level */ static int algorithm = SQUASHFS_LZO1X_999; static int compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT; /* user specified compression level */ static int user_comp_level = -1; /* * This function is called by the options parsing code in mksquashfs.c * to parse any -X compressor option. * * This function returns: * >=0 (number of additional args parsed) on success * -1 if the option was unrecognised, or * -2 if the option was recognised, but otherwise bad in * some way (e.g. invalid parameter) * * Note: this function sets internal compressor state, but does not * pass back the results of the parsing other than success/failure. * The lzo_dump_options() function is called later to get the options in * a format suitable for writing to the filesystem. */ static int lzo_options(char *argv[], int argc) { int i; if (strcmp(argv[0], "-Xalgorithm") == 0) { if (argc < 2) { fprintf(stderr, "lzo: -Xalgorithm missing algorithm\n"); fprintf(stderr, "lzo: -Xalgorithm \n"); goto failed2; } for (i = 0; lzo[i].name; i++) { if (strcmp(argv[1], lzo[i].name) == 0) { algorithm = i; return 1; } } fprintf(stderr, "lzo: -Xalgorithm unrecognised algorithm\n"); goto failed2; } else if (strcmp(argv[0], "-Xcompression-level") == 0) { if (argc < 2) { fprintf(stderr, "lzo: -Xcompression-level missing " "compression level\n"); fprintf(stderr, "lzo: -Xcompression-level it " "should be 1 >= n <= 9\n"); goto failed; } user_comp_level = atoi(argv[1]); if (user_comp_level < 1 || user_comp_level > 9) { fprintf(stderr, "lzo: -Xcompression-level invalid, it " "should be 1 >= n <= 9\n"); goto failed; } return 1; } return -1; failed: return -2; failed2: fprintf(stderr, "lzo: compression algorithm should be one of:\n"); for (i = 0; lzo[i].name; i++) fprintf(stderr, "\t%s\n", lzo[i].name); return -2; } /* * This function is called after all options have been parsed. * It is used to do post-processing on the compressor options using * values that were not expected to be known at option parse time. * * In this case the LZO algorithm may not be known until after the * compression level has been set (-Xalgorithm used after -Xcompression-level) * * This function returns 0 on successful post processing, or * -1 on error */ static int lzo_options_post(int block_size) { /* * Use of compression level only makes sense for * LZO1X_999 algorithm */ if (user_comp_level != -1) { if (algorithm != SQUASHFS_LZO1X_999) { fprintf(stderr, "lzo: -Xcompression-level not " "supported by selected %s algorithm\n", lzo[algorithm].name); fprintf(stderr, "lzo: -Xcompression-level is only " "applicable for the lzo1x_999 algorithm\n"); goto failed; } compression_level = user_comp_level; } return 0; failed: return -1; } /* * This function is called by mksquashfs to dump the parsed * compressor options in a format suitable for writing to the * compressor options field in the filesystem (stored immediately * after the superblock). * * This function returns a pointer to the compression options structure * to be stored (and the size), or NULL if there are no compression * options * */ static void *lzo_dump_options(int block_size, int *size) { static struct lzo_comp_opts comp_opts; /* * If default compression options of SQUASHFS_LZO1X_999 and * compression level of SQUASHFS_LZO1X_999_COMP_DEFAULT then * don't store a compression options structure (this is compatible * with the legacy implementation of LZO for Squashfs) */ if (algorithm == SQUASHFS_LZO1X_999 && compression_level == SQUASHFS_LZO1X_999_COMP_DEFAULT) return NULL; comp_opts.algorithm = algorithm; comp_opts.compression_level = algorithm == SQUASHFS_LZO1X_999 ? compression_level : 0; SQUASHFS_INSWAP_COMP_OPTS(&comp_opts); *size = sizeof(comp_opts); return &comp_opts; } /* * This function is a helper specifically for the append mode of * mksquashfs. Its purpose is to set the internal compressor state * to the stored compressor options in the passed compressor options * structure. * * In effect this function sets up the compressor options * to the same state they were when the filesystem was originally * generated, this is to ensure on appending, the compressor uses * the same compression options that were used to generate the * original filesystem. * * Note, even if there are no compressor options, this function is still * called with an empty compressor structure (size == 0), to explicitly * set the default options, this is to ensure any user supplied * -X options on the appending mksquashfs command line are over-ridden * * This function returns 0 on sucessful extraction of options, and * -1 on error */ static int lzo_extract_options(int block_size, void *buffer, int size) { struct lzo_comp_opts *comp_opts = buffer; if (size == 0) { /* Set default values */ algorithm = SQUASHFS_LZO1X_999; compression_level = SQUASHFS_LZO1X_999_COMP_DEFAULT; return 0; } /* we expect a comp_opts structure of sufficient size to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* Check comp_opts structure for correctness */ switch (comp_opts->algorithm) { case SQUASHFS_LZO1X_1: case SQUASHFS_LZO1X_1_11: case SQUASHFS_LZO1X_1_12: case SQUASHFS_LZO1X_1_15: if (comp_opts->compression_level != 0) { fprintf(stderr, "lzo: bad compression level in " "compression options structure\n"); goto failed; } break; case SQUASHFS_LZO1X_999: if (comp_opts->compression_level < 1 || comp_opts->compression_level > 9) { fprintf(stderr, "lzo: bad compression level in " "compression options structure\n"); goto failed; } compression_level = comp_opts->compression_level; break; default: fprintf(stderr, "lzo: bad algorithm in compression options " "structure\n"); goto failed; } algorithm = comp_opts->algorithm; return 0; failed: fprintf(stderr, "lzo: error reading stored compressor options from " "filesystem!\n"); return -1; } void lzo_display_options(void *buffer, int size) { struct lzo_comp_opts *comp_opts = buffer; /* we expect a comp_opts structure of sufficient size to be present */ if (size < sizeof(*comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); /* Check comp_opts structure for correctness */ switch (comp_opts->algorithm) { case SQUASHFS_LZO1X_1: case SQUASHFS_LZO1X_1_11: case SQUASHFS_LZO1X_1_12: case SQUASHFS_LZO1X_1_15: printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name); break; case SQUASHFS_LZO1X_999: if (comp_opts->compression_level < 1 || comp_opts->compression_level > 9) { fprintf(stderr, "lzo: bad compression level in " "compression options structure\n"); goto failed; } printf("\talgorithm %s\n", lzo[comp_opts->algorithm].name); printf("\tcompression level %d\n", comp_opts->compression_level); break; default: fprintf(stderr, "lzo: bad algorithm in compression options " "structure\n"); goto failed; } return; failed: fprintf(stderr, "lzo: error reading stored compressor options from " "filesystem!\n"); } /* * This function is called by mksquashfs to initialise the * compressor, before compress() is called. * * This function returns 0 on success, and * -1 on error */ static int squashfs_lzo_init(void **strm, int block_size, int datablock) { struct lzo_stream *stream; stream = *strm = malloc(sizeof(struct lzo_stream)); if (stream == NULL) goto failed; stream->workspace = malloc(lzo[algorithm].size); if (stream->workspace == NULL) goto failed2; stream->buffer = malloc(LZO_MAX_EXPANSION(block_size)); if (stream->buffer != NULL) return 0; free(stream->workspace); failed2: free(stream); failed: return -1; } static int lzo_compress(void *strm, void *dest, void *src, int size, int block_size, int *error) { int res; lzo_uint compsize, orig_size = size; struct lzo_stream *stream = strm; res = lzo[algorithm].compress(src, size, stream->buffer, &compsize, stream->workspace); if (res != LZO_E_OK) goto failed; /* Successful compression, however, we need to check that * the compressed size is not larger than the available * buffer space. Normally in other compressor APIs they take * a destination buffer size, and overflows return an error. * With LZO it lacks a destination size and so we must output * to a temporary buffer large enough to accomodate any * result, and explictly check here for overflow */ if (compsize > block_size) return 0; res = lzo1x_optimize(stream->buffer, compsize, src, &orig_size, NULL); if (res != LZO_E_OK || orig_size != size) goto failed; memcpy(dest, stream->buffer, compsize); return compsize; failed: /* fail, compressor specific error code returned in error */ *error = res; return -1; } static int lzo_uncompress(void *dest, void *src, int size, int outsize, int *error) { int res; lzo_uint outlen = outsize; res = lzo1x_decompress_safe(src, size, dest, &outlen, NULL); if (res != LZO_E_OK) { *error = res; return -1; } return outlen; } void lzo_usage() { int i; fprintf(stderr, "\t -Xalgorithm \n"); fprintf(stderr, "\t\tWhere is one of:\n"); for (i = 0; lzo[i].name; i++) fprintf(stderr, "\t\t\t%s%s\n", lzo[i].name, i == SQUASHFS_LZO1X_999 ? " (default)" : ""); fprintf(stderr, "\t -Xcompression-level \n"); fprintf(stderr, "\t\t should be 1 .. 9 (default " "%d)\n", SQUASHFS_LZO1X_999_COMP_DEFAULT); fprintf(stderr, "\t\tOnly applies to lzo1x_999 algorithm\n"); } /* * Helper function for lzo1x_999 compression algorithm. * All other lzo1x_xxx compressors do not take a compression level, * so we need to wrap lzo1x_999 to pass the compression level which * is applicable to it */ int lzo1x_999_wrapper(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, lzo_uintp compsize, lzo_voidp workspace) { return lzo1x_999_compress_level(src, src_len, dst, compsize, workspace, NULL, 0, 0, compression_level); } struct compressor lzo_comp_ops = { .init = squashfs_lzo_init, .compress = lzo_compress, .uncompress = lzo_uncompress, .options = lzo_options, .options_post = lzo_options_post, .dump_options = lzo_dump_options, .extract_options = lzo_extract_options, .display_options = lzo_display_options, .usage = lzo_usage, .id = LZO_COMPRESSION, .name = "lzo", .supported = 1 }; ================================================ FILE: src/squashfs/mksquashfs.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, * 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * mksquashfs.c */ #define FALSE 0 #define TRUE 1 #define MAX_LINE 16384 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef linux # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN # include #else # include # include #endif #include "squashfs_fs.h" #include "squashfs_swap.h" #include "mksquashfs.h" #include "sort.h" #include "pseudo.h" #include "compressor.h" #include "xattr.h" #include "action.h" #include "error.h" #include "progressbar.h" #include "info.h" #include "caches-queues-lists.h" #include "read_fs.h" #include "restore.h" #include "process_fragments.h" int delete = FALSE; int fd; struct squashfs_super_block sBlk; /* filesystem flags for building */ int comp_opts = FALSE; int no_xattrs = XATTR_DEF; int noX = FALSE; int duplicate_checking = TRUE; int noF = FALSE; int no_fragments = FALSE; int always_use_fragments = FALSE; int noI = FALSE; int noD = FALSE; int silent = TRUE; int exportable = TRUE; int sparse_files = TRUE; int old_exclude = TRUE; int use_regex = FALSE; int nopad = FALSE; int exit_on_error = FALSE; long long global_uid = -1, global_gid = -1; /* superblock attributes */ int block_size = SQUASHFS_FILE_SIZE, block_log; unsigned int id_count = 0; int file_count = 0, sym_count = 0, dev_count = 0, dir_count = 0, fifo_count = 0, sock_count = 0; /* write position within data section */ long long bytes = 0, total_bytes = 0; /* in memory directory table - possibly compressed */ char *directory_table = NULL; unsigned int directory_bytes = 0, directory_size = 0, total_directory_bytes = 0; /* cached directory table */ char *directory_data_cache = NULL; unsigned int directory_cache_bytes = 0, directory_cache_size = 0; /* in memory inode table - possibly compressed */ char *inode_table = NULL; unsigned int inode_bytes = 0, inode_size = 0, total_inode_bytes = 0; /* cached inode table */ char *data_cache = NULL; unsigned int cache_bytes = 0, cache_size = 0, inode_count = 0; /* inode lookup table */ squashfs_inode *inode_lookup_table = NULL; /* in memory directory data */ #define I_COUNT_SIZE 128 #define DIR_ENTRIES 32 #define INODE_HASH_SIZE 65536 #define INODE_HASH_MASK (INODE_HASH_SIZE - 1) #define INODE_HASH(dev, ino) (ino & INODE_HASH_MASK) struct cached_dir_index { struct squashfs_dir_index index; char *name; }; struct directory { unsigned int start_block; unsigned int size; unsigned char *buff; unsigned char *p; unsigned int entry_count; unsigned char *entry_count_p; unsigned int i_count; unsigned int i_size; struct cached_dir_index *index; unsigned char *index_count_p; unsigned int inode_number; }; struct inode_info *inode_info[INODE_HASH_SIZE]; /* hash tables used to do fast duplicate searches in duplicate check */ struct file_info *dupl[65536]; int dup_files = 0; /* exclude file handling */ /* list of exclude dirs/files */ struct exclude_info { dev_t st_dev; ino_t st_ino; }; #define EXCLUDE_SIZE 8192 int exclude = 0; struct exclude_info *exclude_paths = NULL; int old_excluded(char *filename, struct stat *buf); struct path_entry { char *name; regex_t *preg; struct pathname *paths; }; struct pathname { int names; struct path_entry *name; }; struct pathnames { int count; struct pathname *path[0]; }; #define PATHS_ALLOC_SIZE 10 struct pathnames *paths = NULL; struct pathname *path = NULL; struct pathname *stickypath = NULL; int excluded(char *name, struct pathnames *paths, struct pathnames **new); int fragments = 0; #define FRAG_SIZE 32768 struct squashfs_fragment_entry *fragment_table = NULL; int fragments_outstanding = 0; int fragments_locked = FALSE; /* current inode number for directories and non directories */ unsigned int inode_no = 1; unsigned int root_inode_number = 0; /* list of source dirs/files */ int source = 0; char **source_path; /* list of root directory entries read from original filesystem */ int old_root_entries = 0; struct old_root_entry_info { char *name; struct inode_info inode; }; struct old_root_entry_info *old_root_entry; /* restore orignal filesystem state if appending to existing filesystem is * cancelled */ int appending = FALSE; char *sdata_cache, *sdirectory_data_cache, *sdirectory_compressed; long long sbytes, stotal_bytes; unsigned int sinode_bytes, scache_bytes, sdirectory_bytes, sdirectory_cache_bytes, sdirectory_compressed_bytes, stotal_inode_bytes, stotal_directory_bytes, sinode_count = 0, sfile_count, ssym_count, sdev_count, sdir_count, sfifo_count, ssock_count, sdup_files; int sfragments; int threads; /* flag whether destination file is a block device */ int block_device = FALSE; /* flag indicating whether files are sorted using sort list(s) */ int sorted = FALSE; /* save destination file name for deleting on error */ char *destination_file = NULL; /* recovery file for abnormal exit on appending */ char *recovery_file = NULL; int recover = TRUE; struct id *id_hash_table[ID_ENTRIES]; struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS]; unsigned int uid_count = 0, guid_count = 0; unsigned int sid_count = 0, suid_count = 0, sguid_count = 0; struct cache *reader_buffer, *fragment_buffer, *reserve_cache; struct cache *bwriter_buffer, *fwriter_buffer; struct queue *to_reader, *to_deflate, *to_writer, *from_writer, *to_frag, *locked_fragment, *to_process_frag; struct seq_queue *to_main; pthread_t reader_thread, writer_thread, main_thread; pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread; pthread_t *restore_thread = NULL; pthread_mutex_t fragment_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t pos_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t dup_mutex = PTHREAD_MUTEX_INITIALIZER; /* user options that control parallelisation */ int processors = -1; int bwriter_size; /* compression operations */ struct compressor *comp = NULL; int compressor_opt_parsed = FALSE; void *stream = NULL; /* xattr stats */ unsigned int xattr_bytes = 0, total_xattr_bytes = 0; /* fragment to file mapping used when appending */ int append_fragments = 0; struct append_file **file_mapping; static char *read_from_disk(long long start, unsigned int avail_bytes); void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type); struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, int blocks, unsigned short checksum, int checksum_flag); struct dir_info *dir_scan1(char *, char *, struct pathnames *, struct dir_ent *(_readdir) (struct dir_info *), int); void dir_scan2(struct dir_info *dir, struct pseudo *pseudo); void dir_scan3(struct dir_info *root, struct dir_info *dir); void dir_scan4(struct dir_info *dir); void dir_scan5(struct dir_info *dir); void dir_scan6(squashfs_inode * inode, struct dir_info *dir_info); struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag, int checksum_frag_flag); long long generic_write_table(int, void *, int, void *, int); void restorefs(); struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth); void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad); unsigned short get_checksum_mem(char *buff, int bytes); int get_physical_memory(); void prep_exit() { if (restore_thread) { if (pthread_self() == *restore_thread) { /* * Recursive failure when trying to restore filesystem! * Nothing to do except to exit, otherwise we'll just * appear to hang. The user should be able to restore * from the recovery file (which is why it was added, in * case of catastrophic failure in Mksquashfs) */ exit(1); } else { /* signal the restore thread to restore */ pthread_kill(*restore_thread, SIGUSR1); pthread_exit(NULL); } } else if (delete) { if (destination_file && !block_device) unlink(destination_file); } else if (recovery_file) unlink(recovery_file); } int add_overflow(int a, int b) { return (INT_MAX - a) < b; } int shift_overflow(int a, int shift) { return (INT_MAX >> shift) < a; } int multiply_overflow(int a, int multiplier) { return (INT_MAX / multiplier) < a; } int multiply_overflowll(long long a, int multiplier) { return (LLONG_MAX / multiplier) < a; } #define MKINODE(A) ((squashfs_inode)(((squashfs_inode) inode_bytes << 16) \ + (((char *)A) - data_cache))) void restorefs() { ERROR("Exiting - restoring original filesystem!\n\n"); bytes = sbytes; memcpy(data_cache, sdata_cache, cache_bytes = scache_bytes); memcpy(directory_data_cache, sdirectory_data_cache, sdirectory_cache_bytes); directory_cache_bytes = sdirectory_cache_bytes; inode_bytes = sinode_bytes; directory_bytes = sdirectory_bytes; memcpy(directory_table + directory_bytes, sdirectory_compressed, sdirectory_compressed_bytes); directory_bytes += sdirectory_compressed_bytes; total_bytes = stotal_bytes; total_inode_bytes = stotal_inode_bytes; total_directory_bytes = stotal_directory_bytes; inode_count = sinode_count; file_count = sfile_count; sym_count = ssym_count; dev_count = sdev_count; dir_count = sdir_count; fifo_count = sfifo_count; sock_count = ssock_count; dup_files = sdup_files; fragments = sfragments; id_count = sid_count; restore_xattrs(); write_filesystem_tables(&sBlk, nopad); exit(1); } void sighandler() { EXIT_MKSQUASHFS(); } int mangle2(void *strm, char *d, char *s, int size, int block_size, int uncompressed, int data_block) { int error, c_byte = 0; if (!uncompressed) { c_byte = compressor_compress(comp, strm, d, s, size, block_size, &error); if (c_byte == -1) BAD_ERROR("mangle2:: %s compress failed with error " "code %d\n", comp->name, error); } if (c_byte == 0 || c_byte >= size) { memcpy(d, s, size); return size | (data_block ? SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT); } return c_byte; } int mangle(char *d, char *s, int size, int block_size, int uncompressed, int data_block) { return mangle2(stream, d, s, size, block_size, uncompressed, data_block); } void *get_inode(int req_size) { int data_space; unsigned short c_byte; while (cache_bytes >= SQUASHFS_METADATA_SIZE) { if ((inode_size - inode_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) { void *it = realloc(inode_table, inode_size + (SQUASHFS_METADATA_SIZE << 1) + 2); if (it == NULL) MEM_ERROR(); inode_table = it; inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2; } c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, data_cache, SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1); inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; total_inode_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET; memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE); cache_bytes -= SQUASHFS_METADATA_SIZE; } data_space = (cache_size - cache_bytes); if (data_space < req_size) { int realloc_size = cache_size == 0 ? ((req_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : req_size - data_space; void *dc = realloc(data_cache, cache_size + realloc_size); if (dc == NULL) MEM_ERROR(); cache_size += realloc_size; data_cache = dc; } cache_bytes += req_size; return data_cache + cache_bytes - req_size; } int read_bytes(int fd, void *buff, int bytes) { int res, count; for (count = 0; count < bytes; count += res) { res = read(fd, buff + count, bytes - count); if (res < 1) { if (res == 0) goto bytes_read; else if (errno != EINTR) { ERROR("Read failed because %s\n", strerror(errno)); return -1; } else res = 0; } } bytes_read: return count; } int read_fs_bytes(int fd, long long byte, int bytes, void *buff) { off_t off = byte; int res = 1; TRACE("read_fs_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); pthread_cleanup_push((void *)pthread_mutex_unlock, &pos_mutex); pthread_mutex_lock(&pos_mutex); if (lseek(fd, off, SEEK_SET) == -1) { ERROR("read_fs_bytes: Lseek on destination failed because %s, " "offset=0x%llx\n", strerror(errno), off); res = 0; } else if (read_bytes(fd, buff, bytes) < bytes) { ERROR("Read on destination failed\n"); res = 0; } pthread_cleanup_pop(1); return res; } int write_bytes(int fd, void *buff, int bytes) { int res, count; for (count = 0; count < bytes; count += res) { res = write(fd, buff + count, bytes - count); if (res == -1) { if (errno != EINTR) { ERROR("Write failed because %s\n", strerror(errno)); return -1; } res = 0; } } return 0; } void write_destination(int fd, long long byte, int bytes, void *buff) { off_t off = byte; pthread_cleanup_push((void *)pthread_mutex_unlock, &pos_mutex); pthread_mutex_lock(&pos_mutex); if (lseek(fd, off, SEEK_SET) == -1) { ERROR("write_destination: Lseek on destination " "failed because %s, offset=0x%llx\n", strerror(errno), off); BAD_ERROR("Probably out of space on output %s\n", block_device ? "block device" : "filesystem"); } if (write_bytes(fd, buff, bytes) == -1) BAD_ERROR("Failed to write to output %s\n", block_device ? "block device" : "filesystem"); pthread_cleanup_pop(1); } long long write_inodes() { unsigned short c_byte; int avail_bytes; char *datap = data_cache; long long start_bytes = bytes; while (cache_bytes) { if (inode_size - inode_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { void *it = realloc(inode_table, inode_size + ((SQUASHFS_METADATA_SIZE << 1) + 2)); if (it == NULL) MEM_ERROR(); inode_size += (SQUASHFS_METADATA_SIZE << 1) + 2; inode_table = it; } avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes; c_byte = mangle(inode_table + inode_bytes + BLOCK_OFFSET, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Inode block @ 0x%x, size %d\n", inode_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, inode_table + inode_bytes, 1); inode_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; total_inode_bytes += avail_bytes + BLOCK_OFFSET; datap += avail_bytes; cache_bytes -= avail_bytes; } write_destination(fd, bytes, inode_bytes, inode_table); bytes += inode_bytes; return start_bytes; } long long write_directories() { unsigned short c_byte; int avail_bytes; char *directoryp = directory_data_cache; long long start_bytes = bytes; while (directory_cache_bytes) { if (directory_size - directory_bytes < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { void *dt = realloc(directory_table, directory_size + ((SQUASHFS_METADATA_SIZE << 1) + 2)); if (dt == NULL) MEM_ERROR(); directory_size += (SQUASHFS_METADATA_SIZE << 1) + 2; directory_table = dt; } avail_bytes = directory_cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : directory_cache_bytes; c_byte = mangle(directory_table + directory_bytes + BLOCK_OFFSET, directoryp, avail_bytes, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, directory_table + directory_bytes, 1); directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; total_directory_bytes += avail_bytes + BLOCK_OFFSET; directoryp += avail_bytes; directory_cache_bytes -= avail_bytes; } write_destination(fd, bytes, directory_bytes, directory_table); bytes += directory_bytes; return start_bytes; } long long write_id_table() { unsigned int id_bytes = SQUASHFS_ID_BYTES(id_count); unsigned int p[id_count]; int i; TRACE("write_id_table: ids %d, id_bytes %d\n", id_count, id_bytes); for (i = 0; i < id_count; i++) { TRACE("write_id_table: id index %d, id %d", i, id_table[i]->id); SQUASHFS_SWAP_INTS(&id_table[i]->id, p + i, 1); } return generic_write_table(id_bytes, p, 0, NULL, noI); } struct id *get_id(unsigned int id) { int hash = ID_HASH(id); struct id *entry = id_hash_table[hash]; for (; entry; entry = entry->next) if (entry->id == id) break; return entry; } struct id *create_id(unsigned int id) { int hash = ID_HASH(id); struct id *entry = malloc(sizeof(struct id)); if (entry == NULL) MEM_ERROR(); entry->id = id; entry->index = id_count++; entry->flags = 0; entry->next = id_hash_table[hash]; id_hash_table[hash] = entry; id_table[entry->index] = entry; return entry; } unsigned int get_uid(unsigned int uid) { struct id *entry = get_id(uid); if (entry == NULL) { if (id_count == SQUASHFS_IDS) BAD_ERROR("Out of uids!\n"); entry = create_id(uid); } if ((entry->flags & ISA_UID) == 0) { entry->flags |= ISA_UID; uid_count++; } return entry->index; } unsigned int get_guid(unsigned int guid) { struct id *entry = get_id(guid); if (entry == NULL) { if (id_count == SQUASHFS_IDS) BAD_ERROR("Out of gids!\n"); entry = create_id(guid); } if ((entry->flags & ISA_GID) == 0) { entry->flags |= ISA_GID; guid_count++; } return entry->index; } #define ALLOC_SIZE 128 char *_pathname(struct dir_ent *dir_ent, char *pathname, int *size) { if (pathname == NULL) { pathname = malloc(ALLOC_SIZE); if (pathname == NULL) MEM_ERROR(); } for (;;) { int res = snprintf(pathname, *size, "%s/%s", dir_ent->our_dir->pathname, dir_ent->source_name ? : dir_ent->name); if (res < 0) BAD_ERROR("snprintf failed in pathname\n"); else if (res >= *size) { /* * pathname is too small to contain the result, so * increase it and try again */ *size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1); pathname = realloc(pathname, *size); if (pathname == NULL) MEM_ERROR(); } else break; } return pathname; } char *pathname(struct dir_ent *dir_ent) { static char *pathname = NULL; static int size = ALLOC_SIZE; if (dir_ent->nonstandard_pathname) return dir_ent->nonstandard_pathname; return pathname = _pathname(dir_ent, pathname, &size); } char *pathname_reader(struct dir_ent *dir_ent) { static char *pathname = NULL; static int size = ALLOC_SIZE; if (dir_ent->nonstandard_pathname) return dir_ent->nonstandard_pathname; return pathname = _pathname(dir_ent, pathname, &size); } char *subpathname(struct dir_ent *dir_ent) { static char *subpath = NULL; static int size = ALLOC_SIZE; int res; if (subpath == NULL) { subpath = malloc(ALLOC_SIZE); if (subpath == NULL) MEM_ERROR(); } for (;;) { if (dir_ent->our_dir->subpath[0] != '\0') res = snprintf(subpath, size, "%s/%s", dir_ent->our_dir->subpath, dir_ent->name); else res = snprintf(subpath, size, "/%s", dir_ent->name); if (res < 0) BAD_ERROR("snprintf failed in subpathname\n"); else if (res >= size) { /* * subpath is too small to contain the result, so * increase it and try again */ size = (res + ALLOC_SIZE) & ~(ALLOC_SIZE - 1); subpath = realloc(subpath, size); if (subpath == NULL) MEM_ERROR(); } else break; } return subpath; } inline unsigned int get_inode_no(struct inode_info *inode) { return inode->inode_number; } inline unsigned int get_parent_no(struct dir_info *dir) { return dir->depth ? get_inode_no(dir->dir_ent->inode) : inode_no; } int create_inode(squashfs_inode * i_no, struct dir_info *dir_info, struct dir_ent *dir_ent, int type, long long byte_size, long long start_block, unsigned int offset, unsigned int *block_list, struct fragment *fragment, struct directory *dir_in, long long sparse) { struct stat *buf = &dir_ent->inode->buf; union squashfs_inode_header inode_header; struct squashfs_base_inode_header *base = &inode_header.base; void *inode; char *filename = pathname(dir_ent); int nlink = dir_ent->inode->nlink; int xattr = read_xattrs(dir_ent); switch (type) { case SQUASHFS_FILE_TYPE: if (dir_ent->inode->nlink > 1 || byte_size >= (1LL << 32) || start_block >= (1LL << 32) || sparse || IS_XATTR(xattr)) type = SQUASHFS_LREG_TYPE; break; case SQUASHFS_DIR_TYPE: if (dir_info->dir_is_ldir || IS_XATTR(xattr)) type = SQUASHFS_LDIR_TYPE; break; case SQUASHFS_SYMLINK_TYPE: if (IS_XATTR(xattr)) type = SQUASHFS_LSYMLINK_TYPE; break; case SQUASHFS_BLKDEV_TYPE: if (IS_XATTR(xattr)) type = SQUASHFS_LBLKDEV_TYPE; break; case SQUASHFS_CHRDEV_TYPE: if (IS_XATTR(xattr)) type = SQUASHFS_LCHRDEV_TYPE; break; case SQUASHFS_FIFO_TYPE: if (IS_XATTR(xattr)) type = SQUASHFS_LFIFO_TYPE; break; case SQUASHFS_SOCKET_TYPE: if (IS_XATTR(xattr)) type = SQUASHFS_LSOCKET_TYPE; break; } base->mode = SQUASHFS_MODE(buf->st_mode); base->uid = get_uid((unsigned int)global_uid == -1 ? buf->st_uid : global_uid); base->inode_type = type; base->guid = get_guid((unsigned int)global_gid == -1 ? buf->st_gid : global_gid); base->mtime = buf->st_mtime; base->inode_number = get_inode_no(dir_ent->inode); if (type == SQUASHFS_FILE_TYPE) { int i; struct squashfs_reg_inode_header *reg = &inode_header.reg; size_t off = offsetof(struct squashfs_reg_inode_header, block_list); inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); reg->file_size = byte_size; reg->start_block = start_block; reg->fragment = fragment->index; reg->offset = fragment->offset; SQUASHFS_SWAP_REG_INODE_HEADER(reg, inode); SQUASHFS_SWAP_INTS(block_list, inode + off, offset); TRACE("File inode, file_size %lld, start_block 0x%llx, blocks " "%d, fragment %d, offset %d, size %d\n", byte_size, start_block, offset, fragment->index, fragment->offset, fragment->size); for (i = 0; i < offset; i++) TRACE("Block %d, size %d\n", i, block_list[i]); } else if (type == SQUASHFS_LREG_TYPE) { int i; struct squashfs_lreg_inode_header *reg = &inode_header.lreg; size_t off = offsetof(struct squashfs_lreg_inode_header, block_list); inode = get_inode(sizeof(*reg) + offset * sizeof(unsigned int)); reg->nlink = nlink; reg->file_size = byte_size; reg->start_block = start_block; reg->fragment = fragment->index; reg->offset = fragment->offset; if (sparse && sparse >= byte_size) sparse = byte_size - 1; reg->sparse = sparse; reg->xattr = xattr; SQUASHFS_SWAP_LREG_INODE_HEADER(reg, inode); SQUASHFS_SWAP_INTS(block_list, inode + off, offset); TRACE("Long file inode, file_size %lld, start_block 0x%llx, " "blocks %d, fragment %d, offset %d, size %d, nlink %d" "\n", byte_size, start_block, offset, fragment->index, fragment->offset, fragment->size, nlink); for (i = 0; i < offset; i++) TRACE("Block %d, size %d\n", i, block_list[i]); } else if (type == SQUASHFS_LDIR_TYPE) { int i; unsigned char *p; struct squashfs_ldir_inode_header *dir = &inode_header.ldir; struct cached_dir_index *index = dir_in->index; unsigned int i_count = dir_in->i_count; unsigned int i_size = dir_in->i_size; if (byte_size >= 1 << 27) BAD_ERROR("directory greater than 2^27-1 bytes!\n"); inode = get_inode(sizeof(*dir) + i_size); dir->inode_type = SQUASHFS_LDIR_TYPE; dir->nlink = dir_ent->dir->directory_count + 2; dir->file_size = byte_size; dir->offset = offset; dir->start_block = start_block; dir->i_count = i_count; dir->parent_inode = get_parent_no(dir_ent->our_dir); dir->xattr = xattr; SQUASHFS_SWAP_LDIR_INODE_HEADER(dir, inode); p = inode + offsetof(struct squashfs_ldir_inode_header, index); for (i = 0; i < i_count; i++) { SQUASHFS_SWAP_DIR_INDEX(&index[i].index, p); p += offsetof(struct squashfs_dir_index, name); memcpy(p, index[i].name, index[i].index.size + 1); p += index[i].index.size + 1; } TRACE("Long directory inode, file_size %lld, start_block " "0x%llx, offset 0x%x, nlink %d\n", byte_size, start_block, offset, dir_ent->dir->directory_count + 2); } else if (type == SQUASHFS_DIR_TYPE) { struct squashfs_dir_inode_header *dir = &inode_header.dir; inode = get_inode(sizeof(*dir)); dir->nlink = dir_ent->dir->directory_count + 2; dir->file_size = byte_size; dir->offset = offset; dir->start_block = start_block; dir->parent_inode = get_parent_no(dir_ent->our_dir); SQUASHFS_SWAP_DIR_INODE_HEADER(dir, inode); TRACE("Directory inode, file_size %lld, start_block 0x%llx, " "offset 0x%x, nlink %d\n", byte_size, start_block, offset, dir_ent->dir->directory_count + 2); } else if (type == SQUASHFS_CHRDEV_TYPE || type == SQUASHFS_BLKDEV_TYPE) { struct squashfs_dev_inode_header *dev = &inode_header.dev; unsigned int major = major(buf->st_rdev); unsigned int minor = minor(buf->st_rdev); if (major > 0xfff) { ERROR("Major %d out of range in device node %s, " "truncating to %d\n", major, filename, major & 0xfff); major &= 0xfff; } if (minor > 0xfffff) { ERROR("Minor %d out of range in device node %s, " "truncating to %d\n", minor, filename, minor & 0xfffff); minor &= 0xfffff; } inode = get_inode(sizeof(*dev)); dev->nlink = nlink; dev->rdev = (major << 8) | (minor & 0xff) | ((minor & ~0xff) << 12); SQUASHFS_SWAP_DEV_INODE_HEADER(dev, inode); TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink); } else if (type == SQUASHFS_LCHRDEV_TYPE || type == SQUASHFS_LBLKDEV_TYPE) { struct squashfs_ldev_inode_header *dev = &inode_header.ldev; unsigned int major = major(buf->st_rdev); unsigned int minor = minor(buf->st_rdev); if (major > 0xfff) { ERROR("Major %d out of range in device node %s, " "truncating to %d\n", major, filename, major & 0xfff); major &= 0xfff; } if (minor > 0xfffff) { ERROR("Minor %d out of range in device node %s, " "truncating to %d\n", minor, filename, minor & 0xfffff); minor &= 0xfffff; } inode = get_inode(sizeof(*dev)); dev->nlink = nlink; dev->rdev = (major << 8) | (minor & 0xff) | ((minor & ~0xff) << 12); dev->xattr = xattr; SQUASHFS_SWAP_LDEV_INODE_HEADER(dev, inode); TRACE("Device inode, rdev 0x%x, nlink %d\n", dev->rdev, nlink); } else if (type == SQUASHFS_SYMLINK_TYPE) { struct squashfs_symlink_inode_header *symlink = &inode_header.symlink; int byte; char buff[65536]; /* overflow safe */ size_t off = offsetof(struct squashfs_symlink_inode_header, symlink); byte = readlink(filename, buff, 65536); if (byte == -1) { ERROR_START("Failed to read symlink %s", filename); ERROR_EXIT(", creating empty symlink\n"); byte = 0; } if (byte == 65536) { ERROR_START("Symlink %s is greater than 65536 bytes!", filename); ERROR_EXIT(" Creating empty symlink\n"); byte = 0; } inode = get_inode(sizeof(*symlink) + byte); symlink->nlink = nlink; symlink->symlink_size = byte; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode); strncpy(inode + off, buff, byte); TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink); } else if (type == SQUASHFS_LSYMLINK_TYPE) { struct squashfs_symlink_inode_header *symlink = &inode_header.symlink; int byte; char buff[65536]; /* overflow safe */ size_t off = offsetof(struct squashfs_symlink_inode_header, symlink); byte = readlink(filename, buff, 65536); if (byte == -1) { ERROR_START("Failed to read symlink %s", filename); ERROR_EXIT(", creating empty symlink\n"); byte = 0; } if (byte == 65536) { ERROR_START("Symlink %s is greater than 65536 bytes!", filename); ERROR_EXIT(" Creating empty symlink\n"); byte = 0; } inode = get_inode(sizeof(*symlink) + byte + sizeof(unsigned int)); symlink->nlink = nlink; symlink->symlink_size = byte; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(symlink, inode); strncpy(inode + off, buff, byte); SQUASHFS_SWAP_INTS(&xattr, inode + off + byte, 1); TRACE("Symbolic link inode, symlink_size %d, nlink %d\n", byte, nlink); } else if (type == SQUASHFS_FIFO_TYPE || type == SQUASHFS_SOCKET_TYPE) { struct squashfs_ipc_inode_header *ipc = &inode_header.ipc; inode = get_inode(sizeof(*ipc)); ipc->nlink = nlink; SQUASHFS_SWAP_IPC_INODE_HEADER(ipc, inode); TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink); } else if (type == SQUASHFS_LFIFO_TYPE || type == SQUASHFS_LSOCKET_TYPE) { struct squashfs_lipc_inode_header *ipc = &inode_header.lipc; inode = get_inode(sizeof(*ipc)); ipc->nlink = nlink; ipc->xattr = xattr; SQUASHFS_SWAP_LIPC_INODE_HEADER(ipc, inode); TRACE("ipc inode, type %s, nlink %d\n", type == SQUASHFS_FIFO_TYPE ? "fifo" : "socket", nlink); } else BAD_ERROR("Unrecognised inode %d in create_inode\n", type); *i_no = MKINODE(inode); inode_count++; TRACE("Created inode 0x%llx, type %d, uid %d, guid %d\n", *i_no, type, base->uid, base->guid); return TRUE; } void add_dir(squashfs_inode inode, unsigned int inode_number, char *name, int type, struct directory *dir) { unsigned char *buff; struct squashfs_dir_entry idir; unsigned int start_block = inode >> 16; unsigned int offset = inode & 0xffff; unsigned int size = strlen(name); size_t name_off = offsetof(struct squashfs_dir_entry, name); if (size > SQUASHFS_NAME_LEN) { size = SQUASHFS_NAME_LEN; ERROR("Filename is greater than %d characters, truncating! ..." "\n", SQUASHFS_NAME_LEN); } if (dir->p + sizeof(struct squashfs_dir_entry) + size + sizeof(struct squashfs_dir_header) >= dir->buff + dir->size) { buff = realloc(dir->buff, dir->size += SQUASHFS_METADATA_SIZE); if (buff == NULL) MEM_ERROR(); dir->p = (dir->p - dir->buff) + buff; if (dir->entry_count_p) dir->entry_count_p = (dir->entry_count_p - dir->buff + buff); dir->index_count_p = dir->index_count_p - dir->buff + buff; dir->buff = buff; } if (dir->entry_count == 256 || start_block != dir->start_block || ((dir->entry_count_p != NULL) && ((dir->p + sizeof(struct squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE)) || ((long long)inode_number - dir->inode_number) > 32767 || ((long long)inode_number - dir->inode_number) < -32768) { if (dir->entry_count_p) { struct squashfs_dir_header dir_header; if ((dir->p + sizeof(struct squashfs_dir_entry) + size - dir->index_count_p) > SQUASHFS_METADATA_SIZE) { if (dir->i_count % I_COUNT_SIZE == 0) { dir->index = realloc(dir->index, (dir->i_count + I_COUNT_SIZE) * sizeof(struct cached_dir_index)); if (dir->index == NULL) MEM_ERROR(); } dir->index[dir->i_count].index.index = dir->p - dir->buff; dir->index[dir->i_count].index.size = size - 1; dir->index[dir->i_count++].name = name; dir->i_size += sizeof(struct squashfs_dir_index) + size; dir->index_count_p = dir->p; } dir_header.count = dir->entry_count - 1; dir_header.start_block = dir->start_block; dir_header.inode_number = dir->inode_number; SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p); } dir->entry_count_p = dir->p; dir->start_block = start_block; dir->entry_count = 0; dir->inode_number = inode_number; dir->p += sizeof(struct squashfs_dir_header); } idir.offset = offset; idir.type = type; idir.size = size - 1; idir.inode_number = ((long long)inode_number - dir->inode_number); SQUASHFS_SWAP_DIR_ENTRY(&idir, dir->p); strncpy((char *)dir->p + name_off, name, size); dir->p += sizeof(struct squashfs_dir_entry) + size; dir->entry_count++; } void write_dir(squashfs_inode * inode, struct dir_info *dir_info, struct directory *dir) { unsigned int dir_size = dir->p - dir->buff; int data_space = directory_cache_size - directory_cache_bytes; unsigned int directory_block, directory_offset, i_count, index; unsigned short c_byte; if (data_space < dir_size) { int realloc_size = directory_cache_size == 0 ? ((dir_size + SQUASHFS_METADATA_SIZE) & ~(SQUASHFS_METADATA_SIZE - 1)) : dir_size - data_space; void *dc = realloc(directory_data_cache, directory_cache_size + realloc_size); if (dc == NULL) MEM_ERROR(); directory_cache_size += realloc_size; directory_data_cache = dc; } if (dir_size) { struct squashfs_dir_header dir_header; dir_header.count = dir->entry_count - 1; dir_header.start_block = dir->start_block; dir_header.inode_number = dir->inode_number; SQUASHFS_SWAP_DIR_HEADER(&dir_header, dir->entry_count_p); memcpy(directory_data_cache + directory_cache_bytes, dir->buff, dir_size); } directory_offset = directory_cache_bytes; directory_block = directory_bytes; directory_cache_bytes += dir_size; i_count = 0; index = SQUASHFS_METADATA_SIZE - directory_offset; while (1) { while (i_count < dir->i_count && dir->index[i_count].index.index < index) dir->index[i_count++].index.start_block = directory_bytes; index += SQUASHFS_METADATA_SIZE; if (directory_cache_bytes < SQUASHFS_METADATA_SIZE) break; if ((directory_size - directory_bytes) < ((SQUASHFS_METADATA_SIZE << 1) + 2)) { void *dt = realloc(directory_table, directory_size + (SQUASHFS_METADATA_SIZE << 1) + 2); if (dt == NULL) MEM_ERROR(); directory_size += SQUASHFS_METADATA_SIZE << 1; directory_table = dt; } c_byte = mangle(directory_table + directory_bytes + BLOCK_OFFSET, directory_data_cache, SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noI, 0); TRACE("Directory block @ 0x%x, size %d\n", directory_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, directory_table + directory_bytes, 1); directory_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; total_directory_bytes += SQUASHFS_METADATA_SIZE + BLOCK_OFFSET; memmove(directory_data_cache, directory_data_cache + SQUASHFS_METADATA_SIZE, directory_cache_bytes - SQUASHFS_METADATA_SIZE); directory_cache_bytes -= SQUASHFS_METADATA_SIZE; } create_inode(inode, dir_info, dir_info->dir_ent, SQUASHFS_DIR_TYPE, dir_size + 3, directory_block, directory_offset, NULL, NULL, dir, 0); #ifdef SQUASHFS_TRACE { unsigned char *dirp; int count; TRACE("Directory contents of inode 0x%llx\n", *inode); dirp = dir->buff; while (dirp < dir->p) { char buffer[SQUASHFS_NAME_LEN + 1]; struct squashfs_dir_entry idir, *idirp; struct squashfs_dir_header dirh; SQUASHFS_SWAP_DIR_HEADER((struct squashfs_dir_header *)dirp, &dirh); count = dirh.count + 1; dirp += sizeof(struct squashfs_dir_header); TRACE("\tStart block 0x%x, count %d\n", dirh.start_block, count); while (count--) { idirp = (struct squashfs_dir_entry *)dirp; SQUASHFS_SWAP_DIR_ENTRY(idirp, &idir); strncpy(buffer, idirp->name, idir.size + 1); buffer[idir.size + 1] = '\0'; TRACE("\t\tname %s, inode offset 0x%x, type " "%d\n", buffer, idir.offset, idir.type); dirp += sizeof(struct squashfs_dir_entry) + idir.size + 1; } } } #endif dir_count++; } static struct file_buffer *get_fragment(struct fragment *fragment) { struct squashfs_fragment_entry *disk_fragment; struct file_buffer *buffer, *compressed_buffer; long long start_block; int res, size, index = fragment->index; char locked; /* * Lookup fragment block in cache. * If the fragment block doesn't exist, then get the compressed version * from the writer cache or off disk, and decompress it. * * This routine has two things which complicate the code: * * 1. Multiple threads can simultaneously lookup/create the * same buffer. This means a buffer needs to be "locked" * when it is being filled in, to prevent other threads from * using it when it is not ready. This is because we now do * fragment duplicate checking in parallel. * 2. We have two caches which need to be checked for the * presence of fragment blocks: the normal fragment cache * and a "reserve" cache. The reserve cache is used to * prevent an unnecessary pipeline stall when the fragment cache * is full of fragments waiting to be compressed. */ if (fragment->index == SQUASHFS_INVALID_FRAG) return NULL; pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); pthread_mutex_lock(&dup_mutex); again: buffer = cache_lookup_nowait(fragment_buffer, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* not in fragment cache, is it in the reserve cache? */ buffer = cache_lookup_nowait(reserve_cache, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* in neither cache, try to get it from the fragment cache */ buffer = cache_get_nowait(fragment_buffer, index); if (!buffer) { /* * no room, get it from the reserve cache, this is * dimensioned so it will always have space (no more than * processors + 1 can have an outstanding reserve buffer) */ buffer = cache_get_nowait(reserve_cache, index); if (!buffer) { /* failsafe */ ERROR("no space in reserve cache\n"); goto again; } } pthread_mutex_unlock(&dup_mutex); compressed_buffer = cache_lookup(fwriter_buffer, index); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); disk_fragment = &fragment_table[index]; size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size); start_block = disk_fragment->start_block; pthread_cleanup_pop(1); if (SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { int error; char *data; if (compressed_buffer) data = compressed_buffer->data; else { data = read_from_disk(start_block, size); if (data == NULL) { ERROR("Failed to read fragment from output" " filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } } res = compressor_uncompress(comp, buffer->data, data, size, block_size, &error); if (res == -1) BAD_ERROR("%s uncompress failed with error code %d\n", comp->name, error); } else if (compressed_buffer) memcpy(buffer->data, compressed_buffer->data, size); else { res = read_fs_bytes(fd, start_block, size, buffer->data); if (res == 0) { ERROR("Failed to read fragment from output " "filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } } cache_unlock(buffer); cache_block_put(compressed_buffer); finished: pthread_cleanup_pop(0); return buffer; } unsigned short get_fragment_checksum(struct file_info *file) { struct file_buffer *frag_buffer; struct append_file *append; int res, index = file->fragment->index; unsigned short checksum; if (index == SQUASHFS_INVALID_FRAG) return 0; pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); pthread_mutex_lock(&dup_mutex); res = file->have_frag_checksum; checksum = file->fragment_checksum; pthread_cleanup_pop(1); if (res) return checksum; frag_buffer = get_fragment(file->fragment); pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); for (append = file_mapping[index]; append; append = append->next) { int offset = append->file->fragment->offset; int size = append->file->fragment->size; unsigned short cksum = get_checksum_mem(frag_buffer->data + offset, size); if (file == append->file) checksum = cksum; pthread_mutex_lock(&dup_mutex); append->file->fragment_checksum = cksum; append->file->have_frag_checksum = TRUE; pthread_mutex_unlock(&dup_mutex); } cache_block_put(frag_buffer); pthread_cleanup_pop(0); return checksum; } void lock_fragments() { pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); fragments_locked = TRUE; pthread_cleanup_pop(1); } void unlock_fragments() { int frg, size; struct file_buffer *write_buffer; pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); /* * Note queue_empty() is inherently racy with respect to concurrent * queue get and pushes. We avoid this because we're holding the * fragment_mutex which ensures no other threads can be using the * queue at this time. */ while (!queue_empty(locked_fragment)) { write_buffer = queue_get(locked_fragment); frg = write_buffer->block; size = SQUASHFS_COMPRESSED_SIZE_BLOCK(fragment_table[frg].size); fragment_table[frg].start_block = bytes; write_buffer->block = bytes; bytes += size; fragments_outstanding--; queue_put(to_writer, write_buffer); TRACE("fragment_locked writing fragment %d, compressed size %d" "\n", frg, size); } fragments_locked = FALSE; pthread_cleanup_pop(1); } /* Called with the fragment_mutex locked */ void add_pending_fragment(struct file_buffer *write_buffer, int c_byte, int fragment) { fragment_table[fragment].size = c_byte; write_buffer->block = fragment; queue_put(locked_fragment, write_buffer); } void write_fragment(struct file_buffer *fragment) { if (fragment == NULL) return; pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); fragment_table[fragment->block].unused = 0; fragments_outstanding++; queue_put(to_frag, fragment); pthread_cleanup_pop(1); } struct file_buffer *allocate_fragment() { struct file_buffer *fragment = cache_get(fragment_buffer, fragments); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); if (fragments % FRAG_SIZE == 0) { void *ft = realloc(fragment_table, (fragments + FRAG_SIZE) * sizeof(struct squashfs_fragment_entry)); if (ft == NULL) MEM_ERROR(); fragment_table = ft; } fragment->size = 0; fragment->block = fragments++; pthread_cleanup_pop(1); return fragment; } static struct fragment empty_fragment = { SQUASHFS_INVALID_FRAG, 0, 0 }; void free_fragment(struct fragment *fragment) { if (fragment != &empty_fragment) free(fragment); } struct fragment *get_and_fill_fragment(struct file_buffer *file_buffer, struct dir_ent *dir_ent) { struct fragment *ffrg; struct file_buffer **fragment; if (file_buffer == NULL || file_buffer->size == 0) return &empty_fragment; fragment = eval_frag_actions(dir_ent); if ((*fragment) && (*fragment)->size + file_buffer->size > block_size) { write_fragment(*fragment); *fragment = NULL; } ffrg = malloc(sizeof(struct fragment)); if (ffrg == NULL) MEM_ERROR(); if (*fragment == NULL) *fragment = allocate_fragment(); ffrg->index = (*fragment)->block; ffrg->offset = (*fragment)->size; ffrg->size = file_buffer->size; memcpy((*fragment)->data + (*fragment)->size, file_buffer->data, file_buffer->size); (*fragment)->size += file_buffer->size; return ffrg; } long long generic_write_table(int length, void *buffer, int length2, void *buffer2, int uncompressed) { int meta_blocks = (length + SQUASHFS_METADATA_SIZE - 1) / SQUASHFS_METADATA_SIZE; long long *list, start_bytes; int compressed_size, i, list_size = meta_blocks * sizeof(long long); unsigned short c_byte; char cbuffer[(SQUASHFS_METADATA_SIZE << 2) + 2]; #ifdef SQUASHFS_TRACE long long obytes = bytes; int olength = length; #endif list = malloc(list_size); if (list == NULL) MEM_ERROR(); for (i = 0; i < meta_blocks; i++) { int avail_bytes = length > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : length; c_byte = mangle(cbuffer + BLOCK_OFFSET, buffer + i * SQUASHFS_METADATA_SIZE, avail_bytes, SQUASHFS_METADATA_SIZE, uncompressed, 0); SQUASHFS_SWAP_SHORTS(&c_byte, cbuffer, 1); list[i] = bytes; compressed_size = SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; TRACE("block %d @ 0x%llx, compressed size %d\n", i, bytes, compressed_size); write_destination(fd, bytes, compressed_size, cbuffer); bytes += compressed_size; total_bytes += avail_bytes; length -= avail_bytes; } start_bytes = bytes; if (length2) { write_destination(fd, bytes, length2, buffer2); bytes += length2; total_bytes += length2; } SQUASHFS_INSWAP_LONG_LONGS(list, meta_blocks); write_destination(fd, bytes, list_size, list); bytes += list_size; total_bytes += list_size; TRACE("generic_write_table: total uncompressed %d compressed %lld\n", olength, bytes - obytes); free(list); return start_bytes; } long long write_fragment_table() { unsigned int frag_bytes = SQUASHFS_FRAGMENT_BYTES(fragments); int i; TRACE("write_fragment_table: fragments %d, frag_bytes %d\n", fragments, frag_bytes); for (i = 0; i < fragments; i++) { TRACE("write_fragment_table: fragment %d, start_block 0x%llx, " "size %d\n", i, fragment_table[i].start_block, fragment_table[i].size); SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]); } return generic_write_table(frag_bytes, fragment_table, 0, NULL, noF); } char read_from_file_buffer[SQUASHFS_FILE_MAX_SIZE]; static char *read_from_disk(long long start, unsigned int avail_bytes) { int res; res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer); if (res == 0) return NULL; return read_from_file_buffer; } char read_from_file_buffer2[SQUASHFS_FILE_MAX_SIZE]; char *read_from_disk2(long long start, unsigned int avail_bytes) { int res; res = read_fs_bytes(fd, start, avail_bytes, read_from_file_buffer2); if (res == 0) return NULL; return read_from_file_buffer2; } /* * Compute 16 bit BSD checksum over the data */ unsigned short get_checksum(char *buff, int bytes, unsigned short chksum) { unsigned char *b = (unsigned char *)buff; while (bytes--) { chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1; chksum += *b++; } return chksum; } unsigned short get_checksum_disk(long long start, long long l, unsigned int *blocks) { unsigned short chksum = 0; unsigned int bytes; struct file_buffer *write_buffer; int i; for (i = 0; l; i++) { bytes = SQUASHFS_COMPRESSED_SIZE_BLOCK(blocks[i]); if (bytes == 0) /* sparse block */ continue; write_buffer = cache_lookup(bwriter_buffer, start); if (write_buffer) { chksum = get_checksum(write_buffer->data, bytes, chksum); cache_block_put(write_buffer); } else { void *data = read_from_disk(start, bytes); if (data == NULL) { ERROR("Failed to checksum data from output" " filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } chksum = get_checksum(data, bytes, chksum); } l -= bytes; start += bytes; } return chksum; } unsigned short get_checksum_mem(char *buff, int bytes) { return get_checksum(buff, bytes, 0); } unsigned short get_checksum_mem_buffer(struct file_buffer *file_buffer) { if (file_buffer == NULL) return 0; else return get_checksum(file_buffer->data, file_buffer->size, 0); } #define DUP_HASH(a) (a & 0xffff) void add_file(long long start, long long file_size, long long file_bytes, unsigned int *block_listp, int blocks, unsigned int fragment, int offset, int bytes) { struct fragment *frg; unsigned int *block_list = block_listp; struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; struct append_file *append_file; struct file_info *file; if (!duplicate_checking || file_size == 0) return; for (; dupl_ptr; dupl_ptr = dupl_ptr->next) { if (file_size != dupl_ptr->file_size) continue; if (blocks != 0 && start != dupl_ptr->start) continue; if (fragment != dupl_ptr->fragment->index) continue; if (fragment != SQUASHFS_INVALID_FRAG && (offset != dupl_ptr->fragment->offset || bytes != dupl_ptr->fragment->size)) continue; return; } frg = malloc(sizeof(struct fragment)); if (frg == NULL) MEM_ERROR(); frg->index = fragment; frg->offset = offset; frg->size = bytes; file = add_non_dup(file_size, file_bytes, block_list, start, frg, 0, 0, FALSE, FALSE); if (fragment == SQUASHFS_INVALID_FRAG) return; append_file = malloc(sizeof(struct append_file)); if (append_file == NULL) MEM_ERROR(); append_file->file = file; append_file->next = file_mapping[fragment]; file_mapping[fragment] = append_file; } int pre_duplicate(long long file_size) { struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; for (; dupl_ptr; dupl_ptr = dupl_ptr->next) if (dupl_ptr->file_size == file_size) return TRUE; return FALSE; } struct file_info *add_non_dup(long long file_size, long long bytes, unsigned int *block_list, long long start, struct fragment *fragment, unsigned short checksum, unsigned short fragment_checksum, int checksum_flag, int checksum_frag_flag) { struct file_info *dupl_ptr = malloc(sizeof(struct file_info)); if (dupl_ptr == NULL) MEM_ERROR(); dupl_ptr->file_size = file_size; dupl_ptr->bytes = bytes; dupl_ptr->block_list = block_list; dupl_ptr->start = start; dupl_ptr->fragment = fragment; dupl_ptr->checksum = checksum; dupl_ptr->fragment_checksum = fragment_checksum; dupl_ptr->have_frag_checksum = checksum_frag_flag; dupl_ptr->have_checksum = checksum_flag; pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); pthread_mutex_lock(&dup_mutex); dupl_ptr->next = dupl[DUP_HASH(file_size)]; dupl[DUP_HASH(file_size)] = dupl_ptr; dup_files++; pthread_cleanup_pop(1); return dupl_ptr; } struct fragment *frag_duplicate(struct file_buffer *file_buffer, char *dont_put) { struct file_info *dupl_ptr; struct file_buffer *buffer; struct file_info *dupl_start = file_buffer->dupl_start; long long file_size = file_buffer->file_size; unsigned short checksum = file_buffer->checksum; int res; if (file_buffer->duplicate) { TRACE("Found duplicate file, fragment %d, size %d, offset %d, " "checksum 0x%x\n", dupl_start->fragment->index, file_size, dupl_start->fragment->offset, checksum); *dont_put = TRUE; return dupl_start->fragment; } else { *dont_put = FALSE; dupl_ptr = dupl[DUP_HASH(file_size)]; } for (; dupl_ptr && dupl_ptr != dupl_start; dupl_ptr = dupl_ptr->next) { if (file_size == dupl_ptr->file_size && file_size == dupl_ptr->fragment->size) { if (get_fragment_checksum(dupl_ptr) == checksum) { buffer = get_fragment(dupl_ptr->fragment); res = memcmp(file_buffer->data, buffer->data + dupl_ptr->fragment->offset, file_size); cache_block_put(buffer); if (res == 0) break; } } } if (!dupl_ptr || dupl_ptr == dupl_start) return NULL; TRACE("Found duplicate file, fragment %d, size %d, offset %d, " "checksum 0x%x\n", dupl_ptr->fragment->index, file_size, dupl_ptr->fragment->offset, checksum); return dupl_ptr->fragment; } struct file_info *duplicate(long long file_size, long long bytes, unsigned int **block_list, long long *start, struct fragment **fragment, struct file_buffer *file_buffer, int blocks, unsigned short checksum, int checksum_flag) { struct file_info *dupl_ptr = dupl[DUP_HASH(file_size)]; int frag_bytes = file_buffer ? file_buffer->size : 0; unsigned short fragment_checksum = file_buffer ? file_buffer->checksum : 0; for (; dupl_ptr; dupl_ptr = dupl_ptr->next) if (file_size == dupl_ptr->file_size && bytes == dupl_ptr->bytes && frag_bytes == dupl_ptr->fragment->size) { long long target_start, dup_start = dupl_ptr->start; int block; if (memcmp(*block_list, dupl_ptr->block_list, blocks * sizeof(unsigned int)) != 0) continue; if (checksum_flag == FALSE) { checksum = get_checksum_disk(*start, bytes, *block_list); checksum_flag = TRUE; } if (!dupl_ptr->have_checksum) { dupl_ptr->checksum = get_checksum_disk(dupl_ptr->start, dupl_ptr->bytes, dupl_ptr->block_list); dupl_ptr->have_checksum = TRUE; } if (checksum != dupl_ptr->checksum || fragment_checksum != get_fragment_checksum(dupl_ptr)) continue; target_start = *start; for (block = 0; block < blocks; block++) { int size = SQUASHFS_COMPRESSED_SIZE_BLOCK((*block_list)[block]); struct file_buffer *target_buffer = NULL; struct file_buffer *dup_buffer = NULL; char *target_data, *dup_data; int res; if (size == 0) continue; target_buffer = cache_lookup(bwriter_buffer, target_start); if (target_buffer) target_data = target_buffer->data; else { target_data = read_from_disk(target_start, size); if (target_data == NULL) { ERROR("Failed to read data from" " output filesystem\n"); BAD_ERROR("Output filesystem" " corrupted?\n"); } } dup_buffer = cache_lookup(bwriter_buffer, dup_start); if (dup_buffer) dup_data = dup_buffer->data; else { dup_data = read_from_disk2(dup_start, size); if (dup_data == NULL) { ERROR("Failed to read data from" " output filesystem\n"); BAD_ERROR("Output filesystem" " corrupted?\n"); } } res = memcmp(target_data, dup_data, size); cache_block_put(target_buffer); cache_block_put(dup_buffer); if (res != 0) break; target_start += size; dup_start += size; } if (block == blocks) { struct file_buffer *frag_buffer = get_fragment(dupl_ptr->fragment); if (frag_bytes == 0 || memcmp(file_buffer->data, frag_buffer->data + dupl_ptr->fragment->offset, frag_bytes) == 0) { TRACE("Found duplicate file, start " "0x%llx, size %lld, checksum " "0x%x, fragment %d, size %d, " "offset %d, checksum 0x%x\n", dupl_ptr->start, dupl_ptr->bytes, dupl_ptr->checksum, dupl_ptr->fragment->index, frag_bytes, dupl_ptr->fragment->offset, fragment_checksum); *block_list = dupl_ptr->block_list; *start = dupl_ptr->start; *fragment = dupl_ptr->fragment; cache_block_put(frag_buffer); return 0; } cache_block_put(frag_buffer); } } return add_non_dup(file_size, bytes, *block_list, *start, *fragment, checksum, fragment_checksum, checksum_flag, TRUE); } inline int is_fragment(struct inode_info *inode) { int file_size = inode->buf.st_size; /* * If this block is to be compressed differently to the * fragment compression then it cannot be a fragment */ if (inode->noF != noF) return FALSE; return !inode->no_fragments && file_size && (file_size < block_size || (inode->always_use_fragments && file_size & (block_size - 1))); } void put_file_buffer(struct file_buffer *file_buffer) { /* * Decide where to send the file buffer: * - compressible non-fragment blocks go to the deflate threads, * - fragments go to the process fragment threads, * - all others go directly to the main thread */ if (file_buffer->error) { file_buffer->fragment = 0; seq_queue_put(to_main, file_buffer); } else if (file_buffer->file_size == 0) seq_queue_put(to_main, file_buffer); else if (file_buffer->fragment) queue_put(to_process_frag, file_buffer); else queue_put(to_deflate, file_buffer); } static int seq = 0; void reader_read_process(struct dir_ent *dir_ent) { long long bytes = 0; struct inode_info *inode = dir_ent->inode; struct file_buffer *prev_buffer = NULL, *file_buffer; int status, byte, res, child; int file = pseudo_exec_file(get_pseudo_file(inode->pseudo_id), &child); if (!file) { file_buffer = cache_get_nohash(reader_buffer); file_buffer->sequence = seq++; goto read_err; } while (1) { file_buffer = cache_get_nohash(reader_buffer); file_buffer->sequence = seq++; file_buffer->noD = inode->noD; byte = read_bytes(file, file_buffer->data, block_size); if (byte == -1) goto read_err2; file_buffer->size = byte; file_buffer->file_size = -1; file_buffer->error = FALSE; file_buffer->fragment = FALSE; bytes += byte; if (byte == 0) break; /* * Update progress bar size. This is done * on every block rather than waiting for all blocks to be * read incase write_file_process() is running in parallel * with this. Otherwise the current progress bar position * may get ahead of the progress bar size. */ progress_bar_size(1); if (prev_buffer) put_file_buffer(prev_buffer); prev_buffer = file_buffer; } /* * Update inode file size now that the size of the dynamic pseudo file * is known. This is needed for the -info option. */ inode->buf.st_size = bytes; res = waitpid(child, &status, 0); close(file); if (res == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) goto read_err; if (prev_buffer == NULL) prev_buffer = file_buffer; else { cache_block_put(file_buffer); seq--; } prev_buffer->file_size = bytes; prev_buffer->fragment = is_fragment(inode); put_file_buffer(prev_buffer); return; read_err2: close(file); read_err: if (prev_buffer) { cache_block_put(file_buffer); seq--; file_buffer = prev_buffer; } file_buffer->error = TRUE; put_file_buffer(file_buffer); } void reader_read_file(struct dir_ent *dir_ent) { struct stat *buf = &dir_ent->inode->buf, buf2; struct file_buffer *file_buffer; int blocks, file, res; long long bytes, read_size; struct inode_info *inode = dir_ent->inode; if (inode->read) return; inode->read = TRUE; again: bytes = 0; read_size = buf->st_size; blocks = (read_size + block_size - 1) >> block_log; file = open(pathname_reader(dir_ent), O_RDONLY); if (file == -1) { file_buffer = cache_get_nohash(reader_buffer); file_buffer->sequence = seq++; goto read_err2; } do { file_buffer = cache_get_nohash(reader_buffer); file_buffer->file_size = read_size; file_buffer->sequence = seq++; file_buffer->noD = inode->noD; file_buffer->error = FALSE; /* * Always try to read block_size bytes from the file rather * than expected bytes (which will be less than the block_size * at the file tail) to check that the file hasn't grown * since being stated. If it is longer (or shorter) than * expected, then restat, and try again. Note the special * case where the file is an exact multiple of the block_size * is dealt with later. */ file_buffer->size = read_bytes(file, file_buffer->data, block_size); if (file_buffer->size == -1) goto read_err; bytes += file_buffer->size; if (blocks > 1) { /* non-tail block should be exactly block_size */ if (file_buffer->size < block_size) goto restat; file_buffer->fragment = FALSE; put_file_buffer(file_buffer); } } while (--blocks > 0); /* Overall size including tail should match */ if (read_size != bytes) goto restat; if (read_size && read_size % block_size == 0) { /* * Special case where we've not tried to read past the end of * the file. We expect to get EOF, i.e. the file isn't larger * than we expect. */ char buffer; int res; res = read_bytes(file, &buffer, 1); if (res == -1) goto read_err; if (res != 0) goto restat; } file_buffer->fragment = is_fragment(inode); put_file_buffer(file_buffer); close(file); return; restat: res = fstat(file, &buf2); if (res == -1) { ERROR("Cannot stat dir/file %s because %s\n", pathname_reader(dir_ent), strerror(errno)); goto read_err; } if (read_size != buf2.st_size) { close(file); memcpy(buf, &buf2, sizeof(struct stat)); file_buffer->error = 2; put_file_buffer(file_buffer); goto again; } read_err: close(file); read_err2: file_buffer->error = TRUE; put_file_buffer(file_buffer); } void reader_scan(struct dir_info *dir) { struct dir_ent *dir_ent = dir->list; for (; dir_ent; dir_ent = dir_ent->next) { struct stat *buf = &dir_ent->inode->buf; if (dir_ent->inode->root_entry) continue; if (IS_PSEUDO_PROCESS(dir_ent->inode)) { reader_read_process(dir_ent); continue; } switch (buf->st_mode & S_IFMT) { case S_IFREG: reader_read_file(dir_ent); break; case S_IFDIR: reader_scan(dir_ent->dir); break; } } } void *reader(void *arg) { if (!sorted) reader_scan(queue_get(to_reader)); else { int i; struct priority_entry *entry; queue_get(to_reader); for (i = 65535; i >= 0; i--) for (entry = priority_list[i]; entry; entry = entry->next) reader_read_file(entry->dir); } pthread_exit(NULL); } void *writer(void *arg) { while (1) { struct file_buffer *file_buffer = queue_get(to_writer); off_t off; if (file_buffer == NULL) { queue_put(from_writer, NULL); continue; } off = file_buffer->block; pthread_cleanup_push((void *)pthread_mutex_unlock, &pos_mutex); pthread_mutex_lock(&pos_mutex); if (lseek(fd, off, SEEK_SET) == -1) { ERROR("writer: Lseek on destination failed because " "%s, offset=0x%llx\n", strerror(errno), off); BAD_ERROR("Probably out of space on output " "%s\n", block_device ? "block device" : "filesystem"); } if (write_bytes(fd, file_buffer->data, file_buffer->size) == -1) BAD_ERROR("Failed to write to output %s\n", block_device ? "block device" : "filesystem"); pthread_cleanup_pop(1); cache_block_put(file_buffer); } } int all_zero(struct file_buffer *file_buffer) { int i; long entries = file_buffer->size / sizeof(long); long *p = (long *)file_buffer->data; for (i = 0; i < entries && p[i] == 0; i++) ; if (i == entries) { for (i = file_buffer->size & ~(sizeof(long) - 1); i < file_buffer->size && file_buffer->data[i] == 0; i++) ; return i == file_buffer->size; } return 0; } void *deflator(void *arg) { struct file_buffer *write_buffer = cache_get_nohash(bwriter_buffer); void *stream = NULL; int res; res = compressor_init(comp, &stream, block_size, 1); if (res) BAD_ERROR("deflator:: compressor_init failed\n"); while (1) { struct file_buffer *file_buffer = queue_get(to_deflate); if (sparse_files && all_zero(file_buffer)) { file_buffer->c_byte = 0; seq_queue_put(to_main, file_buffer); } else { write_buffer->c_byte = mangle2(stream, write_buffer->data, file_buffer->data, file_buffer->size, block_size, file_buffer->noD, 1); write_buffer->sequence = file_buffer->sequence; write_buffer->file_size = file_buffer->file_size; write_buffer->block = file_buffer->block; write_buffer->size = SQUASHFS_COMPRESSED_SIZE_BLOCK(write_buffer->c_byte); write_buffer->fragment = FALSE; write_buffer->error = FALSE; cache_block_put(file_buffer); seq_queue_put(to_main, write_buffer); write_buffer = cache_get_nohash(bwriter_buffer); } } } void *frag_deflator(void *arg) { void *stream = NULL; int res; res = compressor_init(comp, &stream, block_size, 1); if (res) BAD_ERROR("frag_deflator:: compressor_init failed\n"); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); while (1) { int c_byte, compressed_size; struct file_buffer *file_buffer = queue_get(to_frag); struct file_buffer *write_buffer = cache_get(fwriter_buffer, file_buffer->block); c_byte = mangle2(stream, write_buffer->data, file_buffer->data, file_buffer->size, block_size, noF, 1); compressed_size = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte); write_buffer->size = compressed_size; pthread_mutex_lock(&fragment_mutex); if (fragments_locked == FALSE) { fragment_table[file_buffer->block].size = c_byte; fragment_table[file_buffer->block].start_block = bytes; write_buffer->block = bytes; bytes += compressed_size; fragments_outstanding--; pthread_mutex_unlock(&fragment_mutex); queue_put(to_writer, write_buffer); TRACE("Writing fragment %lld, uncompressed size %d, " "compressed size %d\n", file_buffer->block, file_buffer->size, compressed_size); } else { add_pending_fragment(write_buffer, c_byte, file_buffer->block); pthread_mutex_unlock(&fragment_mutex); } cache_block_put(file_buffer); } pthread_cleanup_pop(0); } struct file_buffer *get_file_buffer() { struct file_buffer *file_buffer = seq_queue_get(to_main); return file_buffer; } void write_file_empty(squashfs_inode * inode, struct dir_ent *dir_ent, struct file_buffer *file_buffer, int *duplicate_file) { file_count++; *duplicate_file = FALSE; cache_block_put(file_buffer); create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, 0, 0, 0, NULL, &empty_fragment, NULL, 0); } void write_file_frag(squashfs_inode * inode, struct dir_ent *dir_ent, struct file_buffer *file_buffer, int *duplicate_file) { int size = file_buffer->file_size; struct fragment *fragment; unsigned short checksum = file_buffer->checksum; char dont_put; fragment = frag_duplicate(file_buffer, &dont_put); *duplicate_file = !fragment; if (!fragment) { fragment = get_and_fill_fragment(file_buffer, dir_ent); if (duplicate_checking) add_non_dup(size, 0, NULL, 0, fragment, 0, checksum, TRUE, TRUE); } if (dont_put) free(file_buffer); else cache_block_put(file_buffer); total_bytes += size; file_count++; inc_progress_bar(); create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, size, 0, 0, NULL, fragment, NULL, 0); if (!duplicate_checking) free_fragment(fragment); } int write_file_process(squashfs_inode * inode, struct dir_ent *dir_ent, struct file_buffer *read_buffer, int *duplicate_file) { long long read_size, file_bytes, start; struct fragment *fragment; unsigned int *block_list = NULL; int block = 0, status; long long sparse = 0; struct file_buffer *fragment_buffer = NULL; *duplicate_file = FALSE; lock_fragments(); file_bytes = 0; start = bytes; while (1) { read_size = read_buffer->file_size; if (read_buffer->fragment) fragment_buffer = read_buffer; else { block_list = realloc(block_list, (block + 1) * sizeof(unsigned int)); if (block_list == NULL) MEM_ERROR(); block_list[block++] = read_buffer->c_byte; if (read_buffer->c_byte) { read_buffer->block = bytes; bytes += read_buffer->size; cache_hash(read_buffer, read_buffer->block); file_bytes += read_buffer->size; queue_put(to_writer, read_buffer); } else { sparse += read_buffer->size; cache_block_put(read_buffer); } } inc_progress_bar(); if (read_size != -1) break; read_buffer = get_file_buffer(); if (read_buffer->error) goto read_err; } unlock_fragments(); fragment = get_and_fill_fragment(fragment_buffer, dir_ent); if (duplicate_checking) add_non_dup(read_size, file_bytes, block_list, start, fragment, 0, fragment_buffer ? fragment_buffer->checksum : 0, FALSE, TRUE); cache_block_put(fragment_buffer); file_count++; total_bytes += read_size; create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, block, block_list, fragment, NULL, sparse); if (duplicate_checking == FALSE) { free(block_list); free_fragment(fragment); } return 0; read_err: dec_progress_bar(block); status = read_buffer->error; bytes = start; if (!block_device) { int res; queue_put(to_writer, NULL); if (queue_get(from_writer) != 0) EXIT_MKSQUASHFS(); res = ftruncate(fd, bytes); if (res != 0) BAD_ERROR("Failed to truncate dest file because %s\n", strerror(errno)); } unlock_fragments(); free(block_list); cache_block_put(read_buffer); return status; } int write_file_blocks_dup(squashfs_inode * inode, struct dir_ent *dir_ent, struct file_buffer *read_buffer, int *duplicate_file) { int block, thresh; long long read_size = read_buffer->file_size; long long file_bytes, dup_start, start; struct fragment *fragment; struct file_info *dupl_ptr; int blocks = (read_size + block_size - 1) >> block_log; unsigned int *block_list, *block_listp; struct file_buffer **buffer_list; int status; long long sparse = 0; struct file_buffer *fragment_buffer = NULL; block_list = malloc(blocks * sizeof(unsigned int)); if (block_list == NULL) MEM_ERROR(); block_listp = block_list; buffer_list = malloc(blocks * sizeof(struct file_buffer *)); if (buffer_list == NULL) MEM_ERROR(); lock_fragments(); file_bytes = 0; start = dup_start = bytes; thresh = blocks > bwriter_size ? blocks - bwriter_size : 0; for (block = 0; block < blocks;) { if (read_buffer->fragment) { block_list[block] = 0; buffer_list[block] = NULL; fragment_buffer = read_buffer; blocks = read_size >> block_log; } else { block_list[block] = read_buffer->c_byte; if (read_buffer->c_byte) { read_buffer->block = bytes; bytes += read_buffer->size; file_bytes += read_buffer->size; cache_hash(read_buffer, read_buffer->block); if (block < thresh) { buffer_list[block] = NULL; queue_put(to_writer, read_buffer); } else buffer_list[block] = read_buffer; } else { buffer_list[block] = NULL; sparse += read_buffer->size; cache_block_put(read_buffer); } } inc_progress_bar(); if (++block < blocks) { read_buffer = get_file_buffer(); if (read_buffer->error) goto read_err; } } dupl_ptr = duplicate(read_size, file_bytes, &block_listp, &dup_start, &fragment, fragment_buffer, blocks, 0, FALSE); if (dupl_ptr) { *duplicate_file = FALSE; for (block = thresh; block < blocks; block++) if (buffer_list[block]) queue_put(to_writer, buffer_list[block]); fragment = get_and_fill_fragment(fragment_buffer, dir_ent); dupl_ptr->fragment = fragment; } else { *duplicate_file = TRUE; for (block = thresh; block < blocks; block++) cache_block_put(buffer_list[block]); bytes = start; if (thresh && !block_device) { int res; queue_put(to_writer, NULL); if (queue_get(from_writer) != 0) EXIT_MKSQUASHFS(); res = ftruncate(fd, bytes); if (res != 0) BAD_ERROR("Failed to truncate dest file because" " %s\n", strerror(errno)); } } unlock_fragments(); cache_block_put(fragment_buffer); free(buffer_list); file_count++; total_bytes += read_size; /* * sparse count is needed to ensure squashfs correctly reports a * a smaller block count on stat calls to sparse files. This is * to ensure intelligent applications like cp correctly handle the * file as a sparse file. If the file in the original filesystem isn't * stored as a sparse file then still store it sparsely in squashfs, but * report it as non-sparse on stat calls to preserve semantics */ if (sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size) sparse = 0; create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, dup_start, blocks, block_listp, fragment, NULL, sparse); if (*duplicate_file == TRUE) free(block_list); return 0; read_err: dec_progress_bar(block); status = read_buffer->error; bytes = start; if (thresh && !block_device) { int res; queue_put(to_writer, NULL); if (queue_get(from_writer) != 0) EXIT_MKSQUASHFS(); res = ftruncate(fd, bytes); if (res != 0) BAD_ERROR("Failed to truncate dest file because %s\n", strerror(errno)); } unlock_fragments(); for (blocks = thresh; blocks < block; blocks++) cache_block_put(buffer_list[blocks]); free(buffer_list); free(block_list); cache_block_put(read_buffer); return status; } int write_file_blocks(squashfs_inode * inode, struct dir_ent *dir_ent, struct file_buffer *read_buffer, int *dup) { long long read_size = read_buffer->file_size; long long file_bytes, start; struct fragment *fragment; unsigned int *block_list; int block, status; int blocks = (read_size + block_size - 1) >> block_log; long long sparse = 0; struct file_buffer *fragment_buffer = NULL; if (pre_duplicate(read_size)) return write_file_blocks_dup(inode, dir_ent, read_buffer, dup); *dup = FALSE; block_list = malloc(blocks * sizeof(unsigned int)); if (block_list == NULL) MEM_ERROR(); lock_fragments(); file_bytes = 0; start = bytes; for (block = 0; block < blocks;) { if (read_buffer->fragment) { block_list[block] = 0; fragment_buffer = read_buffer; blocks = read_size >> block_log; } else { block_list[block] = read_buffer->c_byte; if (read_buffer->c_byte) { read_buffer->block = bytes; bytes += read_buffer->size; cache_hash(read_buffer, read_buffer->block); file_bytes += read_buffer->size; queue_put(to_writer, read_buffer); } else { sparse += read_buffer->size; cache_block_put(read_buffer); } } inc_progress_bar(); if (++block < blocks) { read_buffer = get_file_buffer(); if (read_buffer->error) goto read_err; } } unlock_fragments(); fragment = get_and_fill_fragment(fragment_buffer, dir_ent); if (duplicate_checking) add_non_dup(read_size, file_bytes, block_list, start, fragment, 0, fragment_buffer ? fragment_buffer->checksum : 0, FALSE, TRUE); cache_block_put(fragment_buffer); file_count++; total_bytes += read_size; /* * sparse count is needed to ensure squashfs correctly reports a * a smaller block count on stat calls to sparse files. This is * to ensure intelligent applications like cp correctly handle the * file as a sparse file. If the file in the original filesystem isn't * stored as a sparse file then still store it sparsely in squashfs, but * report it as non-sparse on stat calls to preserve semantics */ if (sparse && (dir_ent->inode->buf.st_blocks << 9) >= read_size) sparse = 0; create_inode(inode, NULL, dir_ent, SQUASHFS_FILE_TYPE, read_size, start, blocks, block_list, fragment, NULL, sparse); if (duplicate_checking == FALSE) { free(block_list); free_fragment(fragment); } return 0; read_err: dec_progress_bar(block); status = read_buffer->error; bytes = start; if (!block_device) { int res; queue_put(to_writer, NULL); if (queue_get(from_writer) != 0) EXIT_MKSQUASHFS(); res = ftruncate(fd, bytes); if (res != 0) BAD_ERROR("Failed to truncate dest file because %s\n", strerror(errno)); } unlock_fragments(); free(block_list); cache_block_put(read_buffer); return status; } void write_file(squashfs_inode * inode, struct dir_ent *dir, int *dup) { int status; struct file_buffer *read_buffer; again: read_buffer = get_file_buffer(); status = read_buffer->error; if (status) cache_block_put(read_buffer); else if (read_buffer->file_size == -1) status = write_file_process(inode, dir, read_buffer, dup); else if (read_buffer->file_size == 0) write_file_empty(inode, dir, read_buffer, dup); else if (read_buffer->fragment && read_buffer->c_byte) write_file_frag(inode, dir, read_buffer, dup); else status = write_file_blocks(inode, dir, read_buffer, dup); if (status == 2) { ERROR("File %s changed size while reading filesystem, " "attempting to re-read\n", pathname(dir)); goto again; } else if (status == 1) { ERROR_START("Failed to read file %s", pathname(dir)); ERROR_EXIT(", creating empty file\n"); write_file_empty(inode, dir, NULL, dup); } } #define BUFF_SIZE 512 char *name; char *basename_r(); char *getbase(char *pathname) { static char *b_buffer = NULL; static int b_size = BUFF_SIZE; char *result; if (b_buffer == NULL) { b_buffer = malloc(b_size); if (b_buffer == NULL) MEM_ERROR(); } while (1) { if (*pathname != '/') { result = getcwd(b_buffer, b_size); if (result == NULL && errno != ERANGE) BAD_ERROR("Getcwd failed in getbase\n"); /* enough room for pathname + "/" + '\0' terminator? */ if (result && strlen(pathname) + 2 <= b_size - strlen(b_buffer)) { strcat(strcat(b_buffer, "/"), pathname); break; } } else if (strlen(pathname) < b_size) { strcpy(b_buffer, pathname); break; } /* Buffer not large enough, realloc and try again */ b_buffer = realloc(b_buffer, b_size += BUFF_SIZE); if (b_buffer == NULL) MEM_ERROR(); } name = b_buffer; if (((result = basename_r()) == NULL) || (strcmp(result, "..") == 0)) return NULL; else return result; } char *basename_r() { char *s; char *p; int n = 1; for (;;) { s = name; if (*name == '\0') return NULL; if (*name != '/') { while (*name != '\0' && *name != '/') name++; n = name - s; } while (*name == '/') name++; if (strncmp(s, ".", n) == 0) continue; if ((*name == '\0') || (strncmp(s, "..", n) == 0) || ((p = basename_r()) == NULL)) { s[n] = '\0'; return s; } if (strcmp(p, "..") == 0) continue; return p; } } struct inode_info *lookup_inode2(struct stat *buf, int pseudo, int id) { int ino_hash = INODE_HASH(buf->st_dev, buf->st_ino); struct inode_info *inode; /* * Look-up inode in hash table, if it already exists we have a * hard-link, so increment the nlink count and return it. * Don't do the look-up for directories because we don't hard-link * directories. */ if ((buf->st_mode & S_IFMT) != S_IFDIR) { for (inode = inode_info[ino_hash]; inode; inode = inode->next) { if (memcmp(buf, &inode->buf, sizeof(struct stat)) == 0) { inode->nlink++; return inode; } } } inode = malloc(sizeof(struct inode_info)); if (inode == NULL) MEM_ERROR(); memcpy(&inode->buf, buf, sizeof(struct stat)); inode->read = FALSE; inode->root_entry = FALSE; inode->pseudo_file = pseudo; inode->pseudo_id = id; inode->inode = SQUASHFS_INVALID_BLK; inode->nlink = 1; inode->inode_number = 0; /* * Copy filesystem wide defaults into inode, these filesystem * wide defaults may be altered on an individual inode basis by * user specified actions * */ inode->no_fragments = no_fragments; inode->always_use_fragments = always_use_fragments; inode->noD = noD; inode->noF = noF; if ((buf->st_mode & S_IFMT) == S_IFREG) progress_bar_size((buf->st_size + block_size - 1) >> block_log); inode->next = inode_info[ino_hash]; inode_info[ino_hash] = inode; return inode; } inline struct inode_info *lookup_inode(struct stat *buf) { return lookup_inode2(buf, 0, 0); } inline void alloc_inode_no(struct inode_info *inode, unsigned int use_this) { if (inode->inode_number == 0) inode->inode_number = use_this ? : inode_no++; } inline struct dir_ent *create_dir_entry(char *name, char *source_name, char *nonstandard_pathname, struct dir_info *dir) { struct dir_ent *dir_ent = malloc(sizeof(struct dir_ent)); if (dir_ent == NULL) MEM_ERROR(); dir_ent->name = name; dir_ent->source_name = source_name; dir_ent->nonstandard_pathname = nonstandard_pathname; dir_ent->our_dir = dir; dir_ent->next = NULL; return dir_ent; } inline void add_dir_entry(struct dir_ent *dir_ent, struct dir_info *sub_dir, struct inode_info *inode_info) { struct dir_info *dir = dir_ent->our_dir; if (sub_dir) sub_dir->dir_ent = dir_ent; dir_ent->inode = inode_info; dir_ent->dir = sub_dir; dir_ent->next = dir->list; dir->list = dir_ent; dir->count++; } inline void add_dir_entry2(char *name, char *source_name, char *nonstandard_pathname, struct dir_info *sub_dir, struct inode_info *inode_info, struct dir_info *dir) { struct dir_ent *dir_ent = create_dir_entry(name, source_name, nonstandard_pathname, dir); add_dir_entry(dir_ent, sub_dir, inode_info); } inline void free_dir_entry(struct dir_ent *dir_ent) { if (dir_ent->name) free(dir_ent->name); if (dir_ent->source_name) free(dir_ent->source_name); free(dir_ent); } inline void add_excluded(struct dir_info *dir) { dir->excluded++; } void dir_scan(squashfs_inode * inode, char *pathname, struct dir_ent *(_readdir) (struct dir_info *), int progress) { struct stat buf; struct dir_info *dir_info = dir_scan1(pathname, "", paths, _readdir, 1); struct dir_ent *dir_ent; if (dir_info == NULL) return; /* * Process most actions and any pseudo files */ if (actions() || get_pseudo()) dir_scan2(dir_info, get_pseudo()); /* * Process move actions */ if (move_actions()) { dir_scan3(dir_info, dir_info); do_move_actions(); } /* * Process empty actions */ if (empty_actions()) dir_scan4(dir_info); /* * Sort directories and compute the inode numbers */ dir_scan5(dir_info); dir_ent = create_dir_entry("", NULL, pathname, scan1_opendir("", "", 0)); if (pathname[0] == '\0') { /* * dummy top level directory, if multiple sources specified on * command line */ memset(&buf, 0, sizeof(buf)); buf.st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFDIR; buf.st_uid = getuid(); buf.st_gid = getgid(); buf.st_mtime = time(NULL); buf.st_dev = 0; buf.st_ino = 0; dir_ent->inode = lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0); } else { if (lstat(pathname, &buf) == -1) /* source directory has disappeared? */ BAD_ERROR("Cannot stat source directory %s because %s\n", pathname, strerror(errno)); dir_ent->inode = lookup_inode(&buf); } alloc_inode_no(dir_ent->inode, root_inode_number); dir_ent->dir = dir_info; dir_info->dir_ent = dir_ent; eval_actions(dir_ent); if (sorted) generate_file_priorities(dir_info, 0, &dir_info->dir_ent->inode->buf); if (appending) { sigset_t sigmask; restore_thread = init_restore_thread(); sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGUSR1); if (pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) BAD_ERROR("Failed to set signal mask\n"); write_destination(fd, SQUASHFS_START, 4, "\0\0\0\0"); } queue_put(to_reader, dir_info); if (sorted) sort_files_and_write(dir_info); set_progressbar_state(progress); dir_scan6(inode, dir_info); dir_ent->inode->inode = *inode; dir_ent->inode->type = SQUASHFS_DIR_TYPE; } /* * dir_scan1 routines... * These scan the source directories into memory for processing. * Exclude actions are processed here (in contrast to the other actions) * because they affect what is scanned. */ struct dir_info *scan1_opendir(char *pathname, char *subpath, int depth) { struct dir_info *dir; dir = malloc(sizeof(struct dir_info)); if (dir == NULL) MEM_ERROR(); if (pathname[0] != '\0') { dir->linuxdir = opendir(pathname); if (dir->linuxdir == NULL) { free(dir); return NULL; } } dir->pathname = strdup(pathname); dir->subpath = strdup(subpath); dir->count = 0; dir->directory_count = 0; dir->dir_is_ldir = TRUE; dir->list = NULL; dir->depth = depth; dir->excluded = 0; return dir; } struct dir_ent *scan1_encomp_readdir(struct dir_info *dir) { static int index = 0; if (dir->count < old_root_entries) { int i; for (i = 0; i < old_root_entries; i++) { if (old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE) dir->directory_count++; add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL, &old_root_entry[i].inode, dir); } } while (index < source) { char *basename = NULL; char *dir_name = getbase(source_path[index]); int pass = 1, res; if (dir_name == NULL) { ERROR_START("Bad source directory %s", source_path[index]); ERROR_EXIT(" - skipping ...\n"); index++; continue; } dir_name = strdup(dir_name); for (;;) { struct dir_ent *dir_ent = dir->list; for (; dir_ent && strcmp(dir_ent->name, dir_name) != 0; dir_ent = dir_ent->next) ; if (dir_ent == NULL) break; ERROR("Source directory entry %s already used! - trying" " ", dir_name); if (pass == 1) basename = dir_name; else free(dir_name); res = asprintf(&dir_name, "%s_%d", basename, pass++); if (res == -1) BAD_ERROR("asprintf failed in " "scan1_encomp_readdir\n"); ERROR("%s\n", dir_name); } return create_dir_entry(dir_name, basename, source_path[index++], dir); } return NULL; } struct dir_ent *scan1_single_readdir(struct dir_info *dir) { struct dirent *d_name; int i; if (dir->count < old_root_entries) { for (i = 0; i < old_root_entries; i++) { if (old_root_entry[i].inode.type == SQUASHFS_DIR_TYPE) dir->directory_count++; add_dir_entry2(old_root_entry[i].name, NULL, NULL, NULL, &old_root_entry[i].inode, dir); } } if ((d_name = readdir(dir->linuxdir)) != NULL) { char *basename = NULL; char *dir_name = strdup(d_name->d_name); int pass = 1, res; for (;;) { struct dir_ent *dir_ent = dir->list; for (; dir_ent && strcmp(dir_ent->name, dir_name) != 0; dir_ent = dir_ent->next) ; if (dir_ent == NULL) break; ERROR("Source directory entry %s already used! - trying" " ", dir_name); if (pass == 1) basename = dir_name; else free(dir_name); res = asprintf(&dir_name, "%s_%d", d_name->d_name, pass++); if (res == -1) BAD_ERROR("asprintf failed in " "scan1_single_readdir\n"); ERROR("%s\n", dir_name); } return create_dir_entry(dir_name, basename, NULL, dir); } return NULL; } struct dir_ent *scan1_readdir(struct dir_info *dir) { struct dirent *d_name = readdir(dir->linuxdir); return d_name ? create_dir_entry(strdup(d_name->d_name), NULL, NULL, dir) : NULL; } void scan1_freedir(struct dir_info *dir) { if (dir->pathname[0] != '\0') closedir(dir->linuxdir); } struct dir_info *dir_scan1(char *filename, char *subpath, struct pathnames *paths, struct dir_ent *(_readdir) (struct dir_info *), int depth) { struct dir_info *dir = scan1_opendir(filename, subpath, depth); struct dir_ent *dir_ent; if (dir == NULL) { ERROR_START("Could not open %s", filename); ERROR_EXIT(", skipping...\n"); return NULL; } while ((dir_ent = _readdir(dir))) { struct dir_info *sub_dir; struct stat buf; struct pathnames *new = NULL; char *filename = pathname(dir_ent); char *subpath = NULL; char *dir_name = dir_ent->name; if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0) { free_dir_entry(dir_ent); continue; } if (lstat(filename, &buf) == -1) { ERROR_START("Cannot stat dir/file %s because %s", filename, strerror(errno)); ERROR_EXIT(", ignoring\n"); free_dir_entry(dir_ent); continue; } if ((buf.st_mode & S_IFMT) != S_IFREG && (buf.st_mode & S_IFMT) != S_IFDIR && (buf.st_mode & S_IFMT) != S_IFLNK && (buf.st_mode & S_IFMT) != S_IFCHR && (buf.st_mode & S_IFMT) != S_IFBLK && (buf.st_mode & S_IFMT) != S_IFIFO && (buf.st_mode & S_IFMT) != S_IFSOCK) { ERROR_START("File %s has unrecognised filetype %d", filename, buf.st_mode & S_IFMT); ERROR_EXIT(", ignoring\n"); free_dir_entry(dir_ent); continue; } if ((old_exclude && old_excluded(filename, &buf)) || (!old_exclude && excluded(dir_name, paths, &new))) { add_excluded(dir); free_dir_entry(dir_ent); continue; } if (exclude_actions()) { subpath = subpathname(dir_ent); if (eval_exclude_actions(dir_name, filename, subpath, &buf, depth)) { add_excluded(dir); free_dir_entry(dir_ent); continue; } } if ((buf.st_mode & S_IFMT) == S_IFDIR) { if (subpath == NULL) subpath = subpathname(dir_ent); sub_dir = dir_scan1(filename, subpath, new, scan1_readdir, depth + 1); if (sub_dir == NULL) { free_dir_entry(dir_ent); free(new); continue; } dir->directory_count++; } else sub_dir = NULL; add_dir_entry(dir_ent, sub_dir, lookup_inode(&buf)); free(new); } scan1_freedir(dir); return dir; } /* * dir_scan2 routines... * This processes most actions and any pseudo files */ struct dir_ent *scan2_readdir(struct dir_info *dir, struct dir_ent *dir_ent) { if (dir_ent == NULL) dir_ent = dir->list; else dir_ent = dir_ent->next; for (; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next) ; return dir_ent; } struct dir_ent *scan2_lookup(struct dir_info *dir, char *name) { struct dir_ent *dir_ent = dir->list; for (; dir_ent && strcmp(dir_ent->name, name) != 0; dir_ent = dir_ent->next) ; return dir_ent; } void dir_scan2(struct dir_info *dir, struct pseudo *pseudo) { struct dir_ent *dir_ent = NULL; struct pseudo_entry *pseudo_ent; struct stat buf; static int pseudo_ino = 1; while ((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) { struct inode_info *inode_info = dir_ent->inode; struct stat *buf = &inode_info->buf; char *name = dir_ent->name; eval_actions(dir_ent); if ((buf->st_mode & S_IFMT) == S_IFDIR) dir_scan2(dir_ent->dir, pseudo_subdir(name, pseudo)); } while ((pseudo_ent = pseudo_readdir(pseudo)) != NULL) { dir_ent = scan2_lookup(dir, pseudo_ent->name); if (pseudo_ent->dev->type == 'm') { struct stat *buf; if (dir_ent == NULL) { ERROR_START("Pseudo modify file \"%s\" does " "not exist in source filesystem.", pseudo_ent->pathname); ERROR_EXIT(" Ignoring.\n"); continue; } if (dir_ent->inode->root_entry) { ERROR_START("Pseudo modify file \"%s\" is a " "pre-existing file in the filesystem " "being appended to. It cannot be " "modified.", pseudo_ent->pathname); ERROR_EXIT(" Ignoring.\n"); continue; } buf = &dir_ent->inode->buf; buf->st_mode = (buf->st_mode & S_IFMT) | pseudo_ent->dev->mode; buf->st_uid = pseudo_ent->dev->uid; buf->st_gid = pseudo_ent->dev->gid; continue; } if (dir_ent) { if (dir_ent->inode->root_entry) { ERROR_START("Pseudo file \"%s\" is a " "pre-existing file in the filesystem " "being appended to.", pseudo_ent->pathname); ERROR_EXIT(" Ignoring.\n"); } else { ERROR_START("Pseudo file \"%s\" exists in " "source filesystem \"%s\".", pseudo_ent->pathname, pathname(dir_ent)); ERROR_EXIT("\nIgnoring, exclude it (-e/-ef) to " "override.\n"); } continue; } memset(&buf, 0, sizeof(buf)); buf.st_mode = pseudo_ent->dev->mode; buf.st_uid = pseudo_ent->dev->uid; buf.st_gid = pseudo_ent->dev->gid; buf.st_rdev = makedev(pseudo_ent->dev->major, pseudo_ent->dev->minor); buf.st_mtime = time(NULL); buf.st_ino = pseudo_ino++; if (pseudo_ent->dev->type == 'd') { struct dir_ent *dir_ent = create_dir_entry(pseudo_ent->name, NULL, pseudo_ent->pathname, dir); char *subpath = strdup(subpathname(dir_ent)); struct dir_info *sub_dir = scan1_opendir("", subpath, dir->depth + 1); if (sub_dir == NULL) { ERROR_START("Could not create pseudo directory " "\"%s\"", pseudo_ent->pathname); ERROR_EXIT(", skipping...\n"); free(subpath); pseudo_ino--; continue; } dir_scan2(sub_dir, pseudo_ent->pseudo); dir->directory_count++; add_dir_entry(dir_ent, sub_dir, lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0)); } else if (pseudo_ent->dev->type == 'f') { add_dir_entry2(pseudo_ent->name, NULL, pseudo_ent->pathname, NULL, lookup_inode2(&buf, PSEUDO_FILE_PROCESS, pseudo_ent->dev->pseudo_id), dir); } else { add_dir_entry2(pseudo_ent->name, NULL, pseudo_ent->pathname, NULL, lookup_inode2(&buf, PSEUDO_FILE_OTHER, 0), dir); } } } /* * dir_scan3 routines... * This processes the move action */ void dir_scan3(struct dir_info *root, struct dir_info *dir) { struct dir_ent *dir_ent = NULL; while ((dir_ent = scan2_readdir(dir, dir_ent)) != NULL) { eval_move_actions(root, dir_ent); if ((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) dir_scan3(root, dir_ent->dir); } } /* * dir_scan4 routines... * This processes the empty action. This action has to be processed after * all other actions because the previous exclude and move actions and the * pseudo actions affect whether a directory is empty */ void dir_scan4(struct dir_info *dir) { struct dir_ent *dir_ent = dir->list, *prev = NULL; while (dir_ent) { if ((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) { dir_scan4(dir_ent->dir); if (eval_empty_actions(dir_ent)) { struct dir_ent *tmp = dir_ent; /* * delete sub-directory, this is by definition * empty */ free(dir_ent->dir->pathname); free(dir_ent->dir->subpath); free(dir_ent->dir); /* remove dir_ent from list */ dir_ent = dir_ent->next; if (prev) prev->next = dir_ent; else dir->list = dir_ent; /* free it */ free_dir_entry(tmp); /* update counts */ dir->directory_count--; dir->count--; add_excluded(dir); continue; } } prev = dir_ent; dir_ent = dir_ent->next; } } /* * dir_scan5 routines... * This sorts every directory and computes the inode numbers */ /* * Bottom up linked list merge sort. * * Qsort and other O(n log n) algorithms work well with arrays but not * linked lists. Merge sort another O(n log n) sort algorithm on the other hand * is not ideal for arrays (as it needs an additonal n storage locations * as sorting is not done in place), but it is ideal for linked lists because * it doesn't require any extra storage, */ void sort_directory(struct dir_info *dir) { struct dir_ent *cur, *l1, *l2, *next; int len1, len2, stride = 1; if (dir->list == NULL || dir->count < 2) return; /* * We can consider our linked-list to be made up of stride length * sublists. Eacn iteration around this loop merges adjacent * stride length sublists into larger 2*stride sublists. We stop * when stride becomes equal to the entire list. * * Initially stride = 1 (by definition a sublist of 1 is sorted), and * these 1 element sublists are merged into 2 element sublists, which * are then merged into 4 element sublists and so on. */ do { l2 = dir->list; /* head of current linked list */ cur = NULL; /* empty output list */ /* * Iterate through the linked list, merging adjacent sublists. * On each interation l2 points to the next sublist pair to be * merged (if there's only one sublist left this is simply added * to the output list) */ while (l2) { l1 = l2; for (len1 = 0; l2 && len1 < stride; len1++, l2 = l2->next) ; len2 = stride; /* * l1 points to first sublist. * l2 points to second sublist. * Merge them onto the output list */ while (len1 && l2 && len2) { if (strcmp(l1->name, l2->name) <= 0) { next = l1; l1 = l1->next; len1--; } else { next = l2; l2 = l2->next; len2--; } if (cur) { cur->next = next; cur = next; } else dir->list = cur = next; } /* * One sublist is now empty, copy the other one onto the * output list */ for (; len1; len1--, l1 = l1->next) { if (cur) { cur->next = l1; cur = l1; } else dir->list = cur = l1; } for (; l2 && len2; len2--, l2 = l2->next) { if (cur) { cur->next = l2; cur = l2; } else dir->list = cur = l2; } } cur->next = NULL; stride = stride << 1; } while (stride < dir->count); } void dir_scan5(struct dir_info *dir) { struct dir_ent *dir_ent; unsigned int byte_count = 0; sort_directory(dir); for (dir_ent = dir->list; dir_ent; dir_ent = dir_ent->next) { byte_count += strlen(dir_ent->name) + sizeof(struct squashfs_dir_entry); if (dir_ent->inode->root_entry) continue; alloc_inode_no(dir_ent->inode, 0); if ((dir_ent->inode->buf.st_mode & S_IFMT) == S_IFDIR) dir_scan5(dir_ent->dir); } if ((dir->count < 257 && byte_count < SQUASHFS_METADATA_SIZE)) dir->dir_is_ldir = FALSE; } /* * dir_scan6 routines... * This generates the filesystem metadata and writes it out to the destination */ void scan6_init_dir(struct directory *dir) { dir->buff = malloc(SQUASHFS_METADATA_SIZE); if (dir->buff == NULL) MEM_ERROR(); dir->size = SQUASHFS_METADATA_SIZE; dir->p = dir->index_count_p = dir->buff; dir->entry_count = 256; dir->entry_count_p = NULL; dir->index = NULL; dir->i_count = dir->i_size = 0; } struct dir_ent *scan6_readdir(struct directory *dir, struct dir_info *dir_info, struct dir_ent *dir_ent) { if (dir_ent == NULL) dir_ent = dir_info->list; else dir_ent = dir_ent->next; for (; dir_ent && dir_ent->inode->root_entry; dir_ent = dir_ent->next) add_dir(dir_ent->inode->inode, dir_ent->inode->inode_number, dir_ent->name, dir_ent->inode->type, dir); return dir_ent; } void scan6_freedir(struct directory *dir) { if (dir->index) free(dir->index); free(dir->buff); } void dir_scan6(squashfs_inode * inode, struct dir_info *dir_info) { int squashfs_type; int duplicate_file; struct directory dir; struct dir_ent *dir_ent = NULL; scan6_init_dir(&dir); while ((dir_ent = scan6_readdir(&dir, dir_info, dir_ent)) != NULL) { struct stat *buf = &dir_ent->inode->buf; update_info(dir_ent); if (dir_ent->inode->inode == SQUASHFS_INVALID_BLK) { switch (buf->st_mode & S_IFMT) { case S_IFREG: squashfs_type = SQUASHFS_FILE_TYPE; write_file(inode, dir_ent, &duplicate_file); INFO("file %s, uncompressed size %lld " "bytes %s\n", subpathname(dir_ent), (long long)buf->st_size, duplicate_file ? "DUPLICATE" : ""); break; case S_IFDIR: squashfs_type = SQUASHFS_DIR_TYPE; dir_scan6(inode, dir_ent->dir); break; case S_IFLNK: squashfs_type = SQUASHFS_SYMLINK_TYPE; create_inode(inode, NULL, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL, 0); INFO("symbolic link %s inode 0x%llx\n", subpathname(dir_ent), *inode); sym_count++; break; case S_IFCHR: squashfs_type = SQUASHFS_CHRDEV_TYPE; create_inode(inode, NULL, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL, 0); INFO("character device %s inode 0x%llx" "\n", subpathname(dir_ent), *inode); dev_count++; break; case S_IFBLK: squashfs_type = SQUASHFS_BLKDEV_TYPE; create_inode(inode, NULL, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL, 0); INFO("block device %s inode 0x%llx\n", subpathname(dir_ent), *inode); dev_count++; break; case S_IFIFO: squashfs_type = SQUASHFS_FIFO_TYPE; create_inode(inode, NULL, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL, 0); INFO("fifo %s inode 0x%llx\n", subpathname(dir_ent), *inode); fifo_count++; break; case S_IFSOCK: squashfs_type = SQUASHFS_SOCKET_TYPE; create_inode(inode, NULL, dir_ent, squashfs_type, 0, 0, 0, NULL, NULL, NULL, 0); INFO("unix domain socket %s inode " "0x%llx\n", subpathname(dir_ent), *inode); sock_count++; break; default: BAD_ERROR("%s unrecognised file type, " "mode is %x\n", subpathname(dir_ent), buf->st_mode); } dir_ent->inode->inode = *inode; dir_ent->inode->type = squashfs_type; } else { *inode = dir_ent->inode->inode; squashfs_type = dir_ent->inode->type; switch (squashfs_type) { case SQUASHFS_FILE_TYPE: if (!sorted) INFO("file %s, uncompressed " "size %lld bytes LINK" "\n", subpathname(dir_ent), (long long) buf->st_size); break; case SQUASHFS_SYMLINK_TYPE: INFO("symbolic link %s inode 0x%llx " "LINK\n", subpathname(dir_ent), *inode); break; case SQUASHFS_CHRDEV_TYPE: INFO("character device %s inode 0x%llx " "LINK\n", subpathname(dir_ent), *inode); break; case SQUASHFS_BLKDEV_TYPE: INFO("block device %s inode 0x%llx " "LINK\n", subpathname(dir_ent), *inode); break; case SQUASHFS_FIFO_TYPE: INFO("fifo %s inode 0x%llx LINK\n", subpathname(dir_ent), *inode); break; case SQUASHFS_SOCKET_TYPE: INFO("unix domain socket %s inode " "0x%llx LINK\n", subpathname(dir_ent), *inode); break; } } add_dir(*inode, get_inode_no(dir_ent->inode), dir_ent->name, squashfs_type, &dir); } write_dir(inode, dir_info, &dir); INFO("directory %s inode 0x%llx\n", subpathname(dir_info->dir_ent), *inode); scan6_freedir(&dir); } unsigned int slog(unsigned int block) { int i; for (i = 12; i <= 20; i++) if (block == (1 << i)) return i; return 0; } int old_excluded(char *filename, struct stat *buf) { int i; for (i = 0; i < exclude; i++) if ((exclude_paths[i].st_dev == buf->st_dev) && (exclude_paths[i].st_ino == buf->st_ino)) return TRUE; return FALSE; } #define ADD_ENTRY(buf) \ if(exclude % EXCLUDE_SIZE == 0) { \ exclude_paths = realloc(exclude_paths, (exclude + EXCLUDE_SIZE) \ * sizeof(struct exclude_info)); \ if(exclude_paths == NULL) \ MEM_ERROR(); \ } \ exclude_paths[exclude].st_dev = buf.st_dev; \ exclude_paths[exclude++].st_ino = buf.st_ino; int old_add_exclude(char *path) { int i; char *filename; struct stat buf; if (path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0) { if (lstat(path, &buf) == -1) { ERROR_START("Cannot stat exclude dir/file %s because " "%s", path, strerror(errno)); ERROR_EXIT(", ignoring\n"); return TRUE; } ADD_ENTRY(buf); return TRUE; } for (i = 0; i < source; i++) { int res = asprintf(&filename, "%s/%s", source_path[i], path); if (res == -1) BAD_ERROR("asprintf failed in old_add_exclude\n"); if (lstat(filename, &buf) == -1) { if (!(errno == ENOENT || errno == ENOTDIR)) { ERROR_START("Cannot stat exclude dir/file %s " "because %s", filename, strerror(errno)); ERROR_EXIT(", ignoring\n"); } free(filename); continue; } free(filename); ADD_ENTRY(buf); } return TRUE; } void add_old_root_entry(char *name, squashfs_inode inode, int inode_number, int type) { old_root_entry = realloc(old_root_entry, sizeof(struct old_root_entry_info) * (old_root_entries + 1)); if (old_root_entry == NULL) MEM_ERROR(); old_root_entry[old_root_entries].name = strdup(name); old_root_entry[old_root_entries].inode.inode = inode; old_root_entry[old_root_entries].inode.inode_number = inode_number; old_root_entry[old_root_entries].inode.type = type; old_root_entry[old_root_entries++].inode.root_entry = TRUE; } void initialise_threads(int readq, int fragq, int bwriteq, int fwriteq, int freelst, char *destination_file) { int i; sigset_t sigmask, old_mask; int total_mem = readq; int reader_size; int fragment_size; int fwriter_size; /* * bwriter_size is global because it is needed in * write_file_blocks_dup() */ /* * Never allow the total size of the queues to be larger than * physical memory * * When adding together the possibly user supplied values, make * sure they've not been deliberately contrived to overflow an int */ if (add_overflow(total_mem, fragq)) BAD_ERROR("Queue sizes rediculously too large\n"); total_mem += fragq; if (add_overflow(total_mem, bwriteq)) BAD_ERROR("Queue sizes rediculously too large\n"); total_mem += bwriteq; if (add_overflow(total_mem, fwriteq)) BAD_ERROR("Queue sizes rediculously too large\n"); total_mem += fwriteq; if (total_mem > get_physical_memory()) { ERROR("Total queue sizes larger than physical memory.\n"); ERROR("Mksquashfs will exhaust physical memory and thrash.\n"); BAD_ERROR("Queues too large\n"); } /* * convert from queue size in Mbytes to queue size in * blocks. * * This isn't going to overflow an int unless there exists * systems with more than 8 Petabytes of RAM! */ reader_size = readq << (20 - block_log); fragment_size = fragq << (20 - block_log); bwriter_size = bwriteq << (20 - block_log); fwriter_size = fwriteq << (20 - block_log); /* * setup signal handlers for the main thread, these cleanup * deleting the destination file, if appending the * handlers for SIGTERM and SIGINT will be replaced with handlers * allowing the user to press ^C twice to restore the existing * filesystem. * * SIGUSR1 is an internal signal, which is used by the sub-threads * to tell the main thread to terminate, deleting the destination file, * or if necessary restoring the filesystem on appending */ signal(SIGTERM, sighandler); signal(SIGINT, sighandler); signal(SIGUSR1, sighandler); /* block SIGQUIT and SIGHUP, these are handled by the info thread */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGQUIT); sigaddset(&sigmask, SIGHUP); if (pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) BAD_ERROR("Failed to set signal mask in intialise_threads\n"); /* * temporarily block these signals, so the created sub-threads * will ignore them, ensuring the main thread handles them */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGUSR1); if (pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1) BAD_ERROR("Failed to set signal mask in intialise_threads\n"); if (processors == -1) { #ifndef linux int mib[2]; size_t len = sizeof(processors); mib[0] = CTL_HW; # ifdef HW_AVAILCPU mib[1] = HW_AVAILCPU; # else mib[1] = HW_NCPU; # endif if (sysctl(mib, 2, &processors, &len, NULL, 0) == -1) { ERROR_START("Failed to get number of available " "processors."); ERROR_EXIT(" Defaulting to 1\n"); processors = 1; } #else processors = sysconf(_SC_NPROCESSORS_ONLN); #endif } if (multiply_overflow(processors, 3) || multiply_overflow(processors * 3, sizeof(pthread_t))) BAD_ERROR("Processors too large\n"); deflator_thread = malloc(processors * 3 * sizeof(pthread_t)); if (deflator_thread == NULL) MEM_ERROR(); frag_deflator_thread = &deflator_thread[processors]; frag_thread = &frag_deflator_thread[processors]; to_reader = queue_init(1); to_deflate = queue_init(reader_size); to_process_frag = queue_init(reader_size); to_writer = queue_init(bwriter_size + fwriter_size); from_writer = queue_init(1); to_frag = queue_init(fragment_size); locked_fragment = queue_init(fragment_size); to_main = seq_queue_init(); reader_buffer = cache_init(block_size, reader_size, 0, 0); bwriter_buffer = cache_init(block_size, bwriter_size, 1, freelst); fwriter_buffer = cache_init(block_size, fwriter_size, 1, freelst); fragment_buffer = cache_init(block_size, fragment_size, 1, 0); reserve_cache = cache_init(block_size, processors + 1, 1, 0); pthread_create(&reader_thread, NULL, reader, NULL); pthread_create(&writer_thread, NULL, writer, NULL); init_progress_bar(); init_info(); for (i = 0; i < processors; i++) { if (pthread_create(&deflator_thread[i], NULL, deflator, NULL)) BAD_ERROR("Failed to create thread\n"); if (pthread_create(&frag_deflator_thread[i], NULL, frag_deflator, NULL) != 0) BAD_ERROR("Failed to create thread\n"); if (pthread_create(&frag_thread[i], NULL, frag_thrd, (void *)destination_file) != 0) BAD_ERROR("Failed to create thread\n"); } main_thread = pthread_self(); printf("Parallel mksquashfs: Using %d processor%s\n", processors, processors == 1 ? "" : "s"); /* Restore the signal mask for the main thread */ if (pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1) BAD_ERROR("Failed to set signal mask in intialise_threads\n"); } long long write_inode_lookup_table() { int i, inode_number, lookup_bytes = SQUASHFS_LOOKUP_BYTES(inode_count); void *it; if (inode_count == sinode_count) goto skip_inode_hash_table; it = realloc(inode_lookup_table, lookup_bytes); if (it == NULL) MEM_ERROR(); inode_lookup_table = it; for (i = 0; i < INODE_HASH_SIZE; i++) { struct inode_info *inode; for (inode = inode_info[i]; inode; inode = inode->next) { inode_number = get_inode_no(inode); SQUASHFS_SWAP_LONG_LONGS(&inode->inode, &inode_lookup_table[inode_number - 1], 1); } } skip_inode_hash_table: return generic_write_table(lookup_bytes, inode_lookup_table, 0, NULL, noI); } char *get_component(char *target, char **targname) { char *start; while (*target == '/') target++; start = target; while (*target != '/' && *target != '\0') target++; *targname = strndup(start, target - start); while (*target == '/') target++; return target; } void free_path(struct pathname *paths) { int i; for (i = 0; i < paths->names; i++) { if (paths->name[i].paths) free_path(paths->name[i].paths); free(paths->name[i].name); if (paths->name[i].preg) { regfree(paths->name[i].preg); free(paths->name[i].preg); } } free(paths); } struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) { char *targname; int i, error; target = get_component(target, &targname); if (paths == NULL) { paths = malloc(sizeof(struct pathname)); if (paths == NULL) MEM_ERROR(); paths->names = 0; paths->name = NULL; } for (i = 0; i < paths->names; i++) if (strcmp(paths->name[i].name, targname) == 0) break; if (i == paths->names) { /* allocate new name entry */ paths->names++; paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry)); if (paths->name == NULL) MEM_ERROR(); paths->name[i].name = targname; paths->name[i].paths = NULL; if (use_regex) { paths->name[i].preg = malloc(sizeof(regex_t)); if (paths->name[i].preg == NULL) MEM_ERROR(); error = regcomp(paths->name[i].preg, targname, REG_EXTENDED | REG_NOSUB); if (error) { char str[1024]; /* overflow safe */ regerror(error, paths->name[i].preg, str, 1024); BAD_ERROR("invalid regex %s in export %s, " "because %s\n", targname, alltarget, str); } } else paths->name[i].preg = NULL; if (target[0] == '\0') /* at leaf pathname component */ paths->name[i].paths = NULL; else /* recurse adding child components */ paths->name[i].paths = add_path(NULL, target, alltarget); } else { /* existing matching entry */ free(targname); if (paths->name[i].paths == NULL) { /* No sub-directory which means this is the leaf * component of a pre-existing exclude which subsumes * the exclude currently being added, in which case stop * adding components */ } else if (target[0] == '\0') { /* at leaf pathname component and child components exist * from more specific excludes, delete as they're * subsumed by this exclude */ free_path(paths->name[i].paths); paths->name[i].paths = NULL; } else /* recurse adding child components */ add_path(paths->name[i].paths, target, alltarget); } return paths; } void add_exclude(char *target) { if (target[0] == '/' || strncmp(target, "./", 2) == 0 || strncmp(target, "../", 3) == 0) BAD_ERROR("/, ./ and ../ prefixed excludes not supported with " "-wildcards or -regex options\n"); else if (strncmp(target, "... ", 4) == 0) stickypath = add_path(stickypath, target + 4, target + 4); else path = add_path(path, target, target); } void display_path(int depth, struct pathname *paths) { int i, n; if (paths == NULL) return; for (i = 0; i < paths->names; i++) { for (n = 0; n < depth; n++) printf("\t"); printf("%d: %s\n", depth, paths->name[i].name); display_path(depth + 1, paths->name[i].paths); } } void display_path2(struct pathname *paths, char *string) { int i; char *path; if (paths == NULL) { printf("%s\n", string); return; } for (i = 0; i < paths->names; i++) { int res = asprintf(&path, "%s/%s", string, paths->name[i].name); if (res == -1) BAD_ERROR("asprintf failed in display_path2\n"); display_path2(paths->name[i].paths, path); free(path); } } struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path) { int count = paths == NULL ? 0 : paths->count; if (count % PATHS_ALLOC_SIZE == 0) { paths = realloc(paths, sizeof(struct pathnames) + (count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *)); if (paths == NULL) MEM_ERROR(); } paths->path[count] = path; paths->count = count + 1; return paths; } int excluded_match(char *name, struct pathname *path, struct pathnames **new) { int i; for (i = 0; i < path->names; i++) { int match = use_regex ? regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 : fnmatch(path->name[i].name, name, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0; if (match) { if (path->name[i].paths == NULL || new == NULL) /* match on a leaf component, any subdirectories * in the filesystem should be excluded */ return TRUE; else /* match on a non-leaf component, add any * subdirectories to the new set of * subdirectories to scan for this name */ *new = add_subdir(*new, path->name[i].paths); } } return FALSE; } int excluded(char *name, struct pathnames *paths, struct pathnames **new) { int n; if (stickypath && excluded_match(name, stickypath, NULL)) return TRUE; for (n = 0; paths && n < paths->count; n++) { int res = excluded_match(name, paths->path[n], new); if (res) { free(*new); *new = NULL; return TRUE; } } /* * Either: * - no matching names found, return empty new search set, or * - one or more matches with sub-directories found (no leaf matches), * in which case return new search set. * * In either case return FALSE as we don't want to exclude this entry */ return FALSE; } void process_exclude_file(char *argv) { FILE *fd; char buffer[MAX_LINE + 1]; /* overflow safe */ char *filename; fd = fopen(argv, "r"); if (fd == NULL) BAD_ERROR("Failed to open exclude file \"%s\" because %s\n", argv, strerror(errno)); while (fgets(filename = buffer, MAX_LINE + 1, fd) != NULL) { int len = strlen(filename); if (len == MAX_LINE && filename[len - 1] != '\n') /* line too large */ BAD_ERROR("Line too long when reading " "exclude file \"%s\", larger than %d " "bytes\n", argv, MAX_LINE); /* * Remove '\n' terminator if it exists (the last line * in the file may not be '\n' terminated) */ if (len && filename[len - 1] == '\n') filename[len - 1] = '\0'; /* Skip any leading whitespace */ while (isspace(*filename)) filename++; /* if comment line, skip */ if (*filename == '#') continue; /* * check for initial backslash, to accommodate * filenames with leading space or leading # character */ if (*filename == '\\') filename++; /* if line is now empty after skipping characters, skip it */ if (*filename == '\0') continue; if (old_exclude) old_add_exclude(filename); else add_exclude(filename); } if (ferror(fd)) BAD_ERROR("Reading exclude file \"%s\" failed because %s\n", argv, strerror(errno)); fclose(fd); } #define RECOVER_ID "Squashfs recovery file v1.0\n" #define RECOVER_ID_SIZE 28 void write_recovery_data(struct squashfs_super_block *sBlk) { int res, recoverfd, bytes = sBlk->bytes_used - sBlk->inode_table_start; pid_t pid = getpid(); char *metadata; char header[] = RECOVER_ID; if (recover == FALSE) { printf("No recovery data option specified.\n"); printf("Skipping saving recovery file.\n\n"); return; } metadata = malloc(bytes); if (metadata == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->inode_table_start, bytes, metadata); if (res == 0) { ERROR("Failed to read append filesystem metadata\n"); BAD_ERROR("Filesystem corrupted?\n"); } res = asprintf(&recovery_file, "squashfs_recovery_%s_%d", getbase(destination_file), pid); if (res == -1) MEM_ERROR(); recoverfd = open(recovery_file, O_CREAT | O_TRUNC | O_RDWR, S_IRWXU); if (recoverfd == -1) BAD_ERROR("Failed to create recovery file, because %s. " "Aborting\n", strerror(errno)); if (write_bytes(recoverfd, header, RECOVER_ID_SIZE) == -1) BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno)); if (write_bytes(recoverfd, sBlk, sizeof(struct squashfs_super_block)) == -1) BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno)); if (write_bytes(recoverfd, metadata, bytes) == -1) BAD_ERROR("Failed to write recovery file, because %s\n", strerror(errno)); close(recoverfd); free(metadata); printf("Recovery file \"%s\" written\n", recovery_file); printf("If Mksquashfs aborts abnormally (i.e. power failure), run\n"); printf("mksquashfs dummy %s -recover %s\n", destination_file, recovery_file); printf("to restore filesystem\n\n"); } void read_recovery_data(char *recovery_file, char *destination_file) { int fd, recoverfd, bytes; struct squashfs_super_block orig_sBlk, sBlk; char *metadata; int res; struct stat buf; char header[] = RECOVER_ID; char header2[RECOVER_ID_SIZE]; recoverfd = open(recovery_file, O_RDONLY); if (recoverfd == -1) BAD_ERROR("Failed to open recovery file because %s\n", strerror(errno)); if (stat(destination_file, &buf) == -1) BAD_ERROR("Failed to stat destination file, because %s\n", strerror(errno)); fd = open(destination_file, O_RDWR); if (fd == -1) BAD_ERROR("Failed to open destination file because %s\n", strerror(errno)); res = read_bytes(recoverfd, header2, RECOVER_ID_SIZE); if (res == -1) BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno)); if (res < RECOVER_ID_SIZE) BAD_ERROR("Recovery file appears to be truncated\n"); if (strncmp(header, header2, RECOVER_ID_SIZE) != 0) BAD_ERROR("Not a recovery file\n"); res = read_bytes(recoverfd, &sBlk, sizeof(struct squashfs_super_block)); if (res == -1) BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno)); if (res < sizeof(struct squashfs_super_block)) BAD_ERROR("Recovery file appears to be truncated\n"); res = read_fs_bytes(fd, 0, sizeof(struct squashfs_super_block), &orig_sBlk); if (res == 0) { ERROR("Failed to read superblock from output filesystem\n"); BAD_ERROR("Output filesystem is empty!\n"); } if (memcmp(((char *)&sBlk) + 4, ((char *)&orig_sBlk) + 4, sizeof(struct squashfs_super_block) - 4) != 0) BAD_ERROR("Recovery file and destination file do not seem to " "match\n"); bytes = sBlk.bytes_used - sBlk.inode_table_start; metadata = malloc(bytes); if (metadata == NULL) MEM_ERROR(); res = read_bytes(recoverfd, metadata, bytes); if (res == -1) BAD_ERROR("Failed to read recovery file, because %s\n", strerror(errno)); if (res < bytes) BAD_ERROR("Recovery file appears to be truncated\n"); write_destination(fd, 0, sizeof(struct squashfs_super_block), &sBlk); write_destination(fd, sBlk.inode_table_start, bytes, metadata); close(recoverfd); close(fd); printf("Successfully wrote recovery file \"%s\". Exiting\n", recovery_file); exit(0); } void write_filesystem_tables(struct squashfs_super_block *sBlk, int nopad) { int i; sBlk->fragments = fragments; sBlk->no_ids = id_count; sBlk->inode_table_start = write_inodes(); sBlk->directory_table_start = write_directories(); sBlk->fragment_table_start = write_fragment_table(); sBlk->lookup_table_start = exportable ? write_inode_lookup_table() : SQUASHFS_INVALID_BLK; sBlk->id_table_start = write_id_table(); sBlk->xattr_id_table_start = write_xattrs(); TRACE("sBlk->inode_table_start 0x%llx\n", sBlk->inode_table_start); TRACE("sBlk->directory_table_start 0x%llx\n", sBlk->directory_table_start); TRACE("sBlk->fragment_table_start 0x%llx\n", sBlk->fragment_table_start); if (exportable) TRACE("sBlk->lookup_table_start 0x%llx\n", sBlk->lookup_table_start); sBlk->bytes_used = bytes; sBlk->compression = comp->id; SQUASHFS_INSWAP_SUPER_BLOCK(sBlk); write_destination(fd, SQUASHFS_START, sizeof(*sBlk), sBlk); if (!nopad && (i = bytes & (4096 - 1))) { char temp[4096] = { 0 }; write_destination(fd, bytes, 4096 - i, temp); } close(fd); if (recovery_file) unlink(recovery_file); total_bytes += total_inode_bytes + total_directory_bytes + sizeof(struct squashfs_super_block) + total_xattr_bytes; printf("\n%sSquashfs %d.%d filesystem, %s compressed, data block size" " %d\n", exportable ? "Exportable " : "", SQUASHFS_MAJOR, SQUASHFS_MINOR, comp->name, block_size); printf("\t%s data, %s metadata, %s fragments, %s xattrs\n", noD ? "uncompressed" : "compressed", noI ? "uncompressed" : "compressed", no_fragments ? "no" : noF ? "uncompressed" : "compressed", no_xattrs ? "no" : noX ? "uncompressed" : "compressed"); printf("\tduplicates are %sremoved\n", duplicate_checking ? "" : "not "); printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", bytes / 1024.0, bytes / (1024.0 * 1024.0)); printf("\t%.2f%% of uncompressed filesystem size (%.2f Kbytes)\n", ((float)bytes / total_bytes) * 100.0, total_bytes / 1024.0); printf("Inode table size %d bytes (%.2f Kbytes)\n", inode_bytes, inode_bytes / 1024.0); printf("\t%.2f%% of uncompressed inode table size (%d bytes)\n", ((float)inode_bytes / total_inode_bytes) * 100.0, total_inode_bytes); printf("Directory table size %d bytes (%.2f Kbytes)\n", directory_bytes, directory_bytes / 1024.0); printf("\t%.2f%% of uncompressed directory table size (%d bytes)\n", ((float)directory_bytes / total_directory_bytes) * 100.0, total_directory_bytes); if (total_xattr_bytes) { printf("Xattr table size %d bytes (%.2f Kbytes)\n", xattr_bytes, xattr_bytes / 1024.0); printf("\t%.2f%% of uncompressed xattr table size (%d bytes)\n", ((float)xattr_bytes / total_xattr_bytes) * 100.0, total_xattr_bytes); } if (duplicate_checking) printf("Number of duplicate files found %d\n", file_count - dup_files); else printf("No duplicate files removed\n"); printf("Number of inodes %d\n", inode_count); printf("Number of files %d\n", file_count); if (!no_fragments) printf("Number of fragments %d\n", fragments); printf("Number of symbolic links %d\n", sym_count); printf("Number of device nodes %d\n", dev_count); printf("Number of fifo nodes %d\n", fifo_count); printf("Number of socket nodes %d\n", sock_count); printf("Number of directories %d\n", dir_count); printf("Number of ids (unique uids + gids) %d\n", id_count); printf("Number of uids %d\n", uid_count); for (i = 0; i < id_count; i++) { if (id_table[i]->flags & ISA_UID) { struct passwd *user = getpwuid(id_table[i]->id); printf("\t%s (%d)\n", user == NULL ? "unknown" : user->pw_name, id_table[i]->id); } } printf("Number of gids %d\n", guid_count); for (i = 0; i < id_count; i++) { if (id_table[i]->flags & ISA_GID) { struct group *group = getgrgid(id_table[i]->id); printf("\t%s (%d)\n", group == NULL ? "unknown" : group->gr_name, id_table[i]->id); } } } int parse_numberll(char *start, long long *res, int size) { char *end; long long number; errno = 0; /* To distinguish success/failure after call */ number = strtoll(start, &end, 10); /* * check for strtoll underflow or overflow in conversion, and other * errors. */ if ((errno == ERANGE && (number == LLONG_MIN || number == LLONG_MAX)) || (errno != 0 && number == 0)) return 0; /* reject negative numbers as invalid */ if (number < 0) return 0; if (size) { /* * Check for multiplier and trailing junk. * But first check that a number exists before the * multiplier */ if (end == start) return 0; switch (end[0]) { case 'g': case 'G': if (multiply_overflowll(number, 1073741824)) return 0; number *= 1073741824; if (end[1] != '\0') /* trailing junk after multiplier, but * allow it to be "bytes" */ if (strcmp(end + 1, "bytes")) return 0; break; case 'm': case 'M': if (multiply_overflowll(number, 1048576)) return 0; number *= 1048576; if (end[1] != '\0') /* trailing junk after multiplier, but * allow it to be "bytes" */ if (strcmp(end + 1, "bytes")) return 0; break; case 'k': case 'K': if (multiply_overflowll(number, 1024)) return 0; number *= 1024; if (end[1] != '\0') /* trailing junk after multiplier, but * allow it to be "bytes" */ if (strcmp(end + 1, "bytes")) return 0; break; case '\0': break; default: /* trailing junk after number */ return 0; } } else if (end[0] != '\0') /* trailing junk after number */ return 0; *res = number; return 1; } int parse_number(char *start, int *res, int size) { long long number; if (!parse_numberll(start, &number, size)) return 0; /* check if long result will overflow signed int */ if (number > INT_MAX) return 0; *res = (int)number; return 1; } int parse_num(char *arg, int *res) { return parse_number(arg, res, 0); } int get_physical_memory() { /* Long longs are used here because with PAE, a 32-bit machine can have more than 4GB of physical memory */ long long num_pages = sysconf(_SC_PHYS_PAGES); long long page_size = sysconf(_SC_PAGESIZE); int phys_mem = num_pages * page_size >> 20; if (phys_mem < SQUASHFS_LOWMEM) BAD_ERROR("Mksquashfs requires more physical memory than is " "available!\n"); return phys_mem; } void calculate_queue_sizes(int mem, int *readq, int *fragq, int *bwriteq, int *fwriteq) { *readq = mem / SQUASHFS_READQ_MEM; *bwriteq = mem / SQUASHFS_BWRITEQ_MEM; *fwriteq = mem / SQUASHFS_FWRITEQ_MEM; *fragq = mem - *readq - *bwriteq - *fwriteq; } #define VERSION() \ printf("mksquashfs version 4.3 (2014/05/12)\n");\ printf("copyright (C) 2014 Phillip Lougher "\ "\n\n"); \ printf("This program is free software; you can redistribute it and/or"\ "\n");\ printf("modify it under the terms of the GNU General Public License"\ "\n");\ printf("as published by the Free Software Foundation; either version "\ "2,\n");\ printf("or (at your option) any later version.\n\n");\ printf("This program is distributed in the hope that it will be "\ "useful,\n");\ printf("but WITHOUT ANY WARRANTY; without even the implied warranty "\ "of\n");\ printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\ "\n");\ printf("GNU General Public License for more details.\n"); int main(int argc, char *argv[]) { struct stat buf, source_buf; int res, i; char *b, *root_name = NULL; int keep_as_directory = FALSE; squashfs_inode inode; int readq; int fragq; int bwriteq; int fwriteq; int total_mem = get_physical_memory() / SQUASHFS_TAKE; int progress = TRUE; int force_progress = FALSE; struct file_buffer **fragment = NULL; if (argc > 1 && strcmp(argv[1], "-version") == 0) { VERSION(); exit(0); } block_log = slog(block_size); calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq); for (i = 1; i < argc && argv[i][0] != '-'; i++) ; if (i < 3) goto printOptions; source_path = argv + 1; source = i - 2; /* * Scan the command line for -comp xxx option, this is to ensure * any -X compressor specific options are passed to the * correct compressor */ for (; i < argc; i++) { struct compressor *prev_comp = comp; if (strcmp(argv[i], "-comp") == 0) { if (++i == argc) { ERROR("%s: -comp missing compression type\n", argv[0]); exit(1); } comp = lookup_compressor(argv[i]); if (!comp->supported) { ERROR("%s: Compressor \"%s\" is not supported!" "\n", argv[0], argv[i]); ERROR("%s: Compressors available:\n", argv[0]); display_compressors("", COMP_DEFAULT); exit(1); } if (prev_comp != NULL && prev_comp != comp) { ERROR("%s: -comp multiple conflicting -comp" " options specified on command line" ", previously %s, now %s\n", argv[0], prev_comp->name, comp->name); exit(1); } compressor_opt_parsed = 1; } else if (strcmp(argv[i], "-e") == 0) break; else if (strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0 || strcmp(argv[i], "-pf") == 0 || strcmp(argv[i], "-af") == 0 || strcmp(argv[i], "-comp") == 0) i++; } /* * if no -comp option specified lookup default compressor. Note the * Makefile ensures the default compressor has been built, and so we * don't need to to check for failure here */ if (comp == NULL) comp = lookup_compressor(COMP_DEFAULT); for (i = source + 2; i < argc; i++) { if (strcmp(argv[i], "-action") == 0 || strcmp(argv[i], "-a") == 0) { if (++i == argc) { ERROR("%s: %s missing action\n", argv[0], argv[i - 1]); exit(1); } res = parse_action(argv[i]); if (res == 0) exit(1); } else if (strcmp(argv[i], "-af") == 0) { if (++i == argc) { ERROR("%s: -af missing filename\n", argv[0]); exit(1); } if (read_action_file(argv[i]) == FALSE) exit(1); } else if (strcmp(argv[i], "-comp") == 0) /* parsed previously */ i++; else if (strncmp(argv[i], "-X", 2) == 0) { int args; if (strcmp(argv[i] + 2, "help") == 0) goto print_compressor_options; args = compressor_options(comp, argv + i, argc - i); if (args < 0) { if (args == -1) { ERROR("%s: Unrecognised compressor" " option %s\n", argv[0], argv[i]); if (!compressor_opt_parsed) ERROR("%s: Did you forget to" " specify -comp?\n", argv[0]); print_compressor_options: ERROR("%s: selected compressor \"%s\"" ". Options supported: %s\n", argv[0], comp->name, comp->usage ? "" : "none"); if (comp->usage) comp->usage(); } exit(1); } i += args; } else if (strcmp(argv[i], "-pf") == 0) { if (++i == argc) { ERROR("%s: -pf missing filename\n", argv[0]); exit(1); } if (read_pseudo_file(argv[i]) == FALSE) exit(1); } else if (strcmp(argv[i], "-p") == 0) { if (++i == argc) { ERROR("%s: -p missing pseudo file definition\n", argv[0]); exit(1); } if (read_pseudo_def(argv[i]) == FALSE) exit(1); } else if (strcmp(argv[i], "-recover") == 0) { if (++i == argc) { ERROR("%s: -recover missing recovery file\n", argv[0]); exit(1); } read_recovery_data(argv[i], argv[source + 1]); } else if (strcmp(argv[i], "-no-recovery") == 0) recover = FALSE; else if (strcmp(argv[i], "-wildcards") == 0) { old_exclude = FALSE; use_regex = FALSE; } else if (strcmp(argv[i], "-regex") == 0) { old_exclude = FALSE; use_regex = TRUE; } else if (strcmp(argv[i], "-no-sparse") == 0) sparse_files = FALSE; else if (strcmp(argv[i], "-no-progress") == 0) progress = FALSE; else if (strcmp(argv[i], "-progress") == 0) force_progress = TRUE; else if (strcmp(argv[i], "-no-exports") == 0) exportable = FALSE; else if (strcmp(argv[i], "-processors") == 0) { if ((++i == argc) || !parse_num(argv[i], &processors)) { ERROR("%s: -processors missing or invalid " "processor number\n", argv[0]); exit(1); } if (processors < 1) { ERROR("%s: -processors should be 1 or larger\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-read-queue") == 0) { if ((++i == argc) || !parse_num(argv[i], &readq)) { ERROR("%s: -read-queue missing or invalid " "queue size\n", argv[0]); exit(1); } if (readq < 1) { ERROR("%s: -read-queue should be 1 megabyte or " "larger\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-write-queue") == 0) { if ((++i == argc) || !parse_num(argv[i], &bwriteq)) { ERROR("%s: -write-queue missing or invalid " "queue size\n", argv[0]); exit(1); } if (bwriteq < 2) { ERROR("%s: -write-queue should be 2 megabytes " "or larger\n", argv[0]); exit(1); } fwriteq = bwriteq >> 1; bwriteq -= fwriteq; } else if (strcmp(argv[i], "-fragment-queue") == 0) { if ((++i == argc) || !parse_num(argv[i], &fragq)) { ERROR("%s: -fragment-queue missing or invalid " "queue size\n", argv[0]); exit(1); } if (fragq < 1) { ERROR("%s: -fragment-queue should be 1 " "megabyte or larger\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-mem") == 0) { long long number; if ((++i == argc) || !parse_numberll(argv[i], &number, 1)) { ERROR("%s: -mem missing or invalid mem size\n", argv[0]); exit(1); } /* convert from bytes to Mbytes */ total_mem = number / 1048576; if (total_mem < (SQUASHFS_LOWMEM / SQUASHFS_TAKE)) { ERROR("%s: -mem should be %d Mbytes or " "larger\n", argv[0], SQUASHFS_LOWMEM / SQUASHFS_TAKE); exit(1); } calculate_queue_sizes(total_mem, &readq, &fragq, &bwriteq, &fwriteq); } else if (strcmp(argv[i], "-b") == 0) { if (++i == argc) { ERROR("%s: -b missing block size\n", argv[0]); exit(1); } if (!parse_number(argv[i], &block_size, 1)) { ERROR("%s: -b invalid block size\n", argv[0]); exit(1); } if ((block_log = slog(block_size)) == 0) { ERROR("%s: -b block size not power of two or " "not between 4096 and 1Mbyte\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-ef") == 0) { if (++i == argc) { ERROR("%s: -ef missing filename\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-no-duplicates") == 0) duplicate_checking = FALSE; else if (strcmp(argv[i], "-no-fragments") == 0) no_fragments = TRUE; else if (strcmp(argv[i], "-always-use-fragments") == 0) always_use_fragments = TRUE; else if (strcmp(argv[i], "-sort") == 0) { if (++i == argc) { ERROR("%s: -sort missing filename\n", argv[0]); exit(1); } } else if (strcmp(argv[i], "-all-root") == 0 || strcmp(argv[i], "-root-owned") == 0) global_uid = global_gid = 0; else if (strcmp(argv[i], "-force-uid") == 0) { if (++i == argc) { ERROR("%s: -force-uid missing uid or user\n", argv[0]); exit(1); } if ((global_uid = strtoll(argv[i], &b, 10)), *b == '\0') { if (global_uid < 0 || global_uid > (((long long)1 << 32) - 1)) { ERROR("%s: -force-uid uid out of range" "\n", argv[0]); exit(1); } } else { struct passwd *uid = getpwnam(argv[i]); if (uid) global_uid = uid->pw_uid; else { ERROR("%s: -force-uid invalid uid or " "unknown user\n", argv[0]); exit(1); } } } else if (strcmp(argv[i], "-force-gid") == 0) { if (++i == argc) { ERROR("%s: -force-gid missing gid or group\n", argv[0]); exit(1); } if ((global_gid = strtoll(argv[i], &b, 10)), *b == '\0') { if (global_gid < 0 || global_gid > (((long long)1 << 32) - 1)) { ERROR("%s: -force-gid gid out of range" "\n", argv[0]); exit(1); } } else { struct group *gid = getgrnam(argv[i]); if (gid) global_gid = gid->gr_gid; else { ERROR("%s: -force-gid invalid gid or " "unknown group\n", argv[0]); exit(1); } } } else if (strcmp(argv[i], "-noI") == 0 || strcmp(argv[i], "-noInodeCompression") == 0) noI = TRUE; else if (strcmp(argv[i], "-noD") == 0 || strcmp(argv[i], "-noDataCompression") == 0) noD = TRUE; else if (strcmp(argv[i], "-noF") == 0 || strcmp(argv[i], "-noFragmentCompression") == 0) noF = TRUE; else if (strcmp(argv[i], "-noX") == 0 || strcmp(argv[i], "-noXattrCompression") == 0) noX = TRUE; else if (strcmp(argv[i], "-no-xattrs") == 0) no_xattrs = TRUE; else if (strcmp(argv[i], "-xattrs") == 0) no_xattrs = FALSE; else if (strcmp(argv[i], "-nopad") == 0) nopad = TRUE; else if (strcmp(argv[i], "-info") == 0) silent = FALSE; else if (strcmp(argv[i], "-e") == 0) break; else if (strcmp(argv[i], "-noappend") == 0) delete = TRUE; else if (strcmp(argv[i], "-keep-as-directory") == 0) keep_as_directory = TRUE; else if (strcmp(argv[i], "-exit-on-error") == 0) exit_on_error = TRUE; else if (strcmp(argv[i], "-root-becomes") == 0) { if (++i == argc) { ERROR("%s: -root-becomes: missing name\n", argv[0]); exit(1); } root_name = argv[i]; } else if (strcmp(argv[i], "-version") == 0) { VERSION(); } else { ERROR("%s: invalid option\n\n", argv[0]); printOptions: ERROR("SYNTAX:%s source1 source2 ... dest [options] " "[-e list of exclude\ndirs/files]\n", argv[0]); ERROR("\nFilesystem build options:\n"); ERROR("-comp \t\tselect compression\n"); ERROR("\t\t\tCompressors available:\n"); display_compressors("\t\t\t", COMP_DEFAULT); ERROR("-b \t\tset data block to " ". Default 128 Kbytes\n"); ERROR("\t\t\tOptionally a suffix of K or M can be" " given to specify\n\t\t\tKbytes or Mbytes" " respectively\n"); ERROR("-no-exports\t\tdon't make the filesystem " "exportable via NFS\n"); ERROR("-no-sparse\t\tdon't detect sparse files\n"); ERROR("-no-xattrs\t\tdon't store extended attributes" NOXOPT_STR "\n"); ERROR("-xattrs\t\t\tstore extended attributes" XOPT_STR "\n"); ERROR("-noI\t\t\tdo not compress inode table\n"); ERROR("-noD\t\t\tdo not compress data blocks\n"); ERROR("-noF\t\t\tdo not compress fragment blocks\n"); ERROR("-noX\t\t\tdo not compress extended " "attributes\n"); ERROR("-no-fragments\t\tdo not use fragments\n"); ERROR("-always-use-fragments\tuse fragment blocks for " "files larger than block size\n"); ERROR("-no-duplicates\t\tdo not perform duplicate " "checking\n"); ERROR("-all-root\t\tmake all files owned by root\n"); ERROR("-force-uid uid\t\tset all file uids to uid\n"); ERROR("-force-gid gid\t\tset all file gids to gid\n"); ERROR("-nopad\t\t\tdo not pad filesystem to a multiple " "of 4K\n"); ERROR("-keep-as-directory\tif one source directory is " "specified, create a root\n"); ERROR("\t\t\tdirectory containing that directory, " "rather than the\n"); ERROR("\t\t\tcontents of the directory\n"); ERROR("\nFilesystem filter options:\n"); ERROR("-p \tAdd pseudo file " "definition\n"); ERROR("-pf \tAdd list of pseudo file " "definitions\n"); ERROR("-sort \tsort files according to " "priorities in . One\n"); ERROR("\t\t\tfile or dir with priority per line. " "Priority -32768 to\n"); ERROR("\t\t\t32767, default priority 0\n"); ERROR("-ef \tlist of exclude dirs/files." " One per line\n"); ERROR("-wildcards\t\tAllow extended shell wildcards " "(globbing) to be used in\n\t\t\texclude " "dirs/files\n"); ERROR("-regex\t\t\tAllow POSIX regular expressions to " "be used in exclude\n\t\t\tdirs/files\n"); ERROR("\nFilesystem append options:\n"); ERROR("-noappend\t\tdo not append to existing " "filesystem\n"); ERROR("-root-becomes \twhen appending source " "files/directories, make the\n"); ERROR("\t\t\toriginal root become a subdirectory in " "the new root\n"); ERROR("\t\t\tcalled , rather than adding the new " "source items\n"); ERROR("\t\t\tto the original root\n"); ERROR("\nMksquashfs runtime options:\n"); ERROR("-version\t\tprint version, licence and " "copyright message\n"); ERROR("-exit-on-error\t\ttreat normally ignored errors " "as fatal\n"); ERROR("-recover \t\trecover filesystem data " "using recovery file \n"); ERROR("-no-recovery\t\tdon't generate a recovery " "file\n"); ERROR("-info\t\t\tprint files written to filesystem\n"); ERROR("-no-progress\t\tdon't display the progress " "bar\n"); ERROR("-progress\t\tdisplay progress bar when using " "the -info option\n"); ERROR("-processors \tUse processors." " By default will use number of\n"); ERROR("\t\t\tprocessors available\n"); ERROR("-mem \t\tUse physical memory. " "Currently set to %dM\n", total_mem); ERROR("\t\t\tOptionally a suffix of K, M or G can be" " given to specify\n\t\t\tKbytes, Mbytes or" " Gbytes respectively\n"); ERROR("\nMiscellaneous options:\n"); ERROR("-root-owned\t\talternative name for -all-root" "\n"); ERROR("-noInodeCompression\talternative name for -noI" "\n"); ERROR("-noDataCompression\talternative name for -noD" "\n"); ERROR("-noFragmentCompression\talternative name for " "-noF\n"); ERROR("-noXattrCompression\talternative name for " "-noX\n"); ERROR("\n-Xhelp\t\t\tprint compressor options for" " selected compressor\n"); ERROR("\nCompressors available and compressor specific " "options:\n"); display_compressor_usage(COMP_DEFAULT); exit(1); } } /* * Some compressors may need the options to be checked for validity * once all the options have been processed */ res = compressor_options_post(comp, block_size); if (res) EXIT_MKSQUASHFS(); /* * If the -info option has been selected then disable the * progress bar unless it has been explicitly enabled with * the -progress option */ if (!silent) progress = force_progress; #ifdef SQUASHFS_TRACE /* * Disable progress bar if full debug tracing is enabled. * The progress bar in this case just gets in the way of the * debug trace output */ progress = FALSE; #endif for (i = 0; i < source; i++) if (lstat(source_path[i], &source_buf) == -1) { fprintf(stderr, "Cannot stat source directory \"%s\" " "because %s\n", source_path[i], strerror(errno)); EXIT_MKSQUASHFS(); } destination_file = argv[source + 1]; if (stat(argv[source + 1], &buf) == -1) { if (errno == ENOENT) { /* Does not exist */ fd = open(argv[source + 1], O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd == -1) { perror("Could not create destination file"); exit(1); } delete = TRUE; } else { perror("Could not stat destination file"); exit(1); } } else { if (S_ISBLK(buf.st_mode)) { if ((fd = open(argv[source + 1], O_RDWR)) == -1) { perror("Could not open block device as " "destination"); exit(1); } block_device = 1; } else if (S_ISREG(buf.st_mode)) { fd = open(argv[source + 1], (delete ? O_TRUNC : 0) | O_RDWR); if (fd == -1) { perror("Could not open regular file for " "writing as destination"); exit(1); } } else { ERROR("Destination not block device or regular file\n"); exit(1); } } /* * process the exclude files - must be done afer destination file has * been possibly created */ for (i = source + 2; i < argc; i++) if (strcmp(argv[i], "-ef") == 0) /* * Note presence of filename arg has already * been checked */ process_exclude_file(argv[++i]); else if (strcmp(argv[i], "-e") == 0) break; else if (strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-sort") == 0 || strcmp(argv[i], "-pf") == 0 || strcmp(argv[i], "-af") == 0 || strcmp(argv[i], "-comp") == 0) i++; if (i != argc) { if (++i == argc) { ERROR("%s: -e missing arguments\n", argv[0]); EXIT_MKSQUASHFS(); } while (i < argc) if (old_exclude) old_add_exclude(argv[i++]); else add_exclude(argv[i++]); } /* process the sort files - must be done afer the exclude files */ for (i = source + 2; i < argc; i++) if (strcmp(argv[i], "-sort") == 0) { int res = read_sort_file(argv[++i], source, source_path); if (res == FALSE) BAD_ERROR("Failed to read sort file\n"); sorted++; } else if (strcmp(argv[i], "-e") == 0) break; else if (strcmp(argv[i], "-root-becomes") == 0 || strcmp(argv[i], "-ef") == 0 || strcmp(argv[i], "-pf") == 0 || strcmp(argv[i], "-af") == 0 || strcmp(argv[i], "-comp") == 0) i++; if (!delete) { comp = read_super(fd, &sBlk, argv[source + 1]); if (comp == NULL) { ERROR("Failed to read existing filesystem - will not " "overwrite - ABORTING!\n"); ERROR("To force Mksquashfs to write to this block " "device or file use -noappend\n"); EXIT_MKSQUASHFS(); } block_log = slog(block_size = sBlk.block_size); noI = SQUASHFS_UNCOMPRESSED_INODES(sBlk.flags); noD = SQUASHFS_UNCOMPRESSED_DATA(sBlk.flags); noF = SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.flags); noX = SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.flags); no_fragments = SQUASHFS_NO_FRAGMENTS(sBlk.flags); always_use_fragments = SQUASHFS_ALWAYS_FRAGMENTS(sBlk.flags); duplicate_checking = SQUASHFS_DUPLICATES(sBlk.flags); exportable = SQUASHFS_EXPORTABLE(sBlk.flags); no_xattrs = SQUASHFS_NO_XATTRS(sBlk.flags); comp_opts = SQUASHFS_COMP_OPTS(sBlk.flags); } initialise_threads(readq, fragq, bwriteq, fwriteq, delete, destination_file); res = compressor_init(comp, &stream, SQUASHFS_METADATA_SIZE, 0); if (res) BAD_ERROR("compressor_init failed\n"); if (delete) { int size; void *comp_data = compressor_dump_options(comp, block_size, &size); printf("Creating %d.%d filesystem on %s, block size %d.\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size); /* * store any compressor specific options after the superblock, * and set the COMP_OPT flag to show that the filesystem has * compressor specfic options */ if (comp_data) { unsigned short c_byte = size | SQUASHFS_COMPRESSED_BIT; SQUASHFS_INSWAP_SHORTS(&c_byte, 1); write_destination(fd, sizeof(struct squashfs_super_block), sizeof(c_byte), &c_byte); write_destination(fd, sizeof(struct squashfs_super_block) + sizeof(c_byte), size, comp_data); bytes = sizeof(struct squashfs_super_block) + sizeof(c_byte) + size; comp_opts = TRUE; } else bytes = sizeof(struct squashfs_super_block); } else { unsigned int last_directory_block, inode_dir_offset, inode_dir_file_size, root_inode_size, inode_dir_start_block, uncompressed_data, compressed_data, inode_dir_inode_number, inode_dir_parent_inode; unsigned int root_inode_start = SQUASHFS_INODE_BLK(sBlk.root_inode), root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk.root_inode); if ((bytes = read_filesystem(root_name, fd, &sBlk, &inode_table, &data_cache, &directory_table, &directory_data_cache, &last_directory_block, &inode_dir_offset, &inode_dir_file_size, &root_inode_size, &inode_dir_start_block, &file_count, &sym_count, &dev_count, &dir_count, &fifo_count, &sock_count, &total_bytes, &total_inode_bytes, &total_directory_bytes, &inode_dir_inode_number, &inode_dir_parent_inode, add_old_root_entry, &fragment_table, &inode_lookup_table)) == 0) { ERROR("Failed to read existing filesystem - will not " "overwrite - ABORTING!\n"); ERROR("To force Mksquashfs to write to this block " "device or file use -noappend\n"); EXIT_MKSQUASHFS(); } if ((append_fragments = fragments = sBlk.fragments)) { fragment_table = realloc((char *)fragment_table, ((fragments + FRAG_SIZE - 1) & ~(FRAG_SIZE - 1)) * sizeof(struct squashfs_fragment_entry)); if (fragment_table == NULL) BAD_ERROR("Out of memory in save filesystem state\n"); } printf("Appending to existing %d.%d filesystem on %s, block " "size %d\n", SQUASHFS_MAJOR, SQUASHFS_MINOR, argv[source + 1], block_size); printf("All -b, -noI, -noD, -noF, -noX, no-duplicates, no-fragments, " "-always-use-fragments,\n-exportable and -comp options " "ignored\n"); printf("\nIf appending is not wanted, please re-run with " "-noappend specified!\n\n"); compressed_data = (inode_dir_offset + inode_dir_file_size) & ~(SQUASHFS_METADATA_SIZE - 1); uncompressed_data = (inode_dir_offset + inode_dir_file_size) & (SQUASHFS_METADATA_SIZE - 1); /* save original filesystem state for restoring ... */ sfragments = fragments; sbytes = bytes; sinode_count = sBlk.inodes; scache_bytes = root_inode_offset + root_inode_size; sdirectory_cache_bytes = uncompressed_data; sdata_cache = malloc(scache_bytes); if (sdata_cache == NULL) BAD_ERROR("Out of memory in save filesystem state\n"); sdirectory_data_cache = malloc(sdirectory_cache_bytes); if (sdirectory_data_cache == NULL) BAD_ERROR("Out of memory in save filesystem state\n"); memcpy(sdata_cache, data_cache, scache_bytes); memcpy(sdirectory_data_cache, directory_data_cache + compressed_data, sdirectory_cache_bytes); sinode_bytes = root_inode_start; stotal_bytes = total_bytes; stotal_inode_bytes = total_inode_bytes; stotal_directory_bytes = total_directory_bytes + compressed_data; sfile_count = file_count; ssym_count = sym_count; sdev_count = dev_count; sdir_count = dir_count + 1; sfifo_count = fifo_count; ssock_count = sock_count; sdup_files = dup_files; sid_count = id_count; write_recovery_data(&sBlk); save_xattrs(); appending = TRUE; /* * set the filesystem state up to be able to append to the * original filesystem. The filesystem state differs depending * on whether we're appending to the original root directory, or * if the original root directory becomes a sub-directory * (root-becomes specified on command line, here root_name != * NULL) */ inode_bytes = inode_size = root_inode_start; directory_size = last_directory_block; cache_size = root_inode_offset + root_inode_size; directory_cache_size = inode_dir_offset + inode_dir_file_size; if (root_name) { sdirectory_bytes = last_directory_block; sdirectory_compressed_bytes = 0; root_inode_number = inode_dir_parent_inode; inode_no = sBlk.inodes + 2; directory_bytes = last_directory_block; directory_cache_bytes = uncompressed_data; memmove(directory_data_cache, directory_data_cache + compressed_data, uncompressed_data); cache_bytes = root_inode_offset + root_inode_size; add_old_root_entry(root_name, sBlk.root_inode, inode_dir_inode_number, SQUASHFS_DIR_TYPE); total_directory_bytes += compressed_data; dir_count++; } else { sdirectory_compressed_bytes = last_directory_block - inode_dir_start_block; sdirectory_compressed = malloc(sdirectory_compressed_bytes); if (sdirectory_compressed == NULL) BAD_ERROR("Out of memory in save filesystem " "state\n"); memcpy(sdirectory_compressed, directory_table + inode_dir_start_block, sdirectory_compressed_bytes); sdirectory_bytes = inode_dir_start_block; root_inode_number = inode_dir_inode_number; inode_no = sBlk.inodes + 1; directory_bytes = inode_dir_start_block; directory_cache_bytes = inode_dir_offset; cache_bytes = root_inode_offset; } inode_count = file_count + dir_count + sym_count + dev_count + fifo_count + sock_count; } if (path) paths = add_subdir(paths, path); dump_actions(); dump_pseudos(); if (delete && !keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode)) dir_scan(&inode, source_path[0], scan1_readdir, progress); else if (!keep_as_directory && source == 1 && S_ISDIR(source_buf.st_mode)) dir_scan(&inode, source_path[0], scan1_single_readdir, progress); else dir_scan(&inode, "", scan1_encomp_readdir, progress); sBlk.root_inode = inode; sBlk.inodes = inode_count; sBlk.s_magic = SQUASHFS_MAGIC; sBlk.s_major = SQUASHFS_MAJOR; sBlk.s_minor = SQUASHFS_MINOR; sBlk.block_size = block_size; sBlk.block_log = block_log; sBlk.flags = SQUASHFS_MKFLAGS(noI, noD, noF, noX, no_fragments, always_use_fragments, duplicate_checking, exportable, no_xattrs, comp_opts); sBlk.mkfs_time = time(NULL); disable_info(); while ((fragment = get_frag_action(fragment))) write_fragment(*fragment); unlock_fragments(); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); while (fragments_outstanding) { pthread_mutex_unlock(&fragment_mutex); sched_yield(); pthread_mutex_lock(&fragment_mutex); } pthread_cleanup_pop(1); queue_put(to_writer, NULL); if (queue_get(from_writer) != 0) EXIT_MKSQUASHFS(); set_progressbar_state(FALSE); write_filesystem_tables(&sBlk, nopad); return 0; } ================================================ FILE: src/squashfs/process_fragments.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * process_fragments.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "caches-queues-lists.h" #include "squashfs_fs.h" #include "mksquashfs.h" #include "error.h" #include "progressbar.h" #include "info.h" #include "compressor.h" #include "process_fragments.h" #define FALSE 0 #define TRUE 1 extern struct queue *to_process_frag; extern struct seq_queue *to_main; extern int sparse_files; /* * Compute 16 bit BSD checksum over the data, and check for sparseness */ static int checksum_sparse(struct file_buffer *file_buffer) { unsigned char *b = (unsigned char *)file_buffer->data; unsigned short chksum = 0; int bytes = file_buffer->size, sparse = TRUE, value; while (bytes--) { chksum = (chksum & 1) ? (chksum >> 1) | 0x8000 : chksum >> 1; value = *b++; if (value) { sparse = FALSE; chksum += value; } } file_buffer->checksum = chksum; return sparse; } static int read_filesystem(int fd, long long byte, int bytes, void *buff) { off_t off = byte; TRACE("read_filesystem: reading from position 0x%llx, bytes %d\n", byte, bytes); if (lseek(fd, off, SEEK_SET) == -1) { ERROR("read_filesystem: Lseek on destination failed because %s, " "offset=0x%llx\n", strerror(errno), off); return 0; } else if (read_bytes(fd, buff, bytes) < bytes) { ERROR("Read on destination failed\n"); return 0; } return 1; } static struct file_buffer *get_fragment(struct fragment *fragment, char *data_buffer, int fd) { struct squashfs_fragment_entry *disk_fragment; struct file_buffer *buffer, *compressed_buffer; long long start_block; int res, size, index = fragment->index; char locked; /* * Lookup fragment block in cache. * If the fragment block doesn't exist, then get the compressed version * from the writer cache or off disk, and decompress it. * * This routine has two things which complicate the code: * * 1. Multiple threads can simultaneously lookup/create the * same buffer. This means a buffer needs to be "locked" * when it is being filled in, to prevent other threads from * using it when it is not ready. This is because we now do * fragment duplicate checking in parallel. * 2. We have two caches which need to be checked for the * presence of fragment blocks: the normal fragment cache * and a "reserve" cache. The reserve cache is used to * prevent an unnecessary pipeline stall when the fragment cache * is full of fragments waiting to be compressed. */ pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); pthread_mutex_lock(&dup_mutex); again: buffer = cache_lookup_nowait(fragment_buffer, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* not in fragment cache, is it in the reserve cache? */ buffer = cache_lookup_nowait(reserve_cache, index, &locked); if (buffer) { pthread_mutex_unlock(&dup_mutex); if (locked) /* got a buffer being filled in. Wait for it */ cache_wait_unlock(buffer); goto finished; } /* in neither cache, try to get it from the fragment cache */ buffer = cache_get_nowait(fragment_buffer, index); if (!buffer) { /* * no room, get it from the reserve cache, this is * dimensioned so it will always have space (no more than * processors + 1 can have an outstanding reserve buffer) */ buffer = cache_get_nowait(reserve_cache, index); if (!buffer) { /* failsafe */ ERROR("no space in reserve cache\n"); goto again; } } pthread_mutex_unlock(&dup_mutex); compressed_buffer = cache_lookup(fwriter_buffer, index); pthread_cleanup_push((void *)pthread_mutex_unlock, &fragment_mutex); pthread_mutex_lock(&fragment_mutex); disk_fragment = &fragment_table[index]; size = SQUASHFS_COMPRESSED_SIZE_BLOCK(disk_fragment->size); start_block = disk_fragment->start_block; pthread_cleanup_pop(1); if (SQUASHFS_COMPRESSED_BLOCK(disk_fragment->size)) { int error; char *data; if (compressed_buffer) data = compressed_buffer->data; else { res = read_filesystem(fd, start_block, size, data_buffer); if (res == 0) { ERROR("Failed to read fragment from output" " filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } data = data_buffer; } res = compressor_uncompress(comp, buffer->data, data, size, block_size, &error); if (res == -1) BAD_ERROR("%s uncompress failed with error code %d\n", comp->name, error); } else if (compressed_buffer) memcpy(buffer->data, compressed_buffer->data, size); else { res = read_filesystem(fd, start_block, size, buffer->data); if (res == 0) { ERROR("Failed to read fragment from output " "filesystem\n"); BAD_ERROR("Output filesystem corrupted?\n"); } } cache_unlock(buffer); cache_block_put(compressed_buffer); finished: pthread_cleanup_pop(0); return buffer; } struct file_buffer *get_fragment_cksum(struct file_info *file, char *data_buffer, int fd, unsigned short *checksum) { struct file_buffer *frag_buffer; struct append_file *append; int index = file->fragment->index; frag_buffer = get_fragment(file->fragment, data_buffer, fd); pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); for (append = file_mapping[index]; append; append = append->next) { int offset = append->file->fragment->offset; int size = append->file->fragment->size; char *data = frag_buffer->data + offset; unsigned short cksum = get_checksum_mem(data, size); if (file == append->file) *checksum = cksum; pthread_mutex_lock(&dup_mutex); append->file->fragment_checksum = cksum; append->file->have_frag_checksum = TRUE; pthread_mutex_unlock(&dup_mutex); } pthread_cleanup_pop(0); return frag_buffer; } void *frag_thrd(void *destination_file) { sigset_t sigmask, old_mask; char *data_buffer; int fd; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGUSR1); pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask); fd = open(destination_file, O_RDONLY); if (fd == -1) BAD_ERROR("frag_thrd: can't open destination for reading\n"); data_buffer = malloc(SQUASHFS_FILE_MAX_SIZE); if (data_buffer == NULL) MEM_ERROR(); pthread_cleanup_push((void *)pthread_mutex_unlock, &dup_mutex); while (1) { struct file_buffer *file_buffer = queue_get(to_process_frag); struct file_buffer *buffer; int sparse = checksum_sparse(file_buffer); struct file_info *dupl_ptr; long long file_size; unsigned short checksum; char flag; int res; if (sparse_files && sparse) { file_buffer->c_byte = 0; file_buffer->fragment = FALSE; } else file_buffer->c_byte = file_buffer->size; /* * Specutively pull into the fragment cache any fragment blocks * which contain fragments which *this* fragment may be * be a duplicate. * * By ensuring the fragment block is in cache ahead of time * should eliminate the parallelisation stall when the * main thread needs to read the fragment block to do a * duplicate check on it. * * If this is a fragment belonging to a larger file * (with additional blocks) then ignore it. Here we're * interested in the "low hanging fruit" of files which * consist of only a fragment */ if (file_buffer->file_size != file_buffer->size) { seq_queue_put(to_main, file_buffer); continue; } file_size = file_buffer->file_size; pthread_mutex_lock(&dup_mutex); dupl_ptr = dupl[DUP_HASH(file_size)]; pthread_mutex_unlock(&dup_mutex); file_buffer->dupl_start = dupl_ptr; file_buffer->duplicate = FALSE; for (; dupl_ptr; dupl_ptr = dupl_ptr->next) { if (file_size != dupl_ptr->file_size || file_size != dupl_ptr->fragment->size) continue; pthread_mutex_lock(&dup_mutex); flag = dupl_ptr->have_frag_checksum; checksum = dupl_ptr->fragment_checksum; pthread_mutex_unlock(&dup_mutex); /* * If we have the checksum and it matches then * read in the fragment block. * * If we *don't* have the checksum, then we are * appending, and the fragment block is on the * "old" filesystem. Read it in and checksum * the entire fragment buffer */ if (!flag) { buffer = get_fragment_cksum(dupl_ptr, data_buffer, fd, &checksum); if (checksum != file_buffer->checksum) { cache_block_put(buffer); continue; } } else if (checksum == file_buffer->checksum) buffer = get_fragment(dupl_ptr->fragment, data_buffer, fd); else continue; res = memcmp(file_buffer->data, buffer->data + dupl_ptr->fragment->offset, file_size); cache_block_put(buffer); if (res == 0) { struct file_buffer *dup = malloc(sizeof(*dup)); if (dup == NULL) MEM_ERROR(); memcpy(dup, file_buffer, sizeof(*dup)); cache_block_put(file_buffer); dup->dupl_start = dupl_ptr; dup->duplicate = TRUE; file_buffer = dup; break; } } seq_queue_put(to_main, file_buffer); } pthread_cleanup_pop(0); } ================================================ FILE: src/squashfs/progressbar.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * progressbar.c */ #include #include #include #include #include #include #include #include #include #include #include "error.h" #define FALSE 0 #define TRUE 1 /* flag whether progressbar display is enabled or not */ int display_progress_bar = FALSE; /* flag whether the progress bar is temporarily disbled */ int temp_disabled = FALSE; int rotate = 0; int cur_uncompressed = 0, estimated_uncompressed = 0; int columns; pthread_t progress_thread; pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER; static void sigwinch_handler() { struct winsize winsize; if (ioctl(1, TIOCGWINSZ, &winsize) == -1) { if (isatty(STDOUT_FILENO)) ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " "columns\n"); columns = 80; } else columns = winsize.ws_col; } static void sigalrm_handler() { rotate = (rotate + 1) % 4; } void inc_progress_bar() { cur_uncompressed++; } void dec_progress_bar(int count) { cur_uncompressed -= count; } void progress_bar_size(int count) { estimated_uncompressed += count; } static void progress_bar(long long current, long long max, int columns) { char rotate_list[] = { '|', '/', '-', '\\' }; int max_digits, used, hashes, spaces; static int tty = -1; if (max == 0) return; max_digits = floor(log10(max)) + 1; used = max_digits * 2 + 11; hashes = (current * (columns - used)) / max; spaces = columns - used - hashes; if ((current > max) || (columns - used < 0)) return; if (tty == -1) tty = isatty(STDOUT_FILENO); if (!tty) { static long long previous = -1; /* Updating much more frequently than this results in huge * log files. */ if ((current % 100) != 0 && current != max) return; /* Don't update just to rotate the spinner. */ if (current == previous) return; previous = current; } printf("\r["); while (hashes--) putchar('='); putchar(rotate_list[rotate]); while (spaces--) putchar(' '); printf("] %*lld/%*lld", max_digits, current, max_digits, max); printf(" %3lld%%", current * 100 / max); fflush(stdout); } void enable_progress_bar() { pthread_cleanup_push((void *)pthread_mutex_unlock, &progress_mutex); pthread_mutex_lock(&progress_mutex); if (display_progress_bar) progress_bar(cur_uncompressed, estimated_uncompressed, columns); temp_disabled = FALSE; pthread_cleanup_pop(1); } void disable_progress_bar() { pthread_cleanup_push((void *)pthread_mutex_unlock, &progress_mutex); pthread_mutex_lock(&progress_mutex); if (display_progress_bar) printf("\n"); temp_disabled = TRUE; pthread_cleanup_pop(1); } void set_progressbar_state(int state) { pthread_cleanup_push((void *)pthread_mutex_unlock, &progress_mutex); pthread_mutex_lock(&progress_mutex); if (display_progress_bar != state) { if (display_progress_bar && !temp_disabled) { progress_bar(cur_uncompressed, estimated_uncompressed, columns); printf("\n"); } display_progress_bar = state; } pthread_cleanup_pop(1); } void *progress_thrd(void *arg) { struct timespec requested_time, remaining; struct itimerval itimerval; struct winsize winsize; if (ioctl(1, TIOCGWINSZ, &winsize) == -1) { if (isatty(STDOUT_FILENO)) ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " "columns\n"); columns = 80; } else columns = winsize.ws_col; signal(SIGWINCH, sigwinch_handler); signal(SIGALRM, sigalrm_handler); itimerval.it_value.tv_sec = 0; itimerval.it_value.tv_usec = 250000; itimerval.it_interval.tv_sec = 0; itimerval.it_interval.tv_usec = 250000; setitimer(ITIMER_REAL, &itimerval, NULL); requested_time.tv_sec = 0; requested_time.tv_nsec = 250000000; while (1) { int res = nanosleep(&requested_time, &remaining); if (res == -1 && errno != EINTR) BAD_ERROR("nanosleep failed in progress thread\n"); pthread_mutex_lock(&progress_mutex); if (display_progress_bar && !temp_disabled) progress_bar(cur_uncompressed, estimated_uncompressed, columns); pthread_mutex_unlock(&progress_mutex); } } void init_progress_bar() { pthread_create(&progress_thread, NULL, progress_thrd, NULL); } void progressbar_error(char *fmt, ...) { va_list ap; pthread_cleanup_push((void *)pthread_mutex_unlock, &progress_mutex); pthread_mutex_lock(&progress_mutex); if (display_progress_bar && !temp_disabled) fprintf(stderr, "\n"); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); pthread_cleanup_pop(1); } void progressbar_info(char *fmt, ...) { va_list ap; pthread_cleanup_push((void *)pthread_mutex_unlock, &progress_mutex); pthread_mutex_lock(&progress_mutex); if (display_progress_bar && !temp_disabled) printf("\n"); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); pthread_cleanup_pop(1); } ================================================ FILE: src/squashfs/pseudo.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2012, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * pseudo.c */ #include #include #include #include #include #include #include #include #include #include #include #include "pseudo.h" #include "error.h" #include "progressbar.h" #define TRUE 1 #define FALSE 0 extern int read_file(char *filename, char *type, int (parse_line) (char *)); struct pseudo_dev **pseudo_file = NULL; struct pseudo *pseudo = NULL; int pseudo_count = 0; static char *get_component(char *target, char **targname) { char *start; while (*target == '/') target++; start = target; while (*target != '/' && *target != '\0') target++; *targname = strndup(start, target - start); while (*target == '/') target++; return target; } /* * Add pseudo device target to the set of pseudo devices. Pseudo_dev * describes the pseudo device attributes. */ struct pseudo *add_pseudo(struct pseudo *pseudo, struct pseudo_dev *pseudo_dev, char *target, char *alltarget) { char *targname; int i; target = get_component(target, &targname); if (pseudo == NULL) { pseudo = malloc(sizeof(struct pseudo)); if (pseudo == NULL) MEM_ERROR(); pseudo->names = 0; pseudo->count = 0; pseudo->name = NULL; } for (i = 0; i < pseudo->names; i++) if (strcmp(pseudo->name[i].name, targname) == 0) break; if (i == pseudo->names) { /* allocate new name entry */ pseudo->names++; pseudo->name = realloc(pseudo->name, (i + 1) * sizeof(struct pseudo_entry)); if (pseudo->name == NULL) MEM_ERROR(); pseudo->name[i].name = targname; if (target[0] == '\0') { /* at leaf pathname component */ pseudo->name[i].pseudo = NULL; pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else { /* recurse adding child components */ pseudo->name[i].dev = NULL; pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); } } else { /* existing matching entry */ free(targname); if (pseudo->name[i].pseudo == NULL) { /* No sub-directory which means this is the leaf * component of a pre-existing pseudo file. */ if (target[0] != '\0') { /* * entry must exist as either a 'd' type or * 'm' type pseudo file */ if (pseudo->name[i].dev->type == 'd' || pseudo->name[i].dev->type == 'm') /* recurse adding child components */ pseudo->name[i].pseudo = add_pseudo(NULL, pseudo_dev, target, alltarget); else { ERROR_START("%s already exists as a " "non directory.", pseudo->name[i].name); ERROR_EXIT(". Ignoring %s!\n", alltarget); } } else if (memcmp(pseudo_dev, pseudo->name[i].dev, sizeof(struct pseudo_dev)) != 0) { ERROR_START("%s already exists as a different " "pseudo definition.", alltarget); ERROR_EXIT(" Ignoring!\n"); } else { ERROR_START("%s already exists as an identical " "pseudo definition!", alltarget); ERROR_EXIT(" Ignoring!\n"); } } else { if (target[0] == '\0') { /* * sub-directory exists, which means we can only * add a pseudo file of type 'd' or type 'm' */ if (pseudo->name[i].dev == NULL && (pseudo_dev->type == 'd' || pseudo_dev->type == 'm')) { pseudo->name[i].pathname = strdup(alltarget); pseudo->name[i].dev = pseudo_dev; } else { ERROR_START("%s already exists as a " "different pseudo definition.", pseudo->name[i].name); ERROR_EXIT(" Ignoring %s!\n", alltarget); } } else /* recurse adding child components */ add_pseudo(pseudo->name[i].pseudo, pseudo_dev, target, alltarget); } } return pseudo; } /* * Find subdirectory in pseudo directory referenced by pseudo, matching * filename. If filename doesn't exist or if filename is a leaf file * return NULL */ struct pseudo *pseudo_subdir(char *filename, struct pseudo *pseudo) { int i; if (pseudo == NULL) return NULL; for (i = 0; i < pseudo->names; i++) if (strcmp(filename, pseudo->name[i].name) == 0) return pseudo->name[i].pseudo; return NULL; } struct pseudo_entry *pseudo_readdir(struct pseudo *pseudo) { if (pseudo == NULL) return NULL; while (pseudo->count < pseudo->names) { if (pseudo->name[pseudo->count].dev != NULL) return &pseudo->name[pseudo->count++]; else pseudo->count++; } return NULL; } int pseudo_exec_file(struct pseudo_dev *dev, int *child) { int res, pipefd[2]; res = pipe(pipefd); if (res == -1) { ERROR("Executing dynamic pseudo file, pipe failed\n"); return 0; } *child = fork(); if (*child == -1) { ERROR("Executing dynamic pseudo file, fork failed\n"); goto failed; } if (*child == 0) { close(pipefd[0]); close(STDOUT_FILENO); res = dup(pipefd[1]); if (res == -1) exit(EXIT_FAILURE); execl("/bin/sh", "sh", "-c", dev->command, (char *)NULL); exit(EXIT_FAILURE); } close(pipefd[1]); return pipefd[0]; failed: close(pipefd[0]); close(pipefd[1]); return 0; } void add_pseudo_file(struct pseudo_dev *dev) { pseudo_file = realloc(pseudo_file, (pseudo_count + 1) * sizeof(struct pseudo_dev *)); if (pseudo_file == NULL) MEM_ERROR(); dev->pseudo_id = pseudo_count; pseudo_file[pseudo_count++] = dev; } struct pseudo_dev *get_pseudo_file(int pseudo_id) { return pseudo_file[pseudo_id]; } int read_pseudo_def(char *def) { int n, bytes; unsigned int major = 0, minor = 0, mode; char type, *ptr; char suid[100], sgid[100]; /* overflow safe */ char *filename, *name; char *orig_def = def; long long uid, gid; struct pseudo_dev *dev; /* * Scan for filename, don't use sscanf() and "%s" because * that can't handle filenames with spaces */ filename = malloc(strlen(def) + 1); if (filename == NULL) MEM_ERROR(); for (name = filename; !isspace(*def) && *def != '\0';) { if (*def == '\\') { def++; if (*def == '\0') break; } *name++ = *def++; } *name = '\0'; if (*filename == '\0') { ERROR("Not enough or invalid arguments in pseudo file " "definition \"%s\"\n", orig_def); goto error; } n = sscanf(def, " %c %o %99s %99s %n", &type, &mode, suid, sgid, &bytes); def += bytes; if (n < 4) { ERROR("Not enough or invalid arguments in pseudo file " "definition \"%s\"\n", orig_def); switch (n) { case -1: /* FALLTHROUGH */ case 0: ERROR("Read filename, but failed to read or match " "type\n"); break; case 1: ERROR("Read filename and type, but failed to read or " "match octal mode\n"); break; case 2: ERROR("Read filename, type and mode, but failed to " "read or match uid\n"); break; default: ERROR("Read filename, type, mode and uid, but failed " "to read or match gid\n"); break; } goto error; } switch (type) { case 'b': /* FALLTHROUGH */ case 'c': n = sscanf(def, "%u %u %n", &major, &minor, &bytes); def += bytes; if (n < 2) { ERROR("Not enough or invalid arguments in %s device " "pseudo file definition \"%s\"\n", type == 'b' ? "block" : "character", orig_def); if (n < 1) ERROR("Read filename, type, mode, uid and gid, " "but failed to read or match major\n"); else ERROR("Read filename, type, mode, uid, gid " "and major, but failed to read or " "match minor\n"); goto error; } if (major > 0xfff) { ERROR("Major %d out of range\n", major); goto error; } if (minor > 0xfffff) { ERROR("Minor %d out of range\n", minor); goto error; } /* FALLTHROUGH */ case 'd': /* FALLTHROUGH */ case 'm': /* * Check for trailing junk after expected arguments */ if (def[0] != '\0') { ERROR("Unexpected tailing characters in pseudo file " "definition \"%s\"\n", orig_def); goto error; } break; case 'f': if (def[0] == '\0') { ERROR("Not enough arguments in dynamic file pseudo " "definition \"%s\"\n", orig_def); ERROR("Expected command, which can be an executable " "or a piece of shell script\n"); goto error; } break; default: ERROR("Unsupported type %c\n", type); goto error; } if (mode > 07777) { ERROR("Mode %o out of range\n", mode); goto error; } uid = strtoll(suid, &ptr, 10); if (*ptr == '\0') { if (uid < 0 || uid > ((1LL << 32) - 1)) { ERROR("Uid %s out of range\n", suid); goto error; } } else { struct passwd *pwuid = getpwnam(suid); if (pwuid) uid = pwuid->pw_uid; else { ERROR("Uid %s invalid uid or unknown user\n", suid); goto error; } } gid = strtoll(sgid, &ptr, 10); if (*ptr == '\0') { if (gid < 0 || gid > ((1LL << 32) - 1)) { ERROR("Gid %s out of range\n", sgid); goto error; } } else { struct group *grgid = getgrnam(sgid); if (grgid) gid = grgid->gr_gid; else { ERROR("Gid %s invalid uid or unknown user\n", sgid); goto error; } } switch (type) { case 'b': mode |= S_IFBLK; break; case 'c': mode |= S_IFCHR; break; case 'd': mode |= S_IFDIR; break; case 'f': mode |= S_IFREG; break; } dev = malloc(sizeof(struct pseudo_dev)); if (dev == NULL) MEM_ERROR(); dev->type = type; dev->mode = mode; dev->uid = uid; dev->gid = gid; dev->major = major; dev->minor = minor; if (type == 'f') { dev->command = strdup(def); add_pseudo_file(dev); } pseudo = add_pseudo(pseudo, dev, filename, filename); free(filename); return TRUE; error: ERROR("Pseudo definitions should be of format\n"); ERROR("\tfilename d mode uid gid\n"); ERROR("\tfilename m mode uid gid\n"); ERROR("\tfilename b mode uid gid major minor\n"); ERROR("\tfilename c mode uid gid major minor\n"); ERROR("\tfilename f mode uid command\n"); free(filename); return FALSE; } int read_pseudo_file(char *filename) { return read_file(filename, "pseudo", read_pseudo_def); } struct pseudo *get_pseudo() { return pseudo; } #ifdef SQUASHFS_TRACE static void dump_pseudo(struct pseudo *pseudo, char *string) { int i, res; char *path; for (i = 0; i < pseudo->names; i++) { struct pseudo_entry *entry = &pseudo->name[i]; if (string) { res = asprintf(&path, "%s/%s", string, entry->name); if (res == -1) BAD_ERROR("asprintf failed in dump_pseudo\n"); } else path = entry->name; if (entry->dev) ERROR("%s %c 0%o %d %d %d %d\n", path, entry->dev->type, entry->dev->mode & ~S_IFMT, entry->dev->uid, entry->dev->gid, entry->dev->major, entry->dev->minor); if (entry->pseudo) dump_pseudo(entry->pseudo, path); if (string) free(path); } } void dump_pseudos() { dump_pseudo(pseudo, NULL); } #else void dump_pseudos() { } #endif ================================================ FILE: src/squashfs/read_file.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2012 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * read_file.c */ #include #include #include #include #include #include "error.h" #define TRUE 1 #define FALSE 0 #define MAX_LINE 16384 /* * Read file, passing each line to parse_line() for * parsing. * * Lines can be split across multiple lines using "\". * * Blank lines and comment lines indicated by # are supported. */ int read_file(char *filename, char *type, int (parse_line) (char *)) { FILE *fd; char *def, *err, *line = NULL; int res, size = 0; fd = fopen(filename, "r"); if (fd == NULL) { ERROR("Could not open %s device file \"%s\" because %s\n", type, filename, strerror(errno)); return FALSE; } while (1) { int total = 0; while (1) { int len; if (total + (MAX_LINE + 1) > size) { line = realloc(line, size += (MAX_LINE + 1)); if (line == NULL) MEM_ERROR(); } err = fgets(line + total, MAX_LINE + 1, fd); if (err == NULL) break; len = strlen(line + total); total += len; if (len == MAX_LINE && line[total - 1] != '\n') { /* line too large */ ERROR("Line too long when reading " "%s file \"%s\", larger than " "%d bytes\n", type, filename, MAX_LINE); goto failed; } /* * Remove '\n' terminator if it exists (the last line * in the file may not be '\n' terminated) */ if (len && line[total - 1] == '\n') { line[--total] = '\0'; len--; } /* * If no line continuation then jump out to * process line. Note, we have to be careful to * check for "\\" (backslashed backslash) and to * ensure we don't look at the previous line */ if (len == 0 || line[total - 1] != '\\' || (len >= 2 && strcmp(line + total - 2, "\\\\") == 0)) break; else total--; } if (err == NULL) { if (ferror(fd)) { ERROR("Reading %s file \"%s\" failed " "because %s\n", type, filename, strerror(errno)); goto failed; } /* * At EOF, normally we'll be finished, but, have to * check for special case where we had "\" line * continuation and then hit EOF immediately afterwards */ if (total == 0) break; else line[total] = '\0'; } /* Skip any leading whitespace */ for (def = line; isspace(*def); def++) ; /* if line is now empty after skipping characters, skip it */ if (*def == '\0') continue; /* if comment line, skip */ if (*def == '#') continue; res = parse_line(def); if (res == FALSE) goto failed; } fclose(fd); free(line); return TRUE; failed: fclose(fd); free(line); return FALSE; } ================================================ FILE: src/squashfs/read_fs.c ================================================ /* * Read a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, * 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * read_fs.c */ #define TRUE 1 #define FALSE 0 #include #include #include #include #include #include #include #include #include #if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN #else # include #endif #include #include "squashfs_fs.h" #include "squashfs_swap.h" #include "compressor.h" #include "xattr.h" #include "error.h" #include "mksquashfs.h" int read_block(int fd, long long start, long long *next, int expected, void *block) { unsigned short c_byte; int res, compressed; int outlen = expected ? expected : SQUASHFS_METADATA_SIZE; /* Read block size */ res = read_fs_bytes(fd, start, 2, &c_byte); if (res == 0) return 0; SQUASHFS_INSWAP_SHORTS(&c_byte, 1); compressed = SQUASHFS_COMPRESSED(c_byte); c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); /* * The block size should not be larger than * the uncompressed size (or max uncompressed size if * expected is 0) */ if (c_byte > outlen) return 0; if (compressed) { char buffer[c_byte]; int error; res = read_fs_bytes(fd, start + 2, c_byte, buffer); if (res == 0) return 0; res = compressor_uncompress(comp, block, buffer, c_byte, outlen, &error); if (res == -1) { ERROR("%s uncompress failed with error code %d\n", comp->name, error); return 0; } } else { res = read_fs_bytes(fd, start + 2, c_byte, block); if (res == 0) return 0; res = c_byte; } if (next) *next = start + 2 + c_byte; /* * if expected, then check the (uncompressed) return data * is of the expected size */ if (expected && expected != res) return 0; else return res; } #define NO_BYTES(SIZE) \ (bytes - (cur_ptr - *inode_table) < (SIZE)) #define NO_INODE_BYTES(INODE) NO_BYTES(sizeof(struct INODE)) int scan_inode_table(int fd, long long start, long long end, long long root_inode_start, int root_inode_offset, struct squashfs_super_block *sBlk, union squashfs_inode_header *dir_inode, unsigned char **inode_table, unsigned int *root_inode_block, unsigned int *root_inode_size, long long *uncompressed_file, unsigned int *uncompressed_directory, int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count, unsigned int *id_table) { unsigned char *cur_ptr; int byte, files = 0; unsigned int directory_start_block, bytes = 0, size = 0; struct squashfs_base_inode_header base; TRACE("scan_inode_table: start 0x%llx, end 0x%llx, root_inode_start " "0x%llx\n", start, end, root_inode_start); *root_inode_block = UINT_MAX; while (start < end) { if (start == root_inode_start) { TRACE("scan_inode_table: read compressed block 0x%llx " "containing root inode\n", start); *root_inode_block = bytes; } if (size - bytes < SQUASHFS_METADATA_SIZE) { *inode_table = realloc(*inode_table, size += SQUASHFS_METADATA_SIZE); if (*inode_table == NULL) MEM_ERROR(); } TRACE("scan_inode_table: reading block 0x%llx\n", start); byte = read_block(fd, start, &start, 0, *inode_table + bytes); if (byte == 0) goto corrupted; bytes += byte; /* If this is not the last metadata block in the inode table * then it should be SQUASHFS_METADATA_SIZE in size. * Note, we can't use expected in read_block() above for this * because we don't know if this is the last block until * after reading. */ if (start != end && byte != SQUASHFS_METADATA_SIZE) goto corrupted; } /* * We expect to have found the metadata block containing the * root inode in the above inode_table metadata block scan. If it * hasn't been found then the filesystem is corrupted */ if (*root_inode_block == UINT_MAX) goto corrupted; /* * The number of bytes available after the root inode medata block * should be at least the root inode offset + the size of a * regular directory inode, if not the filesystem is corrupted * * +-----------------------+-----------------------+ * | | directory | * | | inode | * +-----------------------+-----------------------+ * ^ ^ ^ * *root_inode_block root_inode_offset bytes */ if ((bytes - *root_inode_block) < (root_inode_offset + sizeof(struct squashfs_dir_inode_header))) goto corrupted; /* * Read last inode entry which is the root directory inode, and obtain * the last directory start block index. This is used when calculating * the total uncompressed directory size. The directory bytes in the * last * block will be counted as normal. * * Note, the previous check ensures the following calculation won't * underflow, and we won't access beyond the buffer */ *root_inode_size = bytes - (*root_inode_block + root_inode_offset); bytes = *root_inode_block + root_inode_offset; SQUASHFS_SWAP_DIR_INODE_HEADER(*inode_table + bytes, &dir_inode->dir); if (dir_inode->base.inode_type == SQUASHFS_DIR_TYPE) directory_start_block = dir_inode->dir.start_block; else if (dir_inode->base.inode_type == SQUASHFS_LDIR_TYPE) { if (*root_inode_size < sizeof(struct squashfs_ldir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LDIR_INODE_HEADER(*inode_table + bytes, &dir_inode->ldir); directory_start_block = dir_inode->ldir.start_block; } else /* bad type, corrupted filesystem */ goto corrupted; get_uid(id_table[dir_inode->base.uid]); get_guid(id_table[dir_inode->base.guid]); /* allocate fragment to file mapping table */ file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *)); if (file_mapping == NULL) MEM_ERROR(); for (cur_ptr = *inode_table; cur_ptr < *inode_table + bytes; files++) { if (NO_INODE_BYTES(squashfs_base_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_BASE_INODE_HEADER(cur_ptr, &base); TRACE("scan_inode_table: processing inode @ byte position " "0x%x, type 0x%x\n", (unsigned int)(cur_ptr - *inode_table), base.inode_type); get_uid(id_table[base.uid]); get_guid(id_table[base.guid]); switch (base.inode_type) { case SQUASHFS_FILE_TYPE:{ struct squashfs_reg_inode_header inode; int frag_bytes, blocks, i; long long start, file_bytes = 0; unsigned int *block_list; if (NO_INODE_BYTES(squashfs_reg_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_REG_INODE_HEADER(cur_ptr, &inode); frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> sBlk->block_log; start = inode.start_block; TRACE("scan_inode_table: regular file, file_size %d, " "blocks %d\n", inode.file_size, blocks); if (NO_BYTES(blocks * sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; block_list = malloc(blocks * sizeof(unsigned int)); if (block_list == NULL) MEM_ERROR(); cur_ptr += sizeof(inode); SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks); *uncompressed_file += inode.file_size; (*file_count)++; for (i = 0; i < blocks; i++) file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); if (inode.fragment != SQUASHFS_INVALID_FRAG && inode.fragment >= sBlk->fragments) { free(block_list); goto corrupted; } add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); cur_ptr += blocks * sizeof(unsigned int); break; } case SQUASHFS_LREG_TYPE:{ struct squashfs_lreg_inode_header inode; int frag_bytes, blocks, i; long long start, file_bytes = 0; unsigned int *block_list; if (NO_INODE_BYTES(squashfs_lreg_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LREG_INODE_HEADER(cur_ptr, &inode); frag_bytes = inode.fragment == SQUASHFS_INVALID_FRAG ? 0 : inode.file_size % sBlk->block_size; blocks = inode.fragment == SQUASHFS_INVALID_FRAG ? (inode.file_size + sBlk->block_size - 1) >> sBlk->block_log : inode.file_size >> sBlk->block_log; start = inode.start_block; TRACE("scan_inode_table: extended regular " "file, file_size %lld, blocks %d\n", inode.file_size, blocks); if (NO_BYTES(blocks * sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; block_list = malloc(blocks * sizeof(unsigned int)); if (block_list == NULL) MEM_ERROR(); cur_ptr += sizeof(inode); SQUASHFS_SWAP_INTS(cur_ptr, block_list, blocks); *uncompressed_file += inode.file_size; (*file_count)++; for (i = 0; i < blocks; i++) file_bytes += SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); if (inode.fragment != SQUASHFS_INVALID_FRAG && inode.fragment >= sBlk->fragments) { free(block_list); goto corrupted; } add_file(start, inode.file_size, file_bytes, block_list, blocks, inode.fragment, inode.offset, frag_bytes); cur_ptr += blocks * sizeof(unsigned int); break; } case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE:{ struct squashfs_symlink_inode_header inode; if (NO_INODE_BYTES(squashfs_symlink_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(cur_ptr, &inode); (*sym_count)++; if (inode.inode_type == SQUASHFS_LSYMLINK_TYPE) { if (NO_BYTES(inode.symlink_size + sizeof(unsigned int))) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(inode) + inode.symlink_size + sizeof(unsigned int); } else { if (NO_BYTES(inode.symlink_size)) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(inode) + inode.symlink_size; } break; } case SQUASHFS_DIR_TYPE:{ struct squashfs_dir_inode_header dir_inode; if (NO_INODE_BYTES(squashfs_dir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_DIR_INODE_HEADER(cur_ptr, &dir_inode); if (dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count)++; cur_ptr += sizeof(struct squashfs_dir_inode_header); break; } case SQUASHFS_LDIR_TYPE:{ struct squashfs_ldir_inode_header dir_inode; int i; if (NO_INODE_BYTES(squashfs_ldir_inode_header)) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_LDIR_INODE_HEADER(cur_ptr, &dir_inode); if (dir_inode.start_block < directory_start_block) *uncompressed_directory += dir_inode.file_size; (*dir_count)++; cur_ptr += sizeof(struct squashfs_ldir_inode_header); for (i = 0; i < dir_inode.i_count; i++) { struct squashfs_dir_index index; if (NO_BYTES(sizeof(index))) /* corrupted filesystem */ goto corrupted; SQUASHFS_SWAP_DIR_INDEX(cur_ptr, &index); if (NO_BYTES(index.size + 1)) /* corrupted filesystem */ goto corrupted; cur_ptr += sizeof(index) + index.size + 1; } break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: if (NO_INODE_BYTES(squashfs_dev_inode_header)) /* corrupted filesystem */ goto corrupted; (*dev_count)++; cur_ptr += sizeof(struct squashfs_dev_inode_header); break; case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE: if (NO_INODE_BYTES(squashfs_ldev_inode_header)) /* corrupted filesystem */ goto corrupted; (*dev_count)++; cur_ptr += sizeof(struct squashfs_ldev_inode_header); break; case SQUASHFS_FIFO_TYPE: if (NO_INODE_BYTES(squashfs_ipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*fifo_count)++; cur_ptr += sizeof(struct squashfs_ipc_inode_header); break; case SQUASHFS_LFIFO_TYPE: if (NO_INODE_BYTES(squashfs_lipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*fifo_count)++; cur_ptr += sizeof(struct squashfs_lipc_inode_header); break; case SQUASHFS_SOCKET_TYPE: if (NO_INODE_BYTES(squashfs_ipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*sock_count)++; cur_ptr += sizeof(struct squashfs_ipc_inode_header); break; case SQUASHFS_LSOCKET_TYPE: if (NO_INODE_BYTES(squashfs_lipc_inode_header)) /* corrupted filesystem */ goto corrupted; (*sock_count)++; cur_ptr += sizeof(struct squashfs_lipc_inode_header); break; default: ERROR("Unknown inode type %d in scan_inode_table!\n", base.inode_type); goto corrupted; } } printf("Read existing filesystem, %d inodes scanned\n", files); return TRUE; corrupted: ERROR("scan_inode_table: filesystem corruption detected in " "scanning metadata\n"); free(*inode_table); return FALSE; } struct compressor *read_super(int fd, struct squashfs_super_block *sBlk, char *source) { int res, bytes = 0; char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); res = read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block), sBlk); if (res == 0) { ERROR("Can't find a SQUASHFS superblock on %s\n", source); ERROR("Wrong filesystem or filesystem is corrupted!\n"); goto failed_mount; } SQUASHFS_INSWAP_SUPER_BLOCK(sBlk); if (sBlk->s_magic != SQUASHFS_MAGIC) { if (sBlk->s_magic == SQUASHFS_MAGIC_SWAP) ERROR("Pre 4.0 big-endian filesystem on %s, appending" " to this is unsupported\n", source); else { ERROR("Can't find a SQUASHFS superblock on %s\n", source); ERROR("Wrong filesystem or filesystem is corrupted!\n"); } goto failed_mount; } /* Check the MAJOR & MINOR versions */ if (sBlk->s_major != SQUASHFS_MAJOR || sBlk->s_minor > SQUASHFS_MINOR) { if (sBlk->s_major < 4) ERROR("Filesystem on %s is a SQUASHFS %d.%d filesystem." " Appending\nto SQUASHFS %d.%d filesystems is " "not supported. Please convert it to a " "SQUASHFS 4 filesystem\n", source, sBlk->s_major, sBlk->s_minor, sBlk->s_major, sBlk->s_minor); else ERROR("Filesystem on %s is %d.%d, which is a later " "filesystem version than I support\n", source, sBlk->s_major, sBlk->s_minor); goto failed_mount; } /* Check the compression type */ comp = lookup_compressor_id(sBlk->compression); if (!comp->supported) { ERROR("Filesystem on %s uses %s compression, this is " "unsupported by this version\n", source, comp->name); ERROR("Compressors available:\n"); display_compressors("", ""); goto failed_mount; } /* * Read extended superblock information from disk. * * Read compressor specific options from disk if present, and pass * to compressor to set compressor options. * * Note, if there's no compressor options present, the compressor * is still called to set the default options (the defaults may have * been changed by the user specifying options on the command * line which need to be over-ridden). * * Compressor_extract_options is also used to ensure that * we know how decompress a filesystem compressed with these * compression options. */ if (SQUASHFS_COMP_OPTS(sBlk->flags)) { bytes = read_block(fd, sizeof(*sBlk), NULL, 0, buffer); if (bytes == 0) { ERROR("Failed to read compressor options from append " "filesystem\n"); ERROR("Filesystem corrupted?\n"); goto failed_mount; } } res = compressor_extract_options(comp, sBlk->block_size, buffer, bytes); if (res == -1) { ERROR("Compressor failed to set compressor options\n"); goto failed_mount; } printf("Found a valid %sSQUASHFS superblock on %s.\n", SQUASHFS_EXPORTABLE(sBlk->flags) ? "exportable " : "", source); printf("\tCompression used %s\n", comp->name); printf("\tInodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk->flags) ? "un" : ""); printf("\tData is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk->flags) ? "un" : ""); printf("\tFragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk->flags) ? "un" : ""); printf("\tXattrs are %scompressed\n", SQUASHFS_UNCOMPRESSED_XATTRS(sBlk->flags) ? "un" : ""); printf("\tFragments are %spresent in the filesystem\n", SQUASHFS_NO_FRAGMENTS(sBlk->flags) ? "not " : ""); printf("\tAlways-use-fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk->flags) ? "" : "not "); printf("\tDuplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk->flags) ? "" : "not "); printf("\tXattrs are %sstored\n", SQUASHFS_NO_XATTRS(sBlk->flags) ? "not " : ""); printf("\tFilesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk->bytes_used / 1024.0, sBlk->bytes_used / (1024.0 * 1024.0)); printf("\tBlock size %d\n", sBlk->block_size); printf("\tNumber of fragments %d\n", sBlk->fragments); printf("\tNumber of inodes %d\n", sBlk->inodes); printf("\tNumber of ids %d\n", sBlk->no_ids); TRACE("sBlk->inode_table_start %llx\n", sBlk->inode_table_start); TRACE("sBlk->directory_table_start %llx\n", sBlk->directory_table_start); TRACE("sBlk->id_table_start %llx\n", sBlk->id_table_start); TRACE("sBlk->fragment_table_start %llx\n", sBlk->fragment_table_start); TRACE("sBlk->lookup_table_start %llx\n", sBlk->lookup_table_start); TRACE("sBlk->xattr_id_table_start %llx\n", sBlk->xattr_id_table_start); printf("\n"); return comp; failed_mount: return NULL; } unsigned char *squashfs_readdir(int fd, int root_entries, unsigned int directory_start_block, int offset, int size, unsigned int *last_directory_block, struct squashfs_super_block *sBlk, void (push_directory_entry) (char *, squashfs_inode, int, int)) { struct squashfs_dir_header dirh; char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1] __attribute__ ((aligned)); struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *)buffer; unsigned char *directory_table = NULL; int byte, bytes = 0, dir_count; long long start = sBlk->directory_table_start + directory_start_block, last_start_block = start; size += offset; directory_table = malloc((size + SQUASHFS_METADATA_SIZE * 2 - 1) & ~(SQUASHFS_METADATA_SIZE - 1)); if (directory_table == NULL) MEM_ERROR(); while (bytes < size) { int expected = (size - bytes) >= SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : 0; TRACE("squashfs_readdir: reading block 0x%llx, bytes read so " "far %d\n", start, bytes); last_start_block = start; byte = read_block(fd, start, &start, expected, directory_table + bytes); if (byte == 0) { ERROR("Failed to read directory\n"); ERROR("Filesystem corrupted?\n"); free(directory_table); return NULL; } bytes += byte; } if (!root_entries) goto all_done; bytes = offset; while (bytes < size) { SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh); dir_count = dirh.count + 1; TRACE("squashfs_readdir: Read directory header @ byte position " "0x%x, 0x%x directory entries\n", bytes, dir_count); bytes += sizeof(dirh); while (dir_count--) { SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire); bytes += sizeof(*dire); memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_readdir: pushing directory entry %s, " "inode %x:%x, type 0x%x\n", dire->name, dirh.start_block, dire->offset, dire->type); push_directory_entry(dire->name, SQUASHFS_MKINODE(dirh.start_block, dire->offset), dirh.inode_number + dire->inode_number, dire->type); bytes += dire->size + 1; } } all_done: *last_directory_block = (unsigned int)last_start_block - sBlk->directory_table_start; return directory_table; } unsigned int *read_id_table(int fd, struct squashfs_super_block *sBlk) { int indexes = SQUASHFS_ID_BLOCKS(sBlk->no_ids); long long index[indexes]; int bytes = SQUASHFS_ID_BYTES(sBlk->no_ids); unsigned int *id_table; int res, i; id_table = malloc(bytes); if (id_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->id_table_start, SQUASHFS_ID_BLOCK_BYTES(sBlk->no_ids), index); if (res == 0) { ERROR("Failed to read id table index\n"); ERROR("Filesystem corrupted?\n"); free(id_table); return NULL; } SQUASHFS_INSWAP_ID_BLOCKS(index, indexes); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *)id_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read id table block %d, from 0x%llx, length %d\n", i, index[i], length); if (length == 0) { ERROR("Failed to read id table block %d, from 0x%llx, " "length %d\n", i, index[i], length); ERROR("Filesystem corrupted?\n"); free(id_table); return NULL; } } SQUASHFS_INSWAP_INTS(id_table, sBlk->no_ids); for (i = 0; i < sBlk->no_ids; i++) { TRACE("Adding id %d to id tables\n", id_table[i]); create_id(id_table[i]); } return id_table; } int read_fragment_table(int fd, struct squashfs_super_block *sBlk, struct squashfs_fragment_entry **fragment_table) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk->fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk->fragments); long long fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk->fragments, indexes, sBlk->fragment_table_start); if (sBlk->fragments == 0) return 1; *fragment_table = malloc(bytes); if (*fragment_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk->fragments), fragment_table_index); if (res == 0) { ERROR("Failed to read fragment table index\n"); ERROR("Filesystem corrupted?\n"); free(*fragment_table); return 0; } SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((unsigned char *)*fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if (length == 0) { ERROR("Failed to read fragment table block %d, from " "0x%llx, length %d\n", i, fragment_table_index[i], length); ERROR("Filesystem corrupted?\n"); free(*fragment_table); return 0; } } for (i = 0; i < sBlk->fragments; i++) SQUASHFS_INSWAP_FRAGMENT_ENTRY(&(*fragment_table)[i]); return 1; } int read_inode_lookup_table(int fd, struct squashfs_super_block *sBlk, squashfs_inode ** inode_lookup_table) { int lookup_bytes = SQUASHFS_LOOKUP_BYTES(sBlk->inodes); int indexes = SQUASHFS_LOOKUP_BLOCKS(sBlk->inodes); long long index[indexes]; int res, i; if (sBlk->lookup_table_start == SQUASHFS_INVALID_BLK) return 1; *inode_lookup_table = malloc(lookup_bytes); if (*inode_lookup_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->lookup_table_start, SQUASHFS_LOOKUP_BLOCK_BYTES(sBlk->inodes), index); if (res == 0) { ERROR("Failed to read inode lookup table index\n"); ERROR("Filesystem corrupted?\n"); free(*inode_lookup_table); return 0; } SQUASHFS_INSWAP_LONG_LONGS(index, indexes); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : lookup_bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *)*inode_lookup_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read inode lookup table block %d, from 0x%llx, length " "%d\n", i, index[i], length); if (length == 0) { ERROR("Failed to read inode lookup table block %d, " "from 0x%llx, length %d\n", i, index[i], length); ERROR("Filesystem corrupted?\n"); free(*inode_lookup_table); return 0; } } SQUASHFS_INSWAP_LONG_LONGS(*inode_lookup_table, sBlk->inodes); return 1; } long long read_filesystem(char *root_name, int fd, struct squashfs_super_block *sBlk, char **cinode_table, char **data_cache, char **cdirectory_table, char **directory_data_cache, unsigned int *last_directory_block, unsigned int *inode_dir_offset, unsigned int *inode_dir_file_size, unsigned int *root_inode_size, unsigned int *inode_dir_start_block, int *file_count, int *sym_count, int *dev_count, int *dir_count, int *fifo_count, int *sock_count, long long *uncompressed_file, unsigned int *uncompressed_inode, unsigned int *uncompressed_directory, unsigned int *inode_dir_inode_number, unsigned int *inode_dir_parent_inode, void (push_directory_entry) (char *, squashfs_inode, int, int), struct squashfs_fragment_entry **fragment_table, squashfs_inode ** inode_lookup_table) { unsigned char *inode_table = NULL, *directory_table = NULL; long long start = sBlk->inode_table_start; long long end = sBlk->directory_table_start; long long root_inode_start = start + SQUASHFS_INODE_BLK(sBlk->root_inode); unsigned int root_inode_offset = SQUASHFS_INODE_OFFSET(sBlk->root_inode); unsigned int root_inode_block; union squashfs_inode_header inode; unsigned int *id_table = NULL; int res; printf("Scanning existing filesystem...\n"); if (get_xattrs(fd, sBlk) == 0) goto error; if (read_fragment_table(fd, sBlk, fragment_table) == 0) goto error; if (read_inode_lookup_table(fd, sBlk, inode_lookup_table) == 0) goto error; id_table = read_id_table(fd, sBlk); if (id_table == NULL) goto error; res = scan_inode_table(fd, start, end, root_inode_start, root_inode_offset, sBlk, &inode, &inode_table, &root_inode_block, root_inode_size, uncompressed_file, uncompressed_directory, file_count, sym_count, dev_count, dir_count, fifo_count, sock_count, id_table); if (res == 0) goto error; *uncompressed_inode = root_inode_block; if (inode.base.inode_type == SQUASHFS_DIR_TYPE || inode.base.inode_type == SQUASHFS_LDIR_TYPE) { if (inode.base.inode_type == SQUASHFS_DIR_TYPE) { *inode_dir_start_block = inode.dir.start_block; *inode_dir_offset = inode.dir.offset; *inode_dir_file_size = inode.dir.file_size - 3; *inode_dir_inode_number = inode.dir.inode_number; *inode_dir_parent_inode = inode.dir.parent_inode; } else { *inode_dir_start_block = inode.ldir.start_block; *inode_dir_offset = inode.ldir.offset; *inode_dir_file_size = inode.ldir.file_size - 3; *inode_dir_inode_number = inode.ldir.inode_number; *inode_dir_parent_inode = inode.ldir.parent_inode; } directory_table = squashfs_readdir(fd, !root_name, *inode_dir_start_block, *inode_dir_offset, *inode_dir_file_size, last_directory_block, sBlk, push_directory_entry); if (directory_table == NULL) goto error; root_inode_start -= start; *cinode_table = malloc(root_inode_start); if (*cinode_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, start, root_inode_start, *cinode_table); if (res == 0) { ERROR("Failed to read inode table\n"); ERROR("Filesystem corrupted?\n"); goto error; } *cdirectory_table = malloc(*last_directory_block); if (*cdirectory_table == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->directory_table_start, *last_directory_block, *cdirectory_table); if (res == 0) { ERROR("Failed to read directory table\n"); ERROR("Filesystem corrupted?\n"); goto error; } *data_cache = malloc(root_inode_offset + *root_inode_size); if (*data_cache == NULL) MEM_ERROR(); memcpy(*data_cache, inode_table + root_inode_block, root_inode_offset + *root_inode_size); *directory_data_cache = malloc(*inode_dir_offset + *inode_dir_file_size); if (*directory_data_cache == NULL) MEM_ERROR(); memcpy(*directory_data_cache, directory_table, *inode_dir_offset + *inode_dir_file_size); free(id_table); free(inode_table); free(directory_table); return sBlk->inode_table_start; } error: free(id_table); free(inode_table); free(directory_table); return 0; } ================================================ FILE: src/squashfs/read_xattrs.c ================================================ /* * Read a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2010, 2012, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * read_xattrs.c */ /* * Common xattr read code shared between mksquashfs and unsquashfs */ #define TRUE 1 #define FALSE 0 #include #include #if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN #else # include #endif #include "squashfs_fs.h" #include "squashfs_swap.h" #include "xattr.h" #include "error.h" #include extern int read_fs_bytes(int, long long, int, void *); extern int read_block(int, long long, long long *, int, void *); static struct hash_entry { long long start; unsigned int offset; struct hash_entry *next; } *hash_table[65536]; static struct squashfs_xattr_id *xattr_ids; static void *xattrs = NULL; static long long xattr_table_start; /* * Prefix lookup table, storing mapping to/from prefix string and prefix id */ struct prefix prefix_table[] = { {"user.", SQUASHFS_XATTR_USER}, {"trusted.", SQUASHFS_XATTR_TRUSTED}, {"security.", SQUASHFS_XATTR_SECURITY}, {"", -1} }; /* * store mapping from location of compressed block in fs -> * location of uncompressed block in memory */ static void save_xattr_block(long long start, int offset) { struct hash_entry *hash_entry = malloc(sizeof(*hash_entry)); int hash = start & 0xffff; TRACE("save_xattr_block: start %lld, offset %d\n", start, offset); if (hash_entry == NULL) MEM_ERROR(); hash_entry->start = start; hash_entry->offset = offset; hash_entry->next = hash_table[hash]; hash_table[hash] = hash_entry; } /* * map from location of compressed block in fs -> * location of uncompressed block in memory */ static int get_xattr_block(long long start) { int hash = start & 0xffff; struct hash_entry *hash_entry = hash_table[hash]; for (; hash_entry; hash_entry = hash_entry->next) if (hash_entry->start == start) break; TRACE("get_xattr_block: start %lld, offset %d\n", start, hash_entry ? hash_entry->offset : -1); return hash_entry ? hash_entry->offset : -1; } /* * construct the xattr_list entry from the fs xattr, including * mapping name and prefix into a full name */ static int read_xattr_entry(struct xattr_list *xattr, struct squashfs_xattr_entry *entry, void *name) { int i, len, type = entry->type & XATTR_PREFIX_MASK; for (i = 0; prefix_table[i].type != -1; i++) if (prefix_table[i].type == type) break; if (prefix_table[i].type == -1) { ERROR("Unrecognised type in read_xattr_entry\n"); return 0; } len = strlen(prefix_table[i].prefix); xattr->full_name = malloc(len + entry->size + 1); if (xattr->full_name == NULL) MEM_ERROR(); memcpy(xattr->full_name, prefix_table[i].prefix, len); memcpy(xattr->full_name + len, name, entry->size); xattr->full_name[len + entry->size] = '\0'; xattr->name = xattr->full_name + len; xattr->size = entry->size; xattr->type = type; return 1; } /* * Read and decompress the xattr id table and the xattr metadata. * This is cached in memory for later use by get_xattr() */ int read_xattrs_from_disk(int fd, struct squashfs_super_block *sBlk) { int res, bytes, i, indexes, index_bytes, ids; long long *index, start, end; struct squashfs_xattr_table id_table; TRACE("read_xattrs_from_disk\n"); if (sBlk->xattr_id_table_start == SQUASHFS_INVALID_BLK) return SQUASHFS_INVALID_BLK; /* * Read xattr id table, containing start of xattr metadata and the * number of xattrs in the file system */ res = read_fs_bytes(fd, sBlk->xattr_id_table_start, sizeof(id_table), &id_table); if (res == 0) return 0; SQUASHFS_INSWAP_XATTR_TABLE(&id_table); /* * Allocate and read the index to the xattr id table metadata * blocks */ ids = id_table.xattr_ids; xattr_table_start = id_table.xattr_table_start; index_bytes = SQUASHFS_XATTR_BLOCK_BYTES(ids); indexes = SQUASHFS_XATTR_BLOCKS(ids); index = malloc(index_bytes); if (index == NULL) MEM_ERROR(); res = read_fs_bytes(fd, sBlk->xattr_id_table_start + sizeof(id_table), index_bytes, index); if (res == 0) goto failed1; SQUASHFS_INSWAP_LONG_LONGS(index, indexes); /* * Allocate enough space for the uncompressed xattr id table, and * read and decompress it */ bytes = SQUASHFS_XATTR_BYTES(ids); xattr_ids = malloc(bytes); if (xattr_ids == NULL) MEM_ERROR(); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, index[i], NULL, expected, ((unsigned char *)xattr_ids) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr id table block %d, from 0x%llx, length " "%d\n", i, index[i], length); if (length == 0) { ERROR("Failed to read xattr id table block %d, " "from 0x%llx, length %d\n", i, index[i], length); goto failed2; } } /* * Read and decompress the xattr metadata * * Note the first xattr id table metadata block is immediately after * the last xattr metadata block, so we can use index[0] to work out * the end of the xattr metadata */ start = xattr_table_start; end = index[0]; for (i = 0; start < end; i++) { int length; xattrs = realloc(xattrs, (i + 1) * SQUASHFS_METADATA_SIZE); if (xattrs == NULL) MEM_ERROR(); /* store mapping from location of compressed block in fs -> * location of uncompressed block in memory */ save_xattr_block(start, i * SQUASHFS_METADATA_SIZE); length = read_block(fd, start, &start, 0, ((unsigned char *)xattrs) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read xattr block %d, length %d\n", i, length); if (length == 0) { ERROR("Failed to read xattr block %d\n", i); goto failed3; } /* * If this is not the last metadata block in the xattr metadata * then it should be SQUASHFS_METADATA_SIZE in size. * Note, we can't use expected in read_block() above for this * because we don't know if this is the last block until * after reading. */ if (start != end && length != SQUASHFS_METADATA_SIZE) { ERROR("Xattr block %d should be %d bytes in length, " "it is %d bytes\n", i, SQUASHFS_METADATA_SIZE, length); goto failed3; } } /* swap if necessary the xattr id entries */ for (i = 0; i < ids; i++) SQUASHFS_INSWAP_XATTR_ID(&xattr_ids[i]); free(index); return ids; failed3: free(xattrs); failed2: free(xattr_ids); failed1: free(index); return 0; } void free_xattr(struct xattr_list *xattr_list, int count) { int i; for (i = 0; i < count; i++) free(xattr_list[i].full_name); free(xattr_list); } /* * Construct and return the list of xattr name:value pairs for the passed xattr * id * * There are two users for get_xattr(), Mksquashfs uses it to read the * xattrs from the filesystem on appending, and Unsquashfs uses it * to retrieve the xattrs for writing to disk. * * Unfortunately, the two users disagree on what to do with unknown * xattr prefixes, Mksquashfs wants to treat this as fatal otherwise * this will cause xattrs to be be lost on appending. Unsquashfs * on the otherhand wants to retrieve the xattrs which are known and * to ignore the rest, this allows Unsquashfs to cope more gracefully * with future versions which may have unknown xattrs, as long as the * general xattr structure is adhered to, Unsquashfs should be able * to safely ignore unknown xattrs, and to write the ones it knows about, * this is better than completely refusing to retrieve all the xattrs. * * If ignore is TRUE then don't treat unknown xattr prefixes as * a failure to read the xattr. */ struct xattr_list *get_xattr(int i, unsigned int *count, int ignore) { long long start; struct xattr_list *xattr_list = NULL; unsigned int offset; void *xptr; int j = 0, res = 1; TRACE("get_xattr\n"); *count = xattr_ids[i].count; start = SQUASHFS_XATTR_BLK(xattr_ids[i].xattr) + xattr_table_start; offset = SQUASHFS_XATTR_OFFSET(xattr_ids[i].xattr); xptr = xattrs + get_xattr_block(start) + offset; TRACE("get_xattr: xattr_id %d, count %d, start %lld, offset %d\n", i, *count, start, offset); while (j < *count) { struct squashfs_xattr_entry entry; struct squashfs_xattr_val val; if (res != 0) { xattr_list = realloc(xattr_list, (j + 1) * sizeof(struct xattr_list)); if (xattr_list == NULL) MEM_ERROR(); } SQUASHFS_SWAP_XATTR_ENTRY(xptr, &entry); xptr += sizeof(entry); res = read_xattr_entry(&xattr_list[j], &entry, xptr); if (ignore && res == 0) { /* unknown prefix, but ignore flag is set */ (*count)--; continue; } if (res != 1) goto failed; xptr += entry.size; TRACE("get_xattr: xattr %d, type %d, size %d, name %s\n", j, entry.type, entry.size, xattr_list[j].full_name); if (entry.type & SQUASHFS_XATTR_VALUE_OOL) { long long xattr; void *ool_xptr; xptr += sizeof(val); SQUASHFS_SWAP_LONG_LONGS(xptr, &xattr, 1); xptr += sizeof(xattr); start = SQUASHFS_XATTR_BLK(xattr) + xattr_table_start; offset = SQUASHFS_XATTR_OFFSET(xattr); ool_xptr = xattrs + get_xattr_block(start) + offset; SQUASHFS_SWAP_XATTR_VAL(ool_xptr, &val); xattr_list[j].value = ool_xptr + sizeof(val); } else { SQUASHFS_SWAP_XATTR_VAL(xptr, &val); xattr_list[j].value = xptr + sizeof(val); xptr += sizeof(val) + val.vsize; } TRACE("get_xattr: xattr %d, vsize %d\n", j, val.vsize); xattr_list[j++].vsize = val.vsize; } if (*count == 0) goto failed; return xattr_list; failed: free_xattr(xattr_list, j); return NULL; } ================================================ FILE: src/squashfs/restore.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * restore.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "caches-queues-lists.h" #include "squashfs_fs.h" #include "mksquashfs.h" #include "error.h" #include "progressbar.h" #include "info.h" #define FALSE 0 #define TRUE 1 extern pthread_t reader_thread, writer_thread, main_thread; extern pthread_t *deflator_thread, *frag_deflator_thread, *frag_thread; extern struct queue *to_deflate, *to_writer, *to_frag, *to_process_frag; extern struct seq_queue *to_main; extern void restorefs(); extern int processors; static int interrupted = 0; static pthread_t restore_thread; void *restore_thrd(void *arg) { sigset_t sigmask, old_mask; int i, sig; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); sigaddset(&sigmask, SIGUSR1); pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask); while (1) { sigwait(&sigmask, &sig); if ((sig == SIGINT || sig == SIGTERM) && !interrupted) { ERROR("Interrupting will restore original " "filesystem!\n"); ERROR("Interrupt again to quit\n"); interrupted = TRUE; continue; } /* kill main thread/worker threads and restore */ set_progressbar_state(FALSE); disable_info(); /* first kill the reader thread */ pthread_cancel(reader_thread); pthread_join(reader_thread, NULL); /* * then flush the reader to deflator thread(s) output queue. * The deflator thread(s) will idle */ queue_flush(to_deflate); /* now kill the deflator thread(s) */ for (i = 0; i < processors; i++) pthread_cancel(deflator_thread[i]); for (i = 0; i < processors; i++) pthread_join(deflator_thread[i], NULL); /* * then flush the reader to process fragment thread(s) output * queue. The process fragment thread(s) will idle */ queue_flush(to_process_frag); /* now kill the process fragment thread(s) */ for (i = 0; i < processors; i++) pthread_cancel(frag_thread[i]); for (i = 0; i < processors; i++) pthread_join(frag_thread[i], NULL); /* * then flush the reader/deflator/process fragment to main * thread output queue. The main thread will idle */ seq_queue_flush(to_main); /* now kill the main thread */ pthread_cancel(main_thread); pthread_join(main_thread, NULL); /* then flush the main thread to fragment deflator thread(s) * queue. The fragment deflator thread(s) will idle */ queue_flush(to_frag); /* now kill the fragment deflator thread(s) */ for (i = 0; i < processors; i++) pthread_cancel(frag_deflator_thread[i]); for (i = 0; i < processors; i++) pthread_join(frag_deflator_thread[i], NULL); /* * then flush the main thread/fragment deflator thread(s) * to writer thread queue. The writer thread will idle */ queue_flush(to_writer); /* now kill the writer thread */ pthread_cancel(writer_thread); pthread_join(writer_thread, NULL); TRACE("All threads cancelled\n"); restorefs(); } } pthread_t *init_restore_thread() { pthread_create(&restore_thread, NULL, restore_thrd, NULL); return &restore_thread; } ================================================ FILE: src/squashfs/sort.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, * 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * sort.c */ #define TRUE 1 #define FALSE 0 #define MAX_LINE 16384 #include #include #include #include #include #include #include #include #include #include #include "squashfs_fs.h" #include "mksquashfs.h" #include "sort.h" #include "error.h" #include "progressbar.h" int mkisofs_style = -1; struct sort_info { dev_t st_dev; ino_t st_ino; int priority; struct sort_info *next; }; struct sort_info *sort_info_list[65536]; struct priority_entry *priority_list[65536]; extern int silent; extern void write_file(squashfs_inode * inode, struct dir_ent *dir_ent, int *c_size); extern char *pathname(struct dir_ent *dir_ent); void add_priority_list(struct dir_ent *dir, int priority) { struct priority_entry *new_priority_entry; priority += 32768; new_priority_entry = malloc(sizeof(struct priority_entry)); if (new_priority_entry == NULL) MEM_ERROR(); new_priority_entry->dir = dir;; new_priority_entry->next = priority_list[priority]; priority_list[priority] = new_priority_entry; } int get_priority(char *filename, struct stat *buf, int priority) { int hash = buf->st_ino & 0xffff; struct sort_info *s; for (s = sort_info_list[hash]; s; s = s->next) if ((s->st_dev == buf->st_dev) && (s->st_ino == buf->st_ino)) { TRACE("returning priority %d (%s)\n", s->priority, filename); return s->priority; } TRACE("returning priority %d (%s)\n", priority, filename); return priority; } #define ADD_ENTRY(buf, priority) {\ int hash = buf.st_ino & 0xffff;\ struct sort_info *s;\ if((s = malloc(sizeof(struct sort_info))) == NULL) \ MEM_ERROR(); \ s->st_dev = buf.st_dev;\ s->st_ino = buf.st_ino;\ s->priority = priority;\ s->next = sort_info_list[hash];\ sort_info_list[hash] = s;\ } int add_sort_list(char *path, int priority, int source, char *source_path[]) { int i, n; struct stat buf; TRACE("add_sort_list: filename %s, priority %d\n", path, priority); if (strlen(path) > 1 && strcmp(path + strlen(path) - 2, "/*") == 0) path[strlen(path) - 2] = '\0'; TRACE("add_sort_list: filename %s, priority %d\n", path, priority); re_read: if (path[0] == '/' || strncmp(path, "./", 2) == 0 || strncmp(path, "../", 3) == 0 || mkisofs_style == 1) { if (lstat(path, &buf) == -1) goto error; TRACE("adding filename %s, priority %d, st_dev %d, st_ino " "%lld\n", path, priority, (int)buf.st_dev, (long long)buf.st_ino); ADD_ENTRY(buf, priority); return TRUE; } for (i = 0, n = 0; i < source; i++) { char *filename; int res = asprintf(&filename, "%s/%s", source_path[i], path); if (res == -1) BAD_ERROR("asprintf failed in add_sort_list\n"); res = lstat(filename, &buf); free(filename); if (res == -1) { if (!(errno == ENOENT || errno == ENOTDIR)) goto error; continue; } ADD_ENTRY(buf, priority); n++; } if (n == 0 && mkisofs_style == -1 && lstat(path, &buf) != -1) { ERROR("WARNING: Mkisofs style sortlist detected! This is " "supported but please\n"); ERROR("convert to mksquashfs style sortlist! A sortlist entry"); ERROR(" should be\neither absolute (starting with "); ERROR("'/') start with './' or '../' (taken to be\nrelative to " "$PWD), otherwise it "); ERROR("is assumed the entry is relative to one\nof the source " "directories, i.e. with "); ERROR("\"mksquashfs test test.sqsh\",\nthe sortlist "); ERROR("entry \"file\" is assumed to be inside the directory " "test.\n\n"); mkisofs_style = 1; goto re_read; } mkisofs_style = 0; if (n == 1) return TRUE; if (n > 1) { ERROR(" Ambiguous sortlist entry \"%s\"\n\nIt maps to more " "than one source entry! Please use an absolute path." "\n", path); return FALSE; } error: ERROR_START("Cannot stat sortlist entry \"%s\"\n", path); ERROR("This is probably because you're using the wrong file\n"); ERROR("path relative to the source directories."); ERROR_EXIT(" Ignoring"); /* * Historical note * Failure to stat a sortlist entry is deliberately ignored, even * though it is an error. Squashfs release 2.2 changed the behaviour * to treat it as a fatal error, but it was changed back to * the original behaviour to ignore it in release 2.2-r2 following * feedback from users at the time. */ return TRUE; } void generate_file_priorities(struct dir_info *dir, int priority, struct stat *buf) { struct dir_ent *dir_ent = dir->list; priority = get_priority(dir->pathname, buf, priority); for (; dir_ent; dir_ent = dir_ent->next) { struct stat *buf = &dir_ent->inode->buf; if (dir_ent->inode->root_entry) continue; switch (buf->st_mode & S_IFMT) { case S_IFREG: add_priority_list(dir_ent, get_priority(pathname(dir_ent), buf, priority)); break; case S_IFDIR: generate_file_priorities(dir_ent->dir, priority, buf); break; } } } int read_sort_file(char *filename, int source, char *source_path[]) { FILE *fd; char line_buffer[MAX_LINE + 1]; /* overflow safe */ char sort_filename[MAX_LINE + 1]; /* overflow safe */ char *line, *name; int n, priority, res; if ((fd = fopen(filename, "r")) == NULL) { ERROR("Failed to open sort file \"%s\" because %s\n", filename, strerror(errno)); return FALSE; } while (fgets(line = line_buffer, MAX_LINE + 1, fd) != NULL) { int len = strlen(line); if (len == MAX_LINE && line[len - 1] != '\n') { /* line too large */ ERROR("Line too long when reading " "sort file \"%s\", larger than %d " "bytes\n", filename, MAX_LINE); goto failed; } /* * Remove '\n' terminator if it exists (the last line * in the file may not be '\n' terminated) */ if (len && line[len - 1] == '\n') line[len - 1] = '\0'; /* Skip any leading whitespace */ while (isspace(*line)) line++; /* if comment line, skip */ if (*line == '#') continue; /* * Scan for filename, don't use sscanf() and "%s" because * that can't handle filenames with spaces */ for (name = sort_filename; !isspace(*line) && *line != '\0';) { if (*line == '\\') { line++; if (*line == '\0') break; } *name++ = *line++; } *name = '\0'; /* * if filename empty, then line was empty of anything but * whitespace or a backslash character. Skip empy lines */ if (sort_filename[0] == '\0') continue; /* * Scan the rest of the line, we expect a decimal number * which is the filename priority */ errno = 0; res = sscanf(line, "%d%n", &priority, &n); if ((res < 1 || errno) && errno != ERANGE) { if (errno == 0) /* No error, assume EOL or match failure */ ERROR("Sort file \"%s\", can't find priority " "in entry \"%s\", EOL or match " "failure\n", filename, line_buffer); else /* Some other failure not ERANGE */ ERROR("Sscanf failed reading sort file \"%s\" " "because %s\n", filename, strerror(errno)); goto failed; } else if ((errno == ERANGE) || (priority < -32768 || priority > 32767)) { ERROR("Sort file \"%s\", entry \"%s\" has priority " "outside range of -32767:32768.\n", filename, line_buffer); goto failed; } /* Skip any trailing whitespace */ line += n; while (isspace(*line)) line++; if (*line != '\0') { ERROR("Sort file \"%s\", trailing characters after " "priority in entry \"%s\"\n", filename, line_buffer); goto failed; } res = add_sort_list(sort_filename, priority, source, source_path); if (res == FALSE) goto failed; } if (ferror(fd)) { ERROR("Reading sort file \"%s\" failed because %s\n", filename, strerror(errno)); goto failed; } fclose(fd); return TRUE; failed: fclose(fd); return FALSE; } void sort_files_and_write(struct dir_info *dir) { int i; struct priority_entry *entry; squashfs_inode inode; int duplicate_file; for (i = 65535; i >= 0; i--) for (entry = priority_list[i]; entry; entry = entry->next) { TRACE("%d: %s\n", i - 32768, pathname(entry->dir)); if (entry->dir->inode->inode == SQUASHFS_INVALID_BLK) { write_file(&inode, entry->dir, &duplicate_file); INFO("file %s, uncompressed size %lld bytes %s" "\n", pathname(entry->dir), (long long) entry->dir->inode->buf.st_size, duplicate_file ? "DUPLICATE" : ""); entry->dir->inode->inode = inode; entry->dir->inode->type = SQUASHFS_FILE_TYPE; } else INFO("file %s, uncompressed size %lld bytes " "LINK\n", pathname(entry->dir), (long long) entry->dir->inode->buf.st_size); } } ================================================ FILE: src/squashfs/swap.c ================================================ /* * Copyright (c) 2009, 2010 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * swap.c */ #if !defined(linux) && !defined(__CYGWIN__) # define __BYTE_ORDER BYTE_ORDER # define __BIG_ENDIAN BIG_ENDIAN # define __LITTLE_ENDIAN LITTLE_ENDIAN #else # include #endif #if __BYTE_ORDER == __BIG_ENDIAN void swap_le16(void *src, void *dest) { unsigned char *s = src; unsigned char *d = dest; d[0] = s[1]; d[1] = s[0]; } void swap_le32(void *src, void *dest) { unsigned char *s = src; unsigned char *d = dest; d[0] = s[3]; d[1] = s[2]; d[2] = s[1]; d[3] = s[0]; } void swap_le64(void *src, void *dest) { unsigned char *s = src; unsigned char *d = dest; d[0] = s[7]; d[1] = s[6]; d[2] = s[5]; d[3] = s[4]; d[4] = s[3]; d[5] = s[2]; d[6] = s[1]; d[7] = s[0]; } unsigned short inswap_le16(unsigned short num) { return (num >> 8) | ((num & 0xff) << 8); } unsigned int inswap_le32(unsigned int num) { return (num >> 24) | ((num & 0xff0000) >> 8) | ((num & 0xff00) << 8) | ((num & 0xff) << 24); } long long inswap_le64(long long n) { unsigned long long num = n; return (num >> 56) | ((num & 0xff000000000000LL) >> 40) | ((num & 0xff0000000000LL) >> 24) | ((num & 0xff00000000LL) >> 8) | ((num & 0xff000000) << 8) | ((num & 0xff0000) << 24) | ((num & 0xff00) << 40) | ((num & 0xff) << 56); } # define SWAP_LE_NUM(BITS) \ void swap_le##BITS##_num(void *s, void *d, int n) \ {\ int i;\ for(i = 0; i < n; i++, s += BITS / 8, d += BITS / 8)\ swap_le##BITS(s, d);\ } SWAP_LE_NUM(16) SWAP_LE_NUM(32) SWAP_LE_NUM(64) # define INSWAP_LE_NUM(BITS, TYPE) \ void inswap_le##BITS##_num(TYPE *s, int n) \ {\ int i;\ for(i = 0; i < n; i++)\ s[i] = inswap_le##BITS(s[i]);\ } INSWAP_LE_NUM(16, unsigned short) INSWAP_LE_NUM(32, unsigned int) INSWAP_LE_NUM(64, long long) #endif ================================================ FILE: src/squashfs/unsquash-1.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2011, 2012 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquash-1.c */ #include "unsquashfs.h" #include "squashfs_compat.h" void read_block_list_1(unsigned int *block_list, char *block_ptr, int blocks) { unsigned short block_size; int i; TRACE("read_block_list: blocks %d\n", blocks); for (i = 0; i < blocks; i++, block_ptr += 2) { if (swap) { unsigned short sblock_size; memcpy(&sblock_size, block_ptr, sizeof(unsigned short)); SQUASHFS_SWAP_SHORTS_3((&block_size), &sblock_size, 1); } else memcpy(&block_size, block_ptr, sizeof(unsigned short)); block_list[i] = SQUASHFS_COMPRESSED_SIZE(block_size) | (SQUASHFS_COMPRESSED(block_size) ? 0 : SQUASHFS_COMPRESSED_BIT_BLOCK); } } int read_fragment_table_1(long long *directory_table_end) { TRACE("read_fragment_table\n"); *directory_table_end = sBlk.s.fragment_table_start; return TRUE; } struct inode *read_inode_1(unsigned int start_block, unsigned int offset) { static union squashfs_inode_header_1 header; long long start = sBlk.s.inode_table_start + start_block; int bytes = lookup_entry(inode_table_hash, start); char *block_ptr = inode_table + bytes + offset; static struct inode i; TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); if (bytes == -1) EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", start); if (swap) { squashfs_base_inode_header_1 sinode; memcpy(&sinode, block_ptr, sizeof(header.base)); SQUASHFS_SWAP_BASE_INODE_HEADER_1(&header.base, &sinode, sizeof(squashfs_base_inode_header_1)); } else memcpy(&header.base, block_ptr, sizeof(header.base)); i.uid = (uid_t) uid_table[(header.base.inode_type - 1) / SQUASHFS_TYPES * 16 + header.base.uid]; if (header.base.inode_type == SQUASHFS_IPC_TYPE) { squashfs_ipc_inode_header_1 *inodep = &header.ipc; if (swap) { squashfs_ipc_inode_header_1 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_IPC_INODE_HEADER_1(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); if (inodep->type == SQUASHFS_SOCKET_TYPE) { i.mode = S_IFSOCK | header.base.mode; i.type = SQUASHFS_SOCKET_TYPE; } else { i.mode = S_IFIFO | header.base.mode; i.type = SQUASHFS_FIFO_TYPE; } i.uid = (uid_t) uid_table[inodep->offset * 16 + inodep->uid]; } else { i.mode = lookup_type[(header.base.inode_type - 1) % SQUASHFS_TYPES + 1] | header.base.mode; i.type = (header.base.inode_type - 1) % SQUASHFS_TYPES + 1; } i.xattr = SQUASHFS_INVALID_XATTR; i.gid = header.base.guid == 15 ? i.uid : (uid_t) guid_table[header.base.guid]; i.time = sBlk.s.mkfs_time; i.inode_number = inode_number++; switch (i.type) { case SQUASHFS_DIR_TYPE:{ squashfs_dir_inode_header_1 *inode = &header.dir; if (swap) { squashfs_dir_inode_header_1 sinode; memcpy(&sinode, block_ptr, sizeof(header.dir)); SQUASHFS_SWAP_DIR_INODE_HEADER_1(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(header.dir)); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.time = inode->mtime; break; } case SQUASHFS_FILE_TYPE:{ squashfs_reg_inode_header_1 *inode = &header.reg; if (swap) { squashfs_reg_inode_header_1 sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_REG_INODE_HEADER_1(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); i.data = inode->file_size; i.time = inode->mtime; i.blocks = (i.data + sBlk.s.block_size - 1) >> sBlk.s.block_log; i.start = inode->start_block; i.block_ptr = block_ptr + sizeof(*inode); i.fragment = 0; i.frag_bytes = 0; i.offset = 0; i.sparse = 0; break; } case SQUASHFS_SYMLINK_TYPE:{ squashfs_symlink_inode_header_1 *inodep = &header.symlink; if (swap) { squashfs_symlink_inode_header_1 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.symlink = malloc(inodep->symlink_size + 1); if (i.symlink == NULL) EXIT_UNSQUASH("read_inode: failed to malloc " "symlink data\n"); strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header_1), inodep->symlink_size); i.symlink[inodep->symlink_size] = '\0'; i.data = inodep->symlink_size; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE:{ squashfs_dev_inode_header_1 *inodep = &header.dev; if (swap) { squashfs_dev_inode_header_1 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_DEV_INODE_HEADER_1(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.data = inodep->rdev; break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE:{ i.data = 0; break; } default: EXIT_UNSQUASH("Unknown inode type %d in " " read_inode_header_1!\n", header.base.inode_type); } return &i; } struct dir *squashfs_opendir_1(unsigned int block_start, unsigned int offset, struct inode **i) { squashfs_dir_header_2 dirh; char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1] __attribute__ ((aligned)); squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer; long long start; int bytes; int dir_count, size; struct dir_ent *new_dir; struct dir *dir; TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); *i = s_ops.read_inode(block_start, offset); dir = malloc(sizeof(struct dir)); if (dir == NULL) EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n"); dir->dir_count = 0; dir->cur_entry = 0; dir->mode = (*i)->mode; dir->uid = (*i)->uid; dir->guid = (*i)->gid; dir->mtime = (*i)->time; dir->xattr = (*i)->xattr; dir->dirs = NULL; if ((*i)->data == 0) /* * if the directory is empty, skip the unnecessary * lookup_entry, this fixes the corner case with * completely empty filesystems where lookup_entry correctly * returning -1 is incorrectly treated as an error */ return dir; start = sBlk.s.directory_table_start + (*i)->start; bytes = lookup_entry(directory_table_hash, start); if (bytes == -1) EXIT_UNSQUASH("squashfs_opendir: directory block %d not " "found!\n", block_start); bytes += (*i)->offset; size = (*i)->data + bytes; while (bytes < size) { if (swap) { squashfs_dir_header_2 sdirh; memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); } else memcpy(&dirh, directory_table + bytes, sizeof(dirh)); dir_count = dirh.count + 1; TRACE("squashfs_opendir: Read directory header @ byte position " "%d, %d directory entries\n", bytes, dir_count); bytes += sizeof(dirh); /* dir_count should never be larger than 256 */ if (dir_count > 256) goto corrupted; while (dir_count--) { if (swap) { squashfs_dir_entry_2 sdire; memcpy(&sdire, directory_table + bytes, sizeof(sdire)); SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); } else memcpy(dire, directory_table + bytes, sizeof(*dire)); bytes += sizeof(*dire); /* size should never be larger than SQUASHFS_NAME_LEN */ if (dire->size > SQUASHFS_NAME_LEN) goto corrupted; memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_opendir: directory entry %s, inode " "%d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); if ((dir->dir_count % DIR_ENT_SIZE) == 0) { new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent)); if (new_dir == NULL) EXIT_UNSQUASH("squashfs_opendir: " "realloc failed!\n"); dir->dirs = new_dir; } strcpy(dir->dirs[dir->dir_count].name, dire->name); dir->dirs[dir->dir_count].start_block = dirh.start_block; dir->dirs[dir->dir_count].offset = dire->offset; dir->dirs[dir->dir_count].type = dire->type; dir->dir_count++; bytes += dire->size + 1; } } return dir; corrupted: free(dir->dirs); free(dir); return NULL; } int read_uids_guids_1() { int res; TRACE("read_uids_guids: no_uids %d, no_guids %d\n", sBlk.no_uids, sBlk.no_guids); uid_table = malloc((sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int)); if (uid_table == NULL) { ERROR("read_uids_guids: failed to allocate uid/gid table\n"); return FALSE; } guid_table = uid_table + sBlk.no_uids; if (swap) { unsigned int suid_table[sBlk.no_uids + sBlk.no_guids]; res = read_fs_bytes(fd, sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), suid_table); if (res == FALSE) { ERROR("read_uids_guids: failed to read uid/gid table" "\n"); return FALSE; } SQUASHFS_SWAP_INTS_3(uid_table, suid_table, sBlk.no_uids + sBlk.no_guids); } else { res = read_fs_bytes(fd, sBlk.uid_start, (sBlk.no_uids + sBlk.no_guids) * sizeof(unsigned int), uid_table); if (res == FALSE) { ERROR("read_uids_guids: failed to read uid/gid table" "\n"); return FALSE; } } return TRUE; } ================================================ FILE: src/squashfs/unsquash-2.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquash-2.c */ #include "unsquashfs.h" #include "squashfs_compat.h" static squashfs_fragment_entry_2 *fragment_table; void read_block_list_2(unsigned int *block_list, char *block_ptr, int blocks) { TRACE("read_block_list: blocks %d\n", blocks); if (swap) { unsigned int sblock_list[blocks]; memcpy(sblock_list, block_ptr, blocks * sizeof(unsigned int)); SQUASHFS_SWAP_INTS_3(block_list, sblock_list, blocks); } else memcpy(block_list, block_ptr, blocks * sizeof(unsigned int)); } int read_fragment_table_2(long long *directory_table_end) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES_2(sBlk.s.fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES_2(sBlk.s.fragments); unsigned int fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if (sBlk.s.fragments == 0) { *directory_table_end = sBlk.s.fragment_table_start; return TRUE; } fragment_table = malloc(bytes); if (fragment_table == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); if (swap) { unsigned int sfragment_table_index[indexes]; res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), sfragment_table_index); if (res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } SQUASHFS_SWAP_FRAGMENT_INDEXES_2(fragment_table_index, sfragment_table_index, indexes); } else { res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sBlk.s.fragments), fragment_table_index); if (res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((char *)fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%x, length %d\n", i, fragment_table_index[i], length); if (length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table block\n"); return FALSE; } } if (swap) { squashfs_fragment_entry_2 sfragment; for (i = 0; i < sBlk.s.fragments; i++) { SQUASHFS_SWAP_FRAGMENT_ENTRY_2((&sfragment), (&fragment_table[i])); memcpy((char *)&fragment_table[i], (char *)&sfragment, sizeof(squashfs_fragment_entry_2)); } } *directory_table_end = fragment_table_index[0]; return TRUE; } void read_fragment_2(unsigned int fragment, long long *start_block, int *size) { TRACE("read_fragment: reading fragment %d\n", fragment); squashfs_fragment_entry_2 *fragment_entry = &fragment_table[fragment]; *start_block = fragment_entry->start_block; *size = fragment_entry->size; } struct inode *read_inode_2(unsigned int start_block, unsigned int offset) { static union squashfs_inode_header_2 header; long long start = sBlk.s.inode_table_start + start_block; int bytes = lookup_entry(inode_table_hash, start); char *block_ptr = inode_table + bytes + offset; static struct inode i; TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); if (bytes == -1) EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", start); if (swap) { squashfs_base_inode_header_2 sinode; memcpy(&sinode, block_ptr, sizeof(header.base)); SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode, sizeof(squashfs_base_inode_header_2)); } else memcpy(&header.base, block_ptr, sizeof(header.base)); i.xattr = SQUASHFS_INVALID_XATTR; i.uid = (uid_t) uid_table[header.base.uid]; i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : (uid_t) guid_table[header.base.guid]; i.mode = lookup_type[header.base.inode_type] | header.base.mode; i.type = header.base.inode_type; i.time = sBlk.s.mkfs_time; i.inode_number = inode_number++; switch (header.base.inode_type) { case SQUASHFS_DIR_TYPE:{ squashfs_dir_inode_header_2 *inode = &header.dir; if (swap) { squashfs_dir_inode_header_2 sinode; memcpy(&sinode, block_ptr, sizeof(header.dir)); SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir, &sinode); } else memcpy(&header.dir, block_ptr, sizeof(header.dir)); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.time = inode->mtime; break; } case SQUASHFS_LDIR_TYPE:{ squashfs_ldir_inode_header_2 *inode = &header.ldir; if (swap) { squashfs_ldir_inode_header_2 sinode; memcpy(&sinode, block_ptr, sizeof(header.ldir)); SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir, &sinode); } else memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.time = inode->mtime; break; } case SQUASHFS_FILE_TYPE:{ squashfs_reg_inode_header_2 *inode = &header.reg; if (swap) { squashfs_reg_inode_header_2 sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_REG_INODE_HEADER_2(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); i.data = inode->file_size; i.time = inode->mtime; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (i.data + sBlk.s.block_size - 1) >> sBlk.s.block_log : i.data >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = 0; i.block_ptr = block_ptr + sizeof(*inode); break; } case SQUASHFS_SYMLINK_TYPE:{ squashfs_symlink_inode_header_2 *inodep = &header.symlink; if (swap) { squashfs_symlink_inode_header_2 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.symlink = malloc(inodep->symlink_size + 1); if (i.symlink == NULL) EXIT_UNSQUASH("read_inode: failed to malloc " "symlink data\n"); strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header_2), inodep->symlink_size); i.symlink[inodep->symlink_size] = '\0'; i.data = inodep->symlink_size; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE:{ squashfs_dev_inode_header_2 *inodep = &header.dev; if (swap) { squashfs_dev_inode_header_2 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.data = inodep->rdev; break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: i.data = 0; break; default: EXIT_UNSQUASH("Unknown inode type %d in " "read_inode_header_2!\n", header.base.inode_type); } return &i; } ================================================ FILE: src/squashfs/unsquash-3.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2011, 2012, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquash-3.c */ #include "unsquashfs.h" #include "squashfs_compat.h" static squashfs_fragment_entry_3 *fragment_table; int read_fragment_table_3(long long *directory_table_end) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES_3(sBlk.s.fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES_3(sBlk.s.fragments); long long fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if (sBlk.s.fragments == 0) { *directory_table_end = sBlk.s.fragment_table_start; return TRUE; } fragment_table = malloc(bytes); if (fragment_table == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); if (swap) { long long sfragment_table_index[indexes]; res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_3(sBlk.s.fragments), sfragment_table_index); if (res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } SQUASHFS_SWAP_FRAGMENT_INDEXES_3(fragment_table_index, sfragment_table_index, indexes); } else { res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES_3(sBlk.s.fragments), fragment_table_index); if (res == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((char *)fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if (length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table block\n"); return FALSE; } } if (swap) { squashfs_fragment_entry_3 sfragment; for (i = 0; i < sBlk.s.fragments; i++) { SQUASHFS_SWAP_FRAGMENT_ENTRY_3((&sfragment), (&fragment_table[i])); memcpy((char *)&fragment_table[i], (char *)&sfragment, sizeof(squashfs_fragment_entry_3)); } } *directory_table_end = fragment_table_index[0]; return TRUE; } void read_fragment_3(unsigned int fragment, long long *start_block, int *size) { TRACE("read_fragment: reading fragment %d\n", fragment); squashfs_fragment_entry_3 *fragment_entry = &fragment_table[fragment]; *start_block = fragment_entry->start_block; *size = fragment_entry->size; } struct inode *read_inode_3(unsigned int start_block, unsigned int offset) { static union squashfs_inode_header_3 header; long long start = sBlk.s.inode_table_start + start_block; int bytes = lookup_entry(inode_table_hash, start); char *block_ptr = inode_table + bytes + offset; static struct inode i; TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); if (bytes == -1) EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", start); if (swap) { squashfs_base_inode_header_3 sinode; memcpy(&sinode, block_ptr, sizeof(header.base)); SQUASHFS_SWAP_BASE_INODE_HEADER_3(&header.base, &sinode, sizeof(squashfs_base_inode_header_3)); } else memcpy(&header.base, block_ptr, sizeof(header.base)); i.xattr = SQUASHFS_INVALID_XATTR; i.uid = (uid_t) uid_table[header.base.uid]; i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid : (uid_t) guid_table[header.base.guid]; i.mode = lookup_type[header.base.inode_type] | header.base.mode; i.type = header.base.inode_type; i.time = header.base.mtime; i.inode_number = header.base.inode_number; switch (header.base.inode_type) { case SQUASHFS_DIR_TYPE:{ squashfs_dir_inode_header_3 *inode = &header.dir; if (swap) { squashfs_dir_inode_header_3 sinode; memcpy(&sinode, block_ptr, sizeof(header.dir)); SQUASHFS_SWAP_DIR_INODE_HEADER_3(&header.dir, &sinode); } else memcpy(&header.dir, block_ptr, sizeof(header.dir)); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; break; } case SQUASHFS_LDIR_TYPE:{ squashfs_ldir_inode_header_3 *inode = &header.ldir; if (swap) { squashfs_ldir_inode_header_3 sinode; memcpy(&sinode, block_ptr, sizeof(header.ldir)); SQUASHFS_SWAP_LDIR_INODE_HEADER_3(&header.ldir, &sinode); } else memcpy(&header.ldir, block_ptr, sizeof(header.ldir)); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; break; } case SQUASHFS_FILE_TYPE:{ squashfs_reg_inode_header_3 *inode = &header.reg; if (swap) { squashfs_reg_inode_header_3 sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_REG_INODE_HEADER_3(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (i.data + sBlk.s.block_size - 1) >> sBlk.s.block_log : i.data >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = 1; i.block_ptr = block_ptr + sizeof(*inode); break; } case SQUASHFS_LREG_TYPE:{ squashfs_lreg_inode_header_3 *inode = &header.lreg; if (swap) { squashfs_lreg_inode_header_3 sinode; memcpy(&sinode, block_ptr, sizeof(sinode)); SQUASHFS_SWAP_LREG_INODE_HEADER_3(inode, &sinode); } else memcpy(inode, block_ptr, sizeof(*inode)); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + sBlk.s.block_size - 1) >> sBlk.s.block_log : inode->file_size >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = 1; i.block_ptr = block_ptr + sizeof(*inode); break; } case SQUASHFS_SYMLINK_TYPE:{ squashfs_symlink_inode_header_3 *inodep = &header.symlink; if (swap) { squashfs_symlink_inode_header_3 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_SYMLINK_INODE_HEADER_3(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.symlink = malloc(inodep->symlink_size + 1); if (i.symlink == NULL) EXIT_UNSQUASH("read_inode: failed to malloc " "symlink data\n"); strncpy(i.symlink, block_ptr + sizeof(squashfs_symlink_inode_header_3), inodep->symlink_size); i.symlink[inodep->symlink_size] = '\0'; i.data = inodep->symlink_size; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE:{ squashfs_dev_inode_header_3 *inodep = &header.dev; if (swap) { squashfs_dev_inode_header_3 sinodep; memcpy(&sinodep, block_ptr, sizeof(sinodep)); SQUASHFS_SWAP_DEV_INODE_HEADER_3(inodep, &sinodep); } else memcpy(inodep, block_ptr, sizeof(*inodep)); i.data = inodep->rdev; break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: i.data = 0; break; default: EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n", header.base.inode_type); } return &i; } struct dir *squashfs_opendir_3(unsigned int block_start, unsigned int offset, struct inode **i) { squashfs_dir_header_3 dirh; char buffer[sizeof(squashfs_dir_entry_3) + SQUASHFS_NAME_LEN + 1] __attribute__ ((aligned)); squashfs_dir_entry_3 *dire = (squashfs_dir_entry_3 *) buffer; long long start; int bytes; int dir_count, size; struct dir_ent *new_dir; struct dir *dir; TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); *i = s_ops.read_inode(block_start, offset); dir = malloc(sizeof(struct dir)); if (dir == NULL) EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n"); dir->dir_count = 0; dir->cur_entry = 0; dir->mode = (*i)->mode; dir->uid = (*i)->uid; dir->guid = (*i)->gid; dir->mtime = (*i)->time; dir->xattr = (*i)->xattr; dir->dirs = NULL; if ((*i)->data == 3) /* * if the directory is empty, skip the unnecessary * lookup_entry, this fixes the corner case with * completely empty filesystems where lookup_entry correctly * returning -1 is incorrectly treated as an error */ return dir; start = sBlk.s.directory_table_start + (*i)->start; bytes = lookup_entry(directory_table_hash, start); if (bytes == -1) EXIT_UNSQUASH("squashfs_opendir: directory block %d not " "found!\n", block_start); bytes += (*i)->offset; size = (*i)->data + bytes - 3; while (bytes < size) { if (swap) { squashfs_dir_header_3 sdirh; memcpy(&sdirh, directory_table + bytes, sizeof(sdirh)); SQUASHFS_SWAP_DIR_HEADER_3(&dirh, &sdirh); } else memcpy(&dirh, directory_table + bytes, sizeof(dirh)); dir_count = dirh.count + 1; TRACE("squashfs_opendir: Read directory header @ byte position " "%d, %d directory entries\n", bytes, dir_count); bytes += sizeof(dirh); /* dir_count should never be larger than 256 */ if (dir_count > 256) goto corrupted; while (dir_count--) { if (swap) { squashfs_dir_entry_3 sdire; memcpy(&sdire, directory_table + bytes, sizeof(sdire)); SQUASHFS_SWAP_DIR_ENTRY_3(dire, &sdire); } else memcpy(dire, directory_table + bytes, sizeof(*dire)); bytes += sizeof(*dire); /* size should never be larger than SQUASHFS_NAME_LEN */ if (dire->size > SQUASHFS_NAME_LEN) goto corrupted; memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_opendir: directory entry %s, inode " "%d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); if ((dir->dir_count % DIR_ENT_SIZE) == 0) { new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent)); if (new_dir == NULL) EXIT_UNSQUASH("squashfs_opendir: " "realloc failed!\n"); dir->dirs = new_dir; } strcpy(dir->dirs[dir->dir_count].name, dire->name); dir->dirs[dir->dir_count].start_block = dirh.start_block; dir->dirs[dir->dir_count].offset = dire->offset; dir->dirs[dir->dir_count].type = dire->type; dir->dir_count++; bytes += dire->size + 1; } } return dir; corrupted: free(dir->dirs); free(dir); return NULL; } ================================================ FILE: src/squashfs/unsquash-4.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2009, 2010, 2011, 2012, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquash-4.c */ #include "unsquashfs.h" #include "squashfs_swap.h" static struct squashfs_fragment_entry *fragment_table; static unsigned int *id_table; int read_fragment_table_4(long long *directory_table_end) { int res, i; int bytes = SQUASHFS_FRAGMENT_BYTES(sBlk.s.fragments); int indexes = SQUASHFS_FRAGMENT_INDEXES(sBlk.s.fragments); long long fragment_table_index[indexes]; TRACE("read_fragment_table: %d fragments, reading %d fragment indexes " "from 0x%llx\n", sBlk.s.fragments, indexes, sBlk.s.fragment_table_start); if (sBlk.s.fragments == 0) { *directory_table_end = sBlk.s.fragment_table_start; return TRUE; } fragment_table = malloc(bytes); if (fragment_table == NULL) EXIT_UNSQUASH("read_fragment_table: failed to allocate " "fragment table\n"); res = read_fs_bytes(fd, sBlk.s.fragment_table_start, SQUASHFS_FRAGMENT_INDEX_BYTES(sBlk.s.fragments), fragment_table_index); if (res == FALSE) { ERROR("read_fragment_table: failed to read fragment table " "index\n"); return FALSE; } SQUASHFS_INSWAP_FRAGMENT_INDEXES(fragment_table_index, indexes); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); int length = read_block(fd, fragment_table_index[i], NULL, expected, ((char *)fragment_table) + (i * SQUASHFS_METADATA_SIZE)); TRACE("Read fragment table block %d, from 0x%llx, length %d\n", i, fragment_table_index[i], length); if (length == FALSE) { ERROR("read_fragment_table: failed to read fragment " "table index\n"); return FALSE; } } for (i = 0; i < sBlk.s.fragments; i++) SQUASHFS_INSWAP_FRAGMENT_ENTRY(&fragment_table[i]); *directory_table_end = fragment_table_index[0]; return TRUE; } void read_fragment_4(unsigned int fragment, long long *start_block, int *size) { TRACE("read_fragment: reading fragment %d\n", fragment); struct squashfs_fragment_entry *fragment_entry; fragment_entry = &fragment_table[fragment]; *start_block = fragment_entry->start_block; *size = fragment_entry->size; } struct inode *read_inode_4(unsigned int start_block, unsigned int offset) { static union squashfs_inode_header header; long long start = sBlk.s.inode_table_start + start_block; int bytes = lookup_entry(inode_table_hash, start); char *block_ptr = inode_table + bytes + offset; static struct inode i; TRACE("read_inode: reading inode [%d:%d]\n", start_block, offset); if (bytes == -1) EXIT_UNSQUASH("read_inode: inode table block %lld not found\n", start); SQUASHFS_SWAP_BASE_INODE_HEADER(block_ptr, &header.base); i.uid = (uid_t) id_table[header.base.uid]; i.gid = (uid_t) id_table[header.base.guid]; i.mode = lookup_type[header.base.inode_type] | header.base.mode; i.type = header.base.inode_type; i.time = header.base.mtime; i.inode_number = header.base.inode_number; switch (header.base.inode_type) { case SQUASHFS_DIR_TYPE:{ struct squashfs_dir_inode_header *inode = &header.dir; SQUASHFS_SWAP_DIR_INODE_HEADER(block_ptr, inode); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LDIR_TYPE:{ struct squashfs_ldir_inode_header *inode = &header.ldir; SQUASHFS_SWAP_LDIR_INODE_HEADER(block_ptr, inode); i.data = inode->file_size; i.offset = inode->offset; i.start = inode->start_block; i.xattr = inode->xattr; break; } case SQUASHFS_FILE_TYPE:{ struct squashfs_reg_inode_header *inode = &header.reg; SQUASHFS_SWAP_REG_INODE_HEADER(block_ptr, inode); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (i.data + sBlk.s.block_size - 1) >> sBlk.s.block_log : i.data >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = 0; i.block_ptr = block_ptr + sizeof(*inode); i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LREG_TYPE:{ struct squashfs_lreg_inode_header *inode = &header.lreg; SQUASHFS_SWAP_LREG_INODE_HEADER(block_ptr, inode); i.data = inode->file_size; i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG ? 0 : inode->file_size % sBlk.s.block_size; i.fragment = inode->fragment; i.offset = inode->offset; i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ? (inode->file_size + sBlk.s.block_size - 1) >> sBlk.s.block_log : inode->file_size >> sBlk.s.block_log; i.start = inode->start_block; i.sparse = inode->sparse != 0; i.block_ptr = block_ptr + sizeof(*inode); i.xattr = inode->xattr; break; } case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE:{ struct squashfs_symlink_inode_header *inode = &header.symlink; SQUASHFS_SWAP_SYMLINK_INODE_HEADER(block_ptr, inode); i.symlink = malloc(inode->symlink_size + 1); if (i.symlink == NULL) EXIT_UNSQUASH("read_inode: failed to malloc " "symlink data\n"); strncpy(i.symlink, block_ptr + sizeof(struct squashfs_symlink_inode_header), inode->symlink_size); i.symlink[inode->symlink_size] = '\0'; i.data = inode->symlink_size; if (header.base.inode_type == SQUASHFS_LSYMLINK_TYPE) SQUASHFS_SWAP_INTS(block_ptr + sizeof(struct squashfs_symlink_inode_header) + inode->symlink_size, &i.xattr, 1); else i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE:{ struct squashfs_dev_inode_header *inode = &header.dev; SQUASHFS_SWAP_DEV_INODE_HEADER(block_ptr, inode); i.data = inode->rdev; i.xattr = SQUASHFS_INVALID_XATTR; break; } case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE:{ struct squashfs_ldev_inode_header *inode = &header.ldev; SQUASHFS_SWAP_LDEV_INODE_HEADER(block_ptr, inode); i.data = inode->rdev; i.xattr = inode->xattr; break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_SOCKET_TYPE: i.data = 0; i.xattr = SQUASHFS_INVALID_XATTR; break; case SQUASHFS_LFIFO_TYPE: case SQUASHFS_LSOCKET_TYPE:{ struct squashfs_lipc_inode_header *inode = &header.lipc; SQUASHFS_SWAP_LIPC_INODE_HEADER(block_ptr, inode); i.data = 0; i.xattr = inode->xattr; break; } default: EXIT_UNSQUASH("Unknown inode type %d in read_inode!\n", header.base.inode_type); } return &i; } struct dir *squashfs_opendir_4(unsigned int block_start, unsigned int offset, struct inode **i) { struct squashfs_dir_header dirh; char buffer[sizeof(struct squashfs_dir_entry) + SQUASHFS_NAME_LEN + 1] __attribute__ ((aligned)); struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *)buffer; long long start; int bytes; int dir_count, size; struct dir_ent *new_dir; struct dir *dir; TRACE("squashfs_opendir: inode start block %d, offset %d\n", block_start, offset); *i = s_ops.read_inode(block_start, offset); dir = malloc(sizeof(struct dir)); if (dir == NULL) EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n"); dir->dir_count = 0; dir->cur_entry = 0; dir->mode = (*i)->mode; dir->uid = (*i)->uid; dir->guid = (*i)->gid; dir->mtime = (*i)->time; dir->xattr = (*i)->xattr; dir->dirs = NULL; if ((*i)->data == 3) /* * if the directory is empty, skip the unnecessary * lookup_entry, this fixes the corner case with * completely empty filesystems where lookup_entry correctly * returning -1 is incorrectly treated as an error */ return dir; start = sBlk.s.directory_table_start + (*i)->start; bytes = lookup_entry(directory_table_hash, start); if (bytes == -1) EXIT_UNSQUASH("squashfs_opendir: directory block %d not " "found!\n", block_start); bytes += (*i)->offset; size = (*i)->data + bytes - 3; while (bytes < size) { SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh); dir_count = dirh.count + 1; TRACE("squashfs_opendir: Read directory header @ byte position " "%d, %d directory entries\n", bytes, dir_count); bytes += sizeof(dirh); /* dir_count should never be larger than 256 */ if (dir_count > 256) goto corrupted; while (dir_count--) { SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire); bytes += sizeof(*dire); /* size should never be larger than SQUASHFS_NAME_LEN */ if (dire->size > SQUASHFS_NAME_LEN) goto corrupted; memcpy(dire->name, directory_table + bytes, dire->size + 1); dire->name[dire->size + 1] = '\0'; TRACE("squashfs_opendir: directory entry %s, inode " "%d:%d, type %d\n", dire->name, dirh.start_block, dire->offset, dire->type); if ((dir->dir_count % DIR_ENT_SIZE) == 0) { new_dir = realloc(dir->dirs, (dir->dir_count + DIR_ENT_SIZE) * sizeof(struct dir_ent)); if (new_dir == NULL) EXIT_UNSQUASH("squashfs_opendir: " "realloc failed!\n"); dir->dirs = new_dir; } strcpy(dir->dirs[dir->dir_count].name, dire->name); dir->dirs[dir->dir_count].start_block = dirh.start_block; dir->dirs[dir->dir_count].offset = dire->offset; dir->dirs[dir->dir_count].type = dire->type; dir->dir_count++; bytes += dire->size + 1; } } return dir; corrupted: free(dir->dirs); free(dir); return NULL; } int read_uids_guids_4() { int res, i; int bytes = SQUASHFS_ID_BYTES(sBlk.s.no_ids); int indexes = SQUASHFS_ID_BLOCKS(sBlk.s.no_ids); long long id_index_table[indexes]; TRACE("read_uids_guids: no_ids %d\n", sBlk.s.no_ids); id_table = malloc(bytes); if (id_table == NULL) { ERROR("read_uids_guids: failed to allocate id table\n"); return FALSE; } res = read_fs_bytes(fd, sBlk.s.id_table_start, SQUASHFS_ID_BLOCK_BYTES(sBlk.s.no_ids), id_index_table); if (res == FALSE) { ERROR("read_uids_guids: failed to read id index table\n"); return FALSE; } SQUASHFS_INSWAP_ID_BLOCKS(id_index_table, indexes); for (i = 0; i < indexes; i++) { int expected = (i + 1) != indexes ? SQUASHFS_METADATA_SIZE : bytes & (SQUASHFS_METADATA_SIZE - 1); res = read_block(fd, id_index_table[i], NULL, expected, ((char *)id_table) + i * SQUASHFS_METADATA_SIZE); if (res == FALSE) { ERROR("read_uids_guids: failed to read id table block" "\n"); return FALSE; } } SQUASHFS_INSWAP_INTS(id_table, sBlk.s.no_ids); return TRUE; } ================================================ FILE: src/squashfs/unsquashfs.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, * 2012, 2013, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquashfs.c */ #include "unsquashfs.h" #include "squashfs_swap.h" #include "squashfs_compat.h" #include "compressor.h" #include "xattr.h" #include "unsquashfs_info.h" #include "stdarg.h" #ifdef __APPLE__ # include #else # include #endif #include #include #include #include #include #include #include struct cache *fragment_cache, *data_cache; struct queue *to_reader, *to_inflate, *to_writer, *from_writer; pthread_t *thread, *inflator_thread; pthread_mutex_t fragment_mutex; /* user options that control parallelisation */ int processors = -1; struct super_block sBlk; squashfs_operations s_ops; struct compressor *comp; int bytes = 0, swap, file_count = 0, dir_count = 0, sym_count = 0, dev_count = 0, fifo_count = 0; char *inode_table = NULL, *directory_table = NULL; struct hash_table_entry *inode_table_hash[65536], *directory_table_hash[65536]; int fd; unsigned int *uid_table, *guid_table; unsigned int cached_frag = SQUASHFS_INVALID_FRAG; char *fragment_data; char *file_data; char *data; unsigned int block_size; unsigned int block_log; int lsonly = FALSE, info = FALSE, force = FALSE, short_ls = TRUE; int use_regex = FALSE; char **created_inode; int root_process; int columns; int rotate = 0; pthread_mutex_t screen_mutex; int progress = TRUE, progress_enabled = FALSE; unsigned int total_blocks = 0, total_files = 0, total_inodes = 0; unsigned int cur_blocks = 0; int inode_number = 1; int no_xattrs = XATTR_DEF; int user_xattrs = FALSE; int lookup_type[] = { 0, S_IFDIR, S_IFREG, S_IFLNK, S_IFBLK, S_IFCHR, S_IFIFO, S_IFSOCK, S_IFDIR, S_IFREG, S_IFLNK, S_IFBLK, S_IFCHR, S_IFIFO, S_IFSOCK }; struct test table[] = { {S_IFMT, S_IFSOCK, 0, 's'}, {S_IFMT, S_IFLNK, 0, 'l'}, {S_IFMT, S_IFBLK, 0, 'b'}, {S_IFMT, S_IFDIR, 0, 'd'}, {S_IFMT, S_IFCHR, 0, 'c'}, {S_IFMT, S_IFIFO, 0, 'p'}, {S_IRUSR, S_IRUSR, 1, 'r'}, {S_IWUSR, S_IWUSR, 2, 'w'}, {S_IRGRP, S_IRGRP, 4, 'r'}, {S_IWGRP, S_IWGRP, 5, 'w'}, {S_IROTH, S_IROTH, 7, 'r'}, {S_IWOTH, S_IWOTH, 8, 'w'}, {S_IXUSR | S_ISUID, S_IXUSR | S_ISUID, 3, 's'}, {S_IXUSR | S_ISUID, S_ISUID, 3, 'S'}, {S_IXUSR | S_ISUID, S_IXUSR, 3, 'x'}, {S_IXGRP | S_ISGID, S_IXGRP | S_ISGID, 6, 's'}, {S_IXGRP | S_ISGID, S_ISGID, 6, 'S'}, {S_IXGRP | S_ISGID, S_IXGRP, 6, 'x'}, {S_IXOTH | S_ISVTX, S_IXOTH | S_ISVTX, 9, 't'}, {S_IXOTH | S_ISVTX, S_ISVTX, 9, 'T'}, {S_IXOTH | S_ISVTX, S_IXOTH, 9, 'x'}, {0, 0, 0, 0} }; void progress_bar(long long current, long long max, int columns); #define MAX_LINE 16384 void prep_exit() { } void sigwinch_handler() { struct winsize winsize; if (ioctl(1, TIOCGWINSZ, &winsize) == -1) { if (isatty(STDOUT_FILENO)) ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " "columns\n"); columns = 80; } else columns = winsize.ws_col; } void sigalrm_handler() { rotate = (rotate + 1) % 4; } int add_overflow(int a, int b) { return (INT_MAX - a) < b; } int shift_overflow(int a, int shift) { return (INT_MAX >> shift) < a; } int multiply_overflow(int a, int multiplier) { return (INT_MAX / multiplier) < a; } struct queue *queue_init(int size) { struct queue *queue = malloc(sizeof(struct queue)); if (queue == NULL) EXIT_UNSQUASH("Out of memory in queue_init\n"); if (add_overflow(size, 1) || multiply_overflow(size + 1, sizeof(void *))) EXIT_UNSQUASH("Size too large in queue_init\n"); queue->data = malloc(sizeof(void *) * (size + 1)); if (queue->data == NULL) EXIT_UNSQUASH("Out of memory in queue_init\n"); queue->size = size + 1; queue->readp = queue->writep = 0; pthread_mutex_init(&queue->mutex, NULL); pthread_cond_init(&queue->empty, NULL); pthread_cond_init(&queue->full, NULL); return queue; } void queue_put(struct queue *queue, void *data) { int nextp; pthread_mutex_lock(&queue->mutex); while ((nextp = (queue->writep + 1) % queue->size) == queue->readp) pthread_cond_wait(&queue->full, &queue->mutex); queue->data[queue->writep] = data; queue->writep = nextp; pthread_cond_signal(&queue->empty); pthread_mutex_unlock(&queue->mutex); } void *queue_get(struct queue *queue) { void *data; pthread_mutex_lock(&queue->mutex); while (queue->readp == queue->writep) pthread_cond_wait(&queue->empty, &queue->mutex); data = queue->data[queue->readp]; queue->readp = (queue->readp + 1) % queue->size; pthread_cond_signal(&queue->full); pthread_mutex_unlock(&queue->mutex); return data; } void dump_queue(struct queue *queue) { pthread_mutex_lock(&queue->mutex); printf("Max size %d, size %d%s\n", queue->size - 1, queue->readp <= queue->writep ? queue->writep - queue->readp : queue->size - queue->readp + queue->writep, queue->readp == queue->writep ? " (EMPTY)" : ((queue->writep + 1) % queue->size) == queue->readp ? " (FULL)" : ""); pthread_mutex_unlock(&queue->mutex); } /* Called with the cache mutex held */ void insert_hash_table(struct cache *cache, struct cache_entry *entry) { int hash = CALCULATE_HASH(entry->block); entry->hash_next = cache->hash_table[hash]; cache->hash_table[hash] = entry; entry->hash_prev = NULL; if (entry->hash_next) entry->hash_next->hash_prev = entry; } /* Called with the cache mutex held */ void remove_hash_table(struct cache *cache, struct cache_entry *entry) { if (entry->hash_prev) entry->hash_prev->hash_next = entry->hash_next; else cache->hash_table[CALCULATE_HASH(entry->block)] = entry->hash_next; if (entry->hash_next) entry->hash_next->hash_prev = entry->hash_prev; entry->hash_prev = entry->hash_next = NULL; } /* Called with the cache mutex held */ void insert_free_list(struct cache *cache, struct cache_entry *entry) { if (cache->free_list) { entry->free_next = cache->free_list; entry->free_prev = cache->free_list->free_prev; cache->free_list->free_prev->free_next = entry; cache->free_list->free_prev = entry; } else { cache->free_list = entry; entry->free_prev = entry->free_next = entry; } } /* Called with the cache mutex held */ void remove_free_list(struct cache *cache, struct cache_entry *entry) { if (entry->free_prev == NULL || entry->free_next == NULL) /* not in free list */ return; else if (entry->free_prev == entry && entry->free_next == entry) { /* only this entry in the free list */ cache->free_list = NULL; } else { /* more than one entry in the free list */ entry->free_next->free_prev = entry->free_prev; entry->free_prev->free_next = entry->free_next; if (cache->free_list == entry) cache->free_list = entry->free_next; } entry->free_prev = entry->free_next = NULL; } struct cache *cache_init(int buffer_size, int max_buffers) { struct cache *cache = malloc(sizeof(struct cache)); if (cache == NULL) EXIT_UNSQUASH("Out of memory in cache_init\n"); cache->max_buffers = max_buffers; cache->buffer_size = buffer_size; cache->count = 0; cache->used = 0; cache->free_list = NULL; memset(cache->hash_table, 0, sizeof(struct cache_entry *) * 65536); cache->wait_free = FALSE; cache->wait_pending = FALSE; pthread_mutex_init(&cache->mutex, NULL); pthread_cond_init(&cache->wait_for_free, NULL); pthread_cond_init(&cache->wait_for_pending, NULL); return cache; } struct cache_entry *cache_get(struct cache *cache, long long block, int size) { /* * Get a block out of the cache. If the block isn't in the cache * it is added and queued to the reader() and inflate() threads for * reading off disk and decompression. The cache grows until max_blocks * is reached, once this occurs existing discarded blocks on the free * list are reused */ int hash = CALCULATE_HASH(block); struct cache_entry *entry; pthread_mutex_lock(&cache->mutex); for (entry = cache->hash_table[hash]; entry; entry = entry->hash_next) if (entry->block == block) break; if (entry) { /* * found the block in the cache. If the block is currently unused * remove it from the free list and increment cache used count. */ if (entry->used == 0) { cache->used++; remove_free_list(cache, entry); } entry->used++; pthread_mutex_unlock(&cache->mutex); } else { /* * not in the cache * * first try to allocate new block */ if (cache->count < cache->max_buffers) { entry = malloc(sizeof(struct cache_entry)); if (entry == NULL) EXIT_UNSQUASH("Out of memory in cache_get\n"); entry->data = malloc(cache->buffer_size); if (entry->data == NULL) EXIT_UNSQUASH("Out of memory in cache_get\n"); entry->cache = cache; entry->free_prev = entry->free_next = NULL; cache->count++; } else { /* * try to get from free list */ while (cache->free_list == NULL) { cache->wait_free = TRUE; pthread_cond_wait(&cache->wait_for_free, &cache->mutex); } entry = cache->free_list; remove_free_list(cache, entry); remove_hash_table(cache, entry); } /* * Initialise block and insert into the hash table. * Increment used which tracks how many buffers in the * cache are actively in use (the other blocks, count - used, * are in the cache and available for lookup, but can also be * re-used). */ entry->block = block; entry->size = size; entry->used = 1; entry->error = FALSE; entry->pending = TRUE; insert_hash_table(cache, entry); cache->used++; /* * queue to read thread to read and ultimately (via the * decompress threads) decompress the buffer */ pthread_mutex_unlock(&cache->mutex); queue_put(to_reader, entry); } return entry; } void cache_block_ready(struct cache_entry *entry, int error) { /* * mark cache entry as being complete, reading and (if necessary) * decompression has taken place, and the buffer is valid for use. * If an error occurs reading or decompressing, the buffer also * becomes ready but with an error... */ pthread_mutex_lock(&entry->cache->mutex); entry->pending = FALSE; entry->error = error; /* * if the wait_pending flag is set, one or more threads may be waiting * on this buffer */ if (entry->cache->wait_pending) { entry->cache->wait_pending = FALSE; pthread_cond_broadcast(&entry->cache->wait_for_pending); } pthread_mutex_unlock(&entry->cache->mutex); } void cache_block_wait(struct cache_entry *entry) { /* * wait for this cache entry to become ready, when reading and (if * necessary) decompression has taken place */ pthread_mutex_lock(&entry->cache->mutex); while (entry->pending) { entry->cache->wait_pending = TRUE; pthread_cond_wait(&entry->cache->wait_for_pending, &entry->cache->mutex); } pthread_mutex_unlock(&entry->cache->mutex); } void cache_block_put(struct cache_entry *entry) { /* * finished with this cache entry, once the usage count reaches zero it * can be reused and is put onto the free list. As it remains * accessible via the hash table it can be found getting a new lease of * life before it is reused. */ pthread_mutex_lock(&entry->cache->mutex); entry->used--; if (entry->used == 0) { insert_free_list(entry->cache, entry); entry->cache->used--; /* * if the wait_free flag is set, one or more threads may be * waiting on this buffer */ if (entry->cache->wait_free) { entry->cache->wait_free = FALSE; pthread_cond_broadcast(&entry->cache->wait_for_free); } } pthread_mutex_unlock(&entry->cache->mutex); } void dump_cache(struct cache *cache) { pthread_mutex_lock(&cache->mutex); printf("Max buffers %d, Current size %d, Used %d, %s\n", cache->max_buffers, cache->count, cache->used, cache->free_list ? "Free buffers" : "No free buffers"); pthread_mutex_unlock(&cache->mutex); } char *modestr(char *str, int mode) { int i; strcpy(str, "----------"); for (i = 0; table[i].mask != 0; i++) { if ((mode & table[i].mask) == table[i].value) str[table[i].position] = table[i].mode; } return str; } #define TOTALCHARS 25 int print_filename(char *pathname, struct inode *inode) { char str[11], dummy[12], dummy2[12]; /* overflow safe */ char *userstr, *groupstr; int padchars; struct passwd *user; struct group *group; struct tm *t; if (short_ls) { printf("%s\n", pathname); return 1; } user = getpwuid(inode->uid); if (user == NULL) { int res = snprintf(dummy, 12, "%d", inode->uid); if (res < 0) EXIT_UNSQUASH("snprintf failed in print_filename()\n"); else if (res >= 12) /* unsigned int shouldn't ever need more than 11 bytes * (including terminating '\0') to print in base 10 */ userstr = "*"; else userstr = dummy; } else userstr = user->pw_name; group = getgrgid(inode->gid); if (group == NULL) { int res = snprintf(dummy2, 12, "%d", inode->gid); if (res < 0) EXIT_UNSQUASH("snprintf failed in print_filename()\n"); else if (res >= 12) /* unsigned int shouldn't ever need more than 11 bytes * (including terminating '\0') to print in base 10 */ groupstr = "*"; else groupstr = dummy2; } else groupstr = group->gr_name; printf("%s %s/%s ", modestr(str, inode->mode), userstr, groupstr); switch (inode->mode & S_IFMT) { case S_IFREG: case S_IFDIR: case S_IFSOCK: case S_IFIFO: case S_IFLNK: padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr); printf("%*lld ", padchars > 0 ? padchars : 0, inode->data); break; case S_IFCHR: case S_IFBLK: padchars = TOTALCHARS - strlen(userstr) - strlen(groupstr) - 7; printf("%*s%3d,%3d ", padchars > 0 ? padchars : 0, " ", (int)inode->data >> 8, (int)inode->data & 0xff); break; } t = localtime(&inode->time); printf("%d-%02d-%02d %02d:%02d %s", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, pathname); if ((inode->mode & S_IFMT) == S_IFLNK) printf(" -> %s", inode->symlink); printf("\n"); return 1; } void add_entry(struct hash_table_entry *hash_table[], long long start, int bytes) { int hash = CALCULATE_HASH(start); struct hash_table_entry *hash_table_entry; hash_table_entry = malloc(sizeof(struct hash_table_entry)); if (hash_table_entry == NULL) EXIT_UNSQUASH("Out of memory in add_entry\n"); hash_table_entry->start = start; hash_table_entry->bytes = bytes; hash_table_entry->next = hash_table[hash]; hash_table[hash] = hash_table_entry; } int lookup_entry(struct hash_table_entry *hash_table[], long long start) { int hash = CALCULATE_HASH(start); struct hash_table_entry *hash_table_entry; for (hash_table_entry = hash_table[hash]; hash_table_entry; hash_table_entry = hash_table_entry->next) if (hash_table_entry->start == start) return hash_table_entry->bytes; return -1; } int read_fs_bytes(int fd, long long byte, int bytes, void *buff) { off_t off = byte; int res, count; TRACE("read_bytes: reading from position 0x%llx, bytes %d\n", byte, bytes); if (lseek(fd, off, SEEK_SET) == -1) { ERROR("Lseek failed because %s\n", strerror(errno)); return FALSE; } for (count = 0; count < bytes; count += res) { res = read(fd, buff + count, bytes - count); if (res < 1) { if (res == 0) { ERROR("Read on filesystem failed because " "EOF\n"); return FALSE; } else if (errno != EINTR) { ERROR("Read on filesystem failed because %s\n", strerror(errno)); return FALSE; } else res = 0; } } return TRUE; } int read_block(int fd, long long start, long long *next, int expected, void *block) { unsigned short c_byte; int offset = 2, res, compressed; int outlen = expected ? expected : SQUASHFS_METADATA_SIZE; if (swap) { if (read_fs_bytes(fd, start, 2, &c_byte) == FALSE) goto failed; c_byte = (c_byte >> 8) | ((c_byte & 0xff) << 8); } else if (read_fs_bytes(fd, start, 2, &c_byte) == FALSE) goto failed; TRACE("read_block: block @0x%llx, %d %s bytes\n", start, SQUASHFS_COMPRESSED_SIZE(c_byte), SQUASHFS_COMPRESSED(c_byte) ? "compressed" : "uncompressed"); if (SQUASHFS_CHECK_DATA(sBlk.s.flags)) offset = 3; compressed = SQUASHFS_COMPRESSED(c_byte); c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte); /* * The block size should not be larger than * the uncompressed size (or max uncompressed size if * expected is 0) */ if (c_byte > outlen) return 0; if (compressed) { char buffer[c_byte]; int error; res = read_fs_bytes(fd, start + offset, c_byte, buffer); if (res == FALSE) goto failed; res = compressor_uncompress(comp, block, buffer, c_byte, outlen, &error); if (res == -1) { ERROR("%s uncompress failed with error code %d\n", comp->name, error); goto failed; } } else { res = read_fs_bytes(fd, start + offset, c_byte, block); if (res == FALSE) goto failed; res = c_byte; } if (next) *next = start + offset + c_byte; /* * if expected, then check the (uncompressed) return data * is of the expected size */ if (expected && expected != res) return 0; else return res; failed: ERROR("read_block: failed to read block @0x%llx\n", start); return FALSE; } int read_data_block(long long start, unsigned int size, char *block) { int error, res; int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(size); TRACE("read_data_block: block @0x%llx, %d %s bytes\n", start, c_byte, SQUASHFS_COMPRESSED_BLOCK(size) ? "compressed" : "uncompressed"); if (SQUASHFS_COMPRESSED_BLOCK(size)) { if (read_fs_bytes(fd, start, c_byte, data) == FALSE) goto failed; res = compressor_uncompress(comp, block, data, c_byte, block_size, &error); if (res == -1) { ERROR("%s uncompress failed with error code %d\n", comp->name, error); goto failed; } return res; } else { if (read_fs_bytes(fd, start, c_byte, block) == FALSE) goto failed; return c_byte; } failed: ERROR("read_data_block: failed to read block @0x%llx, size %d\n", start, c_byte); return FALSE; } int read_inode_table(long long start, long long end) { int size = 0, bytes = 0, res; TRACE("read_inode_table: start %lld, end %lld\n", start, end); while (start < end) { if (size - bytes < SQUASHFS_METADATA_SIZE) { inode_table = realloc(inode_table, size += SQUASHFS_METADATA_SIZE); if (inode_table == NULL) { ERROR("Out of memory in read_inode_table"); goto failed; } } add_entry(inode_table_hash, start, bytes); res = read_block(fd, start, &start, 0, inode_table + bytes); if (res == 0) { ERROR("read_inode_table: failed to read block\n"); goto failed; } bytes += res; /* * If this is not the last metadata block in the inode table * then it should be SQUASHFS_METADATA_SIZE in size. * Note, we can't use expected in read_block() above for this * because we don't know if this is the last block until * after reading. */ if (start != end && res != SQUASHFS_METADATA_SIZE) { ERROR("read_inode_table: metadata block should be %d " "bytes in length, it is %d bytes\n", SQUASHFS_METADATA_SIZE, res); goto failed; } } return TRUE; failed: free(inode_table); return FALSE; } int set_attributes(char *pathname, int mode, uid_t uid, gid_t guid, time_t time, unsigned int xattr, unsigned int set_mode) { struct utimbuf times = { time, time }; write_xattr(pathname, xattr); if (utime(pathname, ×) == -1) { ERROR("set_attributes: failed to set time on %s, because %s\n", pathname, strerror(errno)); return FALSE; } if (root_process) { if (chown(pathname, uid, guid) == -1) { ERROR("set_attributes: failed to change uid and gids " "on %s, because %s\n", pathname, strerror(errno)); return FALSE; } } else mode &= ~07000; if ((set_mode || (mode & 07000)) && chmod(pathname, (mode_t) mode) == -1) { ERROR("set_attributes: failed to change mode %s, because %s\n", pathname, strerror(errno)); return FALSE; } return TRUE; } int write_bytes(int fd, char *buff, int bytes) { int res, count; for (count = 0; count < bytes; count += res) { res = write(fd, buff + count, bytes - count); if (res == -1) { if (errno != EINTR) { ERROR("Write on output file failed because " "%s\n", strerror(errno)); return -1; } res = 0; } } return 0; } int lseek_broken = FALSE; char *zero_data = NULL; int write_block(int file_fd, char *buffer, int size, long long hole, int sparse) { off_t off = hole; if (hole) { if (sparse && lseek_broken == FALSE) { int error = lseek(file_fd, off, SEEK_CUR); if (error == -1) /* failed to seek beyond end of file */ lseek_broken = TRUE; } if ((sparse == FALSE || lseek_broken) && zero_data == NULL) { if ((zero_data = malloc(block_size)) == NULL) EXIT_UNSQUASH("write_block: failed to alloc " "zero data block\n"); memset(zero_data, 0, block_size); } if (sparse == FALSE || lseek_broken) { int blocks = (hole + block_size - 1) / block_size; int avail_bytes, i; for (i = 0; i < blocks; i++, hole -= avail_bytes) { avail_bytes = hole > block_size ? block_size : hole; if (write_bytes(file_fd, zero_data, avail_bytes) == -1) goto failure; } } } if (write_bytes(file_fd, buffer, size) == -1) goto failure; return TRUE; failure: return FALSE; } pthread_mutex_t open_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t open_empty = PTHREAD_COND_INITIALIZER; int open_unlimited, open_count; void open_init(int count) { open_count = count; open_unlimited = count == -1; } int open_wait(char *pathname, int flags, mode_t mode) { if (!open_unlimited) { pthread_mutex_lock(&open_mutex); while (open_count == 0) pthread_cond_wait(&open_empty, &open_mutex); open_count--; pthread_mutex_unlock(&open_mutex); } return open(pathname, flags, mode); } void close_wake(int fd) { close(fd); if (!open_unlimited) { pthread_mutex_lock(&open_mutex); open_count++; pthread_cond_signal(&open_empty); pthread_mutex_unlock(&open_mutex); } } void queue_file(char *pathname, int file_fd, struct inode *inode) { struct squashfs_file *file = malloc(sizeof(struct squashfs_file)); if (file == NULL) EXIT_UNSQUASH("queue_file: unable to malloc file\n"); file->fd = file_fd; file->file_size = inode->data; file->mode = inode->mode; file->gid = inode->gid; file->uid = inode->uid; file->time = inode->time; file->pathname = strdup(pathname); file->blocks = inode->blocks + (inode->frag_bytes > 0); file->sparse = inode->sparse; file->xattr = inode->xattr; queue_put(to_writer, file); } void queue_dir(char *pathname, struct dir *dir) { struct squashfs_file *file = malloc(sizeof(struct squashfs_file)); if (file == NULL) EXIT_UNSQUASH("queue_dir: unable to malloc file\n"); file->fd = -1; file->mode = dir->mode; file->gid = dir->guid; file->uid = dir->uid; file->time = dir->mtime; file->pathname = strdup(pathname); file->xattr = dir->xattr; queue_put(to_writer, file); } int write_file(struct inode *inode, char *pathname) { unsigned int file_fd, i; unsigned int *block_list; int file_end = inode->data / block_size; long long start = inode->start; TRACE("write_file: regular file, blocks %d\n", inode->blocks); file_fd = open_wait(pathname, O_CREAT | O_WRONLY | (force ? O_TRUNC : 0), (mode_t) inode->mode & 0777); if (file_fd == -1) { ERROR("write_file: failed to create file %s, because %s\n", pathname, strerror(errno)); return FALSE; } block_list = malloc(inode->blocks * sizeof(unsigned int)); if (block_list == NULL) EXIT_UNSQUASH("write_file: unable to malloc block list\n"); s_ops.read_block_list(block_list, inode->block_ptr, inode->blocks); /* * the writer thread is queued a squashfs_file structure describing the * file. If the file has one or more blocks or a fragment they are * queued separately (references to blocks in the cache). */ queue_file(pathname, file_fd, inode); for (i = 0; i < inode->blocks; i++) { int c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(block_list[i]); struct file_entry *block = malloc(sizeof(struct file_entry)); if (block == NULL) EXIT_UNSQUASH("write_file: unable to malloc file\n"); block->offset = 0; block->size = i == file_end ? inode->data & (block_size - 1) : block_size; if (block_list[i] == 0) /* sparse block */ block->buffer = NULL; else { block->buffer = cache_get(data_cache, start, block_list[i]); start += c_byte; } queue_put(to_writer, block); } if (inode->frag_bytes) { int size; long long start; struct file_entry *block = malloc(sizeof(struct file_entry)); if (block == NULL) EXIT_UNSQUASH("write_file: unable to malloc file\n"); s_ops.read_fragment(inode->fragment, &start, &size); block->buffer = cache_get(fragment_cache, start, size); block->offset = inode->offset; block->size = inode->frag_bytes; queue_put(to_writer, block); } free(block_list); return TRUE; } int create_inode(char *pathname, struct inode *i) { TRACE("create_inode: pathname %s\n", pathname); if (created_inode[i->inode_number - 1]) { TRACE("create_inode: hard link\n"); if (force) unlink(pathname); if (link(created_inode[i->inode_number - 1], pathname) == -1) { ERROR("create_inode: failed to create hardlink, " "because %s\n", strerror(errno)); return FALSE; } return TRUE; } switch (i->type) { case SQUASHFS_FILE_TYPE: case SQUASHFS_LREG_TYPE: TRACE("create_inode: regular file, file_size %lld, " "blocks %d\n", i->data, i->blocks); if (write_file(i, pathname)) file_count++; break; case SQUASHFS_SYMLINK_TYPE: case SQUASHFS_LSYMLINK_TYPE: TRACE("create_inode: symlink, symlink_size %lld\n", i->data); if (force) unlink(pathname); if (symlink(i->symlink, pathname) == -1) { ERROR("create_inode: failed to create symlink " "%s, because %s\n", pathname, strerror(errno)); break; } write_xattr(pathname, i->xattr); if (root_process) { if (lchown(pathname, i->uid, i->gid) == -1) ERROR("create_inode: failed to change " "uid and gids on %s, because " "%s\n", pathname, strerror(errno)); } sym_count++; break; case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: case SQUASHFS_LBLKDEV_TYPE: case SQUASHFS_LCHRDEV_TYPE:{ int chrdev = i->type == SQUASHFS_CHRDEV_TYPE; TRACE("create_inode: dev, rdev 0x%llx\n", i->data); if (root_process) { if (force) unlink(pathname); if (mknod(pathname, chrdev ? S_IFCHR : S_IFBLK, makedev((i->data >> 8) & 0xff, i->data & 0xff)) == -1) { ERROR("create_inode: failed to create " "%s device %s, because %s\n", chrdev ? "character" : "block", pathname, strerror(errno)); break; } set_attributes(pathname, i->mode, i->uid, i->gid, i->time, i->xattr, TRUE); dev_count++; } else ERROR("create_inode: could not create %s " "device %s, because you're not " "superuser!\n", chrdev ? "character" : "block", pathname); break; } case SQUASHFS_FIFO_TYPE: case SQUASHFS_LFIFO_TYPE: TRACE("create_inode: fifo\n"); if (force) unlink(pathname); if (mknod(pathname, S_IFIFO, 0) == -1) { ERROR("create_inode: failed to create fifo %s, " "because %s\n", pathname, strerror(errno)); break; } set_attributes(pathname, i->mode, i->uid, i->gid, i->time, i->xattr, TRUE); fifo_count++; break; case SQUASHFS_SOCKET_TYPE: case SQUASHFS_LSOCKET_TYPE: TRACE("create_inode: socket\n"); ERROR("create_inode: socket %s ignored\n", pathname); break; default: ERROR("Unknown inode type %d in create_inode_table!\n", i->type); return FALSE; } created_inode[i->inode_number - 1] = strdup(pathname); return TRUE; } int read_directory_table(long long start, long long end) { int bytes = 0, size = 0, res; TRACE("read_directory_table: start %lld, end %lld\n", start, end); while (start < end) { if (size - bytes < SQUASHFS_METADATA_SIZE) { directory_table = realloc(directory_table, size += SQUASHFS_METADATA_SIZE); if (directory_table == NULL) { ERROR("Out of memory in " "read_directory_table\n"); goto failed; } } add_entry(directory_table_hash, start, bytes); res = read_block(fd, start, &start, 0, directory_table + bytes); if (res == 0) { ERROR("read_directory_table: failed to read block\n"); goto failed; } bytes += res; /* * If this is not the last metadata block in the directory table * then it should be SQUASHFS_METADATA_SIZE in size. * Note, we can't use expected in read_block() above for this * because we don't know if this is the last block until * after reading. */ if (start != end && res != SQUASHFS_METADATA_SIZE) { ERROR("read_directory_table: metadata block " "should be %d bytes in length, it is %d " "bytes\n", SQUASHFS_METADATA_SIZE, res); goto failed; } } return TRUE; failed: free(directory_table); return FALSE; } int squashfs_readdir(struct dir *dir, char **name, unsigned int *start_block, unsigned int *offset, unsigned int *type) { if (dir->cur_entry == dir->dir_count) return FALSE; *name = dir->dirs[dir->cur_entry].name; *start_block = dir->dirs[dir->cur_entry].start_block; *offset = dir->dirs[dir->cur_entry].offset; *type = dir->dirs[dir->cur_entry].type; dir->cur_entry++; return TRUE; } void squashfs_closedir(struct dir *dir) { free(dir->dirs); free(dir); } char *get_component(char *target, char **targname) { char *start; while (*target == '/') target++; start = target; while (*target != '/' && *target != '\0') target++; *targname = strndup(start, target - start); while (*target == '/') target++; return target; } void free_path(struct pathname *paths) { int i; for (i = 0; i < paths->names; i++) { if (paths->name[i].paths) free_path(paths->name[i].paths); free(paths->name[i].name); if (paths->name[i].preg) { regfree(paths->name[i].preg); free(paths->name[i].preg); } } free(paths); } struct pathname *add_path(struct pathname *paths, char *target, char *alltarget) { char *targname; int i, error; TRACE("add_path: adding \"%s\" extract file\n", target); target = get_component(target, &targname); if (paths == NULL) { paths = malloc(sizeof(struct pathname)); if (paths == NULL) EXIT_UNSQUASH("failed to allocate paths\n"); paths->names = 0; paths->name = NULL; } for (i = 0; i < paths->names; i++) if (strcmp(paths->name[i].name, targname) == 0) break; if (i == paths->names) { /* * allocate new name entry */ paths->names++; paths->name = realloc(paths->name, (i + 1) * sizeof(struct path_entry)); if (paths->name == NULL) EXIT_UNSQUASH("Out of memory in add_path\n"); paths->name[i].name = targname; paths->name[i].paths = NULL; if (use_regex) { paths->name[i].preg = malloc(sizeof(regex_t)); if (paths->name[i].preg == NULL) EXIT_UNSQUASH("Out of memory in add_path\n"); error = regcomp(paths->name[i].preg, targname, REG_EXTENDED | REG_NOSUB); if (error) { char str[1024]; /* overflow safe */ regerror(error, paths->name[i].preg, str, 1024); EXIT_UNSQUASH("invalid regex %s in export %s, " "because %s\n", targname, alltarget, str); } } else paths->name[i].preg = NULL; if (target[0] == '\0') /* * at leaf pathname component */ paths->name[i].paths = NULL; else /* * recurse adding child components */ paths->name[i].paths = add_path(NULL, target, alltarget); } else { /* * existing matching entry */ free(targname); if (paths->name[i].paths == NULL) { /* * No sub-directory which means this is the leaf * component of a pre-existing extract which subsumes * the extract currently being added, in which case stop * adding components */ } else if (target[0] == '\0') { /* * at leaf pathname component and child components exist * from more specific extracts, delete as they're * subsumed by this extract */ free_path(paths->name[i].paths); paths->name[i].paths = NULL; } else /* * recurse adding child components */ add_path(paths->name[i].paths, target, alltarget); } return paths; } struct pathnames *init_subdir() { struct pathnames *new = malloc(sizeof(struct pathnames)); if (new == NULL) EXIT_UNSQUASH("Out of memory in init_subdir\n"); new->count = 0; return new; } struct pathnames *add_subdir(struct pathnames *paths, struct pathname *path) { if (paths->count % PATHS_ALLOC_SIZE == 0) { paths = realloc(paths, sizeof(struct pathnames *) + (paths->count + PATHS_ALLOC_SIZE) * sizeof(struct pathname *)); if (paths == NULL) EXIT_UNSQUASH("Out of memory in add_subdir\n"); } paths->path[paths->count++] = path; return paths; } void free_subdir(struct pathnames *paths) { free(paths); } int matches(struct pathnames *paths, char *name, struct pathnames **new) { int i, n; if (paths == NULL) { *new = NULL; return TRUE; } *new = init_subdir(); for (n = 0; n < paths->count; n++) { struct pathname *path = paths->path[n]; for (i = 0; i < path->names; i++) { int match = use_regex ? regexec(path->name[i].preg, name, (size_t) 0, NULL, 0) == 0 : fnmatch(path->name[i].name, name, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0; if (match && path->name[i].paths == NULL) /* * match on a leaf component, any subdirectories * will implicitly match, therefore return an * empty new search set */ goto empty_set; if (match) /* * match on a non-leaf component, add any * subdirectories to the new set of * subdirectories to scan for this name */ *new = add_subdir(*new, path->name[i].paths); } } if ((*new)->count == 0) { /* * no matching names found, delete empty search set, and return * FALSE */ free_subdir(*new); *new = NULL; return FALSE; } /* * one or more matches with sub-directories found (no leaf matches), * return new search set and return TRUE */ return TRUE; empty_set: /* * found matching leaf exclude, return empty search set and return TRUE */ free_subdir(*new); *new = NULL; return TRUE; } void pre_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths) { unsigned int type; char *name; struct pathnames *new; struct inode *i; struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); if (dir == NULL) return; while (squashfs_readdir(dir, &name, &start_block, &offset, &type)) { struct inode *i; char *pathname; int res; TRACE("pre_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); if (!matches(paths, name, &new)) continue; res = asprintf(&pathname, "%s/%s", parent_name, name); if (res == -1) EXIT_UNSQUASH("asprintf failed in dir_scan\n"); if (type == SQUASHFS_DIR_TYPE) pre_scan(parent_name, start_block, offset, new); else if (new == NULL) { if (type == SQUASHFS_FILE_TYPE || type == SQUASHFS_LREG_TYPE) { i = s_ops.read_inode(start_block, offset); if (created_inode[i->inode_number - 1] == NULL) { created_inode[i->inode_number - 1] = (char *)i; total_blocks += (i->data + (block_size - 1)) >> block_log; } total_files++; } total_inodes++; } free_subdir(new); free(pathname); } squashfs_closedir(dir); } void dir_scan(char *parent_name, unsigned int start_block, unsigned int offset, struct pathnames *paths) { unsigned int type; char *name; struct pathnames *new; struct inode *i; struct dir *dir = s_ops.squashfs_opendir(start_block, offset, &i); if (dir == NULL) { ERROR("dir_scan: failed to read directory %s, skipping\n", parent_name); return; } if (lsonly || info) print_filename(parent_name, i); if (!lsonly) { /* * Make directory with default User rwx permissions rather than * the permissions from the filesystem, as these may not have * write/execute permission. These are fixed up later in * set_attributes(). */ int res = mkdir(parent_name, S_IRUSR | S_IWUSR | S_IXUSR); if (res == -1) { /* * Skip directory if mkdir fails, unless we're * forcing and the error is -EEXIST */ if (!force || errno != EEXIST) { ERROR("dir_scan: failed to make directory %s, " "because %s\n", parent_name, strerror(errno)); squashfs_closedir(dir); return; } /* * Try to change permissions of existing directory so * that we can write to it */ res = chmod(parent_name, S_IRUSR | S_IWUSR | S_IXUSR); if (res == -1) ERROR("dir_scan: failed to change permissions " "for directory %s, because %s\n", parent_name, strerror(errno)); } } while (squashfs_readdir(dir, &name, &start_block, &offset, &type)) { char *pathname; int res; TRACE("dir_scan: name %s, start_block %d, offset %d, type %d\n", name, start_block, offset, type); if (!matches(paths, name, &new)) continue; res = asprintf(&pathname, "%s/%s", parent_name, name); if (res == -1) EXIT_UNSQUASH("asprintf failed in dir_scan\n"); if (type == SQUASHFS_DIR_TYPE) { dir_scan(pathname, start_block, offset, new); free(pathname); } else if (new == NULL) { update_info(pathname); i = s_ops.read_inode(start_block, offset); if (lsonly || info) print_filename(pathname, i); if (!lsonly) create_inode(pathname, i); if (i->type == SQUASHFS_SYMLINK_TYPE || i->type == SQUASHFS_LSYMLINK_TYPE) free(i->symlink); } else free(pathname); free_subdir(new); } if (!lsonly) queue_dir(parent_name, dir); squashfs_closedir(dir); dir_count++; } void squashfs_stat(char *source) { time_t mkfs_time = (time_t) sBlk.s.mkfs_time; char *mkfs_str = ctime(&mkfs_time); #if __BYTE_ORDER == __BIG_ENDIAN printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s.s_major == 4 ? "" : swap ? "little endian " : "big endian ", sBlk.s.s_major, sBlk.s.s_minor, source); #else printf("Found a valid %sSQUASHFS %d:%d superblock on %s.\n", sBlk.s.s_major == 4 ? "" : swap ? "big endian " : "little endian ", sBlk.s.s_major, sBlk.s.s_minor, source); #endif printf("Creation or last append time %s", mkfs_str ? mkfs_str : "failed to get time\n"); printf("Filesystem size %.2f Kbytes (%.2f Mbytes)\n", sBlk.s.bytes_used / 1024.0, sBlk.s.bytes_used / (1024.0 * 1024.0)); if (sBlk.s.s_major == 4) { printf("Compression %s\n", comp->name); if (SQUASHFS_COMP_OPTS(sBlk.s.flags)) { char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); int bytes; bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer); if (bytes == 0) { ERROR("Failed to read compressor options\n"); return; } compressor_display_options(comp, buffer, bytes); } } printf("Block size %d\n", sBlk.s.block_size); printf("Filesystem is %sexportable via NFS\n", SQUASHFS_EXPORTABLE(sBlk.s.flags) ? "" : "not "); printf("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(sBlk.s.flags) ? "un" : ""); printf("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(sBlk.s.flags) ? "un" : ""); if (sBlk.s.s_major > 1) { if (SQUASHFS_NO_FRAGMENTS(sBlk.s.flags)) printf("Fragments are not stored\n"); else { printf("Fragments are %scompressed\n", SQUASHFS_UNCOMPRESSED_FRAGMENTS(sBlk.s.flags) ? "un" : ""); printf("Always-use-fragments option is %sspecified\n", SQUASHFS_ALWAYS_FRAGMENTS(sBlk.s.flags) ? "" : "not "); } } if (sBlk.s.s_major == 4) { if (SQUASHFS_NO_XATTRS(sBlk.s.flags)) printf("Xattrs are not stored\n"); else printf("Xattrs are %scompressed\n", SQUASHFS_UNCOMPRESSED_XATTRS(sBlk.s.flags) ? "un" : ""); } if (sBlk.s.s_major < 4) printf("Check data is %spresent in the filesystem\n", SQUASHFS_CHECK_DATA(sBlk.s.flags) ? "" : "not "); if (sBlk.s.s_major > 1) printf("Duplicates are %sremoved\n", SQUASHFS_DUPLICATES(sBlk.s.flags) ? "" : "not "); else printf("Duplicates are removed\n"); if (sBlk.s.s_major > 1) printf("Number of fragments %d\n", sBlk.s.fragments); printf("Number of inodes %d\n", sBlk.s.inodes); if (sBlk.s.s_major == 4) printf("Number of ids %d\n", sBlk.s.no_ids); else { printf("Number of uids %d\n", sBlk.no_uids); printf("Number of gids %d\n", sBlk.no_guids); } TRACE("sBlk.s.inode_table_start 0x%llx\n", sBlk.s.inode_table_start); TRACE("sBlk.s.directory_table_start 0x%llx\n", sBlk.s.directory_table_start); if (sBlk.s.s_major > 1) TRACE("sBlk.s.fragment_table_start 0x%llx\n\n", sBlk.s.fragment_table_start); if (sBlk.s.s_major > 2) TRACE("sBlk.s.lookup_table_start 0x%llx\n\n", sBlk.s.lookup_table_start); if (sBlk.s.s_major == 4) { TRACE("sBlk.s.id_table_start 0x%llx\n", sBlk.s.id_table_start); TRACE("sBlk.s.xattr_id_table_start 0x%llx\n", sBlk.s.xattr_id_table_start); } else { TRACE("sBlk.uid_start 0x%llx\n", sBlk.uid_start); TRACE("sBlk.guid_start 0x%llx\n", sBlk.guid_start); } } int check_compression(struct compressor *comp) { int res, bytes = 0; char buffer[SQUASHFS_METADATA_SIZE] __attribute__ ((aligned)); if (!comp->supported) { ERROR("Filesystem uses %s compression, this is " "unsupported by this version\n", comp->name); ERROR("Decompressors available:\n"); display_compressors("", ""); return 0; } /* * Read compression options from disk if present, and pass to * the compressor to ensure we know how to decompress a filesystem * compressed with these compression options. * * Note, even if there is no compression options we still call the * compressor because some compression options may be mandatory * for some compressors. */ if (SQUASHFS_COMP_OPTS(sBlk.s.flags)) { bytes = read_block(fd, sizeof(sBlk.s), NULL, 0, buffer); if (bytes == 0) { ERROR("Failed to read compressor options\n"); return 0; } } res = compressor_check_options(comp, sBlk.s.block_size, buffer, bytes); return res != -1; } int read_super(char *source) { squashfs_super_block_3 sBlk_3; struct squashfs_super_block sBlk_4; /* * Try to read a Squashfs 4 superblock */ read_fs_bytes(fd, SQUASHFS_START, sizeof(struct squashfs_super_block), &sBlk_4); swap = sBlk_4.s_magic != SQUASHFS_MAGIC; SQUASHFS_INSWAP_SUPER_BLOCK(&sBlk_4); if (sBlk_4.s_magic == SQUASHFS_MAGIC && sBlk_4.s_major == 4 && sBlk_4.s_minor == 0) { s_ops.squashfs_opendir = squashfs_opendir_4; s_ops.read_fragment = read_fragment_4; s_ops.read_fragment_table = read_fragment_table_4; s_ops.read_block_list = read_block_list_2; s_ops.read_inode = read_inode_4; s_ops.read_uids_guids = read_uids_guids_4; memcpy(&sBlk, &sBlk_4, sizeof(sBlk_4)); /* * Check the compression type */ comp = lookup_compressor_id(sBlk.s.compression); return TRUE; } /* * Not a Squashfs 4 superblock, try to read a squashfs 3 superblock * (compatible with 1 and 2 filesystems) */ read_fs_bytes(fd, SQUASHFS_START, sizeof(squashfs_super_block_3), &sBlk_3); /* * Check it is a SQUASHFS superblock */ swap = 0; if (sBlk_3.s_magic != SQUASHFS_MAGIC) { if (sBlk_3.s_magic == SQUASHFS_MAGIC_SWAP) { squashfs_super_block_3 sblk; ERROR("Reading a different endian SQUASHFS filesystem " "on %s\n", source); SQUASHFS_SWAP_SUPER_BLOCK_3(&sblk, &sBlk_3); memcpy(&sBlk_3, &sblk, sizeof(squashfs_super_block_3)); swap = 1; } else { //ERROR("Can't find a SQUASHFS superblock on %s\n", source); goto failed_mount; } } sBlk.s.s_magic = sBlk_3.s_magic; sBlk.s.inodes = sBlk_3.inodes; sBlk.s.mkfs_time = sBlk_3.mkfs_time; sBlk.s.block_size = sBlk_3.block_size; sBlk.s.fragments = sBlk_3.fragments; sBlk.s.block_log = sBlk_3.block_log; sBlk.s.flags = sBlk_3.flags; sBlk.s.s_major = sBlk_3.s_major; sBlk.s.s_minor = sBlk_3.s_minor; sBlk.s.root_inode = sBlk_3.root_inode; sBlk.s.bytes_used = sBlk_3.bytes_used; sBlk.s.inode_table_start = sBlk_3.inode_table_start; sBlk.s.directory_table_start = sBlk_3.directory_table_start; sBlk.s.fragment_table_start = sBlk_3.fragment_table_start; sBlk.s.lookup_table_start = sBlk_3.lookup_table_start; sBlk.no_uids = sBlk_3.no_uids; sBlk.no_guids = sBlk_3.no_guids; sBlk.uid_start = sBlk_3.uid_start; sBlk.guid_start = sBlk_3.guid_start; sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK; /* Check the MAJOR & MINOR versions */ if (sBlk.s.s_major == 1 || sBlk.s.s_major == 2) { sBlk.s.bytes_used = sBlk_3.bytes_used_2; sBlk.uid_start = sBlk_3.uid_start_2; sBlk.guid_start = sBlk_3.guid_start_2; sBlk.s.inode_table_start = sBlk_3.inode_table_start_2; sBlk.s.directory_table_start = sBlk_3.directory_table_start_2; if (sBlk.s.s_major == 1) { sBlk.s.block_size = sBlk_3.block_size_1; sBlk.s.fragment_table_start = sBlk.uid_start; s_ops.squashfs_opendir = squashfs_opendir_1; s_ops.read_fragment_table = read_fragment_table_1; s_ops.read_block_list = read_block_list_1; s_ops.read_inode = read_inode_1; s_ops.read_uids_guids = read_uids_guids_1; } else { sBlk.s.fragment_table_start = sBlk_3.fragment_table_start_2; s_ops.squashfs_opendir = squashfs_opendir_1; s_ops.read_fragment = read_fragment_2; s_ops.read_fragment_table = read_fragment_table_2; s_ops.read_block_list = read_block_list_2; s_ops.read_inode = read_inode_2; s_ops.read_uids_guids = read_uids_guids_1; } } else if (sBlk.s.s_major == 3) { s_ops.squashfs_opendir = squashfs_opendir_3; s_ops.read_fragment = read_fragment_3; s_ops.read_fragment_table = read_fragment_table_3; s_ops.read_block_list = read_block_list_2; s_ops.read_inode = read_inode_3; s_ops.read_uids_guids = read_uids_guids_1; } else { ERROR("Filesystem on %s is (%d:%d), ", source, sBlk.s.s_major, sBlk.s.s_minor); ERROR("which is a later filesystem version than I support!\n"); goto failed_mount; } /* * 1.x, 2.x and 3.x filesystems use gzip compression. */ comp = lookup_compressor("gzip"); return TRUE; failed_mount: return FALSE; } struct pathname *process_extract_files(struct pathname *path, char *filename) { FILE *fd; char buffer[MAX_LINE + 1]; /* overflow safe */ char *name; fd = fopen(filename, "r"); if (fd == NULL) EXIT_UNSQUASH("Failed to open extract file \"%s\" because %s\n", filename, strerror(errno)); while (fgets(name = buffer, MAX_LINE + 1, fd) != NULL) { int len = strlen(name); if (len == MAX_LINE && name[len - 1] != '\n') /* line too large */ EXIT_UNSQUASH("Line too long when reading " "extract file \"%s\", larger than %d " "bytes\n", filename, MAX_LINE); /* * Remove '\n' terminator if it exists (the last line * in the file may not be '\n' terminated) */ if (len && name[len - 1] == '\n') name[len - 1] = '\0'; /* Skip any leading whitespace */ while (isspace(*name)) name++; /* if comment line, skip */ if (*name == '#') continue; /* check for initial backslash, to accommodate * filenames with leading space or leading # character */ if (*name == '\\') name++; /* if line is now empty after skipping characters, skip it */ if (*name == '\0') continue; path = add_path(path, name, name); } if (ferror(fd)) EXIT_UNSQUASH("Reading extract file \"%s\" failed because %s\n", filename, strerror(errno)); fclose(fd); return path; } /* * reader thread. This thread processes read requests queued by the * cache_get() routine. */ void *reader(void *arg) { while (1) { struct cache_entry *entry = queue_get(to_reader); int res = read_fs_bytes(fd, entry->block, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), entry->data); if (res && SQUASHFS_COMPRESSED_BLOCK(entry->size)) /* * queue successfully read block to the inflate * thread(s) for further processing */ queue_put(to_inflate, entry); else /* * block has either been successfully read and is * uncompressed, or an error has occurred, clear pending * flag, set error appropriately, and wake up any * threads waiting on this buffer */ cache_block_ready(entry, !res); } } /* * writer thread. This processes file write requests queued by the * write_file() routine. */ void *writer(void *arg) { int i; while (1) { struct squashfs_file *file = queue_get(to_writer); int file_fd; long long hole = 0; int failed = FALSE; int error; if (file == NULL) { queue_put(from_writer, NULL); continue; } else if (file->fd == -1) { /* write attributes for directory file->pathname */ set_attributes(file->pathname, file->mode, file->uid, file->gid, file->time, file->xattr, TRUE); free(file->pathname); free(file); continue; } TRACE("writer: regular file, blocks %d\n", file->blocks); file_fd = file->fd; for (i = 0; i < file->blocks; i++, cur_blocks++) { struct file_entry *block = queue_get(to_writer); if (block->buffer == 0) { /* sparse file */ hole += block->size; free(block); continue; } cache_block_wait(block->buffer); if (block->buffer->error) failed = TRUE; if (failed) continue; error = write_block(file_fd, block->buffer->data + block->offset, block->size, hole, file->sparse); if (error == FALSE) { ERROR("writer: failed to write data block %d\n", i); failed = TRUE; } hole = 0; cache_block_put(block->buffer); free(block); } if (hole && failed == FALSE) { /* * corner case for hole extending to end of file */ if (file->sparse == FALSE || lseek(file_fd, hole, SEEK_CUR) == -1) { /* * for files which we don't want to write * sparsely, or for broken lseeks which cannot * seek beyond end of file, write_block will do * the right thing */ hole--; if (write_block(file_fd, "\0", 1, hole, file->sparse) == FALSE) { ERROR("writer: failed to write sparse " "data block\n"); failed = TRUE; } } else if (ftruncate(file_fd, file->file_size) == -1) { ERROR("writer: failed to write sparse data " "block\n"); failed = TRUE; } } close_wake(file_fd); if (failed == FALSE) set_attributes(file->pathname, file->mode, file->uid, file->gid, file->time, file->xattr, force); else { ERROR("Failed to write %s, skipping\n", file->pathname); unlink(file->pathname); } free(file->pathname); free(file); } } /* * decompress thread. This decompresses buffers queued by the read thread */ void *inflator(void *arg) { char tmp[block_size]; while (1) { struct cache_entry *entry = queue_get(to_inflate); int error, res; res = compressor_uncompress(comp, tmp, entry->data, SQUASHFS_COMPRESSED_SIZE_BLOCK(entry->size), block_size, &error); if (res == -1) ERROR("%s uncompress failed with error code %d\n", comp->name, error); else memcpy(entry->data, tmp, res); /* * block has been either successfully decompressed, or an error * occurred, clear pending flag, set error appropriately and * wake up any threads waiting on this block */ cache_block_ready(entry, res == -1); } } void *progress_thread(void *arg) { struct timespec requested_time, remaining; struct itimerval itimerval; struct winsize winsize; if (ioctl(1, TIOCGWINSZ, &winsize) == -1) { if (isatty(STDOUT_FILENO)) ERROR("TIOCGWINSZ ioctl failed, defaulting to 80 " "columns\n"); columns = 80; } else columns = winsize.ws_col; signal(SIGWINCH, sigwinch_handler); signal(SIGALRM, sigalrm_handler); itimerval.it_value.tv_sec = 0; itimerval.it_value.tv_usec = 250000; itimerval.it_interval.tv_sec = 0; itimerval.it_interval.tv_usec = 250000; setitimer(ITIMER_REAL, &itimerval, NULL); requested_time.tv_sec = 0; requested_time.tv_nsec = 250000000; while (1) { int res = nanosleep(&requested_time, &remaining); if (res == -1 && errno != EINTR) EXIT_UNSQUASH("nanosleep failed in progress thread\n"); if (progress_enabled) { pthread_mutex_lock(&screen_mutex); progress_bar(sym_count + dev_count + fifo_count + cur_blocks, total_inodes - total_files + total_blocks, columns); pthread_mutex_unlock(&screen_mutex); } } } void initialise_threads(int fragment_buffer_size, int data_buffer_size) { struct rlimit rlim; int i, max_files, res; sigset_t sigmask, old_mask; /* block SIGQUIT and SIGHUP, these are handled by the info thread */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGQUIT); sigaddset(&sigmask, SIGHUP); if (pthread_sigmask(SIG_BLOCK, &sigmask, NULL) == -1) EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" "\n"); /* * temporarily block these signals so the created sub-threads will * ignore them, ensuring the main thread handles them */ sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); sigaddset(&sigmask, SIGTERM); if (pthread_sigmask(SIG_BLOCK, &sigmask, &old_mask) == -1) EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" "\n"); if (processors == -1) { #if !defined(linux) && !defined(__CYGWIN__) int mib[2]; size_t len = sizeof(processors); mib[0] = CTL_HW; # ifdef HW_AVAILCPU mib[1] = HW_AVAILCPU; # else mib[1] = HW_NCPU; # endif if (sysctl(mib, 2, &processors, &len, NULL, 0) == -1) { ERROR("Failed to get number of available processors. " "Defaulting to 1\n"); processors = 1; } #else processors = sysconf(_SC_NPROCESSORS_ONLN); #endif } if (add_overflow(processors, 3) || multiply_overflow(processors + 3, sizeof(pthread_t))) EXIT_UNSQUASH("Processors too large\n"); thread = malloc((3 + processors) * sizeof(pthread_t)); if (thread == NULL) EXIT_UNSQUASH("Out of memory allocating thread descriptors\n"); inflator_thread = &thread[3]; /* * dimensioning the to_reader and to_inflate queues. The size of * these queues is directly related to the amount of block * read-ahead possible. To_reader queues block read requests to * the reader thread and to_inflate queues block decompression * requests to the inflate thread(s) (once the block has been read by * the reader thread). The amount of read-ahead is determined by * the combined size of the data_block and fragment caches which * determine the total number of blocks which can be "in flight" * at any one time (either being read or being decompressed) * * The maximum file open limit, however, affects the read-ahead * possible, in that for normal sizes of the fragment and data block * caches, where the incoming files have few data blocks or one fragment * only, the file open limit is likely to be reached before the * caches are full. This means the worst case sizing of the combined * sizes of the caches is unlikely to ever be necessary. However, is is * obvious read-ahead up to the data block cache size is always possible * irrespective of the file open limit, because a single file could * contain that number of blocks. * * Choosing the size as "file open limit + data block cache size" seems * to be a reasonable estimate. We can reasonably assume the maximum * likely read-ahead possible is data block cache size + one fragment * per open file. * * dimensioning the to_writer queue. The size of this queue is * directly related to the amount of block read-ahead possible. * However, unlike the to_reader and to_inflate queues, this is * complicated by the fact the to_writer queue not only contains * entries for fragments and data_blocks but it also contains * file entries, one per open file in the read-ahead. * * Choosing the size as "2 * (file open limit) + * data block cache size" seems to be a reasonable estimate. * We can reasonably assume the maximum likely read-ahead possible * is data block cache size + one fragment per open file, and then * we will have a file_entry for each open file. */ res = getrlimit(RLIMIT_NOFILE, &rlim); if (res == -1) { ERROR("failed to get open file limit! Defaulting to 1\n"); rlim.rlim_cur = 1; } if (rlim.rlim_cur != RLIM_INFINITY) { max_files = rlim.rlim_cur; struct pollfd *fds = calloc(max_files, sizeof(struct pollfd)); uint cur_file, opened_files = 0; for(cur_file = 0; cur_file < max_files; cur_file++){ fds[cur_file].fd = cur_file; } poll(fds, max_files, 0); for(cur_file = 0; cur_file < max_files; cur_file++){ if(!(fds[cur_file].revents & POLLNVAL)){ opened_files++; } } if(opened_files > max_files){ EXIT_UNSQUASH("Too many open files"); } // leave 10% of the free files free uint margin = (max_files - opened_files) / 10; max_files -= margin; printf("Max Files: %ju, Opened Files: %u, Allocated: %u (Margin: %u)\n", (uintmax_t) rlim.rlim_cur, opened_files, max_files, margin ); free(fds); } else max_files = -1; /* set amount of available files for use by open_wait and close_wake */ open_init(max_files); /* * allocate to_reader, to_inflate and to_writer queues. Set based on * open file limit and cache size, unless open file limit is unlimited, * in which case set purely based on cache limits * * In doing so, check that the user supplied values do not overflow * a signed int */ if (max_files != -1) { if (add_overflow(data_buffer_size, max_files) || add_overflow(data_buffer_size, max_files * 2)) EXIT_UNSQUASH("Data queue size is too large\n"); to_reader = queue_init(max_files + data_buffer_size); to_inflate = queue_init(max_files + data_buffer_size); to_writer = queue_init(max_files * 2 + data_buffer_size); } else { int all_buffers_size; if (add_overflow(fragment_buffer_size, data_buffer_size)) EXIT_UNSQUASH("Data and fragment queues combined are" " too large\n"); all_buffers_size = fragment_buffer_size + data_buffer_size; if (add_overflow(all_buffers_size, all_buffers_size)) EXIT_UNSQUASH("Data and fragment queues combined are" " too large\n"); to_reader = queue_init(all_buffers_size); to_inflate = queue_init(all_buffers_size); to_writer = queue_init(all_buffers_size * 2); } from_writer = queue_init(1); fragment_cache = cache_init(block_size, fragment_buffer_size); data_cache = cache_init(block_size, data_buffer_size); pthread_create(&thread[0], NULL, reader, NULL); pthread_create(&thread[1], NULL, writer, NULL); pthread_create(&thread[2], NULL, progress_thread, NULL); init_info(); pthread_mutex_init(&fragment_mutex, NULL); for (i = 0; i < processors; i++) { if (pthread_create(&inflator_thread[i], NULL, inflator, NULL) != 0) EXIT_UNSQUASH("Failed to create thread\n"); } printf("Parallel unsquashfs: Using %d processor%s\n", processors, processors == 1 ? "" : "s"); if (pthread_sigmask(SIG_SETMASK, &old_mask, NULL) == -1) EXIT_UNSQUASH("Failed to set signal mask in initialise_threads" "\n"); } void enable_progress_bar() { pthread_mutex_lock(&screen_mutex); progress_enabled = progress; pthread_mutex_unlock(&screen_mutex); } void disable_progress_bar() { pthread_mutex_lock(&screen_mutex); if (progress_enabled) { progress_bar(sym_count + dev_count + fifo_count + cur_blocks, total_inodes - total_files + total_blocks, columns); printf("\n"); } progress_enabled = FALSE; pthread_mutex_unlock(&screen_mutex); } void progressbar_error(char *fmt, ...) { va_list ap; pthread_mutex_lock(&screen_mutex); if (progress_enabled) fprintf(stderr, "\n"); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); pthread_mutex_unlock(&screen_mutex); } void progressbar_info(char *fmt, ...) { va_list ap; pthread_mutex_lock(&screen_mutex); if (progress_enabled) printf("\n"); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); pthread_mutex_unlock(&screen_mutex); } void progress_bar(long long current, long long max, int columns) { char rotate_list[] = { '|', '/', '-', '\\' }; int max_digits, used, hashes, spaces; static int tty = -1; if (max == 0) return; max_digits = floor(log10(max)) + 1; used = max_digits * 2 + 11; hashes = (current * (columns - used)) / max; spaces = columns - used - hashes; if ((current > max) || (columns - used < 0)) return; if (tty == -1) tty = isatty(STDOUT_FILENO); if (!tty) { static long long previous = -1; /* * Updating much more frequently than this results in huge * log files. */ if ((current % 100) != 0 && current != max) return; /* Don't update just to rotate the spinner. */ if (current == previous) return; previous = current; } printf("\r["); while (hashes--) putchar('='); putchar(rotate_list[rotate]); while (spaces--) putchar(' '); printf("] %*lld/%*lld", max_digits, current, max_digits, max); printf(" %3lld%%", current * 100 / max); fflush(stdout); } int parse_number(char *arg, int *res) { char *b; long number = strtol(arg, &b, 10); /* check for trailing junk after number */ if (*b != '\0') return 0; /* * check for strtol underflow or overflow in conversion. * Note: strtol can validly return LONG_MIN and LONG_MAX * if the user entered these values, but, additional code * to distinguish this scenario is unnecessary, because for * our purposes LONG_MIN and LONG_MAX are too large anyway */ if (number == LONG_MIN || number == LONG_MAX) return 0; /* reject negative numbers as invalid */ if (number < 0) return 0; /* check if long result will overflow signed int */ if (number > INT_MAX) return 0; *res = number; return 1; } #define VERSION() \ printf("unsquashfs version 4.3 (2014/05/12)\n");\ printf("copyright (C) 2014 Phillip Lougher "\ "\n\n");\ printf("This program is free software; you can redistribute it and/or"\ "\n");\ printf("modify it under the terms of the GNU General Public License"\ "\n");\ printf("as published by the Free Software Foundation; either version "\ "2,\n");\ printf("or (at your option) any later version.\n\n");\ printf("This program is distributed in the hope that it will be "\ "useful,\n");\ printf("but WITHOUT ANY WARRANTY; without even the implied warranty of"\ "\n");\ printf("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"\ "\n");\ printf("GNU General Public License for more details.\n"); int is_squashfs(char *filename) { if ((fd = open(filename, O_RDONLY)) == -1) { ERROR("Could not open %s, because %s\n", filename, strerror(errno)); return FALSE; } char *buffer = (char *)malloc(sizeof(char) * 0x67); if (buffer == NULL) { printf("Memory allocation error!\n"); return FALSE; } int result = read(fd, buffer, 0x67); if (result != 0x67) { printf("File reading error!\n"); return FALSE; } result = memcmp(&buffer[0x64], "cdx", 3); free(buffer); if (!result) return FALSE; result = read_super(filename); close(fd); return result; } int unsquashfs(char *squashfs, char *dest) { int stat_sys = FALSE; struct pathnames *paths = NULL; struct pathname *path = NULL; long long directory_table_end; int fragment_buffer_size = FRAGMENT_BUFFER_DEFAULT; int data_buffer_size = DATA_BUFFER_DEFAULT; pthread_mutex_init(&screen_mutex, NULL); root_process = geteuid() == 0; if (root_process) umask(0); #ifdef SQUASHFS_TRACE /* * Disable progress bar if full debug tracing is enabled. * The progress bar in this case just gets in the way of the * debug trace output */ progress = FALSE; #endif if ((fd = open(squashfs, O_RDONLY)) == -1) { ERROR("Could not open %s, because %s\n", squashfs, strerror(errno)); exit(1); } if (read_super(squashfs) == FALSE) exit(1); if (stat_sys) { squashfs_stat(squashfs); exit(0); } if (!check_compression(comp)) exit(1); block_size = sBlk.s.block_size; block_log = sBlk.s.block_log; /* * Sanity check block size and block log. * * Check they're within correct limits */ if (block_size > SQUASHFS_FILE_MAX_SIZE || block_log > SQUASHFS_FILE_MAX_LOG) EXIT_UNSQUASH("Block size or block_log too large." " File system is corrupt.\n"); /* * Check block_size and block_log match */ if (block_size != (1 << block_log)) EXIT_UNSQUASH("Block size and block_log do not match." " File system is corrupt.\n"); /* * convert from queue size in Mbytes to queue size in * blocks. * * In doing so, check that the user supplied values do not * overflow a signed int */ if (shift_overflow(fragment_buffer_size, 20 - block_log)) EXIT_UNSQUASH("Fragment queue size is too large\n"); else fragment_buffer_size <<= 20 - block_log; if (shift_overflow(data_buffer_size, 20 - block_log)) EXIT_UNSQUASH("Data queue size is too large\n"); else data_buffer_size <<= 20 - block_log; initialise_threads(fragment_buffer_size, data_buffer_size); fragment_data = malloc(block_size); if (fragment_data == NULL) EXIT_UNSQUASH("failed to allocate fragment_data\n"); file_data = malloc(block_size); if (file_data == NULL) EXIT_UNSQUASH("failed to allocate file_data"); data = malloc(block_size); if (data == NULL) EXIT_UNSQUASH("failed to allocate data\n"); created_inode = malloc(sBlk.s.inodes * sizeof(char *)); if (created_inode == NULL) EXIT_UNSQUASH("failed to allocate created_inode\n"); memset(created_inode, 0, sBlk.s.inodes * sizeof(char *)); if (s_ops.read_uids_guids() == FALSE) EXIT_UNSQUASH("failed to uid/gid table\n"); if (s_ops.read_fragment_table(&directory_table_end) == FALSE) EXIT_UNSQUASH("failed to read fragment table\n"); if (read_inode_table(sBlk.s.inode_table_start, sBlk.s.directory_table_start) == FALSE) EXIT_UNSQUASH("failed to read inode table\n"); if (read_directory_table(sBlk.s.directory_table_start, directory_table_end) == FALSE) EXIT_UNSQUASH("failed to read directory table\n"); if (no_xattrs) sBlk.s.xattr_id_table_start = SQUASHFS_INVALID_BLK; if (read_xattrs_from_disk(fd, &sBlk.s) == 0) EXIT_UNSQUASH("failed to read the xattr table\n"); if (path) { paths = init_subdir(); paths = add_subdir(paths, path); } pre_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode), SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths); memset(created_inode, 0, sBlk.s.inodes * sizeof(char *)); inode_number = 1; printf("%d inodes (%d blocks) to write\n\n", total_inodes, total_inodes - total_files + total_blocks); enable_progress_bar(); dir_scan(dest, SQUASHFS_INODE_BLK(sBlk.s.root_inode), SQUASHFS_INODE_OFFSET(sBlk.s.root_inode), paths); queue_put(to_writer, NULL); queue_get(from_writer); disable_progress_bar(); if (!lsonly) { printf("\n"); printf("created %d files\n", file_count); printf("created %d directories\n", dir_count); printf("created %d symlinks\n", sym_count); printf("created %d devices\n", dev_count); printf("created %d fifos\n", fifo_count); } return 0; } ================================================ FILE: src/squashfs/unsquashfs_info.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquashfs_info.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "squashfs_fs.h" #include "unsquashfs.h" #include "error.h" #if defined(__CYGWIN__) || defined(__APPLE__) # define sigtimedwait(a,b,c) sigwaitinfo(a,b) #endif #ifdef __APPLE__ # define sigwaitinfo(a,b) sigwait(a, b) #endif static int silent = 0; char *pathname = NULL; pthread_t info_thread; void disable_info() { if (pathname) free(pathname); pathname = NULL; } void update_info(char *name) { if (pathname) free(pathname); pathname = name; } void dump_state() { disable_progress_bar(); printf("Queue and cache status dump\n"); printf("===========================\n"); printf("file buffer read queue (main thread -> reader thread)\n"); dump_queue(to_reader); printf("file buffer decompress queue (reader thread -> inflate" " thread(s))\n"); dump_queue(to_inflate); printf("file buffer write queue (main thread -> writer thread)\n"); dump_queue(to_writer); printf("\nbuffer cache (uncompressed blocks and compressed blocks " "'in flight')\n"); dump_cache(data_cache); printf("fragment buffer cache (uncompressed frags and compressed" " frags 'in flight')\n"); dump_cache(fragment_cache); enable_progress_bar(); } void *info_thrd(void *arg) { sigset_t sigmask; struct timespec timespec = {.tv_sec = 1,.tv_nsec = 0 }; int sig, waiting = 0; sigemptyset(&sigmask); sigaddset(&sigmask, SIGQUIT); sigaddset(&sigmask, SIGHUP); while (1) { if (waiting) sig = sigtimedwait(&sigmask, NULL, ×pec); else sig = sigwaitinfo(&sigmask, NULL); if (sig == -1) { switch (errno) { case EAGAIN: /* interval timed out */ waiting = 0; /* FALLTHROUGH */ case EINTR: /* if waiting, the wait will be longer, but that's OK */ continue; default: BAD_ERROR("sigtimedwait/sigwaitinfo failed " "because %s\n", strerror(errno)); } } if (sig == SIGQUIT && !waiting) { if (pathname) INFO("%s\n", pathname); /* set one second interval period, if ^\ received within then, dump queue and cache status */ waiting = 1; } else dump_state(); } } void init_info() { pthread_create(&info_thread, NULL, info_thrd, NULL); } ================================================ FILE: src/squashfs/unsquashfs_xattr.c ================================================ /* * Unsquash a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2010, 2012 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * unsquashfs_xattr.c */ #include "unsquashfs.h" #include "xattr.h" #include #define NOSPACE_MAX 10 extern int root_process; extern int user_xattrs; void write_xattr(char *pathname, unsigned int xattr) { unsigned int count; struct xattr_list *xattr_list; int i; static int nonsuper_error = FALSE; static int ignore_xattrs = FALSE; static int nospace_error = 0; if (ignore_xattrs || xattr == SQUASHFS_INVALID_XATTR || sBlk.s.xattr_id_table_start == SQUASHFS_INVALID_BLK) return; xattr_list = get_xattr(xattr, &count, 1); if (xattr_list == NULL) { ERROR("Failed to read xattrs for file %s\n", pathname); return; } for (i = 0; i < count; i++) { int prefix = xattr_list[i].type & SQUASHFS_XATTR_PREFIX_MASK; if (user_xattrs && prefix != SQUASHFS_XATTR_USER) continue; if (root_process || prefix == SQUASHFS_XATTR_USER) { int res = lsetxattr(pathname, xattr_list[i].full_name, xattr_list[i].value, xattr_list[i].vsize, 0); if (res == -1) { if (errno == ENOTSUP) { /* * If the destination filesystem cannot * suppport xattrs, print error, and * disable xattr output as this error is * unlikely to go away, and printing * screenfulls of the same error message * is rather annoying */ ERROR("write_xattr: failed to write " "xattr %s for file %s because " "extended attributes are not " "supported by the destination " "filesystem\n", xattr_list[i].full_name, pathname); ERROR("Ignoring xattrs in " "filesystem\n"); ERROR("To avoid this error message, " "specify -no-xattrs\n"); ignore_xattrs = TRUE; } else if ((errno == ENOSPC || errno == EDQUOT) && nospace_error < NOSPACE_MAX) { /* * Many filesystems like ext2/3/4 have * limits on the amount of xattr * data that can be stored per file * (typically one block or 4K), so * we shouldn't disable xattr ouput, * as the error may be restriced to one * file only. If we get a lot of these * then suppress the error messsage */ ERROR("write_xattr: failed to write " "xattr %s for file %s because " "no extended attribute space " "remaining (per file or " "filesystem limit)\n", xattr_list[i].full_name, pathname); if (++nospace_error == NOSPACE_MAX) ERROR("%d of these errors " "printed, further error " "messages of this type " "are suppressed!\n", NOSPACE_MAX); } else ERROR("write_xattr: failed to write " "xattr %s for file %s because " "%s\n", xattr_list[i].full_name, pathname, strerror(errno)); } } else if (nonsuper_error == FALSE) { /* * if extract user xattrs only then * error message is suppressed, if not * print error, and then suppress further error * messages to avoid possible screenfulls of the * same error message! */ ERROR("write_xattr: could not write xattr %s " "for file %s because you're not " "superuser!\n", xattr_list[i].full_name, pathname); ERROR("write_xattr: to avoid this error message, either" " specify -user-xattrs, -no-xattrs, or run as " "superuser!\n"); ERROR("Further error messages of this type are " "suppressed!\n"); nonsuper_error = TRUE; } } free_xattr(xattr_list, count); } ================================================ FILE: src/squashfs/xattr.c ================================================ /* * Create a squashfs filesystem. This is a highly compressed read only * filesystem. * * Copyright (c) 2008, 2009, 2010, 2012, 2014 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * xattr.c */ #define TRUE 1 #define FALSE 0 #include #include #include #include #include #include #include #include #include #include #include "squashfs_fs.h" #include "squashfs_swap.h" #include "mksquashfs.h" #include "xattr.h" #include "error.h" #include "progressbar.h" /* compressed xattr table */ static char *xattr_table = NULL; static unsigned int xattr_size = 0; /* cached uncompressed xattr data */ static char *data_cache = NULL; static int cache_bytes = 0, cache_size = 0; /* cached uncompressed xattr id table */ static struct squashfs_xattr_id *xattr_id_table = NULL; static int xattr_ids = 0; /* saved compressed xattr table */ unsigned int sxattr_bytes = 0, stotal_xattr_bytes = 0; /* saved cached uncompressed xattr data */ static char *sdata_cache = NULL; static int scache_bytes = 0; /* saved cached uncompressed xattr id table */ static int sxattr_ids = 0; /* xattr hash table for value duplicate detection */ static struct xattr_list *dupl_value[65536]; /* xattr hash table for id duplicate detection */ static struct dupl_id *dupl_id[65536]; /* file system globals from mksquashfs.c */ extern int no_xattrs, noX; extern long long bytes; extern int fd; extern unsigned int xattr_bytes, total_xattr_bytes; /* helper functions from mksquashfs.c */ extern unsigned short get_checksum(char *, int, unsigned short); extern void write_destination(int, long long, int, void *); extern long long generic_write_table(int, void *, int, void *, int); extern int mangle(char *, char *, int, int, int, int); extern char *pathname(struct dir_ent *); /* helper functions and definitions from read_xattrs.c */ extern int read_xattrs_from_disk(int, struct squashfs_super_block *); extern struct xattr_list *get_xattr(int, unsigned int *, int); extern struct prefix prefix_table[]; static int get_prefix(struct xattr_list *xattr, char *name) { int i; xattr->full_name = strdup(name); for (i = 0; prefix_table[i].type != -1; i++) { struct prefix *p = &prefix_table[i]; if (strncmp(xattr->full_name, p->prefix, strlen(p->prefix)) == 0) break; } if (prefix_table[i].type != -1) { xattr->name = xattr->full_name + strlen(prefix_table[i].prefix); xattr->size = strlen(xattr->name); } return prefix_table[i].type; } static int read_xattrs_from_system(char *filename, struct xattr_list **xattrs) { ssize_t size, vsize; char *xattr_names, *p; int i; struct xattr_list *xattr_list = NULL; while (1) { size = llistxattr(filename, NULL, 0); if (size <= 0) { if (size < 0 && errno != ENOTSUP) { ERROR_START("llistxattr for %s failed in " "read_attrs, because %s", filename, strerror(errno)); ERROR_EXIT(". Ignoring"); } return 0; } xattr_names = malloc(size); if (xattr_names == NULL) MEM_ERROR(); size = llistxattr(filename, xattr_names, size); if (size < 0) { free(xattr_names); if (errno == ERANGE) /* xattr list grew? Try again */ continue; else { ERROR_START("llistxattr for %s failed in " "read_attrs, because %s", filename, strerror(errno)); ERROR_EXIT(". Ignoring"); return 0; } } break; } for (i = 0, p = xattr_names; p < xattr_names + size; i++) { struct xattr_list *x = realloc(xattr_list, (i + 1) * sizeof(struct xattr_list)); if (x == NULL) MEM_ERROR(); xattr_list = x; xattr_list[i].type = get_prefix(&xattr_list[i], p); p += strlen(p) + 1; if (xattr_list[i].type == -1) { ERROR("Unrecognised xattr prefix %s\n", xattr_list[i].full_name); free(xattr_list[i].full_name); i--; continue; } while (1) { vsize = lgetxattr(filename, xattr_list[i].full_name, NULL, 0); if (vsize < 0) { ERROR_START("lgetxattr failed for %s in " "read_attrs, because %s", filename, strerror(errno)); ERROR_EXIT(". Ignoring"); free(xattr_list[i].full_name); goto failed; } xattr_list[i].value = malloc(vsize); if (xattr_list[i].value == NULL) MEM_ERROR(); vsize = lgetxattr(filename, xattr_list[i].full_name, xattr_list[i].value, vsize); if (vsize < 0) { free(xattr_list[i].value); if (errno == ERANGE) /* xattr grew? Try again */ continue; else { ERROR_START("lgetxattr failed for %s " "in read_attrs, because %s", filename, strerror(errno)); ERROR_EXIT(". Ignoring"); free(xattr_list[i].full_name); goto failed; } } break; } xattr_list[i].vsize = vsize; TRACE("read_xattrs_from_system: filename %s, xattr name %s," " vsize %d\n", filename, xattr_list[i].full_name, xattr_list[i].vsize); } free(xattr_names); *xattrs = xattr_list; return i; failed: while (--i >= 0) { free(xattr_list[i].full_name); free(xattr_list[i].value); } free(xattr_list); free(xattr_names); return 0; } static int get_xattr_size(struct xattr_list *xattr) { int size = sizeof(struct squashfs_xattr_entry) + sizeof(struct squashfs_xattr_val) + xattr->size; if (xattr->type & XATTR_VALUE_OOL) size += XATTR_VALUE_OOL_SIZE; else size += xattr->vsize; return size; } static void *get_xattr_space(unsigned int req_size, long long *disk) { int data_space; unsigned short c_byte; /* * Move and compress cached uncompressed data into xattr table. */ while (cache_bytes >= SQUASHFS_METADATA_SIZE) { if ((xattr_size - xattr_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) { xattr_table = realloc(xattr_table, xattr_size + (SQUASHFS_METADATA_SIZE << 1) + 2); if (xattr_table == NULL) MEM_ERROR(); xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2; } c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, data_cache, SQUASHFS_METADATA_SIZE, SQUASHFS_METADATA_SIZE, noX, 0); TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1); xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; memmove(data_cache, data_cache + SQUASHFS_METADATA_SIZE, cache_bytes - SQUASHFS_METADATA_SIZE); cache_bytes -= SQUASHFS_METADATA_SIZE; } /* * Ensure there's enough space in the uncompressed data cache */ data_space = cache_size - cache_bytes; if (data_space < req_size) { int realloc_size = req_size - data_space; data_cache = realloc(data_cache, cache_size + realloc_size); if (data_cache == NULL) MEM_ERROR(); cache_size += realloc_size; } if (disk) *disk = ((long long)xattr_bytes << 16) | cache_bytes; cache_bytes += req_size; return data_cache + cache_bytes - req_size; } static struct dupl_id *check_id_dupl(struct xattr_list *xattr_list, int xattrs) { struct dupl_id *entry; int i; unsigned short checksum = 0; /* compute checksum over all xattrs */ for (i = 0; i < xattrs; i++) { struct xattr_list *xattr = &xattr_list[i]; checksum = get_checksum(xattr->full_name, strlen(xattr->full_name), checksum); checksum = get_checksum(xattr->value, xattr->vsize, checksum); } for (entry = dupl_id[checksum]; entry; entry = entry->next) { if (entry->xattrs != xattrs) continue; for (i = 0; i < xattrs; i++) { struct xattr_list *xattr = &xattr_list[i]; struct xattr_list *dup_xattr = &entry->xattr_list[i]; if (strcmp(xattr->full_name, dup_xattr->full_name)) break; if (memcmp(xattr->value, dup_xattr->value, xattr->vsize)) break; } if (i == xattrs) break; } if (entry == NULL) { /* no duplicate exists */ entry = malloc(sizeof(*entry)); if (entry == NULL) MEM_ERROR(); entry->xattrs = xattrs; entry->xattr_list = xattr_list; entry->xattr_id = SQUASHFS_INVALID_XATTR; entry->next = dupl_id[checksum]; dupl_id[checksum] = entry; } return entry; } static void check_value_dupl(struct xattr_list *xattr) { struct xattr_list *entry; if (xattr->vsize < XATTR_VALUE_OOL_SIZE) return; /* Check if this is a duplicate of an existing value */ xattr->vchecksum = get_checksum(xattr->value, xattr->vsize, 0); for (entry = dupl_value[xattr->vchecksum]; entry; entry = entry->vnext) { if (entry->vsize != xattr->vsize) continue; if (memcmp(entry->value, xattr->value, xattr->vsize) == 0) break; } if (entry == NULL) { /* * No duplicate exists, add to hash table, and mark as * requiring writing */ xattr->vnext = dupl_value[xattr->vchecksum]; dupl_value[xattr->vchecksum] = xattr; xattr->ool_value = SQUASHFS_INVALID_BLK; } else { /* * Duplicate exists, make type XATTR_VALUE_OOL, and * remember where the duplicate is */ xattr->type |= XATTR_VALUE_OOL; xattr->ool_value = entry->ool_value; /* on appending don't free duplicate values because the * duplicate value already points to the non-duplicate value */ if (xattr->value != entry->value) { free(xattr->value); xattr->value = entry->value; } } } static int get_xattr_id(int xattrs, struct xattr_list *xattr_list, long long xattr_disk, struct dupl_id *xattr_dupl) { int i, size = 0; struct squashfs_xattr_id *xattr_id; xattr_id_table = realloc(xattr_id_table, (xattr_ids + 1) * sizeof(struct squashfs_xattr_id)); if (xattr_id_table == NULL) MEM_ERROR(); /* get total uncompressed size of xattr data, needed for stat */ for (i = 0; i < xattrs; i++) size += strlen(xattr_list[i].full_name) + 1 + xattr_list[i].vsize; xattr_id = &xattr_id_table[xattr_ids]; xattr_id->xattr = xattr_disk; xattr_id->count = xattrs; xattr_id->size = size; /* * keep track of total uncompressed xattr data, needed for mksquashfs * file system summary */ total_xattr_bytes += size; xattr_dupl->xattr_id = xattr_ids++; return xattr_dupl->xattr_id; } long long write_xattrs() { unsigned short c_byte; int i, avail_bytes; char *datap = data_cache; long long start_bytes = bytes; struct squashfs_xattr_table header; if (xattr_ids == 0) return SQUASHFS_INVALID_BLK; /* * Move and compress cached uncompressed data into xattr table. */ while (cache_bytes) { if ((xattr_size - xattr_bytes) < ((SQUASHFS_METADATA_SIZE << 1)) + 2) { xattr_table = realloc(xattr_table, xattr_size + (SQUASHFS_METADATA_SIZE << 1) + 2); if (xattr_table == NULL) MEM_ERROR(); xattr_size += (SQUASHFS_METADATA_SIZE << 1) + 2; } avail_bytes = cache_bytes > SQUASHFS_METADATA_SIZE ? SQUASHFS_METADATA_SIZE : cache_bytes; c_byte = mangle(xattr_table + xattr_bytes + BLOCK_OFFSET, datap, avail_bytes, SQUASHFS_METADATA_SIZE, noX, 0); TRACE("Xattr block @ 0x%x, size %d\n", xattr_bytes, c_byte); SQUASHFS_SWAP_SHORTS(&c_byte, xattr_table + xattr_bytes, 1); xattr_bytes += SQUASHFS_COMPRESSED_SIZE(c_byte) + BLOCK_OFFSET; datap += avail_bytes; cache_bytes -= avail_bytes; } /* * Write compressed xattr table to file system */ write_destination(fd, bytes, xattr_bytes, xattr_table); bytes += xattr_bytes; /* * Swap if necessary the xattr id table */ for (i = 0; i < xattr_ids; i++) SQUASHFS_INSWAP_XATTR_ID(&xattr_id_table[i]); header.xattr_ids = xattr_ids; header.xattr_table_start = start_bytes; SQUASHFS_INSWAP_XATTR_TABLE(&header); return generic_write_table(xattr_ids * sizeof(struct squashfs_xattr_id), xattr_id_table, sizeof(header), &header, noX); } int generate_xattrs(int xattrs, struct xattr_list *xattr_list) { int total_size, i; int xattr_value_max; void *xp; long long xattr_disk; struct dupl_id *xattr_dupl; /* * check if the file xattrs are a complete duplicate of a pre-existing * id */ xattr_dupl = check_id_dupl(xattr_list, xattrs); if (xattr_dupl->xattr_id != SQUASHFS_INVALID_XATTR) return xattr_dupl->xattr_id; /* * Scan the xattr_list deciding which type to assign to each * xattr. The choice is fairly straightforward, and depends on the * size of each xattr name/value and the overall size of the * resultant xattr list stored in the xattr metadata table. * * Choices are whether to store data inline or out of line. * * The overall goal is to optimise xattr scanning and lookup, and * to enable the file system layout to scale from a couple of * small xattr name/values to a large number of large xattr * names/values without affecting performance. While hopefully * enabling the common case of a couple of small xattr name/values * to be stored efficiently * * Code repeatedly scans, doing the following * move xattr data out of line if it exceeds * xattr_value_max. Where xattr_value_max is * initially XATTR_INLINE_MAX. If the final uncompressed * xattr list is larger than XATTR_TARGET_MAX then more * aggressively move xattr data out of line by repeatedly * setting inline threshold to 1/2, then 1/4, 1/8 of * XATTR_INLINE_MAX until target achieved or there's * nothing left to move out of line */ xattr_value_max = XATTR_INLINE_MAX; while (1) { for (total_size = 0, i = 0; i < xattrs; i++) { struct xattr_list *xattr = &xattr_list[i]; xattr->type &= XATTR_PREFIX_MASK; /* all inline */ if (xattr->vsize > xattr_value_max) xattr->type |= XATTR_VALUE_OOL; total_size += get_xattr_size(xattr); } /* * If the total size of the uncompressed xattr list is <= * XATTR_TARGET_MAX we're done */ if (total_size <= XATTR_TARGET_MAX) break; if (xattr_value_max == XATTR_VALUE_OOL_SIZE) break; /* * Inline target not yet at minimum and so reduce it, and * try again */ xattr_value_max /= 2; if (xattr_value_max < XATTR_VALUE_OOL_SIZE) xattr_value_max = XATTR_VALUE_OOL_SIZE; } /* * Check xattr values for duplicates */ for (i = 0; i < xattrs; i++) { check_value_dupl(&xattr_list[i]); } /* * Add each out of line value to the file system xattr table * if it doesn't already exist as a duplicate */ for (i = 0; i < xattrs; i++) { struct xattr_list *xattr = &xattr_list[i]; if ((xattr->type & XATTR_VALUE_OOL) && (xattr->ool_value == SQUASHFS_INVALID_BLK)) { struct squashfs_xattr_val val; int size = sizeof(val) + xattr->vsize; xp = get_xattr_space(size, &xattr->ool_value); val.vsize = xattr->vsize; SQUASHFS_SWAP_XATTR_VAL(&val, xp); memcpy(xp + sizeof(val), xattr->value, xattr->vsize); } } /* * Create xattr list and add to file system xattr table */ get_xattr_space(0, &xattr_disk); for (i = 0; i < xattrs; i++) { struct xattr_list *xattr = &xattr_list[i]; struct squashfs_xattr_entry entry; struct squashfs_xattr_val val; xp = get_xattr_space(sizeof(entry) + xattr->size, NULL); entry.type = xattr->type; entry.size = xattr->size; SQUASHFS_SWAP_XATTR_ENTRY(&entry, xp); memcpy(xp + sizeof(entry), xattr->name, xattr->size); if (xattr->type & XATTR_VALUE_OOL) { int size = sizeof(val) + XATTR_VALUE_OOL_SIZE; xp = get_xattr_space(size, NULL); val.vsize = XATTR_VALUE_OOL_SIZE; SQUASHFS_SWAP_XATTR_VAL(&val, xp); SQUASHFS_SWAP_LONG_LONGS(&xattr->ool_value, xp + sizeof(val), 1); } else { int size = sizeof(val) + xattr->vsize; xp = get_xattr_space(size, &xattr->ool_value); val.vsize = xattr->vsize; SQUASHFS_SWAP_XATTR_VAL(&val, xp); memcpy(xp + sizeof(val), xattr->value, xattr->vsize); } } /* * Add to xattr id lookup table */ return get_xattr_id(xattrs, xattr_list, xattr_disk, xattr_dupl); } int read_xattrs(void *d) { struct dir_ent *dir_ent = d; struct inode_info *inode = dir_ent->inode; char *filename = pathname(dir_ent); struct xattr_list *xattr_list; int xattrs; if (no_xattrs || IS_PSEUDO(inode) || inode->root_entry) return SQUASHFS_INVALID_XATTR; xattrs = read_xattrs_from_system(filename, &xattr_list); if (xattrs == 0) return SQUASHFS_INVALID_XATTR; return generate_xattrs(xattrs, xattr_list); } /* * Add the existing xattr ids and xattr metadata in the file system being * appended to, to the in-memory xattr cache. This allows duplicate checking to * take place against the xattrs already in the file system being appended to, * and ensures the pre-existing xattrs are written out along with any new xattrs */ int get_xattrs(int fd, struct squashfs_super_block *sBlk) { int ids, res, i, id; unsigned int count; TRACE("get_xattrs\n"); res = read_xattrs_from_disk(fd, sBlk); if (res == SQUASHFS_INVALID_BLK || res == 0) goto done; ids = res; /* * for each xattr id read and construct its list of xattr * name:value pairs, and add them to the in-memory xattr cache */ for (i = 0; i < ids; i++) { struct xattr_list *xattr_list = get_xattr(i, &count, 0); if (xattr_list == NULL) { res = 0; goto done; } id = generate_xattrs(count, xattr_list); /* * Sanity check, the new xattr id should be the same as the * xattr id in the original file system */ if (id != i) { ERROR("BUG, different xattr_id in get_xattrs\n"); res = 0; goto done; } } done: return res; } /* * Save current state of xattrs, needed for restoring state in the event of an * abort in appending */ void save_xattrs() { /* save the current state of the compressed xattr data */ sxattr_bytes = xattr_bytes; stotal_xattr_bytes = total_xattr_bytes; /* * save the current state of the cached uncompressed xattr data. * Note we have to save the contents of the data cache because future * operations will delete the current contents */ sdata_cache = malloc(cache_bytes); if (sdata_cache == NULL) MEM_ERROR(); memcpy(sdata_cache, data_cache, cache_bytes); scache_bytes = cache_bytes; /* save the current state of the xattr id table */ sxattr_ids = xattr_ids; } /* * Restore xattrs in the event of an abort in appending */ void restore_xattrs() { /* restore the state of the compressed xattr data */ xattr_bytes = sxattr_bytes; total_xattr_bytes = stotal_xattr_bytes; /* restore the state of the uncomoressed xattr data */ memcpy(data_cache, sdata_cache, scache_bytes); cache_bytes = scache_bytes; /* restore the state of the xattr id table */ xattr_ids = sxattr_ids; } ================================================ FILE: src/squashfs/xz_wrapper.c ================================================ /* * Copyright (c) 2010, 2011, 2012, 2013 * Phillip Lougher * * 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 2, * 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, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * xz_wrapper.c * * Support for XZ (LZMA2) compression using XZ Utils liblzma * http://tukaani.org/xz/ */ #include #include #include #include #include "squashfs_fs.h" #include "xz_wrapper.h" #include "compressor.h" static struct bcj bcj[] = { {"x86", LZMA_FILTER_X86, 0}, {"powerpc", LZMA_FILTER_POWERPC, 0}, {"ia64", LZMA_FILTER_IA64, 0}, {"arm", LZMA_FILTER_ARM, 0}, {"armthumb", LZMA_FILTER_ARMTHUMB, 0}, {"sparc", LZMA_FILTER_SPARC, 0}, {NULL, LZMA_VLI_UNKNOWN, 0} }; static int filter_count = 1; static int dictionary_size = 0; static float dictionary_percent = 0; /* * This function is called by the options parsing code in mksquashfs.c * to parse any -X compressor option. * * Two specific options are supported: * -Xbcj * -Xdict-size * * This function returns: * >=0 (number of additional args parsed) on success * -1 if the option was unrecognised, or * -2 if the option was recognised, but otherwise bad in * some way (e.g. invalid parameter) * * Note: this function sets internal compressor state, but does not * pass back the results of the parsing other than success/failure. * The xz_dump_options() function is called later to get the options in * a format suitable for writing to the filesystem. */ static int xz_options(char *argv[], int argc) { int i; char *name; if (strcmp(argv[0], "-Xbcj") == 0) { if (argc < 2) { fprintf(stderr, "xz: -Xbcj missing filter\n"); goto failed; } name = argv[1]; while (name[0] != '\0') { for (i = 0; bcj[i].name; i++) { int n = strlen(bcj[i].name); if ((strncmp(name, bcj[i].name, n) == 0) && (name[n] == '\0' || name[n] == ',')) { if (bcj[i].selected == 0) { bcj[i].selected = 1; filter_count++; } name += name[n] == ',' ? n + 1 : n; break; } } if (bcj[i].name == NULL) { fprintf(stderr, "xz: -Xbcj unrecognised " "filter\n"); goto failed; } } return 1; } else if (strcmp(argv[0], "-Xdict-size") == 0) { char *b; float size; if (argc < 2) { fprintf(stderr, "xz: -Xdict-size missing dict-size\n"); goto failed; } size = strtof(argv[1], &b); if (*b == '%') { if (size <= 0 || size > 100) { fprintf(stderr, "xz: -Xdict-size percentage " "should be 0 < dict-size <= 100\n"); goto failed; } dictionary_percent = size; dictionary_size = 0; } else { if ((float)((int)size) != size) { fprintf(stderr, "xz: -Xdict-size can't be " "fractional unless a percentage of the" " block size\n"); goto failed; } dictionary_percent = 0; dictionary_size = (int)size; if (*b == 'k' || *b == 'K') dictionary_size *= 1024; else if (*b == 'm' || *b == 'M') dictionary_size *= 1024 * 1024; else if (*b != '\0') { fprintf(stderr, "xz: -Xdict-size invalid " "dict-size\n"); goto failed; } } return 1; } return -1; failed: return -2; } /* * This function is called after all options have been parsed. * It is used to do post-processing on the compressor options using * values that were not expected to be known at option parse time. * * In this case block_size may not be known until after -Xdict-size has * been processed (in the case where -b is specified after -Xdict-size) * * This function returns 0 on successful post processing, or * -1 on error */ static int xz_options_post(int block_size) { /* * if -Xdict-size has been specified use this to compute the datablock * dictionary size */ if (dictionary_size || dictionary_percent) { int n; if (dictionary_size) { if (dictionary_size > block_size) { fprintf(stderr, "xz: -Xdict-size is larger than" " block_size\n"); goto failed; } } else dictionary_size = block_size * dictionary_percent / 100; if (dictionary_size < 8192) { fprintf(stderr, "xz: -Xdict-size should be 8192 bytes " "or larger\n"); goto failed; } /* * dictionary_size must be storable in xz header as either * 2^n or as 2^n+2^(n+1) */ n = ffs(dictionary_size) - 1; if (dictionary_size != (1 << n) && dictionary_size != ((1 << n) + (1 << (n + 1)))) { fprintf(stderr, "xz: -Xdict-size is an unsupported " "value, dict-size must be storable in xz " "header\n"); fprintf(stderr, "as either 2^n or as 2^n+2^(n+1). " "Example dict-sizes are 75%%, 50%%, 37.5%%, " "25%%,\n"); fprintf(stderr, "or 32K, 16K, 8K etc.\n"); goto failed; } } else /* No -Xdict-size specified, use defaults */ dictionary_size = block_size; return 0; failed: return -1; } /* * This function is called by mksquashfs to dump the parsed * compressor options in a format suitable for writing to the * compressor options field in the filesystem (stored immediately * after the superblock). * * This function returns a pointer to the compression options structure * to be stored (and the size), or NULL if there are no compression * options */ static void *xz_dump_options(int block_size, int *size) { static struct comp_opts comp_opts; int flags = 0, i; /* * don't store compressor specific options in file system if the * default options are being used - no compressor options in the * file system means the default options are always assumed * * Defaults are: * metadata dictionary size: SQUASHFS_METADATA_SIZE * datablock dictionary size: block_size * 1 filter */ if (dictionary_size == block_size && filter_count == 1) return NULL; for (i = 0; bcj[i].name; i++) flags |= bcj[i].selected << i; comp_opts.dictionary_size = dictionary_size; comp_opts.flags = flags; SQUASHFS_INSWAP_COMP_OPTS(&comp_opts); *size = sizeof(comp_opts); return &comp_opts; } /* * This function is a helper specifically for the append mode of * mksquashfs. Its purpose is to set the internal compressor state * to the stored compressor options in the passed compressor options * structure. * * In effect this function sets up the compressor options * to the same state they were when the filesystem was originally * generated, this is to ensure on appending, the compressor uses * the same compression options that were used to generate the * original filesystem. * * Note, even if there are no compressor options, this function is still * called with an empty compressor structure (size == 0), to explicitly * set the default options, this is to ensure any user supplied * -X options on the appending mksquashfs command line are over-ridden * * This function returns 0 on sucessful extraction of options, and * -1 on error */ static int xz_extract_options(int block_size, void *buffer, int size) { struct comp_opts *comp_opts = buffer; int flags, i, n; if (size == 0) { /* set defaults */ dictionary_size = block_size; flags = 0; } else { /* check passed comp opts struct is of the correct length */ if (size != sizeof(struct comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); dictionary_size = comp_opts->dictionary_size; flags = comp_opts->flags; /* * check that the dictionary size seems correct - the dictionary * size should 2^n or 2^n+2^(n+1) */ n = ffs(dictionary_size) - 1; if (dictionary_size != (1 << n) && dictionary_size != ((1 << n) + (1 << (n + 1)))) goto failed; } filter_count = 1; for (i = 0; bcj[i].name; i++) { if ((flags >> i) & 1) { bcj[i].selected = 1; filter_count++; } else bcj[i].selected = 0; } return 0; failed: fprintf(stderr, "xz: error reading stored compressor options from " "filesystem!\n"); return -1; } void xz_display_options(void *buffer, int size) { struct comp_opts *comp_opts = buffer; int dictionary_size, flags, printed; int i, n; /* check passed comp opts struct is of the correct length */ if (size != sizeof(struct comp_opts)) goto failed; SQUASHFS_INSWAP_COMP_OPTS(comp_opts); dictionary_size = comp_opts->dictionary_size; flags = comp_opts->flags; /* * check that the dictionary size seems correct - the dictionary * size should 2^n or 2^n+2^(n+1) */ n = ffs(dictionary_size) - 1; if (dictionary_size != (1 << n) && dictionary_size != ((1 << n) + (1 << (n + 1)))) goto failed; printf("\tDictionary size %d\n", dictionary_size); printed = 0; for (i = 0; bcj[i].name; i++) { if ((flags >> i) & 1) { if (printed) printf(", "); else printf("\tFilters selected: "); printf("%s", bcj[i].name); printed = 1; } } if (!printed) printf("\tNo filters specified\n"); else printf("\n"); return; failed: fprintf(stderr, "xz: error reading stored compressor options from " "filesystem!\n"); } /* * This function is called by mksquashfs to initialise the * compressor, before compress() is called. * * This function returns 0 on success, and * -1 on error */ static int xz_init(void **strm, int block_size, int datablock) { int i, j, filters = datablock ? filter_count : 1; struct filter *filter = malloc(filters * sizeof(struct filter)); struct xz_stream *stream; if (filter == NULL) goto failed; stream = *strm = malloc(sizeof(struct xz_stream)); if (stream == NULL) goto failed2; stream->filter = filter; stream->filters = filters; memset(filter, 0, filters * sizeof(struct filter)); stream->dictionary_size = datablock ? dictionary_size : SQUASHFS_METADATA_SIZE; filter[0].filter[0].id = LZMA_FILTER_LZMA2; filter[0].filter[0].options = &stream->opt; filter[0].filter[1].id = LZMA_VLI_UNKNOWN; for (i = 0, j = 1; datablock && bcj[i].name; i++) { if (bcj[i].selected) { filter[j].buffer = malloc(block_size); if (filter[j].buffer == NULL) goto failed3; filter[j].filter[0].id = bcj[i].id; filter[j].filter[1].id = LZMA_FILTER_LZMA2; filter[j].filter[1].options = &stream->opt; filter[j].filter[2].id = LZMA_VLI_UNKNOWN; j++; } } return 0; failed3: for (i = 1; i < filters; i++) free(filter[i].buffer); free(stream); failed2: free(filter); failed: return -1; } static int xz_compress(void *strm, void *dest, void *src, int size, int block_size, int *error) { int i; lzma_ret res = 0; struct xz_stream *stream = strm; struct filter *selected = NULL; stream->filter[0].buffer = dest; for (i = 0; i < stream->filters; i++) { struct filter *filter = &stream->filter[i]; if (lzma_lzma_preset(&stream->opt, LZMA_PRESET_DEFAULT)) goto failed; stream->opt.dict_size = stream->dictionary_size; filter->length = 0; res = lzma_stream_buffer_encode(filter->filter, LZMA_CHECK_CRC32, NULL, src, size, filter->buffer, &filter->length, block_size); if (res == LZMA_OK) { if (!selected || selected->length > filter->length) selected = filter; } else if (res != LZMA_BUF_ERROR) goto failed; } if (!selected) /* * Output buffer overflow. Return out of buffer space */ return 0; if (selected->buffer != dest) memcpy(dest, selected->buffer, selected->length); return (int)selected->length; failed: /* * All other errors return failure, with the compressor * specific error code in *error */ *error = res; return -1; } static int xz_uncompress(void *dest, void *src, int size, int outsize, int *error) { size_t src_pos = 0; size_t dest_pos = 0; uint64_t memlimit = MEMLIMIT; lzma_ret res = lzma_stream_buffer_decode(&memlimit, 0, NULL, src, &src_pos, size, dest, &dest_pos, outsize); if (res == LZMA_OK && size == (int)src_pos) return (int)dest_pos; else { *error = res; return -1; } } void xz_usage() { fprintf(stderr, "\t -Xbcj filter1,filter2,...,filterN\n"); fprintf(stderr, "\t\tCompress using filter1,filter2,...,filterN in"); fprintf(stderr, " turn\n\t\t(in addition to no filter), and choose"); fprintf(stderr, " the best compression.\n"); fprintf(stderr, "\t\tAvailable filters: x86, arm, armthumb,"); fprintf(stderr, " powerpc, sparc, ia64\n"); fprintf(stderr, "\t -Xdict-size \n"); fprintf(stderr, "\t\tUse as the XZ dictionary size. The"); fprintf(stderr, " dictionary size\n\t\tcan be specified as a"); fprintf(stderr, " percentage of the block size, or as an\n\t\t"); fprintf(stderr, "absolute value. The dictionary size must be less"); fprintf(stderr, " than or equal\n\t\tto the block size and 8192 bytes"); fprintf(stderr, " or larger. It must also be\n\t\tstorable in the xz"); fprintf(stderr, " header as either 2^n or as 2^n+2^(n+1).\n\t\t"); fprintf(stderr, "Example dict-sizes are 75%%, 50%%, 37.5%%, 25%%, or"); fprintf(stderr, " 32K, 16K, 8K\n\t\tetc.\n"); } struct compressor xz_comp_ops = { .init = xz_init, .compress = xz_compress, .uncompress = xz_uncompress, .options = xz_options, .options_post = xz_options_post, .dump_options = xz_dump_options, .extract_options = xz_extract_options, .display_options = xz_display_options, .usage = xz_usage, .id = XZ_COMPRESSION, .name = "xz", .supported = 1 }; ================================================ FILE: src/stream/CMakeLists.txt ================================================ add_library(stream crc32.c tsfile.c) target_include_directories(stream PUBLIC ${INC}/stream) target_link_libraries(stream utils) ================================================ FILE: src/stream/crc32.c ================================================ #include static const unsigned int crc_table[256] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; uint32_t str_crc32(const unsigned char *data, int len) { uint32_t crc = 0xffffffff; uint32_t i; for (i = 0; i < len; i++) crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff]; return crc; } ================================================ FILE: src/stream/tsfile.c ================================================ /** * TS file Decryption * (C) 2020 the epk2extract authors **/ /* Transport Stream Header (or 4-byte prefix) consists of 32-bit: Sync byte 8bit 0x47 Transport Error Indicator (TEI) 1bit Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error [11] Payload Unit Start Indicator 1bit 1 means start of PES data or PSI otherwise zero only. Transport Priority 1bit 1 means higher priority than other packets with the same PID. PID 13bit Packet ID Scrambling control 2bit '00' = Not scrambled. The following per DVB spec:[12] '01' = Reserved for future use, '10' = Scrambled with even key, '11' = Scrambled with odd key Adaptation field exist 2bit '01' = no adaptation fields, payload only, '10' = adaptation field only, '11' = adaptation field and payload Continuity counter 4bit Incremented only when a payload is present (i.e., adaptation field exist is 01 or 11)[13] */ #include #include #include #include #include #include #include #include #include "util.h" #include "stream/crc32.h" #include "stream/tsfile.h" #define TS_PACKET_SIZE 192 static AES_KEY AESkey; static bool do_unwrap_func(const uint8_t unwrap_key[], const uint8_t aes_key[], uint8_t unwrapped_key[]) { puts("Wrapped key: "); for (unsigned int i = 0; i < 24; i++){ printf("%02" PRIX8, aes_key[i]); } // 8 bytes of 0xB7 (B7B7B7B7B7B7B7B7) const uint8_t wrap_iv[8] = {0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7}; // TODO: replace these deprecated functions // unwrap 'aes_key' with 'unwrap_key' into 'unwrapped_key' AES_set_decrypt_key(unwrap_key, 128, &AESkey); AES_unwrap_key(&AESkey, wrap_iv, unwrapped_key, aes_key, 24); uint8_t accum = 0; puts("\nUnwrapped key: "); for (unsigned int i = 0; i < 16; i++){ printf("%02" PRIX8, unwrapped_key[i]); // Record any bits that are set accum |= unwrapped_key[i]; } putchar('\n'); // If all bits were zero, return false return (accum != 0); } static int setKey(char *keyPath) { int ret = -1; FILE *keyFile = fopen(keyPath, "r"); if (keyFile == NULL) { fprintf(stderr, "%s not found.\n", keyPath); return ret; } struct stat statBuf; if((ret=fstat(fileno(keyFile), &statBuf)) < 0){ fprintf(stderr, "setKey: stat failed\n"); return ret; } bool doUnwrap; switch(statBuf.st_size){ case 16: printf("=> Unwrapped AES-128 key detected\n"); doUnwrap = false; break; case 24: printf("=> Wrapped AES-128 key detected\n"); doUnwrap = true; break; default: fprintf(stderr, "Unknown or invalid key found (key size=%jd)\n", (intmax_t) statBuf.st_size); return -1; } int keySz = statBuf.st_size; uint8_t aes_key[keySz]; memset(&aes_key, 0x00, keySz); int read = fread(&aes_key, keySz, 1, keyFile); fclose(keyFile); if(read != 1){ fprintf(stderr, "key read error\n"); return -1; } if(doUnwrap){ uint8_t unwrapped_key[16]; uint8_t unwrap_key[16]; // set unwrap_key: 0x01, 0x02, 0x03, ... 0x0F for (int i = 0; i < sizeof(unwrap_key); i++){ unwrap_key[i] = i; //printf("%02" PRIx8, unwrap_key[i]); } putchar('\n'); if (!do_unwrap_func(unwrap_key, aes_key, unwrapped_key)) { // If unwrapping failed, try alternative KEK from ww#8543 puts("Failed to unwrap key; trying again with alternative key encryption key...\n"); const uint8_t unwrap_key2[16] = {0xb1, 0x52, 0x73, 0x3f, 0x68, 0x61, 0x3b, 0x6a, 0x40, 0x6c, 0x7a, 0xa4, 0xbe, 0x28, 0xb8, 0xb6}; if (!do_unwrap_func(unwrap_key2, aes_key, unwrapped_key)) { puts("Failed to unwrap key\n"); return -1; } } AES_set_decrypt_key(unwrapped_key, 128, &AESkey); } else { AES_set_decrypt_key(aes_key, 128, &AESkey); } return 0; } // minimum number of TS packets (sync bytes) that must be present #define MIN_TS_PACKETS 3 uint8_t *findTsPacket(MFILE *tsFile, long offset){ if(offset >= msize(tsFile)){ return NULL; } uint8_t *head; uint8_t *cur; int syncPackets; do { // abort in case no valid sync is found in the first bytes of the file if(offset >= (TS_PACKET_SIZE * 2)){ return NULL; } syncPackets = 0; // find initial sync position sequentially for(head = mdata(tsFile, uint8_t) + offset; moff(tsFile, head) < msize(tsFile) && *head != 0x47; head++ ); // EOF condition if(*head != 0x47) break; ++syncPackets; cur = head; // found the initial sync. now check next packets for(int i=0; // syncPacketsaudio_stream_type == -1) ? AUDIO_TYPE_MPEG2 : opts->audio_stream_type; int video_stream_type = (opts->video_stream_type == -1) ? VIDEO_TYPE_H264 : opts->video_stream_type; // Gather information for PMT construction unsigned char stream_count = 0; for (unsigned int i = 0; i < 8192; i++) { //Count video stream PIDs (0xE0-0xEF) if (PIDs->type[i] >= 0xE0 && PIDs->type[i] <= 0xEF) { stream_count++; } //Count audio stream PIDs (0xC0-0xDF) else if (PIDs->type[i] >= 0xC0 && PIDs->type[i] <= 0xDF) { stream_count++; } } unsigned char PMT_size = 21 + stream_count * 5; uint8_t outBuf[TS_PACKET_SIZE]; memset(outBuf, 0xFF, TS_PACKET_SIZE); // Fill PMT uint8_t PMT[TS_PACKET_SIZE - 4]; memset(PMT, 0xFF, TS_PACKET_SIZE - 4); const uint8_t PMT_header[17] = { /** 0x0: Transport header (TS) **/ 0x47, // sync byte 0x40, // PUSI flag 0xB1, 0x10, /** 0x4: PSI **/ 0x00, // pointer field /** 0x5: table header **/ 0x02, // program_map_section 0xB0, 0x00, // section length in bytes including crc /** 0x8: table syntax data **/ 0x00, 0x01, // program number 0xC1, 0x00, 0x00, /** 0xD: PMT data **/ 0xE4, 0x7E, // PCR PID 0xF0, 0x00 // Program info length /** 0x11 **/ }; memcpy(PMT, PMT_header, sizeof(PMT_header)); PMT[7] = 13 + stream_count * 5; uint32_t pmt_data; stream_count = 0; for (unsigned int i = 0; i < 8192; i++){ uint32_t packed_pid = pack_pid(i); if (PIDs->number[i] > 0) { printf("PID %X : %d Type: %hhX PCRs: %X\n", i, PIDs->number[i], PIDs->type[i], (unsigned int) PIDs->pcr_count[i]); if (PIDs->pcr_count[i] > 0) { // Set PCR PID pmt_data = (0 | (packed_pid << 12) // program info length (0 for now) | 0 & 0xFFF ); PMT[13] = (pmt_data >> 24) & 0xFF; PMT[14] = (pmt_data >> 16) & 0xFF; PMT[15] = (pmt_data >> 8) & 0xFF; PMT[16] = (pmt_data >> 0) & 0xFF; } uint32_t es_data = (0 | (packed_pid << 12) // ES info length (0 for now) | 0 & 0xFFF ); //Set video stream data in PMT if (PIDs->type[i] >= 0xE0 && PIDs->type[i] <= 0xEF) { PMT[17 + stream_count * 5] = video_stream_type; // stream type PMT[18 + stream_count * 5] = (es_data >> 24) & 0xFF; PMT[19 + stream_count * 5] = (es_data >> 16) & 0xFF; PMT[20 + stream_count * 5] = (es_data >> 8) & 0xFF; PMT[21 + stream_count * 5] = (es_data >> 0) & 0xF; stream_count++; } //Set audio stream data in PMT else if (PIDs->type[i] >= 0xC0 && PIDs->type[i] <= 0xDF) { PMT[17 + stream_count * 5] = audio_stream_type; // stream type PMT[18 + stream_count * 5] = (es_data >> 24) & 0xFF; PMT[19 + stream_count * 5] = (es_data >> 16) & 0xFF; PMT[20 + stream_count * 5] = (es_data >> 8) & 0xFF; PMT[21 + stream_count * 5] = (es_data >> 0) & 0xF; stream_count++; } } } // Set CRC32 // A checksum of the entire table // excluding the pointer field, pointer filler bytes (aka none) // and the trailing CRC32. uint32_t crc = str_crc32(&PMT[5], PMT[7] - 1); PMT[PMT_size - 4] = (crc >> 24) & 0xFF; PMT[PMT_size - 3] = (crc >> 16) & 0xFF; PMT[PMT_size - 2] = (crc >> 8) & 0xFF; PMT[PMT_size - 1] = crc & 0xFF; memcpy(outBuf, PMT, sizeof(PMT)); fseek(outFile, 0xBC, SEEK_SET); fwrite(outBuf, 1, TS_PACKET_SIZE, outFile); } void processTsPacket(uint8_t *packet, struct tables *PIDs, FILE *outFile){ uint8_t outBuf[TS_PACKET_SIZE]; // data offset int offset = 4; // Transport scrambling control int tsc = packet[3] & 0xC0; // either 0x20 or 0x30 int have_adapt_field = (packet[3] & 0x30) > 0x10; // either 0x10 or 0x30 int have_payload_field = (packet[3] & 0x30) != 0x20; int pid = (0 | ((packet[1] & 0x1F) << 8) | packet[2] ); if(!have_payload_field){ return; } if ( // LG Netcast writes even/odd DVB-CSA flag, even tho the key is fixed tsc == 0x80 || tsc == 0xC0 // WebOS uses the "reserved" flag instead || tsc == 0x40 ) { // packet is encrypted, so we copy the original (readonly) for modifications memcpy(outBuf, packet, TS_PACKET_SIZE); // now set the pointer to the copy packet = &outBuf[0]; if(have_adapt_field){ offset += (packet[4] + 1); // adaption field length + sizeof length field } packet[3] &= ~0xC0; // remove scrambling bits if (offset > TS_PACKET_SIZE){ //application will crash without this check when file is corrupted offset = TS_PACKET_SIZE; } // NOTE: 4 seems to be custom LG padding, excluded from AES int data_length = TS_PACKET_SIZE - offset - 4; unsigned blocks = data_length / AES_BLOCK_SIZE; for (unsigned int i = 0; i < blocks; i++){ // in-place decrypt (ECB) AES_decrypt( &packet[offset + i * AES_BLOCK_SIZE], &packet[offset + i * AES_BLOCK_SIZE], &AESkey); } }; // Search PCR if (have_adapt_field){ if (packet[5] & 0x10){ // check if PCR exists PIDs->pcr_count[pid]++; } } // Count PES packets only // check PES start code prefix if(packet[offset + 0] == 0 && packet[offset + 1] == 0 && packet[offset + 2] == 1 ){ PIDs->number[pid]++; // stream ID. Examples: Audio streams (0xC0-0xDF), Video streams (0xE0-0xEF) PIDs->type[pid] = packet[offset + 3]; } fwrite(packet, 1, TS_PACKET_SIZE, outFile); } void convertSTR2TS_internal(char *inFilename, char *outFilename, struct tsfile_options *opts) { MFILE *inFile = mopen(inFilename, O_RDONLY); if (inFile == NULL) { printf("Can't open file %s\n", inFilename); return; } struct tables PIDs; memset(&PIDs, 0, sizeof(PIDs)); do { const char *mode = (opts->append) ? "a+b" : "wb"; FILE *outFile = fopen(outFilename, mode);; if (outFile == NULL) { fprintf(stderr, "Can't open file %s\n", outFilename); break; } do { uint8_t *packet = findTsPacket(inFile, 0); if(packet == NULL){ fprintf(stderr, "Could not find sync\n"); break; } writeHeaders(outFile); long offset; for(; (offset=moff(inFile, packet)) < msize(inFile) && offset + TS_PACKET_SIZE < msize(inFile) ; packet += TS_PACKET_SIZE ){ if(packet[0] != 0x47){ fprintf(stderr, "\nLost sync at offset %" PRIx64 "\n", offset); packet = findTsPacket(inFile, offset); } if(packet == NULL){ fprintf(stderr, "error: lost sync\n"); break; } processTsPacket(packet, &PIDs, outFile); } } while(0); writePMT(&PIDs, outFile, opts); fclose(outFile); } while(0); mclose(inFile); } void convertSTR2TS(char *inFilename, struct tsfile_options *opts) { char *baseDir = my_dirname(inFilename); char *keyPath; asprintf(&keyPath, "%s/dvr", baseDir); if (0 != setKey(keyPath)){ free(keyPath); err_exit("Load DVR Key-file failed for %s/dvr\n", baseDir); } free(keyPath); char *baseName = my_basename(inFilename); char *outFilename; asprintf(&outFilename, "%s/%s.ts", baseDir, baseName); printf("Output File: %s\n", outFilename); convertSTR2TS_internal(inFilename, outFilename, opts); free(baseName); free(baseDir); } void processPIF(const char *filename, char *dest_file) { FILE *file = fopen(filename, "r"); if (file == NULL) { err_exit("Can't open file %s\n", filename); } struct stat statBuf; if(stat(filename, &statBuf) < 0){ err_exit("stat() failed for %s\n", filename); } size_t filesize = statBuf.st_size; char *baseDir = my_dirname(filename); char *keyPath; asprintf(&keyPath, "%s/dvr", baseDir); if (0 != setKey(keyPath)){ free(keyPath); err_exit("Load DVR Key-file failed for %s/dvr\n", baseDir); } free(keyPath); int append = 0; char *buffer = calloc(1, filesize); int read = fread(buffer, 1, filesize, file); if (read == filesize) { int i; for (i = 0; i < (filesize - 5); i++) { if (!memcmp(&buffer[i], "/mnt/", 5) && !memcmp(&buffer[i + strlen(&buffer[i]) - 3], "STR", 3)) { char *strName = strrchr(&buffer[i], '/') + 1; char *filePath; asprintf(&filePath, "%s/%s", baseDir, strName); printf("Converting file: %s -> %s\n", filePath, dest_file); struct tsfile_options opts = { // $TODO: add a way to specify these .video_stream_type = -1, .audio_stream_type = -1, .append = append }; convertSTR2TS_internal(filePath, dest_file, &opts); free(filePath); append = 1; } } } fclose(file); free(buffer); free(baseDir); } ================================================ FILE: src/symfile.c ================================================ /* * Copyright (c) 2011 Roman Tokarev * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY CONTRIBUTORS ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #define MAGIC 0xB12791EE struct symfile_header { uint32_t magic; uint32_t unknown; uint32_t size; uint32_t n_symbols; uint32_t tail_size; }__attribute__((packed)); struct sym_table sym_table = { .n_symbols = 0, .sym_entry = NULL, .hash = NULL, .n_dwarf_lst = 0, .dwarf_lst = NULL, .dwarf_data = NULL, .sym_name = NULL }; int symfile_load(const char *fname) { int fd = -1; struct stat st_buf; void *p; struct symfile_header *header; uint32_t *has_hash, *has_dwarf; uint32_t dwarf_data_size = 0; fd = open(fname, O_RDONLY); if (fd == -1) { fprintf(stderr, "can't open `%s': %m\n", fname); return -1; } if (fstat(fd, &st_buf) != 0) { fprintf(stderr, "fstat for `%s' is failed: %m\n", fname); return -1; } p = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); header = p; p += sizeof(*header); if (header == NULL) { fprintf(stderr, "can't mmap `%s': %m\n", fname); return -1; } if (header->magic != MAGIC) { //fprintf(stderr, "bad magic 0x%x from `%s'\n", header->magic, fname); return -1; } if ((header->size + sizeof(*header)) != (uint32_t) st_buf.st_size) { fprintf(stderr, "bad file `%s' size: %zu, expected size: %lu\n", fname, st_buf.st_size, header->size + sizeof(*header)); return -1; } if ((header->tail_size + sizeof(struct sym_entry) * header->n_symbols) != header->size) { fprintf(stderr, "file `%s' is broken\n", fname); return -1; } sym_table.n_symbols = header->n_symbols; sym_table.sym_entry = p; p += sizeof(sym_table.sym_entry[0]) * sym_table.n_symbols; has_hash = p; p += sizeof(*has_hash); if (*has_hash != 2 && *has_hash != 0) { fprintf(stderr, "unsupported file `%s' format (unexpected has_hash 0x%x)\n", fname, *has_hash); return -1; } if (*has_hash == 2) { sym_table.hash = p; p += sizeof(sym_table.hash[0]) * ((sym_table.n_symbols + 1) & (~0 - 1)); } has_dwarf = p; p += sizeof(*has_dwarf); if (*has_dwarf == 1) { sym_table.n_dwarf_lst = *(uint32_t *) p; p += sizeof(sym_table.n_dwarf_lst); dwarf_data_size = *(uint32_t *) p; p += sizeof(dwarf_data_size); sym_table.dwarf_lst = p; p += sizeof(sym_table.dwarf_lst[0]) * sym_table.n_dwarf_lst; sym_table.dwarf_data = p; p += dwarf_data_size; sym_table.sym_name = p; } else { sym_table.sym_name = (char *)has_dwarf; } printf("`%s' has been successfully loaded\n", fname); return 0; } uint32_t symfile_addr_by_name(const char *name) { unsigned i = 0; for (i = 0; i < sym_table.n_symbols; ++i) { char *sym_name = sym_table.sym_name + sym_table.sym_entry[i].sym_name_off; if (strcmp(sym_name, name) == 0) return sym_table.sym_entry[i].addr; } return 0; } uint32_t symfile_n_symbols() { return sym_table.n_symbols; } void symfile_write_idc(const char *fname) { FILE *outfile = fopen(fname, "w"); fprintf(outfile, "%s\n\n", "#include "); fprintf(outfile, "%s\n", "static main() {"); unsigned i = 0; for (i = 0; i < sym_table.n_symbols; ++i) { char *sym_name = sym_table.sym_name + sym_table.sym_entry[i].sym_name_off; uint32_t addr = sym_table.sym_entry[i].addr; uint32_t end = sym_table.sym_entry[i].end; //printf("%s: %x...%x\n", sym_name, addr, end); fprintf(outfile, "MakeNameEx( 0x%x, \"%s\", SN_NOWARN | SN_CHECK);\n", addr, sym_name); fprintf(outfile, "if(SegName(0x%x)==\".text\") {\n", addr); fprintf(outfile, " MakeCode(0x%x);\n", addr); fprintf(outfile, " MakeFunction(0x%x, 0x%x);\n", addr, end); fprintf(outfile, "};\n"); } fprintf(outfile, "%s\n", "}"); fclose(outfile); //printf("n_dwarf_lst: %d\n", sym_table.n_dwarf_lst); //printf("dwarf_lst.d1: %d\n", sym_table.dwarf_lst->d1); //printf("dwarf_lst.d2: %d\n", sym_table.dwarf_lst->d2); //hexdump(sym_table.dwarf_data, 15000); } const char *symfile_name_by_addr(uint32_t addr) { int i = 0; for (i = sym_table.n_symbols - 1; i >= 0; --i) { if (sym_table.sym_entry[i].addr <= addr && sym_table.sym_entry[i].end > addr) return sym_table.sym_name + sym_table.sym_entry[i].sym_name_off; } return NULL; } ================================================ FILE: src/thpool.c ================================================ /* ******************************** * Author: Johan Hanssen Seferidis * License: MIT * Description: Library providing a threading pool where you can add * work. For usage, check the thpool.h file or README.md * *//** @file thpool.h *//* * ********************************/ #include #include #include #include #include #include #include #if defined(__linux__) #include #endif #include "thpool.h" #ifdef THPOOL_DEBUG #define THPOOL_DEBUG 1 #else #define THPOOL_DEBUG 0 #endif static volatile int threads_keepalive; static volatile int threads_on_hold; /* ========================== STRUCTURES ============================ */ /* Binary semaphore */ typedef struct bsem { pthread_mutex_t mutex; pthread_cond_t cond; int v; } bsem; /* Job */ typedef struct job{ struct job* prev; /* pointer to previous job */ void (*function)(void* arg); /* function pointer */ void* arg; /* function's argument */ } job; /* Job queue */ typedef struct jobqueue{ pthread_mutex_t rwmutex; /* used for queue r/w access */ job *front; /* pointer to front of queue */ job *rear; /* pointer to rear of queue */ bsem *has_jobs; /* flag as binary semaphore */ int len; /* number of jobs in queue */ } jobqueue; /* Thread */ typedef struct thread{ int id; /* friendly id */ pthread_t pthread; /* pointer to actual thread */ struct thpool_* thpool_p; /* access to thpool */ } thread; /* Threadpool */ typedef struct thpool_{ thread** threads; /* pointer to threads */ volatile int num_threads_alive; /* threads currently alive */ volatile int num_threads_working; /* threads currently working */ pthread_mutex_t thcount_lock; /* used for thread count etc */ pthread_cond_t threads_all_idle; /* signal to thpool_wait */ jobqueue* jobqueue_p; /* pointer to the job queue */ } thpool_; /* ========================== PROTOTYPES ============================ */ static int thread_init(thpool_* thpool_p, struct thread** thread_p, int id); static void* thread_do(struct thread* thread_p); static void thread_hold(); static void thread_destroy(struct thread* thread_p); static int jobqueue_init(thpool_* thpool_p); static void jobqueue_clear(thpool_* thpool_p); static void jobqueue_push(thpool_* thpool_p, struct job* newjob_p); static struct job* jobqueue_pull(thpool_* thpool_p); static void jobqueue_destroy(thpool_* thpool_p); static void bsem_init(struct bsem *bsem_p, int value); static void bsem_reset(struct bsem *bsem_p); static void bsem_post(struct bsem *bsem_p); static void bsem_post_all(struct bsem *bsem_p); static void bsem_wait(struct bsem *bsem_p); /* ========================== THREADPOOL ============================ */ /* Initialise thread pool */ struct thpool_* thpool_init(int num_threads){ threads_on_hold = 0; threads_keepalive = 1; if (num_threads < 0){ num_threads = 0; } /* Make new thread pool */ thpool_* thpool_p; thpool_p = (struct thpool_*)malloc(sizeof(struct thpool_)); if (thpool_p == NULL){ fprintf(stderr, "thpool_init(): Could not allocate memory for thread pool\n"); return NULL; } thpool_p->num_threads_alive = 0; thpool_p->num_threads_working = 0; /* Initialise the job queue */ if (jobqueue_init(thpool_p) == -1){ fprintf(stderr, "thpool_init(): Could not allocate memory for job queue\n"); free(thpool_p); return NULL; } /* Make threads in pool */ thpool_p->threads = (struct thread**)malloc(num_threads * sizeof(struct thread *)); if (thpool_p->threads == NULL){ fprintf(stderr, "thpool_init(): Could not allocate memory for threads\n"); jobqueue_destroy(thpool_p); free(thpool_p->jobqueue_p); free(thpool_p); return NULL; } pthread_mutex_init(&(thpool_p->thcount_lock), NULL); pthread_cond_init(&thpool_p->threads_all_idle, NULL); /* Thread init */ int n; for (n=0; nthreads[n], n); if (THPOOL_DEBUG) printf("THPOOL_DEBUG: Created thread %d in pool \n", n); } /* Wait for threads to initialize */ while (thpool_p->num_threads_alive != num_threads) {} return thpool_p; } /* Add work to the thread pool */ int thpool_add_work(thpool_* thpool_p, void (*function_p)(void*), void* arg_p){ job* newjob; newjob=(struct job*)malloc(sizeof(struct job)); if (newjob==NULL){ fprintf(stderr, "thpool_add_work(): Could not allocate memory for new job\n"); return -1; } /* add function and argument */ newjob->function=function_p; newjob->arg=arg_p; /* add job to queue */ pthread_mutex_lock(&thpool_p->jobqueue_p->rwmutex); jobqueue_push(thpool_p, newjob); pthread_mutex_unlock(&thpool_p->jobqueue_p->rwmutex); return 0; } /* Wait until all jobs have finished */ void thpool_wait(thpool_* thpool_p){ pthread_mutex_lock(&thpool_p->thcount_lock); while (thpool_p->jobqueue_p->len || thpool_p->num_threads_working) { pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock); } pthread_mutex_unlock(&thpool_p->thcount_lock); } /* Destroy the threadpool */ void thpool_destroy(thpool_* thpool_p){ /* No need to destory if it's NULL */ if (thpool_p == NULL) return ; volatile int threads_total = thpool_p->num_threads_alive; /* End each thread 's infinite loop */ threads_keepalive = 0; /* Give one second to kill idle threads */ double TIMEOUT = 1.0; time_t start, end; double tpassed = 0.0; time (&start); while (tpassed < TIMEOUT && thpool_p->num_threads_alive){ bsem_post_all(thpool_p->jobqueue_p->has_jobs); time (&end); tpassed = difftime(end,start); } /* Poll remaining threads */ while (thpool_p->num_threads_alive){ bsem_post_all(thpool_p->jobqueue_p->has_jobs); sleep(1); } /* Job queue cleanup */ jobqueue_destroy(thpool_p); free(thpool_p->jobqueue_p); /* Deallocs */ int n; for (n=0; n < threads_total; n++){ thread_destroy(thpool_p->threads[n]); } free(thpool_p->threads); free(thpool_p); } /* Pause all threads in threadpool */ void thpool_pause(thpool_* thpool_p) { int n; for (n=0; n < thpool_p->num_threads_alive; n++){ pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1); } } /* Resume all threads in threadpool */ void thpool_resume(thpool_* thpool_p) { threads_on_hold = 0; } /* ============================ THREAD ============================== */ /* Initialize a thread in the thread pool * * @param thread address to the pointer of the thread to be created * @param id id to be given to the thread * @return 0 on success, -1 otherwise. */ static int thread_init (thpool_* thpool_p, struct thread** thread_p, int id){ *thread_p = (struct thread*)malloc(sizeof(struct thread)); if (thread_p == NULL){ fprintf(stderr, "thread_init(): Could not allocate memory for thread\n"); return -1; } (*thread_p)->thpool_p = thpool_p; (*thread_p)->id = id; pthread_create(&(*thread_p)->pthread, NULL, (void *)thread_do, (*thread_p)); pthread_detach((*thread_p)->pthread); return 0; } /* Sets the calling thread on hold */ static void thread_hold () { threads_on_hold = 1; while (threads_on_hold){ sleep(1); } } /* What each thread is doing * * In principle this is an endless loop. The only time this loop gets interuppted is once * thpool_destroy() is invoked or the program exits. * * @param thread thread that will run this function * @return nothing */ static void* thread_do(struct thread* thread_p){ /* Set thread name for profiling and debuging */ char thread_name[128] = {0}; sprintf(thread_name, "thread-pool-%d", thread_p->id); #if defined(__linux__) /* Use prctl instead to prevent using _GNU_SOURCE flag and implicit declaration */ prctl(PR_SET_NAME, thread_name); #elif defined(__APPLE__) && defined(__MACH__) pthread_setname_np(thread_name); #else fprintf(stderr, "thread_do(): pthread_setname_np is not supported on this system"); #endif /* Assure all threads have been created before starting serving */ thpool_* thpool_p = thread_p->thpool_p; /* Register signal handler */ struct sigaction act; sigemptyset(&act.sa_mask); act.sa_flags = 0; act.sa_handler = thread_hold; if (sigaction(SIGUSR1, &act, NULL) == -1) { fprintf(stderr, "thread_do(): cannot handle SIGUSR1"); } /* Mark thread as alive (initialized) */ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive += 1; pthread_mutex_unlock(&thpool_p->thcount_lock); while(threads_keepalive){ bsem_wait(thpool_p->jobqueue_p->has_jobs); if (threads_keepalive){ pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working++; pthread_mutex_unlock(&thpool_p->thcount_lock); /* Read job from queue and execute it */ void (*func_buff)(void* arg); void* arg_buff; job* job_p; pthread_mutex_lock(&thpool_p->jobqueue_p->rwmutex); job_p = jobqueue_pull(thpool_p); pthread_mutex_unlock(&thpool_p->jobqueue_p->rwmutex); if (job_p) { func_buff = job_p->function; arg_buff = job_p->arg; func_buff(arg_buff); free(job_p); } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_working--; if (!thpool_p->num_threads_working) { pthread_cond_signal(&thpool_p->threads_all_idle); } pthread_mutex_unlock(&thpool_p->thcount_lock); } } pthread_mutex_lock(&thpool_p->thcount_lock); thpool_p->num_threads_alive --; pthread_mutex_unlock(&thpool_p->thcount_lock); return NULL; } /* Frees a thread */ static void thread_destroy (thread* thread_p){ free(thread_p); } /* ============================ JOB QUEUE =========================== */ /* Initialize queue */ static int jobqueue_init(thpool_* thpool_p){ thpool_p->jobqueue_p = (struct jobqueue*)malloc(sizeof(struct jobqueue)); if (thpool_p->jobqueue_p == NULL){ return -1; } thpool_p->jobqueue_p->len = 0; thpool_p->jobqueue_p->front = NULL; thpool_p->jobqueue_p->rear = NULL; thpool_p->jobqueue_p->has_jobs = (struct bsem*)malloc(sizeof(struct bsem)); if (thpool_p->jobqueue_p->has_jobs == NULL){ return -1; } pthread_mutex_init(&(thpool_p->jobqueue_p->rwmutex), NULL); bsem_init(thpool_p->jobqueue_p->has_jobs, 0); return 0; } /* Clear the queue */ static void jobqueue_clear(thpool_* thpool_p){ while(thpool_p->jobqueue_p->len){ free(jobqueue_pull(thpool_p)); } thpool_p->jobqueue_p->front = NULL; thpool_p->jobqueue_p->rear = NULL; bsem_reset(thpool_p->jobqueue_p->has_jobs); thpool_p->jobqueue_p->len = 0; } /* Add (allocated) job to queue * * Notice: Caller MUST hold a mutex */ static void jobqueue_push(thpool_* thpool_p, struct job* newjob){ newjob->prev = NULL; switch(thpool_p->jobqueue_p->len){ case 0: /* if no jobs in queue */ thpool_p->jobqueue_p->front = newjob; thpool_p->jobqueue_p->rear = newjob; break; default: /* if jobs in queue */ thpool_p->jobqueue_p->rear->prev = newjob; thpool_p->jobqueue_p->rear = newjob; } thpool_p->jobqueue_p->len++; bsem_post(thpool_p->jobqueue_p->has_jobs); } /* Get first job from queue(removes it from queue) * * Notice: Caller MUST hold a mutex */ static struct job* jobqueue_pull(thpool_* thpool_p){ job* job_p; job_p = thpool_p->jobqueue_p->front; switch(thpool_p->jobqueue_p->len){ case 0: /* if no jobs in queue */ break; case 1: /* if one job in queue */ thpool_p->jobqueue_p->front = NULL; thpool_p->jobqueue_p->rear = NULL; thpool_p->jobqueue_p->len = 0; break; default: /* if >1 jobs in queue */ thpool_p->jobqueue_p->front = job_p->prev; thpool_p->jobqueue_p->len--; /* more than one job in queue -> post it */ bsem_post(thpool_p->jobqueue_p->has_jobs); } return job_p; } /* Free all queue resources back to the system */ static void jobqueue_destroy(thpool_* thpool_p){ jobqueue_clear(thpool_p); free(thpool_p->jobqueue_p->has_jobs); } /* ======================== SYNCHRONISATION ========================= */ /* Init semaphore to 1 or 0 */ static void bsem_init(bsem *bsem_p, int value) { if (value < 0 || value > 1) { fprintf(stderr, "bsem_init(): Binary semaphore can take only values 1 or 0"); exit(1); } pthread_mutex_init(&(bsem_p->mutex), NULL); pthread_cond_init(&(bsem_p->cond), NULL); bsem_p->v = value; } /* Reset semaphore to 0 */ static void bsem_reset(bsem *bsem_p) { bsem_init(bsem_p, 0); } /* Post to at least one thread */ static void bsem_post(bsem *bsem_p) { pthread_mutex_lock(&bsem_p->mutex); bsem_p->v = 1; pthread_cond_signal(&bsem_p->cond); pthread_mutex_unlock(&bsem_p->mutex); } /* Post to all threads */ static void bsem_post_all(bsem *bsem_p) { pthread_mutex_lock(&bsem_p->mutex); bsem_p->v = 1; pthread_cond_broadcast(&bsem_p->cond); pthread_mutex_unlock(&bsem_p->mutex); } /* Wait on semaphore until semaphore has value 0 */ static void bsem_wait(bsem* bsem_p) { pthread_mutex_lock(&bsem_p->mutex); while (bsem_p->v != 1) { pthread_cond_wait(&bsem_p->cond, &bsem_p->mutex); } bsem_p->v = 0; pthread_mutex_unlock(&bsem_p->mutex); } ================================================ FILE: src/tools/CMakeLists.txt ================================================ add_executable(lzhsenc lzhsenc.c) add_executable(lzhs_scanner lzhs_scanner.c) add_executable(idb_extract idb_extract.c) add_executable(jffs2extract jffs2extract.c) add_executable(tsfile tsfile.c) target_link_libraries(idb_extract mfile utils) target_link_libraries(lzhsenc lzhs) target_link_libraries(lzhs_scanner utils lzhs) target_link_libraries(jffs2extract jffs2 mfile utils) target_link_libraries(tsfile stream utils) ================================================ FILE: src/tools/idb_extract.c ================================================ /** * Image Database dumper * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include "mfile.h" #include "util.h" #define IDB_VERSION "IDB_VERSION=" #define IDB_NUM_IMG "IDB_NUM_IMG=" #define IDB_HDR_ENDMARK "IDB_HDR_ENDMARK" #define IDB_V1 "1.1" char *READ_TO(MFILE *mfile, char *ptr, char ch){ while(*ptr != ch){ ptr++; if(moff(mfile, ptr) >= msize(mfile)){ fprintf(stderr, "Unexpected EOF!\n"); return NULL; } } return ptr; } char *READ_AFTER(MFILE *mfile, char *ptr, char ch){ ptr = READ_TO(mfile, ptr, ch); if(ptr == NULL) return ptr; return ++ptr; } struct idb_file { uint major; uint minor; unsigned long num_img; }; struct __attribute__((packed)) idb_entry { uint32_t unk1; uint32_t unk2; uint32_t size; uint32_t offset; }; int process_idb(MFILE *mf){ uint8_t *data = mdata(mf, uint8_t); uint8_t *p = data; struct idb_file idb; if(strncmp(p, IDB_VERSION, strlen(IDB_VERSION))){ fprintf(stderr, "Not an IDB file (no version TAG)\n"); return -1; } p += strlen(IDB_VERSION); if(strncmp(p, IDB_V1, strlen(IDB_V1))){ fprintf(stderr, "Unsupported version %.*s\n", READ_TO(mf, p, '\n') - (char *)p, p); return -1; } idb.major = 1; idb.minor = 1; p += strlen(IDB_V1); if((p=READ_AFTER(mf, p, '\n')) == NULL) return -1; if(strncmp(p, IDB_NUM_IMG, strlen(IDB_NUM_IMG))){ fprintf(stderr, "Cannot find number of pictures TAG\n"); return -1; } p += strlen(IDB_NUM_IMG); idb.num_img = strtoul((char *)p, (char **)&p, 10); if(idb.num_img == 0){ fprintf(stderr, "Invalid number of pictures (%zu)\n", idb.num_img); return -1; } do { p = READ_AFTER(mf, p, '\n'); if(p == NULL){ fprintf(stderr, "Cannot find header end TAG\n"); return -1; } } while(strncmp(p, IDB_HDR_ENDMARK, strlen(IDB_HDR_ENDMARK))); p = READ_AFTER(mf, p, '\n'); if(p == NULL){ return -1; } /* Smx: this is either wrong or we're not extracting all of the pictures */ printf("[IDB] Extracting %lu pictures\n", idb.num_img); struct idb_entry *entry = (struct idb_entry *)p; off_t hdr_end = entry->offset; char *file_dir = my_dirname(mf->path); char *file_base = my_basename(mf->path); char *file_name = remove_ext(file_base); char *dest_dir; asprintf(&dest_dir, "%s/%s", file_dir, file_name); createFolder(dest_dir); free(file_dir); free(file_base); free(file_name); uint i = 0; for(i=0; moff(mf, entry) < hdr_end; entry++){ /* Smx: I don't know why there are many dupes with size 0 */ if(entry->size == 0) continue; i++; printf("[IDB:0x%08X] Picture %u (%u bytes)\n", entry->offset, i, entry->size); char *out_file; asprintf(&out_file, "%s/%d.png", dest_dir, i); MFILE *out = mfopen(out_file, "w+"); if(!out){ fprintf(stderr, "Cannot open '%s' for writing\n", out_file); free(out_file); return -1; } mfile_map(out, entry->size); memcpy( mdata(out, void), &data[entry->offset], entry->size ); mclose(out); free(out_file); } free(dest_dir); return 0; } int main(int argc, char *argv[]){ int ret = EXIT_FAILURE; if(argc < 2){ fprintf(stderr, "Usage: %s [IDB__.lr]\n", argv[0]); goto exit_e0; } MFILE *mf = mopen(argv[1], O_RDONLY); if(!mf){ fprintf(stderr, "mopen failed!\n"); return -1; } if(!process_idb(mf)) ret = EXIT_SUCCESS; mclose(mf); exit_e0: return ret; } ================================================ FILE: src/tools/jffs2extract.c ================================================ /** * Copyright 2018 Smx * All right reserved */ #include #include #include #include #include #include #include "jffs2/jffs2.h" #include "util.h" int main(int argc, char *argv[]){ if(argc < 2){ usage: fprintf(stderr, "Usage: %s [file.jffs2]\n" " -e [erase block size]\n" " if a value is specified, it will be used as erase block size\n" " if no value is specified, it will be guessed (EXPERIMENTAL)\n" " -v\n" " be verbose\n" " -k\n" " keep a copy of detected unlinked files\n", argv[0]); return 1; } int erase_size = -1; int verbose = 0; bool keep_unlinked = false; int c; while ((c = getopt (argc, argv, "e:vk")) != -1){ switch(c){ case 'e': erase_size = strtoul(optarg, NULL, 16); break; case 'v': verbose++; break; case 'k': keep_unlinked = true; break; case '?': break; } } char *filename; if(optind < argc){ filename = argv[optind]; } else { goto usage; } char *dir_name = my_dirname(filename); char *base_name = my_basename(filename); char *outpath; asprintf(&outpath, "%s/%s.unjffs2", dir_name, base_name); free(dir_name); free(base_name); struct jffs2_main_args args = { .erase_size = erase_size, .keep_unlinked = keep_unlinked, .verbose = verbose }; printf("Extracting %s to %s\n", filename, outpath); int ret = jffs2extract(filename, outpath, args); free(outpath); return ret; } ================================================ FILE: src/tools/lzhs_scanner.c ================================================ /** * LZHS Scanner tool * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include "mfile.h" #include "lzhs/lzhs.h" #include "mediatek.h" #include "util.h" void scan_lzhs(const char *filename, int extract) { struct lzhs_header *header = NULL; char *outname, *outdecode; MFILE *file = mopen(filename, O_RDONLY); if (file == NULL) { printf("Can't open file %s\n", filename); exit(1); } int i, count = 0; for (i = 0; icompressedSize >= msize(file)){ continue; } count++; off_t fileOff = moff(file, header); char *fstring; if(!(fileOff % MTK_LOADER_OFF)){ fstring="mtk loader"; } else if(!(fileOff % MTK_UBOOT_OFF)){ fstring="mtk uboot"; } else { fstring="LZHS header"; } printf("Found possible %-12s at offset @0x%08X (Checksum: 0x%02X, compressedSize: 0x%08X, uncompressedSize: 0x%08X)\n", fstring, fileOff, header->checksum, header->compressedSize, header->uncompressedSize ); if (extract) { char *dirn = my_dirname(filename); char *filen = my_basename(filename); asprintf(&outname, "%s/%s_file%d.lzhs", dirn, filen, count); printf("Extracting to %s\n", outname); MFILE *out = mfopen(outname, "w+"); if (out == NULL) { err_exit("Cannot open file %s for writing\n", outname); } mfile_map(out, sizeof(*header) + header->compressedSize); memcpy( mdata(out, void), (uint8_t *)header, sizeof(*header) + header->compressedSize ); uint8_t out_checksum; asprintf(&outdecode, "%s/%s_file%d.unlzhs", dirn, filen, count); lzhs_decode(out, 0, outdecode, &out_checksum); if(extract == 2 && out_checksum != header->checksum){ printf("Checksum Mismatch, Skipping\n"); unlink(outname); unlink(outdecode); } printf("\n"); mclose(out); free(outname); free(outdecode); free(dirn); free(filen); } } } mclose(file); } int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: \n"); printf("'%s [in] 0' scan\n", argv[0]); printf("'%s [in] 1' scan and extract\n", argv[0]); printf("'%s [in] 2' scan and extract chunks with valid checksum only\n", argv[0]); return 1; } scan_lzhs(argv[1], atoi(argv[2])); return 0; } ================================================ FILE: src/tools/lzhsenc.c ================================================ /** * LZHS Encoding tool * Copyright 2016 Smx * All right reserved */ #include #include "lzhs/lzhs.h" int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: %s [in] [out.lzhs]\n", argv[0]); return 1; } printf("LZHS Encoding %s => %s...\n", argv[1], argv[2]); lzhs_encode(argv[1], argv[2]); return 0; } ================================================ FILE: src/tools/tsfile.c ================================================ #include #include #include #include #include "stream/tsfile.h" /* STR and PIF */ #include "util.h" int main(int argc, char *argv[]){ char *tsfile = NULL; int ac = -1, vc = -1; int argi; // positional argument index for(int i=1; i\n" " -ac : specify audio codec (hex)\n" " -vc : specify video codec (hex)\n" , argv[0]); return 1; } // disable output buffering setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); if(!isSTRfile(tsfile)){ fprintf(stderr, "%s is not a valid STR file\n", tsfile); return 1; } struct tsfile_options opts = { .video_stream_type = vc, .audio_stream_type = ac, .append = 0 }; convertSTR2TS(tsfile, &opts); return 0; } ================================================ FILE: src/util.c ================================================ /** * Miscellaneous utilities * Copyright 2016 Smx * Copyright 2016 lprot * All right reserved */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "mfile.h" #include "util.h" //partinfo #include #include "partinfo.h" const char *modelname = NULL; part_struct_type part_type = STRUCT_INVALID; //jffs2 #include "jffs2/jffs2.h" //lzhs #include "lzhs/lzhs.h" //kernel #include "u-boot/image.h" #include //minigzip #include "minigzip.h" //boot and tzfw #include //mtk pkg #include "mediatek_pkg.h" char *remove_ext(const char *mystr) { char *retstr, *lastdot; if (mystr == NULL) return NULL; if ((retstr = (char *)malloc(strlen(mystr) + 1)) == NULL) return NULL; strcpy(retstr, mystr); lastdot = strrchr(retstr, '.'); if (lastdot != NULL) *lastdot = '\0'; return retstr; } char *get_ext(const char *mystr) { char *retstr, *lastdot; if (mystr == NULL) return NULL; if ((retstr = (char *)malloc(strlen(mystr) + 1)) == NULL) return NULL; lastdot = strrchr(mystr, '.'); if (lastdot != NULL) { sprintf(retstr, "%s", lastdot + 1); int i; for (i = 0; retstr[i]; i++) retstr[i] = tolower(retstr[i]); } return retstr; } /** * basename and dirname might modify the source path. * they also return a pointer to static memory that might be overwritten in subsequent calls */ char *my_basename(const char *path){ char *cpy = strdup(path); char *ret = basename(cpy); ret = strdup(ret); free(cpy); return ret; } char *my_dirname(const char *path){ char *cpy = strdup(path); char *ret = dirname(cpy); ret = strdup(ret); free(cpy); return ret; } int count_tokens(const char *str, char tok, int sz){ int no = 0; for(int i=0; i G_VERBOSE) return; #endif #endif char *file = my_basename(fn); char *dir = my_dirname(fn); char *parent = my_dirname(dir); const char *relative = dir + strlen(parent) + 1; printf("[%s/%s:%d] ", relative, file, lineno); free(file); free(dir); free(parent); va_list arglist; va_start(arglist, fmt); vprintf(fmt, arglist); va_end(arglist); if (newline) printf("\n"); } void SwapBytes(void *pv, size_t n) { unsigned char *p = pv; for (size_t lo = 0, hi = n - 1; hi > lo; lo++, hi--) { unsigned char tmp = p[lo]; p[lo] = p[hi]; p[hi] = tmp; } } void getch(void) { struct termios oldattr, newattr; tcgetattr(STDIN_FILENO, &oldattr); newattr = oldattr; newattr.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &newattr); getchar(); tcsetattr(STDIN_FILENO, TCSANOW, &oldattr); } void hexdump(const void *pAddressIn, long lSize) { char szBuf[100]; long lIndent = 1; long lOutLen, lIndex, lIndex2, lOutLen2; long lRelPos; struct { const char *pData; unsigned long lSize; } buf; unsigned char ucTmp; const unsigned char *pTmp, *pAddress = pAddressIn; buf.pData = (const char *) pAddress; buf.lSize = lSize; while (buf.lSize > 0) { pTmp = (unsigned char *)buf.pData; lOutLen = (int)buf.lSize; if (lOutLen > 16) lOutLen = 16; // create a 64-character formatted output line: sprintf(szBuf, " > %08tX", pTmp - pAddress); lOutLen2 = lOutLen; for (lIndex = 1 + lIndent, lIndex2 = 53 - 15 + lIndent, lRelPos = 0; lOutLen2; lOutLen2--, lIndex += 2, lIndex2++) { ucTmp = *pTmp++; sprintf(szBuf + lIndex, "%02hhX ", ucTmp); if (!isprint(ucTmp)) ucTmp = '.'; // nonprintable char szBuf[lIndex2] = ucTmp; if (!(++lRelPos & 3)) { // extra blank after 4 bytes lIndex++; szBuf[lIndex + 2] = ' '; } } if (!(lRelPos & 3)) lIndex--; szBuf[lIndex] = '<'; szBuf[lIndex + 1] = ' '; puts(szBuf); buf.pData += lOutLen; buf.lSize -= lOutLen; } } int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { int rv = remove(fpath); if (rv != 0) perror(fpath); return rv; } void rmrf(const char *path) { struct stat status; if (stat(path, &status) == 0) nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } FORMAT_PRINTF(1, 2) int err_ret(const char *format, ...) { if (format != NULL) { va_list args; va_start(args, format); vprintf(format, args); va_end(args); } #ifdef __CYGWIN__ puts("Press any key to continue..."); getch(); #endif return EXIT_FAILURE; } void createFolder(const char *directory) { struct stat st; if (stat(directory, &st) != 0) { if (mkdir((const char *)directory, 0744) != 0){ err_exit("FATAL: Can't create directory '%s' (%s)\n\n", directory, strerror(errno)); } } } MFILE *is_lz4(const char *lz4file) { MFILE *file = mopen(lz4file, O_RDONLY); if (!file){ err_exit("Can't open file %s\n\n", lz4file); } if(!memcmp(mdata(file, uint8_t), "LZ4P", 4)) return file; mclose(file); return NULL; } bool is_nfsb_mem(MFILE *file, off_t offset){ uint8_t *data = &(mdata(file, uint8_t))[offset]; if(memcmp(data, "NFSB", 4) != 0){ return false; } const char algo_md5[] = "md5"; const char algo_sha256[] = "sha256"; const int offsets[] = { 0x0E, 0x1A }; const char *algos[] = { algo_md5, algo_sha256 }; const int lengths[] = { sizeof(algo_md5) - 1, sizeof(algo_sha256) - 1 }; const int num_offsets = countof(offsets); const int num_algos = countof(algos); for(int i=0; i 0 && gzfilename[i] == 0x00){ return file; } mclose(file); return NULL; } int is_jffs2(const char *filename) { FILE *file = fopen(filename, "rb"); if (file == NULL) { err_exit("Can't open file %s\n", filename); } size_t headerSize = 0x2; unsigned short magic = JFFS2_MAGIC_BITMASK; unsigned char buffer[headerSize]; int read = fread(&buffer, 1, headerSize, file); int result = 0; if (read == headerSize) { result = !memcmp(&buffer[0x0], &magic, 2); if (!result) { magic = JFFS2_OLD_MAGIC_BITMASK; result = !memcmp(&buffer[0x0], &magic, 2); } } fclose(file); return result; } int isSTRfile(const char *filename) { FILE *file = fopen(filename, "rb"); if (file == NULL) { err_exit("Can't open file %s\n", filename); } size_t headerSize = 0xC0 * 4; unsigned char buffer[headerSize]; int read = fread(&buffer, 1, headerSize, file); int result = 0; if (read == headerSize && buffer[4] == 0x47 && buffer[0xC0 + 4] == 0x47 && buffer[0xC0 * 2 + 4] == 0x47 && buffer[0xC0 * 3 + 4] == 0x47) result = 1; fclose(file); return result; } int isdatetime(const char *datetime) { struct tm time_val; // datetime format is YYYYMMDD if (strptime(datetime, "%Y%m%d", &time_val) != 0 && ((time_val.tm_year+1900) > 2005)) { return 1; } else { return 0; } } /* detect_model - detect model and corresponding part struct */ static void detect_model(const struct p2_device_info *pid) { part_type = STRUCT_INVALID; int ismtk1 = !strcmp("mtk3569-emmc", pid->name); //match mtk2012 int ismtk2 = !strcmp("mtk3598-emmc", pid->name); //match mtk2013 int is1152 = !strcmp("l9_emmc", pid->name); //match 1152 int is1154 = !strcmp("h13_emmc", pid->name); //match 1154/lg1311 int isbcm1 = !strcmp("bcm35xx_map0", pid->name); //match broadcom int isbcm2 = !strcmp("bcm35230_map0", pid->name); //match broadcom int ismstar = !strcmp("mstar_map0", pid->name); //match mstar int islm14 = !strcmp("mstar-emmc", pid->name); //match lm14 if (ismtk1) modelname = "Mtk 2012 - MTK5369 (Cortex-A9 single-core)"; else if (ismtk2) modelname = "Mtk 2013 - MTK5398 (Cobra Cortex-A9 dual-core)"; else if (is1152) modelname = "LG1152 (L9)"; else if (is1154) modelname = "LG1154 (H13) / LG1311 (M14)"; else if (isbcm1) modelname = "BCM 2010 - BCM35XX"; else if (isbcm2) modelname = "BCM 2011 - BCM35230"; else if (ismstar) modelname = "Mstar Saturn6 / Saturn7 / M1 / M1a / LM1"; else if (islm14) modelname = "Mstar LM14"; else return; if (ismtk2 || is1154 || islm14) { part_type = STRUCT_PARTINFOv2; } else if (ismtk1 || is1152) { part_type = STRUCT_PARTINFOv1; } else { part_type = STRUCT_MTDINFO; } return; } int isPartPakfile(const char *filename) { FILE *file = fopen(filename, "rb"); if (file == NULL) err_exit("Can't open file %s\n", filename); struct p2_partmap_info partinfo; fread(&partinfo, 1, sizeof(struct p2_partmap_info), file); char *cmagic = NULL; asprintf(&cmagic, "%x", partinfo.magic); int r = isdatetime(cmagic); free(cmagic); if (r == 0) { return 0; } printf("Found valid partpak magic 0x%x in %s\n", partinfo.magic, filename); detect_model(&(partinfo.dev)); fclose(file); if (part_type == STRUCT_INVALID) { return 0; } return 1; } int is_kernel(const char *image_file) { FILE *file = fopen(image_file, "rb"); if (file == NULL) err_exit("Can't open file %s", image_file); size_t header_size = sizeof(struct image_header); unsigned char buffer[header_size]; int read = fread(&buffer, 1, header_size, file); if (read != header_size) return 0; fclose(file); struct image_header *image_header = (struct image_header *)(&buffer); int result = image_header->ih_magic == ntohl(IH_MAGIC); return result; } void extract_kernel(const char *image_file, const char *destination_file) { FILE *file = fopen(image_file, "rb"); if (file == NULL) err_exit("Can't open file %s", image_file); fseek(file, 0, SEEK_END); int fileLength = ftell(file); rewind(file); unsigned char *buffer = malloc(fileLength); int read = fread(buffer, 1, fileLength, file); if (read != fileLength) { err_exit("Error reading file. read %d bytes from %d.\n", read, fileLength); free(buffer); } fclose(file); FILE *out = fopen(destination_file, "wb"); int header_size = sizeof(struct image_header); fwrite(buffer + header_size, 1, read - header_size, out); free(buffer); fclose(out); } /** * asprintf that allows reuse of strp in variadic arguments (frees strp and replaces it with newly allocated string) */ FORMAT_PRINTF(2, 3) int asprintf_inplace(char **strp, const char *fmt, ...) { if ((strp == NULL) || (fmt == NULL)) { err_exit("Error: %s called with NULL argument.\n", __func__); } va_list args; va_start(args, fmt); char *new_strp = NULL; int result = vasprintf(&new_strp, fmt, args); va_end(args); free(*strp); *strp = new_strp; return result; } ================================================ FILE: src/util_crypto.c ================================================ /** * Miscellaneous utilities * Copyright 2016 Smx * All right reserved */ #include #include #include #include #include #include #include "config.h" #include "util.h" #include "util_crypto.h" static char *keyFileName = NULL; void setKeyFile(const char *keyFile){ if(keyFileName != NULL) free(keyFileName); keyFileName = (char *)keyFile; } void setKeyFile_LG(){ char *path; asprintf(&path, "%s/AES.key", config_opts.config_dir); setKeyFile(path); } void setKeyFile_MTK(){ char *path; asprintf(&path, "%s/MTK.key", config_opts.config_dir); setKeyFile(path); } KeyPair *find_AES_key(uint8_t *in_data, size_t in_data_size, CompareFunc fCompare, int key_type, void **dataOut, int verbose){ AES_KEY aesKey; int found = 0; if(keyFileName == NULL){ err_exit("No key file selected!\n"); } FILE *fp = fopen(keyFileName, "r"); if (fp == NULL) { fprintf(stderr, "Error: Cannot open key file.\n"); return NULL; } uint8_t key_buf[MAX_KEY_SIZE]; uint8_t iv_buf[MAX_KEY_SIZE]; memset(&key_buf, 0x00, sizeof(key_buf)); memset(&iv_buf, 0x00, sizeof(iv_buf)); ssize_t read; size_t len = 0; char *line = NULL; while ((read = getline(&line, &len, fp)) != -1) { if ((line[0] == '#') || (line[0] == '\0') || (line[0] == '\n') || (line[0] == '\r')) { /* skip commented or empty line */ continue; } char *pos = line; uint8_t *buf = (uint8_t *)&key_buf; size_t count; if(verbose){ printf("[+] Trying AES Key "); } read_key: for (count = 0; count < MAX_KEY_SIZE; count++) { if(!isprint(*pos) || *pos == ','){ break; } if(!sscanf(pos, "%2hhx", &buf[count])){ break; } if(verbose){ printf("%02X", buf[count]); } pos += 2; } if(key_type == KEY_CBC && *pos == ','){ //repeat for IV buf = (uint8_t *)&iv_buf; pos++; if(verbose) printf(", IV: "); goto read_key; } int key_bits = count * 8; if(verbose){ printf(" (aes %d) %s\n", key_bits, pos); } AES_set_decrypt_key((uint8_t *)&key_buf, key_bits, &aesKey); uint8_t *tmp_data = calloc(1, in_data_size); switch(key_type){ case KEY_CBC:; uint8_t iv_tmp[16]; memcpy(&iv_tmp, &iv_buf, sizeof(iv_tmp)); AES_cbc_encrypt(in_data, tmp_data, in_data_size, &aesKey, (uint8_t *)&iv_tmp, AES_DECRYPT); break; case KEY_ECB:; size_t blocks = in_data_size / AES_BLOCK_SIZE; size_t i; for(i=0; i 0; if(found && dataOut != NULL){ *dataOut = tmp_data; } else { free(tmp_data); } if(found){ KeyPair *key = calloc(1, sizeof(KeyPair)); memcpy(&(key->key), &aesKey, sizeof(aesKey)); if(key_type == KEY_CBC){ memcpy(&(key->ivec), &iv_buf, sizeof(iv_buf)); } free(line); fclose(fp); return key; } } if(line != NULL){ free(line); } fclose(fp); return NULL; }