From 4f8991cfe0f3b2cce20dc450da1a248c5031a25a Mon Sep 17 00:00:00 2001 From: Vadim Troshchinskiy Date: Tue, 12 Nov 2024 14:17:06 +0000 Subject: [PATCH] Add pylkid --- .../.github/workflows/ci.yml | 22 + .../.github/workflows/codeql-analysis.yml | 44 + .../pyblkid/opengnsys-pyblkid-0.3/.gitignore | 6 + .../pyblkid/opengnsys-pyblkid-0.3/LICENSE | 504 +++++++++ .../pyblkid/opengnsys-pyblkid-0.3/MANIFEST.in | 5 + .../pyblkid/opengnsys-pyblkid-0.3/Makefile | 35 + .../pyblkid/opengnsys-pyblkid-0.3/README.md | 38 + .../opengnsys-pyblkid-0.3/pyproject.toml | 3 + .../pyblkid/opengnsys-pyblkid-0.3/setup.py | 78 ++ .../pyblkid/opengnsys-pyblkid-0.3/src/cache.c | 336 ++++++ .../pyblkid/opengnsys-pyblkid-0.3/src/cache.h | 44 + .../opengnsys-pyblkid-0.3/src/partitions.c | 534 ++++++++++ .../opengnsys-pyblkid-0.3/src/partitions.h | 68 ++ .../pyblkid/opengnsys-pyblkid-0.3/src/probe.c | 959 ++++++++++++++++++ .../pyblkid/opengnsys-pyblkid-0.3/src/probe.h | 39 + .../opengnsys-pyblkid-0.3/src/pyblkid.c | 631 ++++++++++++ .../opengnsys-pyblkid-0.3/src/pyblkid.h | 25 + .../opengnsys-pyblkid-0.3/src/topology.c | 141 +++ .../opengnsys-pyblkid-0.3/src/topology.h | 38 + .../opengnsys-pyblkid-0.3/tests/__init__.py | 0 .../opengnsys-pyblkid-0.3/tests/gpt.img.xz | Bin 0 -> 2140 bytes .../opengnsys-pyblkid-0.3/tests/test.img.xz | Bin 0 -> 1612 bytes .../opengnsys-pyblkid-0.3/tests/test_blkid.py | 98 ++ .../opengnsys-pyblkid-0.3/tests/test_cache.py | 68 ++ .../tests/test_partitions.py | 140 +++ .../opengnsys-pyblkid-0.3/tests/test_probe.py | 292 ++++++ .../opengnsys-pyblkid-0.3/tests/utils.py | 43 + .../pyblkid/opengnsys-pyblkid_0.3.orig.tar.xz | Bin 0 -> 28652 bytes 28 files changed, 4191 insertions(+) create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/ci.yml create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/codeql-analysis.yml create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/.gitignore create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/LICENSE create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/MANIFEST.in create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/Makefile create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/README.md create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/pyproject.toml create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/setup.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.c create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.h create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.c create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.h create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.c create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.h create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.c create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.h create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.c create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.h create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/__init__.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/gpt.img.xz create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/test.img.xz create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/test_blkid.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/test_cache.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/test_partitions.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/test_probe.py create mode 100644 packages/pyblkid/opengnsys-pyblkid-0.3/tests/utils.py create mode 100644 packages/pyblkid/opengnsys-pyblkid_0.3.orig.tar.xz diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/ci.yml b/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/ci.yml new file mode 100644 index 0000000..a7a0e2a --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/ci.yml @@ -0,0 +1,22 @@ +name: CI + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get -qq update + sudo apt-get -y -qq install python3-pkgconfig + sudo apt-get -y -qq install libblkid-dev libblkid1 python3-dev + - name: Run tests + run: sudo make test diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/codeql-analysis.yml b/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..f18aee6 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/.github/workflows/codeql-analysis.yml @@ -0,0 +1,44 @@ +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp', 'python' ] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + + - name: Install build dependencies + run: | + sudo apt-get -qq update + sudo apt-get -y -qq install python3-pkgconfig + sudo apt-get -y -qq install libblkid-dev libblkid1 python3-dev + - name: Build + run: | + make + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/.gitignore b/packages/pyblkid/opengnsys-pyblkid-0.3/.gitignore new file mode 100644 index 0000000..1da7567 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/.gitignore @@ -0,0 +1,6 @@ +env/ +build/ + +tests/__pycache__/* + +tests/*.img diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/LICENSE b/packages/pyblkid/opengnsys-pyblkid-0.3/LICENSE new file mode 100644 index 0000000..8000a6f --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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 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. + + This 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 this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random + Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/MANIFEST.in b/packages/pyblkid/opengnsys-pyblkid-0.3/MANIFEST.in new file mode 100644 index 0000000..ffc631f --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/MANIFEST.in @@ -0,0 +1,5 @@ +include LICENSE README.md +include MANIFEST.in +include Makefile +recursive-include src *.h +recursive-include tests *.py diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/Makefile b/packages/pyblkid/opengnsys-pyblkid-0.3/Makefile new file mode 100644 index 0000000..cb10d58 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/Makefile @@ -0,0 +1,35 @@ +# Copyright (C) 2020 Red Hat, Inc. +# +# This 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. +# +# This 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 this library; if not, see . + +PYTHON ?= python3 + + +default: all + +all: + @$(PYTHON) setup.py build + +test: all + @env PYTHONPATH=$$(find $$(pwd) -name "*.so" | head -n 1 | xargs dirname):src \ + $(PYTHON) -m unittest discover -v + +run-ipython: all + @env PYTHONPATH=$$(find $$(pwd) -name "*.so" | head -n 1 | xargs dirname):src i$(PYTHON) + +run-root-ipython: all + @sudo env PYTHONPATH=$$(find $$(pwd) -name "*.so" | head -n 1 | xargs dirname):src i$(PYTHON) + +clean: + -rm -r build diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/README.md b/packages/pyblkid/opengnsys-pyblkid-0.3/README.md new file mode 100644 index 0000000..0cc57a1 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/README.md @@ -0,0 +1,38 @@ +# pylibblkid + +[![PyPI version](https://badge.fury.io/py/pylibblkid.svg)](https://badge.fury.io/py/pylibblkid) + +Python bindings for libblkid library. + +## Usage examples + +### Probing a device +```python +import blkid + +pr = blkid.Probe() +pr.set_device("/dev/sda1") + +pr.enable_superblocks(True) +pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID) + +pr.do_safeprobe() + +# print device properties as a dictionary +print(dict(pr)) +``` + +### Searching for device with specified label +```python +import blkid + +cache = blkid.Cache() +cache.probe_all() + +dev = cache.find_device("LABEL", "mylabel") + +# if found print found device and its properties +if dev: + print(dev.devname) + print(dev.tags) +``` diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/pyproject.toml b/packages/pyblkid/opengnsys-pyblkid-0.3/pyproject.toml new file mode 100644 index 0000000..3725998 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools", "pkgconfig"] +build-backend = "setuptools.build_meta" diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/setup.py b/packages/pyblkid/opengnsys-pyblkid-0.3/setup.py new file mode 100644 index 0000000..0019dac --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/setup.py @@ -0,0 +1,78 @@ +# Copyright (C) 2020 Red Hat, Inc. +# +# This 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. +# +# This 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 this library; if not, see . + +import sys + +import pkgconfig +from setuptools import Extension, setup + +pkgs = pkgconfig.list_all() +if "blkid" not in pkgs: + print("Please install libblkid-dev or libblkid-devel") + exit(1) + +vers = sys.version_info +if f"python-{vers.major}.{vers.minor}" not in pkgs: + print("Please install python3-dev or python3-devel") + exit(1) + + +# define macros for blkid releases +macros = [] +blkid_releases = ['2.24', '2.25', '2.30', '2.31', '2.36', '2.37', '2.39', '2.40'] +for blkid_ver in blkid_releases: + if pkgconfig.installed("blkid", f">= {blkid_ver}"): + ver_list = blkid_ver.split('.') + full_release = '_'.join(ver_list) + macros.append((f"HAVE_BLKID_{full_release}", "1")) + if len(ver_list) > 2: + major_minor = '_'.join(ver_list[:2]) + macros.append((f"HAVE_BLKID_{major_minor}", "1")) + + +with open("README.md", "r") as f: + long_description = f.read() + + +def main(): + setup(name="pylibblkid", + version="0.3", + description="Python interface for the libblkid C library", + long_description=long_description, + long_description_content_type="text/markdown", + author="Vojtech Trefny", + author_email="vtrefny@redhat.com", + url="http://github.com/vojtechtrefny/pyblkid", + ext_modules=[Extension("blkid", + sources=["src/pyblkid.c", + "src/topology.c", + "src/partitions.c", + "src/cache.c", + "src/probe.c",], + include_dirs=["/usr/include"], + libraries=["blkid"], + library_dirs=["/usr/lib"], + define_macros=macros, + extra_compile_args=["-std=c99", "-Wall", "-Wextra", "-Werror"])], + classifiers=["Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)", + "Programming Language :: C", + "Programming Language :: Python :: 3", + "Operating System :: POSIX :: Linux"]) + + +if __name__ == "__main__": + main() diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.c b/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.c new file mode 100644 index 0000000..66bd6af --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ + +#include "cache.h" + +#include +#include + +#define UNUSED __attribute__((unused)) + + +PyObject *Cache_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + CacheObject *self = (CacheObject*) type->tp_alloc (type, 0); + + if (self) + self->cache = NULL; + + return (PyObject *) self; +} + +int Cache_init (CacheObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *filename = NULL; + char *kwlist[] = { "filename", NULL }; + int ret = 0; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|s", kwlist, &filename)) { + return -1; + } + + ret = blkid_get_cache (&(self->cache), filename); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get cache"); + return -1; + } + + return 0; +} + +void Cache_dealloc (CacheObject *self) { + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyDoc_STRVAR(Cache_probe_all__doc__, +"probe_all (removable=False, new_only=False)\n\n" +"Probes all block devices.\n\n" +"With removable=True also adds removable block devices to cache. Don't forget that " +"removable devices could be pretty slow. It's very bad idea to call this function by default." +"With new_only=True this will scan only newly connected devices."); +static PyObject *Cache_probe_all (CacheObject *self, PyObject *args, PyObject *kwargs) { + bool removable = false; + bool new = false; + char *kwlist[] = { "removable", "new_only", NULL }; + int ret = 0; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|pp", kwlist, &removable, &new)) { + return NULL; + } + + if (new) { + ret = blkid_probe_all_new (self->cache); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to probe new devices"); + return NULL; + } + } else { + ret = blkid_probe_all (self->cache); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to probe block devices"); + return NULL; + } + + if (removable) { + ret = blkid_probe_all_removable (self->cache); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to probe removable devices"); + return NULL; + } + } + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Cache_gc__doc__, +"gc\n\n" +"Removes garbage (non-existing devices) from the cache."); +static PyObject *Cache_gc (CacheObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_gc_cache (self->cache); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Cache_get_device__doc__, +"get_device (name)\n\n" +"Get device from cache.\n\n"); +static PyObject *Cache_get_device (CacheObject *self, PyObject *args, PyObject *kwargs) { + const char *name = NULL; + char *kwlist[] = { "name", NULL }; + blkid_dev device = NULL; + DeviceObject *dev_obj = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &name)) + return NULL; + + device = blkid_get_dev (self->cache, name, BLKID_DEV_FIND); + if (device == NULL) + Py_RETURN_NONE; + + dev_obj = PyObject_New (DeviceObject, &DeviceType); + if (!dev_obj) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Device object"); + return NULL; + } + + dev_obj->device = device; + dev_obj->cache = self->cache; + + return (PyObject *) dev_obj; +} + +PyDoc_STRVAR(Cache_find_device__doc__, +"find_device (tag, value)\n\n" +"Returns a device which matches a particular tag/value pair.\n" +" If there is more than one device that matches the search specification, " +"it returns the one with the highest priority\n\n"); +static PyObject *Cache_find_device (CacheObject *self, PyObject *args, PyObject *kwargs) { + const char *tag = NULL; + const char *value = NULL; + char *kwlist[] = { "tag", "value", NULL }; + blkid_dev device = NULL; + DeviceObject *dev_obj = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss", kwlist, &tag, &value)) + return NULL; + + device = blkid_find_dev_with_tag (self->cache, tag, value); + if (device == NULL) + Py_RETURN_NONE; + + dev_obj = PyObject_New (DeviceObject, &DeviceType); + if (!dev_obj) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Device object"); + return NULL; + } + + dev_obj->device = device; + dev_obj->cache = self->cache; + + return (PyObject *) dev_obj; +} + +static PyMethodDef Cache_methods[] = { + {"probe_all", (PyCFunction)(void(*)(void)) Cache_probe_all, METH_VARARGS|METH_KEYWORDS, Cache_probe_all__doc__}, + {"gc", (PyCFunction) Cache_gc, METH_NOARGS, Cache_gc__doc__}, + {"get_device", (PyCFunction)(void(*)(void)) Cache_get_device, METH_VARARGS|METH_KEYWORDS, Cache_get_device__doc__}, + {"find_device", (PyCFunction)(void(*)(void)) Cache_find_device, METH_VARARGS|METH_KEYWORDS, Cache_find_device__doc__}, + {NULL, NULL, 0, NULL}, +}; + +static PyObject *Cache_get_devices (CacheObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_dev_iterate iter; + blkid_dev device = NULL; + DeviceObject *dev_obj = NULL; + PyObject *list = NULL; + + list = PyList_New (0); + if (!list) { + PyErr_NoMemory (); + return NULL; + } + + iter = blkid_dev_iterate_begin (self->cache); + while (blkid_dev_next (iter, &device) == 0) { + dev_obj = PyObject_New (DeviceObject, &DeviceType); + if (!dev_obj) { + PyErr_NoMemory (); + return NULL; + } + dev_obj->device = device; + dev_obj->cache = self->cache; + PyList_Append (list, (PyObject *) dev_obj); + Py_DECREF (dev_obj); + + } + blkid_dev_iterate_end(iter); + + return (PyObject *) list; +} + +static PyGetSetDef Cache_getseters[] = { + {"devices", (getter) Cache_get_devices, NULL, "returns all devices in the cache", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject CacheType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Cache", + .tp_basicsize = sizeof (CacheObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Cache_new, + .tp_dealloc = (destructor) Cache_dealloc, + .tp_init = (initproc) Cache_init, + .tp_methods = Cache_methods, + .tp_getset = Cache_getseters, +}; + +/*********************** DEVICE ***********************/ +PyObject *Device_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + DeviceObject *self = (DeviceObject*) type->tp_alloc (type, 0); + + if (self) { + self->device = NULL; + self->cache = NULL; + } + + return (PyObject *) self; +} + +int Device_init (DeviceObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + return 0; +} + +void Device_dealloc (DeviceObject *self) { + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyDoc_STRVAR(Device_verify__doc__, +"verify\n\n" +"Verify that the data in device is consistent with what is on the actual" +"block device. Normally this will be called when finding items in the cache, " +"but for long running processes is also desirable to revalidate an item before use."); +static PyObject *Device_verify (DeviceObject *self, PyObject *Py_UNUSED (ignored)) { + self->device = blkid_verify (self->cache, self->device); + + Py_RETURN_NONE; +} + +static PyMethodDef Device_methods[] = { + {"verify", (PyCFunction) Device_verify, METH_NOARGS, Device_verify__doc__}, + {NULL, NULL, 0, NULL}, +}; + +static PyObject *Device_get_devname (DeviceObject *self, PyObject *Py_UNUSED (ignored)) { + const char *name = blkid_dev_devname (self->device); + + if (!name) + Py_RETURN_NONE; + + return PyUnicode_FromString (name); +} + +static PyObject *Device_get_tags (DeviceObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_tag_iterate iter; + const char *type = NULL; + const char *value = NULL; + PyObject *dict = NULL; + PyObject *py_value = NULL; + + dict = PyDict_New (); + if (!dict) { + PyErr_NoMemory (); + return NULL; + } + + iter = blkid_tag_iterate_begin (self->device); + while (blkid_tag_next (iter, &type, &value) == 0) { + py_value = PyUnicode_FromString (value); + if (py_value == NULL) { + Py_INCREF (Py_None); + py_value = Py_None; + } + + PyDict_SetItemString (dict, type, py_value); + Py_DECREF (py_value); + } + blkid_tag_iterate_end(iter); + + return (PyObject *) dict; +} + +static PyObject *Device_str (PyObject *self) { + char *str = NULL; + int ret = 0; + PyObject *py_str = NULL; + intptr_t id = (intptr_t) self; + PyObject *py_name = PyObject_GetAttrString (self, "devname"); + + ret = asprintf (&str, "blkid.Device instance (0x%" PRIxPTR "): %s", id, PyUnicode_AsUTF8 (py_name)); + + Py_DECREF (py_name); + + if (ret < 0) + Py_RETURN_NONE; + + py_str = PyUnicode_FromString (str); + + free (str); + + return py_str; +} + +static PyGetSetDef Device_getseters[] = { + {"devname", (getter) Device_get_devname, NULL, "returns the name previously used for Cache.get_device.", NULL}, + {"tags", (getter) Device_get_tags, NULL, "returns all tags for this device.", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject DeviceType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Device", + .tp_basicsize = sizeof (DeviceObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Device_new, + .tp_dealloc = (destructor) Device_dealloc, + .tp_init = (initproc) Device_init, + .tp_methods = Device_methods, + .tp_getset = Device_getseters, + .tp_str = Device_str, +}; diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.h b/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.h new file mode 100644 index 0000000..33b526d --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/cache.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ +#ifndef CACHE_H +#define CACHE_H + +#include + +#include + +typedef struct { + PyObject_HEAD + blkid_cache cache; +} CacheObject; + +extern PyTypeObject CacheType; + +PyObject *Cache_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Cache_init (CacheObject *self, PyObject *args, PyObject *kwargs); +void Cache_dealloc (CacheObject *self); + +typedef struct { + PyObject_HEAD + blkid_dev device; + blkid_cache cache; +} DeviceObject; + +extern PyTypeObject DeviceType; + +#endif /* CACHE_H */ diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.c b/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.c new file mode 100644 index 0000000..5778afc --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.c @@ -0,0 +1,534 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ + +#include "partitions.h" + +#include + +#define UNUSED __attribute__((unused)) + + +/*********************** PARTLIST ***********************/ +PyObject *Partlist_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + PartlistObject *self = (PartlistObject*) type->tp_alloc (type, 0); + + if (self) + self->Parttable_object = NULL; + + return (PyObject *) self; +} + +int Partlist_init (PartlistObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + return 0; +} + +void Partlist_dealloc (PartlistObject *self) { + if (self->Parttable_object) + Py_DECREF (self->Parttable_object); + + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyObject *_Partlist_get_partlist_object (blkid_probe probe) { + PartlistObject *result = NULL; + blkid_partlist partlist = NULL; + + if (!probe) { + PyErr_SetString (PyExc_RuntimeError, "internal error"); + return NULL; + } + + partlist = blkid_probe_get_partitions (probe); + if (!partlist) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get partitions"); + return NULL; + } + + result = PyObject_New (PartlistObject, &PartlistType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partlist object"); + return NULL; + } + Py_INCREF (result); + + result->partlist = partlist; + result->Parttable_object = NULL; + + return (PyObject *) result; +} + +PyDoc_STRVAR(Partlist_get_partition__doc__, +"get_partition (number)\n\n" +"Get partition by number.\n\n" +"It's possible that the list of partitions is *empty*, but there is a valid partition table on the disk.\n" +"This happen when on-disk details about partitions are unknown or the partition table is empty."); +static PyObject *Partlist_get_partition (PartlistObject *self, PyObject *args, PyObject *kwargs) { + char *kwlist[] = { "number", NULL }; + int partnum = 0; + int numof = 0; + blkid_partition blkid_part = NULL; + PartitionObject *result = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &partnum)) { + return NULL; + } + + numof = blkid_partlist_numof_partitions (self->partlist); + if (numof < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get number of partitions"); + return NULL; + } + + if (partnum > numof) { + PyErr_Format (PyExc_RuntimeError, "Cannot get partition %d, partition table has only %d partitions", partnum, numof); + return NULL; + } + + blkid_part = blkid_partlist_get_partition (self->partlist, partnum); + if (!blkid_part) { + PyErr_Format (PyExc_RuntimeError, "Failed to get partition %d", partnum); + return NULL; + } + + result = PyObject_New (PartitionObject, &PartitionType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partition object"); + return NULL; + } + + result->number = partnum; + result->partition = blkid_part; + result->Parttable_object = NULL; + + return (PyObject *) result; +} + +#ifdef HAVE_BLKID_2_25 +PyDoc_STRVAR(Partlist_get_partition_by_partno__doc__, +"get_partition_by_partno(number)\n\n" +"Get partition by partition number.\n\n" +"This does not assume any order of partitions and correctly handles \"out of order\" " +"partition tables. partition N is located after partition N+1 on the disk."); +static PyObject *Partlist_get_partition_by_partno (PartlistObject *self, PyObject *args, PyObject *kwargs) { + char *kwlist[] = { "number", NULL }; + int partno = 0; + blkid_partition blkid_part = NULL; + PartitionObject *result = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &partno)) { + return NULL; + } + + blkid_part = blkid_partlist_get_partition_by_partno (self->partlist, partno); + if (!blkid_part) { + PyErr_Format (PyExc_RuntimeError, "Failed to get partition %d", partno); + return NULL; + } + + result = PyObject_New (PartitionObject, &PartitionType); + if (!result) { + PyErr_NoMemory (); + return NULL; + } + + result->number = partno; + result->partition = blkid_part; + result->Parttable_object = NULL; + + return (PyObject *) result; +} +#endif + +static int _Py_Dev_Converter (PyObject *obj, void *p) { +#ifdef HAVE_LONG_LONG + *((dev_t *)p) = PyLong_AsUnsignedLongLong (obj); +#else + *((dev_t *)p) = PyLong_AsUnsignedLong (obj); +#endif + if (PyErr_Occurred ()) + return 0; + return 1; +} + +#ifdef HAVE_LONG_LONG + #define _PyLong_FromDev PyLong_FromLongLong +#else + #define _PyLong_FromDev PyLong_FromLong +#endif + +PyDoc_STRVAR(Partlist_devno_to_partition__doc__, +"devno_to_partition (devno)\n\n" +"Get partition by devno.\n"); +static PyObject *Partlist_devno_to_partition (PartlistObject *self, PyObject *args, PyObject *kwargs) { + dev_t devno = 0; + char *kwlist[] = { "devno", NULL }; + blkid_partition blkid_part = NULL; + PartitionObject *result = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_devname", kwlist, _Py_Dev_Converter, &devno)) + return NULL; + + blkid_part = blkid_partlist_devno_to_partition (self->partlist, devno); + if (!blkid_part) { + PyErr_Format (PyExc_RuntimeError, "Failed to get partition %zu", devno); + return NULL; + } + + result = PyObject_New (PartitionObject, &PartitionType); + if (!result) { + PyErr_NoMemory (); + return NULL; + } + + result->number = blkid_partition_get_partno (blkid_part); + result->partition = blkid_part; + result->Parttable_object = NULL; + + return (PyObject *) result; +} + +static PyMethodDef Partlist_methods[] = { + {"get_partition", (PyCFunction)(void(*)(void)) Partlist_get_partition, METH_VARARGS|METH_KEYWORDS, Partlist_get_partition__doc__}, +#ifdef HAVE_BLKID_2_25 + {"get_partition_by_partno", (PyCFunction)(void(*)(void)) Partlist_get_partition_by_partno, METH_VARARGS|METH_KEYWORDS, Partlist_get_partition_by_partno__doc__}, +#endif + {"devno_to_partition", (PyCFunction)(void(*)(void)) Partlist_devno_to_partition, METH_VARARGS|METH_KEYWORDS, Partlist_devno_to_partition__doc__}, + {NULL, NULL, 0, NULL}, +}; + +static PyObject *Partlist_get_table (PartlistObject *self, PyObject *Py_UNUSED (ignored)) { + if (self->Parttable_object) { + Py_INCREF (self->Parttable_object); + return self->Parttable_object; + } + + self->Parttable_object = _Parttable_get_parttable_object (self->partlist); + + return self->Parttable_object; +} + +static PyObject *Partlist_get_numof_partitions (PartlistObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_partlist_numof_partitions (self->partlist); + if (ret < 0) { + PyErr_SetString (PyExc_MemoryError, "Failed to get number of partitions"); + return NULL; + } + + return PyLong_FromLong (ret); +} + + +static PyGetSetDef Partlist_getseters[] = { + {"table", (getter) Partlist_get_table, NULL, "binary interface for partition table on the device", NULL}, + {"numof_partitions", (getter) Partlist_get_numof_partitions, NULL, "number of partitions in the list", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject PartlistType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Partlist", + .tp_basicsize = sizeof (PartlistObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Partlist_new, + .tp_dealloc = (destructor) Partlist_dealloc, + .tp_init = (initproc) Partlist_init, + .tp_methods = Partlist_methods, + .tp_getset = Partlist_getseters, +}; + + +/*********************** PARTTABLE ***********************/ +PyObject *Parttable_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + ParttableObject *self = (ParttableObject*) type->tp_alloc (type, 0); + + return (PyObject *) self; +} + +int Parttable_init (ParttableObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + return 0; +} + +void Parttable_dealloc (ParttableObject *self) { + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyObject *_Parttable_get_parttable_object (blkid_partlist partlist) { + ParttableObject *result = NULL; + blkid_parttable table = NULL; + + if (!partlist) { + PyErr_SetString(PyExc_RuntimeError, "internal error"); + return NULL; + } + + table = blkid_partlist_get_table (partlist); + if (!table) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get partitions"); + return NULL; + } + + result = PyObject_New (ParttableObject, &ParttableType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Parttable object"); + return NULL; + } + Py_INCREF (result); + + result->table = table; + + return (PyObject *) result; +} + +PyDoc_STRVAR(Parttable_get_parent__doc__, +"get_parent ()\n\n" +"Parent for nested partition tables."); +static PyObject *Parttable_get_parent (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_partition blkid_part = NULL; + PartitionObject *result = NULL; + + blkid_part = blkid_parttable_get_parent (self->table); + if (!blkid_part) + Py_RETURN_NONE; + + result = PyObject_New (PartitionObject, &PartitionType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Partition object"); + return NULL; + } + + result->number = 0; + result->partition = blkid_part; + + return (PyObject *) result; +} + +static PyMethodDef Parttable_methods[] = { + {"get_parent", (PyCFunction)(void(*)(void)) Parttable_get_parent, METH_NOARGS, Parttable_get_parent__doc__}, + {NULL, NULL, 0, NULL}, +}; + +static PyObject *Parrtable_get_type (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { + const char *pttype = blkid_parttable_get_type (self->table); + + return PyUnicode_FromString (pttype); +} + +static PyObject *Parrtable_get_id (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { + const char *ptid = blkid_parttable_get_id (self->table); + + return PyUnicode_FromString (ptid); +} + +static PyObject *Parrtable_get_offset (ParttableObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t offset = blkid_parttable_get_offset (self->table); + + return PyLong_FromLongLong (offset); +} + +static PyGetSetDef Parttable_getseters[] = { + {"type", (getter) Parrtable_get_type, NULL, "partition table type (type name, e.g. 'dos', 'gpt', ...)", NULL}, + {"id", (getter) Parrtable_get_id, NULL, "GPT disk UUID or DOS disk ID (in hex format)", NULL}, + {"offset", (getter) Parrtable_get_offset, NULL, "position (in bytes) of the partition table", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject ParttableType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Parttable", + .tp_basicsize = sizeof (ParttableObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Parttable_new, + .tp_dealloc = (destructor) Parttable_dealloc, + .tp_init = (initproc) Parttable_init, + .tp_methods = Parttable_methods, + .tp_getset = Parttable_getseters, +}; + +/*********************** PARTITION ***********************/ +PyObject *Partition_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + PartitionObject *self = (PartitionObject*) type->tp_alloc (type, 0); + + if (self) + self->Parttable_object = NULL; + + return (PyObject *) self; +} + +int Partition_init (PartitionObject *self, PyObject *args, PyObject *kwargs) { + char *kwlist[] = { "number", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "i", kwlist, &(self->number))) { + return -1; + } + + self->partition = NULL; + + return 0; +} + +void Partition_dealloc (PartitionObject *self) { + if (self->Parttable_object) + Py_DECREF (self->Parttable_object); + + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +static PyObject *Partition_get_type (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + int type = blkid_partition_get_type (self->partition); + + return PyLong_FromLong (type); +} + +static PyObject *Partition_get_type_string (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + const char *type = blkid_partition_get_type_string (self->partition); + + return PyUnicode_FromString (type); +} + +static PyObject *Partition_get_uuid (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + const char *uuid = blkid_partition_get_uuid (self->partition); + + return PyUnicode_FromString (uuid); +} + +static PyObject *Partition_get_is_extended (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + int extended = blkid_partition_is_extended (self->partition); + + if (extended == 1) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Partition_get_is_logical (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + int logical = blkid_partition_is_logical (self->partition); + + if (logical == 1) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Partition_get_is_primary (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + int primary = blkid_partition_is_primary (self->partition); + + if (primary == 1) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject *Partition_get_name (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + const char *name = blkid_partition_get_name (self->partition); + + return PyUnicode_FromString (name); +} + +static PyObject *Partition_get_flags (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long long flags = blkid_partition_get_flags (self->partition); + + return PyLong_FromUnsignedLongLong (flags); +} + +static PyObject *Partition_get_partno (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + int partno = blkid_partition_get_partno (self->partition); + + return PyLong_FromLong (partno); +} + +static PyObject *Partition_get_size (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t size = blkid_partition_get_size (self->partition); + + return PyLong_FromLongLong (size); +} + +static PyObject *Partition_get_start (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t start = blkid_partition_get_start (self->partition); + + return PyLong_FromLongLong (start); +} + +PyObject *_Partition_get_parttable_object (blkid_partition partition) { + ParttableObject *result = NULL; + blkid_parttable table = NULL; + + if (!partition) { + PyErr_SetString(PyExc_RuntimeError, "internal error"); + return NULL; + } + + table = blkid_partition_get_table (partition); + if (!table) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get partition table"); + return NULL; + } + + result = PyObject_New (ParttableObject, &ParttableType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Parttable object"); + return NULL; + } + Py_INCREF (result); + + result->table = table; + + return (PyObject *) result; +} + +static PyObject *Partition_get_table (PartitionObject *self, PyObject *Py_UNUSED (ignored)) { + if (self->Parttable_object) { + Py_INCREF (self->Parttable_object); + return self->Parttable_object; + } + + self->Parttable_object = _Partition_get_parttable_object (self->partition); + + return self->Parttable_object; +} + +static PyGetSetDef Partition_getseters[] = { + {"type", (getter) Partition_get_type, NULL, "partition type", NULL}, + {"type_string", (getter) Partition_get_type_string, NULL, "partition type string, note the type string is supported by a small subset of partition tables (e.g Mac and EFI GPT)", NULL}, + {"uuid", (getter) Partition_get_uuid, NULL, "partition UUID string if supported by PT (e.g. GPT)", NULL}, + {"is_extended", (getter) Partition_get_is_extended, NULL, "returns whether the partition is extendedor not ", NULL}, + {"is_logical", (getter) Partition_get_is_logical, NULL, "returns whether the partition is logical or not", NULL}, + {"is_primary", (getter) Partition_get_is_primary, NULL, "returns whether the partition is primary or not", NULL}, + {"name", (getter) Partition_get_name, NULL, "partition name string if supported by PT (e.g. Mac)", NULL}, + {"flags", (getter) Partition_get_flags, NULL, "partition flags (or attributes for gpt)", NULL}, + {"partno", (getter) Partition_get_partno, NULL, "proposed partition number (e.g. 'N' from sda'N') or -1 in case of error", NULL}, + {"size", (getter) Partition_get_size, NULL, "size of the partition (in 512-sectors)", NULL}, + {"start", (getter) Partition_get_start, NULL, "start of the partition (in 512-sectors)", NULL}, + {"table", (getter) Partition_get_table, NULL, "partition table object (usually the same for all partitions, except nested partition tables)", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject PartitionType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Partition", + .tp_basicsize = sizeof (PartitionObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Partition_new, + .tp_dealloc = (destructor) Partition_dealloc, + .tp_init = (initproc) Partition_init, + .tp_getset = Partition_getseters, +}; diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.h b/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.h new file mode 100644 index 0000000..b68f91d --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/partitions.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ +#ifndef PARTITIONS_H +#define PARTITIONS_H + +#include + +#include + +typedef struct { + PyObject_HEAD + blkid_partlist partlist; + PyObject *Parttable_object; +} PartlistObject; + +extern PyTypeObject PartlistType; + +PyObject *Partlist_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Partlist_init (PartlistObject *self, PyObject *args, PyObject *kwargs); +void Partlist_dealloc (PartlistObject *self); + +PyObject *_Partlist_get_partlist_object (blkid_probe probe); + + +typedef struct { + PyObject_HEAD + blkid_parttable table; +} ParttableObject; + +extern PyTypeObject ParttableType; + +PyObject *Parttable_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Parttable_init (ParttableObject *self, PyObject *args, PyObject *kwargs); +void Parttable_dealloc (ParttableObject *self); + +PyObject *_Parttable_get_parttable_object (blkid_partlist partlist); + +typedef struct { + PyObject_HEAD + int number; + blkid_partition partition; + PyObject *Parttable_object; +} PartitionObject; + +extern PyTypeObject PartitionType; + +PyObject *Partition_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Partition_init (PartitionObject *self, PyObject *args, PyObject *kwargs); +void Partition_dealloc (PartitionObject *self); + +PyObject *_Partition_get_parttable_object (blkid_partition partition); + +#endif /* PARTITIONS_H */ diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.c b/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.c new file mode 100644 index 0000000..e4a2e7b --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.c @@ -0,0 +1,959 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ + +#include "probe.h" +#include "topology.h" +#include "partitions.h" + +#include +#include +#include +#include + +#define UNUSED __attribute__((unused)) + + +PyObject *Probe_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + ProbeObject *self = (ProbeObject*) type->tp_alloc (type, 0); + + if (self) { + self->probe = NULL; + self->fd = -1; + self->topology = NULL; + self->partlist = NULL; + } + + return (PyObject *) self; +} + +int Probe_init (ProbeObject *self, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + if (self->probe) + blkid_free_probe (self->probe); + + self->probe = blkid_new_probe (); + if (!self->probe) { + PyErr_SetString (PyExc_MemoryError, "Failed to create new Probe."); + return -1; + } + + return 0; +} + +void Probe_dealloc (ProbeObject *self) { + if (!self->probe) + /* if init fails */ + return; + + if (self->fd > 0) + close (self->fd); + + if (self->topology) + Py_DECREF (self->topology); + + if (self->partlist) + Py_DECREF (self->partlist); + + blkid_free_probe (self->probe); + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyDoc_STRVAR(Probe_set_device__doc__, +"set_device (device, flags=os.O_RDONLY|os.O_CLOEXEC, offset=0, size=0)\n\n" +"Assigns the device to probe control struct, resets internal buffers and resets the current probing.\n\n" +"'flags' define flags for the 'open' system call. By default the device will be opened as read-only.\n" +"'offset' and 'size' specify begin and size of probing area (zero means whole device/file)"); +static PyObject *Probe_set_device (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + char *kwlist[] = { "device", "flags", "offset", "size", NULL }; + char *device = NULL; + blkid_loff_t offset = 0; + blkid_loff_t size = 0; + int flags = O_RDONLY|O_CLOEXEC; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s|iKK", kwlist, &device, &flags, &offset, &size)) { + return NULL; + } + + self->fd = open (device, flags); + if (self->fd == -1) { + PyErr_Format (PyExc_OSError, "Failed to open device '%s': %s", device, strerror (errno)); + return NULL; + } + + ret = blkid_probe_set_device (self->probe, self->fd, offset, size); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set device"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_enable_superblocks__doc__, +"enable_superblocks (enable)\n\n" \ +"Enables/disables the superblocks probing for non-binary interface."); +static PyObject *Probe_enable_superblocks (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + bool enable = false; + char *kwlist[] = { "enable", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "p", kwlist, &enable)) { + return NULL; + } + + ret = blkid_probe_enable_superblocks (self->probe, enable); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to %s superblocks probing", enable ? "enable" : "disable"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_set_superblocks_flags__doc__, +"set_superblocks_flags (flags)\n\n" \ +"Sets probing flags to the superblocks prober. This function is optional, the default are blkid.SUBLKS_DEFAULTS flags.\n" +"Use blkid.SUBLKS_* constants for the 'flags' argument."); +static PyObject *Probe_set_superblocks_flags (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + int flags = 0; + char *kwlist[] = { "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &flags)) { + return NULL; + } + + ret = blkid_probe_set_superblocks_flags (self->probe, flags); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set partition flags"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_filter_superblocks_type__doc__, +"filter_superblocks_type (flag, names)\n\n" \ +"Filter superblocks prober results based on type.\n" +"blkid.FLTR_NOTIN - probe for all items which are NOT IN names\n" +"blkid.FLTR_ONLYIN - probe for items which are IN names\n" +"names: array of probing function names (e.g. 'vfat')."); +static PyObject *Probe_filter_superblocks_type (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + int flag = 0; + PyObject *pynames = NULL; + PyObject *pystring = NULL; + Py_ssize_t len = 0; + char **names = NULL; + char *kwlist[] = { "flag", "names", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO", kwlist, &flag, &pynames)) { + return NULL; + } + + if (!PySequence_Check (pynames)) { + PyErr_SetString (PyExc_AttributeError, "Failed to parse list of names for filter"); + return NULL; + } + + len = PySequence_Size (pynames); + if (len < 1) { + PyErr_SetString (PyExc_AttributeError, "Failed to parse list of names for filter"); + return NULL; + } + + names = malloc(sizeof (char *) * (len + 1)); + if (!names) { + PyErr_NoMemory (); + return NULL; + } + + for (Py_ssize_t i = 0; i < len; i++) { + pystring = PyUnicode_AsEncodedString (PySequence_GetItem (pynames, i), "utf-8", "replace"); + names[i] = strdup (PyBytes_AsString (pystring)); + Py_DECREF (pystring); + } + names[len] = NULL; + + ret = blkid_probe_filter_superblocks_type (self->probe, flag, names); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set probe filter"); + for (Py_ssize_t i = 0; i < len; i++) + free(names[i]); + free (names); + return NULL; + } + + for (Py_ssize_t i = 0; i < len; i++) + free(names[i]); + free (names); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_filter_superblocks_usage__doc__, +"filter_superblocks_usage (flag, usage)\n\n" \ +"Filter superblocks prober results based on usage.\n" +"blkid.FLTR_NOTIN - probe for all items which are NOT IN names\n" +"blkid.FLTR_ONLYIN - probe for items which are IN names\n" +"usage: blkid.USAGE_* flags"); +static PyObject *Probe_filter_superblocks_usage (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + int flag = 0; + int usage = 0; + char *kwlist[] = { "flag", "usage", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &flag, &usage)) { + return NULL; + } + + ret = blkid_probe_filter_superblocks_usage (self->probe, flag, usage); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set probe filter"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_invert_superblocks_filter__doc__, +"invert_superblocks_filter ()\n\n" +"This function inverts superblocks probing filter.\n"); +static PyObject *Probe_invert_superblocks_filter (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_invert_superblocks_filter (self->probe); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to invert superblock probing filter"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_reset_superblocks_filter__doc__, +"reset_superblocks_filter ()\n\n" +"This function resets superblocks probing filter.\n"); +static PyObject *Probe_reset_superblocks_filter (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_reset_superblocks_filter (self->probe); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to reset superblock probing filter"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_enable_partitions__doc__, +"enable_partitions (enable)\n\n" \ +"Enables/disables the partitions probing for non-binary interface."); +static PyObject *Probe_enable_partitions (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + bool enable = false; + char *kwlist[] = { "enable", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "p", kwlist, &enable)) { + return NULL; + } + + ret = blkid_probe_enable_partitions (self->probe, enable); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to %s partitions probing", enable ? "enable" : "disable"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_set_partitions_flags__doc__, +"set_partitions_flags (flags)\n\n" \ +"Sets probing flags to the partitions prober. This function is optional.\n" +"Use blkid.PARTS_* constants for the 'flags' argument."); +static PyObject *Probe_set_partitions_flags (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + int flags = 0; + char *kwlist[] = { "flags", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i", kwlist, &flags)) { + return NULL; + } + + ret = blkid_probe_set_partitions_flags (self->probe, flags); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set superblock flags"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_filter_partitions_type__doc__, +"filter_partitions_type (flag, names)\n\n" \ +"Filter partitions prober results based on type.\n" +"blkid.FLTR_NOTIN - probe for all items which are NOT IN names\n" +"blkid.FLTR_ONLYIN - probe for items which are IN names\n" +"names: array of probing function names (e.g. 'vfat')."); +static PyObject *Probe_filter_partitions_type (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + int flag = 0; + PyObject *pynames = NULL; + PyObject *pystring = NULL; + Py_ssize_t len = 0; + char **names = NULL; + char *kwlist[] = { "flag", "names", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "iO", kwlist, &flag, &pynames)) { + return NULL; + } + + if (!PySequence_Check (pynames)) { + PyErr_SetString (PyExc_AttributeError, "Failed to parse list of names for filter"); + return NULL; + } + + len = PySequence_Size (pynames); + if (len < 1) { + PyErr_SetString (PyExc_AttributeError, "Failed to parse list of names for filter"); + return NULL; + } + + names = malloc(sizeof (char *) * (len + 1)); + if (!names) { + PyErr_NoMemory (); + return NULL; + } + + for (Py_ssize_t i = 0; i < len; i++) { + pystring = PyUnicode_AsEncodedString (PySequence_GetItem (pynames, i), "utf-8", "replace"); + names[i] = strdup (PyBytes_AsString (pystring)); + Py_DECREF (pystring); + } + names[len] = NULL; + + ret = blkid_probe_filter_partitions_type (self->probe, flag, names); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to set probe filter"); + for (Py_ssize_t i = 0; i < len; i++) + free(names[i]); + free (names); + return NULL; + } + + for (Py_ssize_t i = 0; i < len; i++) + free(names[i]); + free (names); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_invert_partitions_filter__doc__, +"invert_partitions_filter ()\n\n" +"This function inverts partitions probing filter.\n"); +static PyObject *Probe_invert_partitions_filter (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_invert_partitions_filter (self->probe); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to invert superblock probing filter"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_reset_partitions_filter__doc__, +"reset_partitions_filter ()\n\n" +"This function resets partitions probing filter.\n"); +static PyObject *Probe_reset_partitions_filter (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_reset_partitions_filter (self->probe); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to reset superblock probing filter"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_enable_topology__doc__, +"enable_topology (enable)\n\n" \ +"Enables/disables the topology probing for non-binary interface."); +static PyObject *Probe_enable_topology (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + bool enable = false; + char *kwlist[] = { "enable", NULL }; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "p", kwlist, &enable)) { + return NULL; + } + + ret = blkid_probe_enable_topology (self->probe, enable); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to %s topology probing", enable ? "enable" : "disable"); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Probe_lookup_value__doc__, +"lookup_value (name)\n\n" \ +"Assigns the device to probe control struct, resets internal buffers and resets the current probing."); +static PyObject *Probe_lookup_value (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + char *kwlist[] = { "name", NULL }; + char *name = NULL; + const char *value = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name)) { + return NULL; + } + + ret = blkid_probe_lookup_value (self->probe, name, &value, NULL); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to lookup '%s'", name); + return NULL; + } + + return PyBytes_FromString (value); +} + +PyDoc_STRVAR(Probe_do_safeprobe__doc__, +"do_safeprobe ()\n\n" +"This function gathers probing results from all enabled chains and checks for ambivalent results" +"(e.g. more filesystems on the device).\n" +"Returns True on success, False if nothing is detected.\n\n" +"Note about superblocks chain -- the function does not check for filesystems when a RAID signature is detected.\n" +"The function also does not check for collision between RAIDs. The first detected RAID is returned.\n" +"The function checks for collision between partition table and RAID signature -- it's recommended to " +"enable partitions chain together with superblocks chain.\n"); +static PyObject *Probe_do_safeprobe (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + if (self->fd < 0) { + PyErr_SetString (PyExc_ValueError, "No device set"); + return NULL; + } + + if (self->topology) { + Py_DECREF (self->topology); + self->topology = NULL; + } + + if (self->partlist) { + Py_DECREF (self->partlist); + self->partlist = NULL; + } + + ret = blkid_do_safeprobe (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to safeprobe the device"); + return NULL; + } + + if (ret == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(Probe_do_fullprobe__doc__, +"do_fullprobe ()\n\n" +"Returns True on success, False if nothing is detected.\n" +"This function gathers probing results from all enabled chains. Same as do_safeprobe() but " +"does not check for collision between probing result."); +static PyObject *Probe_do_fullprobe (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + if (self->fd < 0) { + PyErr_SetString (PyExc_ValueError, "No device set"); + return NULL; + } + + if (self->topology) { + Py_DECREF (self->topology); + self->topology = NULL; + } + + if (self->partlist) { + Py_DECREF (self->partlist); + self->partlist = NULL; + } + + ret = blkid_do_fullprobe (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to fullprobe the device"); + return NULL; + } + + if (ret == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(Probe_do_probe__doc__, +"do_probe ()\n\n" +"Calls probing functions in all enabled chains. The superblocks chain is enabled by default.\n" +"Returns True on success, False if nothing is detected.\n\n" +"The do_probe() stores result from only one probing function. It's necessary to call this routine " +"in a loop to get results from all probing functions in all chains. The probing is reset by " +"reset_probe() or by filter functions."); +static PyObject *Probe_do_probe (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + if (self->fd < 0) { + PyErr_SetString (PyExc_ValueError, "No device set"); + return NULL; + } + + if (self->topology) { + Py_DECREF (self->topology); + self->topology = NULL; + } + + if (self->partlist) { + Py_DECREF (self->partlist); + self->partlist = NULL; + } + + ret = blkid_do_probe (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to probe the device"); + return NULL; + } + + if (ret == 0) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +PyDoc_STRVAR(Probe_step_back__doc__, +"step_back ()\n\n" +"This function move pointer to the probing chain one step back -- it means that the previously " +"used probing function will be called again in the next Probe.do_probe() call.\n" +"This is necessary for example if you erase or modify on-disk superblock according to the " +"current libblkid probing result.\n" +"Note that Probe.hide_range() changes semantic of this function and cached buffers are " +"not reset, but library uses in-memory modified buffers to call the next probing function."); +static PyObject *Probe_step_back (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_step_back (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to step back the probe"); + return NULL; + } + + Py_RETURN_NONE; +} + +#ifdef HAVE_BLKID_2_31 +PyDoc_STRVAR(Probe_reset_buffers__doc__, +"reset_buffers ()\n\n" +"libblkid reuse all already read buffers from the device. The buffers may be modified by Probe.hide_range().\n" +"This function reset and free all cached buffers. The next Probe.do_probe() will read all data from the device."); +static PyObject *Probe_reset_buffers (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_probe_reset_buffers (self->probe); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to reset buffers"); + return NULL; + } + + Py_RETURN_NONE; +} +#endif + +PyDoc_STRVAR(Probe_reset_probe__doc__, +"reset_probe ()\n\n" +"Zeroize probing results and resets the current probing (this has impact to do_probe() only).\n" +"This function does not touch probing filters and keeps assigned device."); +static PyObject *Probe_reset_probe (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_reset_probe (self->probe); + + if (self->topology) { + Py_DECREF (self->topology); + self->topology = NULL; + } + + if (self->partlist) { + Py_DECREF (self->partlist); + self->partlist = NULL; + } + + Py_RETURN_NONE; +} + +#ifdef HAVE_BLKID_2_31 +PyDoc_STRVAR(Probe_hide_range__doc__, +"hide_range (offset, length)\n\n" \ +"This function modifies in-memory cached data from the device. The specified range is zeroized. " +"This is usable together with Probe.step_back(). The next Probe.do_probe() will not see specified area.\n" +"Note that this is usable for already (by library) read data, and this function is not a way " +"how to hide any large areas on your device.\n" +"The function Probe.reset_buffers() reverts all."); +static PyObject *Probe_hide_range (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + char *kwlist[] = { "offset", "length", NULL }; + uint64_t offset = 0; + uint64_t length = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &offset, &length)) { + return NULL; + } + + ret = blkid_probe_hide_range (self->probe, offset, length); + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to hide range"); + return NULL; + } + + Py_RETURN_NONE; +} +#endif + +#ifdef HAVE_BLKID_2_40 +PyDoc_STRVAR(Probe_wipe_all__doc__, +"wipe_all ()\n\n" +"This function erases all detectable signatures from probe. The probe has to be open in O_RDWR mode. " +"All other necessary configurations will be enabled automatically."); +static PyObject *Probe_wipe_all (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + int ret = 0; + + ret = blkid_wipe_all (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to probe the device"); + return NULL; + } + + Py_RETURN_NONE; +} +#endif + +PyDoc_STRVAR(Probe_do_wipe__doc__, +"do_wipe (dryrun=False)\n\n" +"This function erases the current signature detected by the probe. The probe has to be open in " +"O_RDWR mode, blkid.SUBLKS_MAGIC or/and blkid.PARTS_MAGIC flags has to be enabled (if you want " +"to erase also superblock with broken check sums then use blkid.SUBLKS_BADCSUM too).\n\n" +"After successful signature removing the probe prober will be moved one step back and the next " +"do_probe() call will again call previously called probing function. All in-memory cached data " +"from the device are always reset."); +static PyObject *Probe_do_wipe (ProbeObject *self, PyObject *args, PyObject *kwargs) { + int ret = 0; + char *kwlist[] = { "dryrun", NULL }; + bool dryrun = false; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p", kwlist, &dryrun)) { + return NULL; + } + + ret = blkid_do_wipe (self->probe, dryrun); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to wipe the device: %s", strerror (errno)); + return NULL; + } + + Py_RETURN_NONE; +} + +static PyObject * probe_to_dict (ProbeObject *self) { + PyObject *dict = NULL; + int ret = 0; + int nvalues = 0; + const char *name = NULL; + const char *value = NULL; + PyObject *py_value = NULL; + + ret = blkid_probe_numof_values (self->probe); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get probe results"); + return NULL; + } + nvalues = ret; + + dict = PyDict_New (); + if (!dict) { + PyErr_NoMemory (); + return NULL; + } + + for (int i = 0; i < nvalues; i++) { + ret = blkid_probe_get_value (self->probe, i, &name, &value, NULL); + if (ret < 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get probe results"); + return NULL; + } + + py_value = PyUnicode_FromString (value); + if (py_value == NULL) { + Py_INCREF (Py_None); + py_value = Py_None; + } + + PyDict_SetItemString (dict, name, py_value); + Py_DECREF (py_value); + } + + return dict; +} + +PyDoc_STRVAR(Probe_items__doc__, +"items ()\n"); +static PyObject *Probe_items (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + PyObject *dict = probe_to_dict (self); + + if (PyErr_Occurred ()) + return NULL; + + PyObject *ret = PyDict_Items (dict); + PyDict_Clear (dict); + + return ret; +} + +PyDoc_STRVAR(Probe_values__doc__, +"values ()\n"); +static PyObject *Probe_values (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + PyObject *dict = probe_to_dict (self); + + if (PyErr_Occurred ()) + return NULL; + + PyObject *ret = PyDict_Values (dict); + PyDict_Clear (dict); + + return ret; +} + +PyDoc_STRVAR(Probe_keys__doc__, +"keys ()\n"); +static PyObject *Probe_keys (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + PyObject *dict = probe_to_dict (self); + + if (PyErr_Occurred ()) + return NULL; + + PyObject *ret = PyDict_Keys (dict); + PyDict_Clear (dict); + + return ret; +} + +static PyMethodDef Probe_methods[] = { + {"set_device", (PyCFunction)(void(*)(void)) Probe_set_device, METH_VARARGS|METH_KEYWORDS, Probe_set_device__doc__}, + {"do_safeprobe", (PyCFunction) Probe_do_safeprobe, METH_NOARGS, Probe_do_safeprobe__doc__}, + {"do_fullprobe", (PyCFunction) Probe_do_fullprobe, METH_NOARGS, Probe_do_fullprobe__doc__}, + {"do_probe", (PyCFunction) Probe_do_probe, METH_NOARGS, Probe_do_probe__doc__}, + {"step_back", (PyCFunction) Probe_step_back, METH_NOARGS, Probe_step_back__doc__}, +#ifdef HAVE_BLKID_2_31 + {"reset_buffers", (PyCFunction) Probe_reset_buffers, METH_NOARGS, Probe_reset_buffers__doc__}, +#endif + {"reset_probe", (PyCFunction) Probe_reset_probe, METH_NOARGS, Probe_reset_probe__doc__}, +#ifdef HAVE_BLKID_2_31 + {"hide_range", (PyCFunction)(void(*)(void)) Probe_hide_range, METH_VARARGS|METH_KEYWORDS, Probe_hide_range__doc__}, +#endif +#ifdef HAVE_BLKID_2_40 + {"wipe_all", (PyCFunction) Probe_wipe_all, METH_NOARGS, Probe_wipe_all__doc__}, +#endif + {"do_wipe", (PyCFunction)(void(*)(void)) Probe_do_wipe, METH_VARARGS|METH_KEYWORDS, Probe_do_wipe__doc__}, + {"enable_partitions", (PyCFunction)(void(*)(void)) Probe_enable_partitions, METH_VARARGS|METH_KEYWORDS, Probe_enable_partitions__doc__}, + {"set_partitions_flags", (PyCFunction)(void(*)(void)) Probe_set_partitions_flags, METH_VARARGS|METH_KEYWORDS, Probe_set_partitions_flags__doc__}, + {"filter_partitions_type", (PyCFunction)(void(*)(void)) Probe_filter_partitions_type, METH_VARARGS|METH_KEYWORDS, Probe_filter_partitions_type__doc__}, + {"invert_partitions_filter", (PyCFunction) Probe_invert_partitions_filter, METH_NOARGS, Probe_invert_partitions_filter__doc__}, + {"reset_partitions_filter", (PyCFunction) Probe_reset_partitions_filter, METH_NOARGS, Probe_reset_partitions_filter__doc__}, + {"enable_topology", (PyCFunction)(void(*)(void)) Probe_enable_topology, METH_VARARGS|METH_KEYWORDS, Probe_enable_topology__doc__}, + {"enable_superblocks", (PyCFunction)(void(*)(void)) Probe_enable_superblocks, METH_VARARGS|METH_KEYWORDS, Probe_enable_superblocks__doc__}, + {"filter_superblocks_type", (PyCFunction)(void(*)(void)) Probe_filter_superblocks_type, METH_VARARGS|METH_KEYWORDS, Probe_filter_superblocks_type__doc__}, + {"filter_superblocks_usage", (PyCFunction)(void(*)(void)) Probe_filter_superblocks_usage, METH_VARARGS|METH_KEYWORDS, Probe_filter_superblocks_usage__doc__}, + {"set_superblocks_flags", (PyCFunction)(void(*)(void)) Probe_set_superblocks_flags, METH_VARARGS|METH_KEYWORDS, Probe_set_superblocks_flags__doc__}, + {"invert_superblocks_filter", (PyCFunction) Probe_invert_superblocks_filter, METH_NOARGS, Probe_invert_superblocks_filter__doc__}, + {"reset_superblocks_filter", (PyCFunction) Probe_reset_superblocks_filter, METH_NOARGS, Probe_reset_superblocks_filter__doc__}, + {"lookup_value", (PyCFunction)(void(*)(void)) Probe_lookup_value, METH_VARARGS|METH_KEYWORDS, Probe_lookup_value__doc__}, + {"items", (PyCFunction) Probe_items, METH_NOARGS, Probe_items__doc__}, + {"values", (PyCFunction) Probe_values, METH_NOARGS, Probe_values__doc__}, + {"keys", (PyCFunction) Probe_keys, METH_NOARGS, Probe_keys__doc__}, + {NULL, NULL, 0, NULL} +}; + +static PyObject *Probe_get_devno (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + dev_t devno = blkid_probe_get_devno (self->probe); + + return PyLong_FromUnsignedLong (devno); +} + +static PyObject *Probe_get_fd (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + return PyLong_FromLong (self->fd); +} + +static PyObject *Probe_get_offset (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t offset = blkid_probe_get_offset (self->probe); + + return PyLong_FromLongLong (offset); +} + +static PyObject *Probe_get_sectors (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t sectors = blkid_probe_get_sectors (self->probe); + + return PyLong_FromLongLong (sectors); +} + +static PyObject *Probe_get_size (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + blkid_loff_t size = blkid_probe_get_size (self->probe); + + return PyLong_FromLongLong (size); +} + +static PyObject *Probe_get_sector_size (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned int sector_size = blkid_probe_get_sectorsize (self->probe); + + return PyLong_FromUnsignedLong (sector_size); +} + +#ifdef HAVE_BLKID_2_30 +static int Probe_set_sector_size (ProbeObject *self, PyObject *value, void *closure UNUSED) { + unsigned int sector_size = 0; + int ret = 0; + + if (!PyLong_Check (value)) { + PyErr_SetString (PyExc_TypeError, "Invalid argument"); + + return -1; + } + + sector_size = PyLong_AsLong (value); + + ret = blkid_probe_set_sectorsize (self->probe, sector_size); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to set sector size"); + return -1; + } + + return 0; +} +#endif + +static PyObject *Probe_get_wholedisk_devno (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + dev_t devno = blkid_probe_get_wholedisk_devno (self->probe); + + return PyLong_FromUnsignedLong (devno); +} + +static PyObject *Probe_get_is_wholedisk (ProbeObject *self __attribute__((unused)), PyObject *Py_UNUSED (ignored)) { + int wholedisk = blkid_probe_is_wholedisk (self->probe); + + return PyBool_FromLong (wholedisk); +} + +static PyObject *Probe_get_topology (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + if (self->topology) { + Py_INCREF (self->topology); + return self->topology; + } + + self->topology = _Topology_get_topology_object (self->probe); + + return self->topology; +} + +static PyObject *Probe_get_partitions (ProbeObject *self, PyObject *Py_UNUSED (ignored)) { + if (self->partlist) { + Py_INCREF (self->partlist); + return self->partlist; + } + + self->partlist = _Partlist_get_partlist_object (self->probe); + + return self->partlist; +} + +static PyGetSetDef Probe_getseters[] = { + {"devno", (getter) Probe_get_devno, NULL, "block device number, or 0 for regular files", NULL}, + {"fd", (getter) Probe_get_fd, NULL, "file descriptor for assigned device/file or -1 in case of error", NULL}, + {"offset", (getter) Probe_get_offset, NULL, "offset of probing area as defined by Probe.set_device() or -1 in case of error", NULL}, + {"sectors", (getter) Probe_get_sectors, NULL, "512-byte sector count or -1 in case of error", NULL}, + {"size", (getter) Probe_get_size, NULL, "size of probing area as defined by Probe.set_device()", NULL}, +#ifdef HAVE_BLKID_2_30 + {"sector_size", (getter) Probe_get_sector_size, (setter) Probe_set_sector_size, "block device logical sector size (BLKSSZGET ioctl, default 512).", NULL}, +#else + {"sector_size", (getter) Probe_get_sector_size, NULL, "block device logical sector size (BLKSSZGET ioctl, default 512).", NULL}, +#endif + {"wholedisk_devno", (getter) Probe_get_wholedisk_devno, NULL, "device number of the wholedisk, or 0 for regular files", NULL}, + {"is_wholedisk", (getter) Probe_get_is_wholedisk, NULL, "True if the device is whole-disk, False otherwise", NULL}, + {"topology", (getter) Probe_get_topology, NULL, "binary interface for topology values", NULL}, + {"partitions", (getter) Probe_get_partitions, NULL, "binary interface for partitions", NULL}, + {NULL, NULL, NULL, NULL, NULL} +}; + +static Py_ssize_t Probe_len (ProbeObject *self) { + int ret = 0; + + ret = blkid_probe_numof_values (self->probe); + if (ret < 0) + return 0; + + return (Py_ssize_t) ret; + +} + +static PyObject * Probe_getitem (ProbeObject *self, PyObject *item) { + int ret = 0; + const char *key = NULL; + const char *value = NULL; + + if (!PyUnicode_Check (item)) { + PyErr_SetObject(PyExc_KeyError, item); + return NULL; + } + + key = PyUnicode_AsUTF8 (item); + + ret = blkid_probe_lookup_value (self->probe, key, &value, NULL); + if (ret != 0) { + PyErr_SetObject (PyExc_KeyError, item); + return NULL; + } + + return PyBytes_FromString (value); +} + + + +PyMappingMethods ProbeMapping = { + .mp_length = (lenfunc) Probe_len, + .mp_subscript = (binaryfunc) Probe_getitem, +}; + +PyTypeObject ProbeType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Probe", + .tp_basicsize = sizeof (ProbeObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Probe_new, + .tp_dealloc = (destructor) Probe_dealloc, + .tp_init = (initproc) Probe_init, + .tp_methods = Probe_methods, + .tp_getset = Probe_getseters, + .tp_as_mapping = &ProbeMapping, +}; diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.h b/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.h new file mode 100644 index 0000000..055aaa0 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/probe.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ +#ifndef PROBE_H +#define PROBE_H + +#include + +#include + +typedef struct { + PyObject_HEAD + blkid_probe probe; + PyObject *topology; + PyObject *partlist; + int fd; +} ProbeObject; + +extern PyTypeObject ProbeType; + +PyObject *Probe_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Probe_init (ProbeObject *self, PyObject *args, PyObject *kwargs); +void Probe_dealloc (ProbeObject *self); + +#endif /* PROBE_H */ diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.c b/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.c new file mode 100644 index 0000000..c254473 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.c @@ -0,0 +1,631 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ + +#include "pyblkid.h" +#include "probe.h" +#include "topology.h" +#include "partitions.h" +#include "cache.h" + +#include +#include +#include + +#define UNUSED __attribute__((unused)) + + +PyDoc_STRVAR(Blkid_init_debug__doc__, +"init_debug (mask)\n\n" +"If the mask is not specified then this function reads LIBBLKID_DEBUG environment variable to get the mask.\n" +"Already initialized debugging stuff cannot be changed. It does not have effect to call this function twice.\n\n" +"Use '0xffff' to enable full debugging.\n"); +static PyObject *Blkid_init_debug (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + int mask = 0; + char *kwlist[] = { "mask", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "|i", kwlist, &mask)) + return NULL; + + blkid_init_debug (mask); + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Blkid_known_fstype__doc__, +"known_fstype (fstype)\n\n" +"Returns whether fstype is a known filesystem type or not.\n"); +static PyObject *Blkid_known_fstype (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + const char *fstype = NULL; + char *kwlist[] = { "fstype", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &fstype)) + return NULL; + + return PyBool_FromLong (blkid_known_fstype (fstype)); +} + +PyDoc_STRVAR(Blkid_send_uevent__doc__, +"send_uevent (devname, action)\n\n"); +static PyObject *Blkid_send_uevent (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + const char *devname = NULL; + const char *action = NULL; + char *kwlist[] = { "devname", "action", NULL }; + int ret = 0; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss", kwlist, &devname, &action)) + return NULL; + + ret = blkid_send_uevent (devname, action); + if (ret < 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to send %s uevent do device '%s'", action, devname); + return NULL; + } + + Py_RETURN_NONE; +} + +PyDoc_STRVAR(Blkid_known_pttype__doc__, +"known_pttype (pttype)\n\n" +"Returns whether pttype is a known partition type or not.\n"); +static PyObject *Blkid_known_pttype (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + const char *pttype = NULL; + char *kwlist[] = { "pttype", NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &pttype)) + return NULL; + + return PyBool_FromLong (blkid_known_pttype (pttype)); +} + +static int _Py_Dev_Converter (PyObject *obj, void *p) { +#ifdef HAVE_LONG_LONG + *((dev_t *)p) = PyLong_AsUnsignedLongLong (obj); +#else + *((dev_t *)p) = PyLong_AsUnsignedLong (obj); +#endif + if (PyErr_Occurred ()) + return 0; + return 1; +} + +#ifdef HAVE_LONG_LONG + #define _PyLong_FromDev PyLong_FromLongLong +#else + #define _PyLong_FromDev PyLong_FromLong +#endif + +PyDoc_STRVAR(Blkid_devno_to_devname__doc__, +"devno_to_devname (devno)\n\n" +"This function finds the pathname to a block device with a given device number.\n"); +static PyObject *Blkid_devno_to_devname (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + dev_t devno = 0; + char *kwlist[] = { "devno", NULL }; + char *devname = NULL; + PyObject *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_devname", kwlist, _Py_Dev_Converter, &devno)) + return NULL; + + devname = blkid_devno_to_devname (devno); + if (!devname) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get devname"); + return NULL; + } + + ret = PyUnicode_FromString (devname); + free (devname); + + return ret; +} + +PyDoc_STRVAR(Blkid_devno_to_wholedisk__doc__, +"devno_to_wholedisk (devno)\n\n" +"This function uses sysfs to convert the devno device number to the name and devno of the whole disk."); +static PyObject *Blkid_devno_to_wholedisk (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + dev_t devno = 0; + dev_t diskdevno = 0; + char *kwlist[] = { "devno", NULL }; +#ifdef HAVE_BLKID_2_28 + char diskname[32]; +#else + char diskname[PATH_MAX]; +#endif + int ret = 0; + PyObject *tuple = NULL; + PyObject *py_name = NULL; + PyObject *py_devno = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O&:devno_to_wholedisk", kwlist, _Py_Dev_Converter, &devno)) + return NULL; + +#ifdef HAVE_BLKID_2_28 + ret = blkid_devno_to_wholedisk (devno, diskname, 32, &diskdevno); +#else + ret = blkid_devno_to_wholedisk (devno, diskname, PATH_MAX, &diskdevno); +#endif + if (ret != 0) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get whole disk name"); + return NULL; + } + + tuple = PyTuple_New (2); + + py_name = PyUnicode_FromString (diskname); + if (py_name == NULL) { + Py_INCREF (Py_None); + py_name = Py_None; + } + PyTuple_SetItem (tuple, 0, py_name); + + py_devno = _PyLong_FromDev (diskdevno); + if (py_devno == NULL) { + Py_INCREF (Py_None); + py_devno = Py_None; + } + PyTuple_SetItem (tuple, 1, py_devno); + + return tuple; +} + +PyDoc_STRVAR(Blkid_parse_version_string__doc__, +"parse_version_string (version)\n\n" +"Convert version string (e.g. '2.16.0') to release version code (e.g. '2160').\n"); +static PyObject *Blkid_parse_version_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *ver_str = NULL; + char *kwlist[] = { "version", NULL }; + int ret = 0; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &ver_str)) + return NULL; + + ret = blkid_parse_version_string (ver_str); + + return PyLong_FromLong (ret); +} + +PyDoc_STRVAR(Blkid_get_library_version__doc__, +"get_library_version ()\n\n" +"Returns tuple of release version code (int), version string and date.\n"); +static PyObject *Blkid_get_library_version (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { + const char *ver_str = NULL; + const char *date = NULL; + int ver_code = 0; + PyObject *ret = NULL; + PyObject *py_code = NULL; + PyObject *py_ver = NULL; + PyObject *py_date = NULL; + + ver_code = blkid_get_library_version (&ver_str, &date); + + ret = PyTuple_New (3); + + py_code = PyLong_FromLong (ver_code); + PyTuple_SetItem (ret, 0, py_code); + + py_ver = PyUnicode_FromString (ver_str); + if (py_ver == NULL) { + Py_INCREF (Py_None); + py_ver = Py_None; + } + PyTuple_SetItem (ret, 1, py_ver); + + py_date = PyUnicode_FromString (date); + if (py_date == NULL) { + Py_INCREF (Py_None); + py_date = Py_None; + } + PyTuple_SetItem (ret, 2, py_date); + + return ret; +} + +PyDoc_STRVAR(Blkid_parse_tag_string__doc__, +"parse_tag_string (tag)\n\n" +"Parse a 'NAME=value' string, returns tuple of type and value.\n"); +static PyObject *Blkid_parse_tag_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *tag_str = NULL; + char *kwlist[] = { "tag", NULL }; + int ret = 0; + char *type = NULL; + char *value = NULL; + PyObject *py_type = NULL; + PyObject *py_value = NULL; + PyObject *tuple = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &tag_str)) + return NULL; + + ret = blkid_parse_tag_string (tag_str, &type, &value); + if (ret < 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to parse tag '%s'", tag_str); + return NULL; + } + + tuple = PyTuple_New (2); + + py_type = PyUnicode_FromString (type); + if (py_type == NULL) { + Py_INCREF (Py_None); + py_type = Py_None; + } + PyTuple_SetItem (tuple, 0, py_type); + free (type); + + py_value = PyUnicode_FromString (value); + if (py_value == NULL) { + Py_INCREF (Py_None); + py_value = Py_None; + } + PyTuple_SetItem (tuple, 1, py_value); + free (value); + + return tuple; +} + +PyDoc_STRVAR(Blkid_get_dev_size__doc__, +"get_dev_size (device)\n\n" +"Returns size (in bytes) of the block device or size of the regular file.\n"); +static PyObject *Blkid_get_dev_size (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *device = NULL; + char *kwlist[] = { "device", NULL }; + blkid_loff_t ret = 0; + int fd = 0; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &device)) + return NULL; + + fd = open (device, O_RDONLY|O_CLOEXEC); + if (fd == -1) { + PyErr_Format (PyExc_OSError, "Failed to open device '%s': %s", device, strerror (errno)); + return NULL; + } + + ret = blkid_get_dev_size (fd); + if (ret == 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to get size of device '%s'", device); + close (fd); + return NULL; + } + + close (fd); + return PyLong_FromLongLong (ret); +} + +PyDoc_STRVAR(Blkid_encode_string__doc__, +"encode_string (string)\n\n" +"Encode all potentially unsafe characters of a string to the corresponding hex value prefixed by '\\x'.\n"); +static PyObject *Blkid_encode_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *string = NULL; + char *kwlist[] = { "string", NULL }; + char *encoded_string = NULL; + int ret = 0; + size_t inlen = 0; + size_t outlen = 0; + PyObject *py_ret = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &string)) + return NULL; + + inlen = strlen (string); + outlen = inlen * 4; + encoded_string = malloc (sizeof (char) * (outlen + 1 )); + + ret = blkid_encode_string (string, encoded_string, outlen); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to encode string"); + free (encoded_string); + return NULL; + } + + py_ret = PyUnicode_FromString (encoded_string); + free (encoded_string); + + return py_ret; +} + +PyDoc_STRVAR(Blkid_safe_string__doc__, +"safe_string (string)\n\n" +"Allows plain ascii, hex-escaping and valid utf8. Replaces all whitespaces with '_'.\n"); +static PyObject *Blkid_safe_string (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *string = NULL; + char *kwlist[] = { "string", NULL }; + char *safe_string = NULL; + int ret = 0; + size_t inlen = 0; + size_t outlen = 0; + PyObject *py_ret = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &string)) + return NULL; + + inlen = strlen (string); + outlen = inlen * 4; + safe_string = malloc (sizeof (char) * (outlen + 1 )); + + ret = blkid_safe_string (string, safe_string, outlen); + if (ret != 0) { + PyErr_Format (PyExc_RuntimeError, "Failed to make safe string"); + free (safe_string); + return NULL; + } + + py_ret = PyUnicode_FromString (safe_string); + free (safe_string); + + return py_ret; +} + +#ifdef HAVE_BLKID_2_30 +PyDoc_STRVAR(Blkid_partition_types__doc__, +"partition_types ()\n\n" +"List of supported partition types.\n"); +static PyObject *Blkid_partition_types (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { + PyObject *ret = NULL; + PyObject *py_name = NULL; + size_t idx = 0; + const char *name = NULL; + + ret = PyList_New (0); + + while (blkid_partitions_get_name (idx++, &name) == 0) { + py_name = PyUnicode_FromString (name); + if (py_name != NULL) + PyList_Append (ret, py_name); + } + + return ret; +} +#endif + +PyDoc_STRVAR(Blkid_superblocks__doc__, +"superblocks ()\n\n" +"List of supported superblocks.\n"); +static PyObject *Blkid_superblocks (ProbeObject *self UNUSED, PyObject *Py_UNUSED (ignored)) { + PyObject *ret = NULL; + PyObject *py_name = NULL; + size_t idx = 0; + const char *name = NULL; + + ret = PyList_New (0); + + while (blkid_superblocks_get_name (idx++, &name, NULL) == 0) { + py_name = PyUnicode_FromString (name); + if (py_name != NULL) + PyList_Append (ret, py_name); + } + + return ret; +} + +PyDoc_STRVAR(Blkid_evaluate_tag__doc__, +"evaluate_tag (token, value)\n\n" +"Get device name that match the specified token (e.g \"LABEL\" or \"UUID\") and token value.\n" +"The evaluation could be controlled by the /etc/blkid.conf config file. The default is to try \"udev\" and then \"scan\" method.\n"); +static PyObject *Blkid_evaluate_tag (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *token = NULL; + char *value = NULL; + char *kwlist[] = { "token", "value", NULL }; + PyObject *py_ret = NULL; + char *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss", kwlist, &token, &value)) + return NULL; + + + ret = blkid_evaluate_tag (token, value, NULL); + if (ret == NULL) { + Py_INCREF (Py_None); + py_ret = Py_None; + } else { + py_ret = PyUnicode_FromString (ret); + free (ret); + } + + return py_ret; +} + +PyDoc_STRVAR(Blkid_evaluate_spec__doc__, +"evaluate_spec (spec)\n\n" +"Get device name that match the unparsed tag (e.g. \"LABEL=foo\") or path (e.g. /dev/dm-0)\n" +"The evaluation could be controlled by the /etc/blkid.conf config file. The default is to try \"udev\" and then \"scan\" method.\n"); +static PyObject *Blkid_evaluate_spec (PyObject *self UNUSED, PyObject *args, PyObject *kwargs) { + char *spec = NULL; + char *kwlist[] = { "spec", NULL }; + PyObject *py_ret = NULL; + char *ret = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s", kwlist, &spec)) + return NULL; + + + ret = blkid_evaluate_spec (spec, NULL); + if (ret == NULL) { + Py_INCREF (Py_None); + py_ret = Py_None; + } else { + py_ret = PyUnicode_FromString (ret); + free (ret); + } + + return py_ret; +} + +static PyMethodDef BlkidMethods[] = { + {"init_debug", (PyCFunction)(void(*)(void)) Blkid_init_debug, METH_VARARGS|METH_KEYWORDS, Blkid_init_debug__doc__}, + {"known_fstype", (PyCFunction)(void(*)(void)) Blkid_known_fstype, METH_VARARGS|METH_KEYWORDS, Blkid_known_fstype__doc__}, + {"send_uevent", (PyCFunction)(void(*)(void)) Blkid_send_uevent, METH_VARARGS|METH_KEYWORDS, Blkid_send_uevent__doc__}, + {"devno_to_devname", (PyCFunction)(void(*)(void)) Blkid_devno_to_devname, METH_VARARGS|METH_KEYWORDS, Blkid_devno_to_devname__doc__}, + {"devno_to_wholedisk", (PyCFunction)(void(*)(void)) Blkid_devno_to_wholedisk, METH_VARARGS|METH_KEYWORDS, Blkid_devno_to_wholedisk__doc__}, + {"known_pttype", (PyCFunction)(void(*)(void)) Blkid_known_pttype, METH_VARARGS|METH_KEYWORDS, Blkid_known_pttype__doc__}, + {"parse_version_string", (PyCFunction)(void(*)(void)) Blkid_parse_version_string, METH_VARARGS|METH_KEYWORDS, Blkid_parse_version_string__doc__}, + {"get_library_version", (PyCFunction) Blkid_get_library_version, METH_NOARGS, Blkid_get_library_version__doc__}, + {"parse_tag_string", (PyCFunction)(void(*)(void)) Blkid_parse_tag_string, METH_VARARGS|METH_KEYWORDS, Blkid_parse_tag_string__doc__}, + {"get_dev_size", (PyCFunction)(void(*)(void)) Blkid_get_dev_size, METH_VARARGS|METH_KEYWORDS, Blkid_get_dev_size__doc__}, + {"encode_string", (PyCFunction)(void(*)(void)) Blkid_encode_string, METH_VARARGS|METH_KEYWORDS, Blkid_encode_string__doc__}, + {"safe_string", (PyCFunction)(void(*)(void)) Blkid_safe_string, METH_VARARGS|METH_KEYWORDS, Blkid_safe_string__doc__}, +#ifdef HAVE_BLKID_2_30 + {"partition_types", (PyCFunction) Blkid_partition_types, METH_NOARGS, Blkid_partition_types__doc__}, +#endif + {"superblocks", (PyCFunction) Blkid_superblocks, METH_NOARGS, Blkid_superblocks__doc__}, + {"evaluate_tag", (PyCFunction)(void(*)(void)) Blkid_evaluate_tag, METH_VARARGS|METH_KEYWORDS, Blkid_evaluate_tag__doc__}, + {"evaluate_spec", (PyCFunction)(void(*)(void)) Blkid_evaluate_spec, METH_VARARGS|METH_KEYWORDS, Blkid_evaluate_spec__doc__}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef blkidmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "blkid", + .m_doc = "Python interface for the libblkid C library", + .m_size = -1, + .m_methods = BlkidMethods, +}; + +PyMODINIT_FUNC PyInit_blkid (void) { + PyObject *module = NULL; + + if (PyType_Ready (&ProbeType) < 0) + return NULL; + + if (PyType_Ready (&TopologyType) < 0) + return NULL; + + if (PyType_Ready (&PartlistType) < 0) + return NULL; + + if (PyType_Ready (&ParttableType) < 0) + return NULL; + + if (PyType_Ready (&PartitionType) < 0) + return NULL; + + if (PyType_Ready (&CacheType) < 0) + return NULL; + + if (PyType_Ready (&DeviceType) < 0) + return NULL; + + module = PyModule_Create (&blkidmodule); + if (!module) + return NULL; + + PyModule_AddIntConstant (module, "FLTR_NOTIN", BLKID_FLTR_NOTIN); + PyModule_AddIntConstant (module, "FLTR_ONLYIN", BLKID_FLTR_ONLYIN); + + PyModule_AddIntConstant (module, "DEV_CREATE", BLKID_DEV_CREATE); + PyModule_AddIntConstant (module, "DEV_FIND", BLKID_DEV_FIND); + PyModule_AddIntConstant (module, "DEV_NORMAL", BLKID_DEV_NORMAL); + PyModule_AddIntConstant (module, "DEV_VERIFY", BLKID_DEV_VERIFY); + + PyModule_AddIntConstant (module, "PARTS_ENTRY_DETAILS", BLKID_PARTS_ENTRY_DETAILS); + PyModule_AddIntConstant (module, "PARTS_FORCE_GPT", BLKID_PARTS_FORCE_GPT); + PyModule_AddIntConstant (module, "PARTS_MAGIC", BLKID_PARTS_MAGIC); + +#ifdef HAVE_BLKID_2_24 + PyModule_AddIntConstant (module, "SUBLKS_BADCSUM", BLKID_SUBLKS_BADCSUM); +#endif + PyModule_AddIntConstant (module, "SUBLKS_DEFAULT", BLKID_SUBLKS_DEFAULT); +#ifdef HAVE_BLKID_2_39 + PyModule_AddIntConstant (module, "SUBLKS_FSINFO", BLKID_SUBLKS_FSINFO); +#endif + PyModule_AddIntConstant (module, "SUBLKS_LABEL", BLKID_SUBLKS_LABEL); + PyModule_AddIntConstant (module, "SUBLKS_LABELRAW", BLKID_SUBLKS_LABELRAW); + PyModule_AddIntConstant (module, "SUBLKS_MAGIC", BLKID_SUBLKS_MAGIC); + PyModule_AddIntConstant (module, "SUBLKS_SECTYPE", BLKID_SUBLKS_SECTYPE); + PyModule_AddIntConstant (module, "SUBLKS_TYPE", BLKID_SUBLKS_TYPE); + PyModule_AddIntConstant (module, "SUBLKS_USAGE", BLKID_SUBLKS_USAGE); + PyModule_AddIntConstant (module, "SUBLKS_UUID", BLKID_SUBLKS_UUID); + PyModule_AddIntConstant (module, "SUBLKS_UUIDRAW", BLKID_SUBLKS_UUIDRAW); + PyModule_AddIntConstant (module, "SUBLKS_VERSION", BLKID_SUBLKS_VERSION); + + PyModule_AddIntConstant (module, "USAGE_CRYPTO", BLKID_USAGE_CRYPTO); + PyModule_AddIntConstant (module, "USAGE_FILESYSTEM", BLKID_USAGE_FILESYSTEM); + PyModule_AddIntConstant (module, "USAGE_OTHER", BLKID_USAGE_OTHER); + PyModule_AddIntConstant (module, "USAGE_RAID", BLKID_USAGE_RAID); + + Py_INCREF (&ProbeType); + if (PyModule_AddObject (module, "Probe", (PyObject *) &ProbeType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&TopologyType); + if (PyModule_AddObject (module, "Topology", (PyObject *) &TopologyType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&PartlistType); + if (PyModule_AddObject (module, "Partlist", (PyObject *) &PartlistType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (&PartlistType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&ParttableType); + if (PyModule_AddObject (module, "Parttable", (PyObject *) &ParttableType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (&PartlistType); + Py_DECREF (&ParttableType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&PartitionType); + if (PyModule_AddObject (module, "Partition", (PyObject *) &PartitionType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (&PartlistType); + Py_DECREF (&ParttableType); + Py_DECREF (&PartitionType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&CacheType); + if (PyModule_AddObject (module, "Cache", (PyObject *) &CacheType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (&PartlistType); + Py_DECREF (&ParttableType); + Py_DECREF (&PartitionType); + Py_DECREF (&CacheType); + Py_DECREF (module); + return NULL; + } + + Py_INCREF (&DeviceType); + if (PyModule_AddObject (module, "Device", (PyObject *) &DeviceType) < 0) { + Py_DECREF (&ProbeType); + Py_DECREF (&TopologyType); + Py_DECREF (&PartlistType); + Py_DECREF (&ParttableType); + Py_DECREF (&PartitionType); + Py_DECREF (&CacheType); + Py_DECREF (&DeviceType); + Py_DECREF (module); + return NULL; + } + + return module; +} diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.h b/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.h new file mode 100644 index 0000000..d42bee0 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/pyblkid.h @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ +#ifndef PYBLKID_H +#define PYBLKID_H + +#include + +extern PyMODINIT_FUNC PyInit_blkid (void); + +#endif /* PYBLKID_H */ diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.c b/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.c new file mode 100644 index 0000000..bf74c92 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ + +#include "topology.h" + +#include + +#define UNUSED __attribute__((unused)) + + +PyObject *Topology_new (PyTypeObject *type, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + TopologyObject *self = (TopologyObject*) type->tp_alloc (type, 0); + + return (PyObject *) self; +} + +int Topology_init (TopologyObject *self UNUSED, PyObject *args UNUSED, PyObject *kwargs UNUSED) { + return 0; +} + +void Topology_dealloc (TopologyObject *self) { + Py_TYPE (self)->tp_free ((PyObject *) self); +} + +PyObject *_Topology_get_topology_object (blkid_probe probe) { + TopologyObject *result = NULL; + blkid_topology topology = NULL; + + if (!probe) { + PyErr_SetString(PyExc_RuntimeError, "internal error"); + return NULL; + } + + topology = blkid_probe_get_topology (probe); + if (!topology) { + PyErr_SetString (PyExc_RuntimeError, "Failed to get topology"); + return NULL; + } + + result = PyObject_New (TopologyObject, &TopologyType); + if (!result) { + PyErr_SetString (PyExc_MemoryError, "Failed to create a new Topology object"); + return NULL; + } + Py_INCREF (result); + + result->topology = topology; + + return (PyObject *) result; +} + +static PyObject *Topology_get_alignment_offset (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long alignment_offset = blkid_topology_get_alignment_offset (self->topology); + + return PyLong_FromUnsignedLong (alignment_offset); +} + +static PyObject *Topology_get_logical_sector_size (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long logical_sector_size = blkid_topology_get_logical_sector_size (self->topology); + + return PyLong_FromUnsignedLong (logical_sector_size); +} + +static PyObject *Topology_get_minimum_io_size (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long minimum_io_size = blkid_topology_get_minimum_io_size (self->topology); + + return PyLong_FromUnsignedLong (minimum_io_size); +} + +static PyObject *Topology_get_optimal_io_size (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long optimal_io_size = blkid_topology_get_optimal_io_size (self->topology); + + return PyLong_FromUnsignedLong (optimal_io_size); +} + +static PyObject *Topology_get_physical_sector_size (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + unsigned long physical_sector_size = blkid_topology_get_physical_sector_size (self->topology); + + return PyLong_FromUnsignedLong (physical_sector_size); +} + +#ifdef HAVE_BLKID_2_36 +static PyObject *Topology_get_dax (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + int dax = blkid_topology_get_dax (self->topology); + + if (dax == 1) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} +#endif + +#ifdef HAVE_BLKID_2_39 +static PyObject *Topology_get_diskseq (TopologyObject *self, PyObject *Py_UNUSED (ignored)) { + uint64_t diskseq = blkid_topology_get_diskseq (self->topology); + + return PyLong_FromUnsignedLongLong (diskseq); +} +#endif + +static PyGetSetDef Topology_getseters[] = { + {"alignment_offset", (getter) Topology_get_alignment_offset, NULL, "alignment offset in bytes or 0", NULL}, + {"logical_sector_size", (getter) Topology_get_logical_sector_size, NULL, "logical sector size (BLKSSZGET ioctl) in bytes or 0", NULL}, + {"minimum_io_size", (getter) Topology_get_minimum_io_size, NULL, "minimum io size in bytes or 0", NULL}, + {"optimal_io_size", (getter) Topology_get_optimal_io_size, NULL, "optimal io size in bytes or 0", NULL}, + {"physical_sector_size", (getter) Topology_get_physical_sector_size, NULL, "logical sector size (BLKSSZGET ioctl) in bytes or 0", NULL}, +#ifdef HAVE_BLKID_2_36 + {"dax", (getter) Topology_get_dax, NULL, "whether DAX is supported or not", NULL}, +#endif +#ifdef HAVE_BLKID_2_39 + {"diskseq", (getter) Topology_get_diskseq, NULL, "disk sequence number", NULL}, +#endif + {NULL, NULL, NULL, NULL, NULL} +}; + +PyTypeObject TopologyType = { + PyVarObject_HEAD_INIT (NULL, 0) + .tp_name = "blkid.Topology", + .tp_basicsize = sizeof (TopologyObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_new = Topology_new, + .tp_dealloc = (destructor) Topology_dealloc, + .tp_init = (initproc) Topology_init, + .tp_getset = Topology_getseters, +}; diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.h b/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.h new file mode 100644 index 0000000..acd6e83 --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/src/topology.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2020 Red Hat, Inc. + * + * This 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. + * + * This 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 this library; if not, see . + * + */ +#ifndef TOPOLOGY_H +#define TOPOLOGY_H + +#include + +#include + +typedef struct { + PyObject_HEAD + blkid_topology topology; +} TopologyObject; + +extern PyTypeObject TopologyType; + +PyObject *Topology_new (PyTypeObject *type, PyObject *args, PyObject *kwargs); +int Topology_init (TopologyObject *self, PyObject *args, PyObject *kwargs); +void Topology_dealloc (TopologyObject *self); + +PyObject *_Topology_get_topology_object (blkid_probe probe); + +#endif /* TOPOLOGY_H */ diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/tests/__init__.py b/packages/pyblkid/opengnsys-pyblkid-0.3/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/tests/gpt.img.xz b/packages/pyblkid/opengnsys-pyblkid-0.3/tests/gpt.img.xz new file mode 100644 index 0000000000000000000000000000000000000000..9a085b46662b0d7154b6cbc064a546b86a089971 GIT binary patch literal 2140 zcmexsUKJ6=z`*kC+7>q^21Q0O1_p)_{ilon|JPzli)CQQ|NEzh<)Lbm{lX}#=>IJy zZ5!JRKQs4DP2kH(_~TJ~iF1!cpzNXW=46q#>#dHmHJAhj8W+C4^e=AX!!S1;)s|kj zb003IKQz2})7kN>`SprvlRQ?i2k@QNOK!a2+faCE?_;SPHjUTk%|8BGXl*y+`f9sY zol=DW zr`@|tS`%e068GuN)Rwlqyle!seOF(i*QEI>2>_m<=;Uz#;EI9oGTQ1}Jhy`=&UnhN&i1s?v z5?LI7R$!CIp{1VrTP3#1-%@&;DV9>V@05R@o^X(hsYY7qxsA`&lvn&<>%RH5{u-~e zeQo*bW)a1_i&v{Y+ld4xm92?<@-&*2s*^KP*156u)#>xR=> zIrq0(e>k#NFMbujop+kk1Yy4a0+W9fRz&{bKKp;Fh8zFNKQ;G$&oa;pJJ8?yxw-K` z>Jio8A73Y$8L}?j@Gk#gfv-Ey#fgHe)+WgAI=4|>A||r!Wm-_gzL)g0nrBID&iwxZ zjM@xuii4N`-M6mBP-_16Uc!h z_y?h1=n{;9{Pvqh1B`?uKN?^pmJyHuyUBQYG)odwsO~B~>iAill{qkCdB&VrCI0>G z^SUS8|HtylCiH9lQo%dZzj3g}G{$*EMrMaU>d!Gdct^!_dCJuLYp(sdf99Q%)P!x1 zPTk)9MbC2PDi_N$mktXzE&Cz!It=Y{r~@?w}8}V1&Ao2 zxU<$HMSgw4{NZ|ZGc^ZSDt%bzvePY}^N40R^*@34PDizNH{^4;gJf$}Hfxu-_jghN z4sIN-;A9ASC6OiOlxpxUL1QXc-Nt#xk>ahcX} z$ft)SzjaMQI9}SK2VvkgO)pX0>W3UB^0ZG_O^O+W51+=#S#;=9cbKW@s17uQB{>+i zI5K0hA$_q^D6!P@7BZV3`hK@j0ei5`|F;-TXZl`V=ijKZxLPlK9HQ`T)Je+IZ8F^* z&$tRb$H^uuzi)RZIE-_-gvStI__>094R_)O?ZqK$aWg55L5NHC0MOL!g(lPcp>`U* zMSR(tJ{3y>?S6?--6$-M>{w&oPJm0sTUGkkUM5agoXI~~&cicw1v2_~xN7j}Q!AG| z^?t84p_lwDqhNTf#AyR)~H+!aJe57NekE6!7IVxPh7$>*$khd z!6aw1-T?N1;OcPV58yY%=}#=I)s}gm3h+H=_XBjINW=Ff%x)=+C6V#w=A#xjq|pa)xf`FwJ!5lfuh1yJ|AA zesM-|2qOV)6IV1&_%_2TXs0oM)x(iQx4`}i<0{2o(5nd!5wq|_`FV%mf2lp>z=r=K z^}*4H;0`SffxLvMp^vipxsM&bb2#@&2HsGAetJX6$MYmB; z5v>d=mqnuh>CuS4g#OlJD&8AxH$p`4y&UYtp^YnHrjxb7b-=jlpV|pnIW*9%%EzCd z_-sPUh(BBakI+u9CMc9~A3cvG;c%IRH(c$%caS+{lve*^Oo zgJ=yimtWN5SK^N_$=2b`2xbnYxuMTMIR3N_>cnqps&q>gZQXB>IIL`buvsm>5B5AC z4gOeudJrNjh9o%M*;`WEm6NGYI*(*ks2T`dl2*nVh}*YtgQz|^ITg%|>z{RrO@mTv zd!1eFlXGd_p-A!w$VIwlEKC1dCaiJ{7LupFIgcdaaGs|Wq*vO-ec3+QiJXTP7ZLDt zn9n@vVqVdSQtG7py`^K-^>3Nfk(Pj`8DTf_Uu~HWVo|ilnN(=vlx*X zB8bhz5%o0BiY5B%ElM5#8d!z1Juk2D7$cz-ICm>@&$snJ3Yh-cpRPcy(EHK-`P*jm3mj(l0$#6Rqz%n= 2300: + pr.sector_size = 4096 + self.assertEqual(pr.sector_size, 4096) + else: + with self.assertRaises(AttributeError): + pr.sector_size = 4096 + + pr.reset_probe() + + def test_probing(self): + pr = blkid.Probe() + + with self.assertRaises(ValueError): + pr.do_probe() + + pr.set_device(self.loop_dev) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_MAGIC) + + ret = pr.do_probe() + self.assertTrue(ret) + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + pr.step_back() + ret = pr.do_probe() + self.assertTrue(ret) + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + if hasattr(pr, "reset_buffers"): + pr.reset_buffers() + + pr.step_back() + ret = pr.do_probe() + self.assertTrue(ret) + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + if hasattr(pr, "hide_range"): + offset = pr.lookup_value("SBMAGIC_OFFSET") + magic = pr.lookup_value("SBMAGIC") + pr.hide_range(int(offset), len(magic)) + + pr.step_back() + ret = pr.do_probe() + self.assertFalse(ret) + + with self.assertRaises(RuntimeError): + usage = pr.lookup_value("USAGE") + + def test_safe_probing(self): + pr = blkid.Probe() + pr.set_device(self.loop_dev) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID) + + # not probed yet, len should be 0 + self.assertEqual(len(pr), 0) + self.assertFalse(pr.keys()) + self.assertFalse(pr.values()) + self.assertFalse(pr.items()) + + ret = pr.do_safeprobe() + self.assertTrue(ret) + + # three or more items should be in the probe now + self.assertGreaterEqual(len(pr), 3) + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + usage = pr["USAGE"] + self.assertEqual(usage, b"filesystem") + + fstype = pr.lookup_value("TYPE") + self.assertEqual(fstype, b"ext3") + + fstype = pr["TYPE"] + self.assertEqual(fstype, b"ext3") + + fsuuid = pr.lookup_value("UUID") + self.assertEqual(fsuuid, b"35f66dab-477e-4090-a872-95ee0e493ad6") + + fsuuid = pr["UUID"] + self.assertEqual(fsuuid, b"35f66dab-477e-4090-a872-95ee0e493ad6") + + keys = pr.keys() + self.assertIn("USAGE", keys) + self.assertIn("TYPE", keys) + self.assertIn("UUID", keys) + + values = pr.values() + self.assertIn("filesystem", values) + self.assertIn("ext3", values) + self.assertIn("35f66dab-477e-4090-a872-95ee0e493ad6", values) + + items = pr.items() + self.assertIn(("USAGE", "filesystem"), items) + self.assertIn(("TYPE", "ext3"), items) + self.assertIn(("UUID", "35f66dab-477e-4090-a872-95ee0e493ad6"), items) + + def test_probe_filter_type(self): + pr = blkid.Probe() + pr.set_device(self.loop_dev) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID) + + pr.filter_superblocks_type(blkid.FLTR_ONLYIN, ["ext3", "ext4"]) + ret = pr.do_safeprobe() + self.assertTrue(ret) + + fstype = pr.lookup_value("TYPE") + self.assertEqual(fstype, b"ext3") + + pr.filter_superblocks_type(blkid.FLTR_NOTIN, ["ext3", "ext4"]) + ret = pr.do_safeprobe() + self.assertFalse(ret) + + with self.assertRaises(RuntimeError): + fstype = pr.lookup_value("TYPE") + + pr.filter_superblocks_type(blkid.FLTR_NOTIN, ["vfat", "ntfs"]) + ret = pr.do_safeprobe() + self.assertTrue(ret) + + fstype = pr.lookup_value("TYPE") + self.assertEqual(fstype, b"ext3") + + # invert the filter + pr.invert_superblocks_filter() + ret = pr.do_safeprobe() + self.assertFalse(ret) + + with self.assertRaises(RuntimeError): + fstype = pr.lookup_value("TYPE") + + # reset to default + pr.reset_superblocks_filter() + ret = pr.do_safeprobe() + self.assertTrue(ret) + + fstype = pr.lookup_value("TYPE") + self.assertEqual(fstype, b"ext3") + + def test_probe_filter_usage(self): + pr = blkid.Probe() + pr.set_device(self.loop_dev) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID) + + pr.filter_superblocks_usage(blkid.FLTR_ONLYIN, blkid.USAGE_FILESYSTEM) + pr.do_safeprobe() + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + pr.filter_superblocks_usage(blkid.FLTR_NOTIN, blkid.USAGE_FILESYSTEM | blkid.USAGE_CRYPTO) + pr.do_safeprobe() + + with self.assertRaises(RuntimeError): + usage = pr.lookup_value("USAGE") + + pr.filter_superblocks_usage(blkid.FLTR_NOTIN, blkid.USAGE_RAID | blkid.USAGE_CRYPTO) + pr.do_safeprobe() + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + # invert the filter + pr.invert_superblocks_filter() + pr.do_safeprobe() + + with self.assertRaises(RuntimeError): + usage = pr.lookup_value("USAGE") + + # reset to default + pr.reset_superblocks_filter() + pr.do_safeprobe() + + usage = pr.lookup_value("USAGE") + self.assertEqual(usage, b"filesystem") + + def test_topology(self): + pr = blkid.Probe() + pr.set_device(self.loop_dev) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID) + + pr.enable_topology(True) + + ret = pr.do_safeprobe() + self.assertTrue(ret) + + self.assertIsNotNone(pr.topology) + + self.assertEqual(pr.topology.alignment_offset, 0) + self.assertEqual(pr.topology.logical_sector_size, 512) + self.assertEqual(pr.topology.minimum_io_size, 512) + self.assertEqual(pr.topology.optimal_io_size, 0) + self.assertEqual(pr.topology.physical_sector_size, 512) + + if self.ver_code >= 2360: + self.assertFalse(pr.topology.dax) + else: + with self.assertRaises(AttributeError): + self.assertIsNone(pr.topology.dax) + + +@unittest.skipUnless(os.geteuid() == 0, "requires root access") +class WipeTestCase(unittest.TestCase): + + test_image = "test.img.xz" + loop_dev = None + + def setUp(self): + test_dir = os.path.abspath(os.path.dirname(__file__)) + self.loop_dev = utils.loop_setup(os.path.join(test_dir, self.test_image)) + + def tearDown(self): + test_dir = os.path.abspath(os.path.dirname(__file__)) + if self.loop_dev: + utils.loop_teardown(self.loop_dev, + filename=os.path.join(test_dir, self.test_image)) + + def test_wipe(self): + pr = blkid.Probe() + pr.set_device(self.loop_dev, flags=os.O_RDWR) + + pr.enable_superblocks(True) + pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_MAGIC) + + while pr.do_probe(): + pr.do_wipe(False) + + pr.reset_probe() + + ret = pr.do_probe() + self.assertFalse(ret) + + +if __name__ == "__main__": + unittest.main() diff --git a/packages/pyblkid/opengnsys-pyblkid-0.3/tests/utils.py b/packages/pyblkid/opengnsys-pyblkid-0.3/tests/utils.py new file mode 100644 index 0000000..668f73e --- /dev/null +++ b/packages/pyblkid/opengnsys-pyblkid-0.3/tests/utils.py @@ -0,0 +1,43 @@ +import os +import subprocess + + +def run_command(command): + res = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + + out, err = res.communicate() + if res.returncode != 0: + output = out.decode().strip() + "\n\n" + err.decode().strip() + else: + output = out.decode().strip() + return (res.returncode, output) + + +def read_file(filename): + with open(filename, "r") as f: + content = f.read() + return content + + +def loop_setup(filename): + if filename.endswith(".xz") and not os.path.exists(filename[:-3]): + ret, out = run_command("xz --decompress --keep %s" % filename) + if ret != 0: + raise RuntimeError("Failed to decompress file %s: %s" % (filename, out)) + filename = filename[:-3] + + ret, out = run_command("losetup --show --partscan -f %s" % filename) + if ret != 0: + raise RuntimeError("Failed to create loop device from %s: %s" % (filename, out)) + return out + + +def loop_teardown(loopdev, filename=None): + ret, out = run_command("losetup -d %s" % loopdev) + if ret != 0: + raise RuntimeError("Failed to detach loop device %s: %s" % (loopdev, out)) + + # remove the extracted test file + if filename and filename.endswith(".xz") and os.path.exists(filename[:-3]): + os.remove(filename[:-3]) diff --git a/packages/pyblkid/opengnsys-pyblkid_0.3.orig.tar.xz b/packages/pyblkid/opengnsys-pyblkid_0.3.orig.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..a9b34c7b59b01fc0f6c679bf821f9526079ebedd GIT binary patch literal 28652 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