Initial copy of jnr-posix Change-Id: Iff648b0fd3faa67dbec0549bd5f88056abd9ce8a
diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..4adfdaa --- /dev/null +++ b/LICENSE.txt
@@ -0,0 +1,1076 @@ +jnr-posix is released under a tri EPL/GPL/LGPL license. You can use it, +redistribute it and/or modify it under the terms of the: + + Eclipse Public License version 2.0 + OR + GNU General Public License version 2 + OR + GNU Lesser General Public License version 2.1 + +The complete text of the Eclipse Public License is as follows: + + Eclipse Public License - v 2.0 + + THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE + PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION + OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. + + 1. DEFINITIONS + + "Contribution" means: + + a) in the case of the initial Contributor, the initial content + Distributed under this Agreement, and + + b) in the case of each subsequent Contributor: + i) changes to the Program, and + ii) additions to the Program; + where such changes and/or additions to the Program originate from + and are Distributed by that particular Contributor. A Contribution + "originates" from a Contributor if it was added to the Program by + such Contributor itself or anyone acting on such Contributor's behalf. + Contributions do not include changes or additions to the Program that + are not Modified Works. + + "Contributor" means any person or entity that Distributes the Program. + + "Licensed Patents" mean patent claims licensable by a Contributor which + are necessarily infringed by the use or sale of its Contribution alone + or when combined with the Program. + + "Program" means the Contributions Distributed in accordance with this + Agreement. + + "Recipient" means anyone who receives the Program under this Agreement + or any Secondary License (as applicable), including Contributors. + + "Derivative Works" shall mean any work, whether in Source Code or other + form, that is based on (or derived from) the Program and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. + + "Modified Works" shall mean any work in Source Code or other form that + results from an addition to, deletion from, or modification of the + contents of the Program, including, for purposes of clarity any new file + in Source Code form that contains any contents of the Program. Modified + Works shall not include works that contain only declarations, + interfaces, types, classes, structures, or files of the Program solely + in each case in order to link to, bind by name, or subclass the Program + or Modified Works thereof. + + "Distribute" means the acts of a) distributing or b) making available + in any manner that enables the transfer of a copy. + + "Source Code" means the form of a Program preferred for making + modifications, including but not limited to software source code, + documentation source, and configuration files. + + "Secondary License" means either the GNU General Public License, + Version 2.0, or any later versions of that license, including any + exceptions or additional permissions as identified by the initial + Contributor. + + 2. GRANT OF RIGHTS + + a) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free copyright + license to reproduce, prepare Derivative Works of, publicly display, + publicly perform, Distribute and sublicense the Contribution of such + Contributor, if any, and such Derivative Works. + + b) Subject to the terms of this Agreement, each Contributor hereby + grants Recipient a non-exclusive, worldwide, royalty-free patent + license under Licensed Patents to make, use, sell, offer to sell, + import and otherwise transfer the Contribution of such Contributor, + if any, in Source Code or other form. This patent license shall + apply to the combination of the Contribution and the Program if, at + the time the Contribution is added by the Contributor, such addition + of the Contribution causes such combination to be covered by the + Licensed Patents. The patent license shall not apply to any other + combinations which include the Contribution. No hardware per se is + licensed hereunder. + + c) Recipient understands that although each Contributor grants the + licenses to its Contributions set forth herein, no assurances are + provided by any Contributor that the Program does not infringe the + patent or other intellectual property rights of any other entity. + Each Contributor disclaims any liability to Recipient for claims + brought by any other entity based on infringement of intellectual + property rights or otherwise. As a condition to exercising the + rights and licenses granted hereunder, each Recipient hereby + assumes sole responsibility to secure any other intellectual + property rights needed, if any. For example, if a third party + patent license is required to allow Recipient to Distribute the + Program, it is Recipient's responsibility to acquire that license + before distributing the Program. + + d) Each Contributor represents that to its knowledge it has + sufficient copyright rights in its Contribution, if any, to grant + the copyright license set forth in this Agreement. + + e) Notwithstanding the terms of any Secondary License, no + Contributor makes additional grants to any Recipient (other than + those set forth in this Agreement) as a result of such Recipient's + receipt of the Program under the terms of a Secondary License + (if permitted under the terms of Section 3). + + 3. REQUIREMENTS + + 3.1 If a Contributor Distributes the Program in any form, then: + + a) the Program must also be made available as Source Code, in + accordance with section 3.2, and the Contributor must accompany + the Program with a statement that the Source Code for the Program + is available under this Agreement, and informs Recipients how to + obtain it in a reasonable manner on or through a medium customarily + used for software exchange; and + + b) the Contributor may Distribute the Program under a license + different than this Agreement, provided that such license: + i) effectively disclaims on behalf of all other Contributors all + warranties and conditions, express and implied, including + warranties or conditions of title and non-infringement, and + implied warranties or conditions of merchantability and fitness + for a particular purpose; + + ii) effectively excludes on behalf of all other Contributors all + liability for damages, including direct, indirect, special, + incidental and consequential damages, such as lost profits; + + iii) does not attempt to limit or alter the recipients' rights + in the Source Code under section 3.2; and + + iv) requires any subsequent distribution of the Program by any + party to be under a license that satisfies the requirements + of this section 3. + + 3.2 When the Program is Distributed as Source Code: + + a) it must be made available under this Agreement, or if the + Program (i) is combined with other material in a separate file or + files made available under a Secondary License, and (ii) the initial + Contributor attached to the Source Code the notice described in + Exhibit A of this Agreement, then the Program may be made available + under the terms of such Secondary Licenses, and + + b) a copy of this Agreement must be included with each copy of + the Program. + + 3.3 Contributors may not remove or alter any copyright, patent, + trademark, attribution notices, disclaimers of warranty, or limitations + of liability ("notices") contained within the Program from any copy of + the Program which they Distribute, provided that Contributors may add + their own appropriate notices. + + 4. COMMERCIAL DISTRIBUTION + + Commercial distributors of software may accept certain responsibilities + with respect to end users, business partners and the like. While this + license is intended to facilitate the commercial use of the Program, + the Contributor who includes the Program in a commercial product + offering should do so in a manner which does not create potential + liability for other Contributors. Therefore, if a Contributor includes + the Program in a commercial product offering, such Contributor + ("Commercial Contributor") hereby agrees to defend and indemnify every + other Contributor ("Indemnified Contributor") against any losses, + damages and costs (collectively "Losses") arising from claims, lawsuits + and other legal actions brought by a third party against the Indemnified + Contributor to the extent caused by the acts or omissions of such + Commercial Contributor in connection with its distribution of the Program + in a commercial product offering. The obligations in this section do not + apply to any claims or Losses relating to any actual or alleged + intellectual property infringement. In order to qualify, an Indemnified + Contributor must: a) promptly notify the Commercial Contributor in + writing of such claim, and b) allow the Commercial Contributor to control, + and cooperate with the Commercial Contributor in, the defense and any + related settlement negotiations. The Indemnified Contributor may + participate in any such claim at its own expense. + + For example, a Contributor might include the Program in a commercial + product offering, Product X. That Contributor is then a Commercial + Contributor. If that Commercial Contributor then makes performance + claims, or offers warranties related to Product X, those performance + claims and warranties are such Commercial Contributor's responsibility + alone. Under this section, the Commercial Contributor would have to + defend claims against the other Contributors related to those performance + claims and warranties, and if a court requires any other Contributor to + pay any damages as a result, the Commercial Contributor must pay + those damages. + + 5. NO WARRANTY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR + IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF + TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. Each Recipient is solely responsible for determining the + appropriateness of using and distributing the Program and assumes all + risks associated with its exercise of rights under this Agreement, + including but not limited to the risks and costs of program errors, + compliance with applicable laws, damage to or loss of data, programs + or equipment, and unavailability or interruption of operations. + + 6. DISCLAIMER OF LIABILITY + + EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT + PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS + SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST + PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE + EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + 7. GENERAL + + If any provision of this Agreement is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this Agreement, and without further + action by the parties hereto, such provision shall be reformed to the + minimum extent necessary to make such provision valid and enforceable. + + If Recipient institutes patent litigation against any entity + (including a cross-claim or counterclaim in a lawsuit) alleging that the + Program itself (excluding combinations of the Program with other software + or hardware) infringes such Recipient's patent(s), then such Recipient's + rights granted under Section 2(b) shall terminate as of the date such + litigation is filed. + + All Recipient's rights under this Agreement shall terminate if it + fails to comply with any of the material terms or conditions of this + Agreement and does not cure such failure in a reasonable period of + time after becoming aware of such noncompliance. If all Recipient's + rights under this Agreement terminate, Recipient agrees to cease use + and distribution of the Program as soon as reasonably practicable. + However, Recipient's obligations under this Agreement and any licenses + granted by Recipient relating to the Program shall continue and survive. + + Everyone is permitted to copy and distribute copies of this Agreement, + but in order to avoid inconsistency the Agreement is copyrighted and + may only be modified in the following manner. The Agreement Steward + reserves the right to publish new versions (including revisions) of + this Agreement from time to time. No one other than the Agreement + Steward has the right to modify this Agreement. The Eclipse Foundation + is the initial Agreement Steward. The Eclipse Foundation may assign the + responsibility to serve as the Agreement Steward to a suitable separate + entity. Each new version of the Agreement will be given a distinguishing + version number. The Program (including Contributions) may always be + Distributed subject to the version of the Agreement under which it was + received. In addition, after a new version of the Agreement is published, + Contributor may elect to Distribute the Program (including its + Contributions) under the new version. + + Except as expressly stated in Sections 2(a) and 2(b) above, Recipient + receives no rights or licenses to the intellectual property of any + Contributor under this Agreement, whether expressly, by implication, + estoppel or otherwise. All rights in the Program not expressly granted + under this Agreement are reserved. Nothing in this Agreement is intended + to be enforceable by any entity that is not a Contributor or Recipient. + No third-party beneficiary rights are created under this Agreement. + + Exhibit A - Form of Secondary Licenses Notice + + "This Source Code may also be made available under the following + Secondary Licenses when the conditions for such availability set forth + in the Eclipse Public License, v. 2.0 are satisfied: {name license(s), + version(s), and exceptions or additional permissions here}." + + Simply including a copy of this Agreement, including this Exhibit A + is not sufficient to license the Source Code under Secondary Licenses. + + If it is not possible or desirable to put the notice in a particular + file, then You may include the notice in a location (such as a LICENSE + file in a relevant directory) where a recipient would be likely to + look for such a notice. + + You may add additional accurate notices of copyright ownership. + +The complete text of the GNU General Public License v2 is as follows: + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General Public + License is intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too. + + When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it + in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights. + + We protect your rights with two steps: (1) copyright the software, and + (2) offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations. + + Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains + a notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of + running the Program is not restricted, and the output from the Program + is covered only if its contents constitute a work based on the + Program (independent of having been made by running the Program). + Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the + notices that refer to this License and to the absence of any warranty; + and give any other recipients of the Program a copy of this License + along with the Program. + + You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion + of it, thus forming a work based on the Program, and copy and + distribute such modifications or work under the terms of Section 1 + above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of + a storage or distribution medium does not bring the other work under + the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + + The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to + control compilation and installation of the executable. However, as a + special exception, the source code distributed need not include + anything that is normally distributed (in either source or binary + form) with the major components (compiler, kernel, and so on) of the + operating system on which the executable runs, unless that component + itself accompanies the executable. + + If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense or distribute the Program is + void, and will automatically terminate your rights under this License. + However, parties who have received copies, or rights, from you under + this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 5. You are not required to accept this License, since you have not + signed it. However, nothing else grants you permission to modify or + distribute the Program or its derivative works. These actions are + prohibited by law if you do not accept this License. Therefore, by + modifying or distributing the Program (or any work based on the + Program), you indicate your acceptance of this License to do so, and + all its terms and conditions for copying, distributing or modifying + the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the + original licensor to copy, distribute or modify the Program subject to + these terms and conditions. You may not impose any further + restrictions on the recipients' exercise of the rights granted herein. + You are not responsible for enforcing compliance by third parties to + this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot + distribute so as to satisfy simultaneously your obligations under this + License and any other pertinent obligations, then as a consequence you + may not distribute the Program at all. For example, if a patent + license would not permit royalty-free redistribution of the Program by + all those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be to + refrain entirely from distribution of the Program. + + If any portion of this section is held invalid or unenforceable under + any particular circumstance, the balance of the section is intended to + apply and the section as a whole is intended to apply in other + circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any + such claims; this section has the sole purpose of protecting the + integrity of the free software distribution system, which is + implemented by public license practices. Many people have made + generous contributions to the wide range of software distributed + through that system in reliance on consistent application of that + system; it is up to the author/donor to decide if he or she is willing + to distribute software through any other system and a licensee cannot + impose that choice. + + This section is intended to make thoroughly clear what is believed to + be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in + certain countries either by patents or by copyrighted interfaces, the + original copyright holder who places the Program under this License + may add an explicit geographical distribution limitation excluding + those countries, so that distribution is permitted only in or among + countries not thus excluded. In such case, this License incorporates + the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions + of the General Public License from time to time. Such new versions will + be similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free Software + Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free software and + of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING + OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED + TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY + YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER + PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + +The complete text of the GNU Lesser General Public License 2.1 is as follows: + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + + That's all there is to it!
diff --git a/MANIFEST.MF b/MANIFEST.MF new file mode 100644 index 0000000..ba6fb81 --- /dev/null +++ b/MANIFEST.MF
@@ -0,0 +1,2 @@ +Implementation-Title: JNA-POSIX +Implementation-Version: 0.5
diff --git a/README.md b/README.md new file mode 100644 index 0000000..f6d9b54 --- /dev/null +++ b/README.md
@@ -0,0 +1,9 @@ +Java Native Runtime - POSIX +=========================== + +[](https://travis-ci.org/jnr/jnr-posix) +[](https://ci.appveyor.com/project/jnr/jnr-posix/branch/master) +Overview +-------- + +jnr-posix is a lightweight cross-platform POSIX emulation layer for Java, written in Java and is part of the JNR project (http://github.com/jnr)
diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..2167919 --- /dev/null +++ b/pom.xml
@@ -0,0 +1,248 @@ +<?xml version="1.0" ?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.sonatype.oss</groupId> + <artifactId>oss-parent</artifactId> + <version>7</version> + </parent> + + <groupId>com.github.jnr</groupId> + <artifactId>jnr-posix</artifactId> + <packaging>jar</packaging> + <version>3.1.21-SNAPSHOT</version> + <name>jnr-posix</name> + <description> + Common cross-project/cross-platform POSIX APIs + </description> + + <issueManagement> + <system>JIRA</system> + <url>http://jira.codehaus.org/browse/JRUBY</url> + </issueManagement> + + <scm> + <connection>scm:git:git@github.com:jnr/jnr-posix.git</connection> + <developerConnection>scm:git:git@github.com:jnr/jnr-posix.git</developerConnection> + <url>git@github.com:jnr/jnr-posix.git</url> + </scm> + + <licenses> + <license> + <name>Eclipse Public License - v 2.0</name> + <url>https://www.eclipse.org/legal/epl-2.0/</url> + <distribution>repo</distribution> + </license> + <license> + <name>GNU General Public License Version 2</name> + <url>http://www.gnu.org/copyleft/gpl.html</url> + <distribution>repo</distribution> + </license> + <license> + <name>GNU Lesser General Public License Version 2.1</name> + <url>http://www.gnu.org/licenses/lgpl.html</url> + <distribution>repo</distribution> + </license> + </licenses> + + <developers> + <developer> + <id>enebo</id> + <name>Thomas E Enebo</name> + <email>tom.enebo@gmail.com</email> + </developer> + <developer> + <id>wmeissner</id> + <name>Wayne Meissner</name> + <email>wmeissner@gmail.com</email> + </developer> + <developer> + <id>headius</id> + <name>Charles Oliver Nutter</name> + <email>headius@headius.com</email> + </developer> + </developers> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <maven.compiler.source>8</maven.compiler.source> + <maven.compiler.target>8</maven.compiler.target> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.1</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.github.jnr</groupId> + <artifactId>jnr-ffi</artifactId> + <version>2.2.17</version> + </dependency> + <dependency> + <groupId>com.github.jnr</groupId> + <artifactId>jnr-constants</artifactId> + <version>0.10.4</version> + </dependency> + </dependencies> + + <build> + <extensions> + <extension> + <groupId>org.apache.maven.wagon</groupId> + <artifactId>wagon-webdav-jackrabbit</artifactId> + <version>1.0-beta-7</version> + </extension> + </extensions> + <plugins> + <plugin> + <groupId>org.apache.felix</groupId> + <artifactId>maven-bundle-plugin</artifactId> + <version>2.3.7</version> + <configuration> + <instructions> + <Implementation-Title>JNA-POSIX</Implementation-Title> + <Implementation-Version>0.5</Implementation-Version> + <_nouses>true</_nouses> + <Import-Package>!sun.misc,*</Import-Package> + </instructions> + </configuration> + <executions> + <execution> + <id>bundle-manifest</id> + <phase>process-classes</phase> + <goals> + <goal>manifest</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>2.3.1</version> + <configuration> + <archive> + <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile> + <manifestEntries> + <Automatic-Module-Name>org.jnrproject.posix</Automatic-Module-Name> + </manifestEntries> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <version>2.2.1</version> + <executions> + <execution> + <id>attach-sources</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.2.0</version> + <executions> + <execution> + <id>attach-javadocs</id> + <goals> + <goal>jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + </plugin> + </plugins> + </build> + <profiles> + <profile> + <id>non-windows-unit-tests</id> + <activation><os><family>!windows</family></os></activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.18.1</version> + <configuration> + <forkCount>2</forkCount> + <reuseForks>false</reuseForks> + <includes> + <include>**/*Test.java</include> + </includes> + <excludes> + <exclude>**/windows/*Test.java</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>windows-unit-tests</id> + <activation><os><family>windows</family></os></activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>2.18.1</version> + <configuration> + <forkCount>2</forkCount> + <reuseForks>false</reuseForks> + </configuration> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>java9</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <executions> + <execution> + <id>default-compile</id> + <phase>compile</phase> + <goals><goal>compile</goal></goals> + <configuration> + <includes> + <include>jnr/posix/util/SunMiscSignal.java</include> + </includes> + </configuration> + </execution> + <execution> + <id>java9-compile</id> + <phase>compile</phase> + <goals><goal>compile</goal></goals> + <configuration> + <!-- Use -release compiler option rather than source/target if 9+ --> + <release>${maven.compiler.target}</release> + <excludes> + <exclude>jnr/posix/util/SunMiscSignal.java</exclude> + </excludes> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> + <activation> + <jdk>[9,)</jdk> + </activation> + </profile> + </profiles> +</project>
diff --git a/src/main/java/jnr/posix/AbstractJavaFileStat.java b/src/main/java/jnr/posix/AbstractJavaFileStat.java new file mode 100644 index 0000000..fae6bde --- /dev/null +++ b/src/main/java/jnr/posix/AbstractJavaFileStat.java
@@ -0,0 +1,133 @@ +package jnr.posix; + +public abstract class AbstractJavaFileStat implements FileStat { + protected final POSIXHandler handler; + protected final POSIX posix; + + public AbstractJavaFileStat(POSIX posix, POSIXHandler handler) { + this.handler = handler; + this.posix = posix; + } + + public boolean isBlockDev() { + handler.unimplementedError("block device detection"); + + return false; + } + + /** + * Limitation: [see JRUBY-1516] We just pick more likely value. This is a little scary. + */ + public boolean isCharDev() { + return false; + } + + public boolean isFifo() { + handler.unimplementedError("fifo file detection"); + + return false; + } + + public boolean isNamedPipe() { + handler.unimplementedError("piped file detection"); + + return false; + } + + public boolean isSetgid() { + handler.unimplementedError("setgid detection"); + + return false; + } + + public boolean isSetuid() { + handler.unimplementedError("setuid detection"); + + return false; + } + + public boolean isSocket() { + handler.unimplementedError("socket file type detection"); + + return false; + } + + public boolean isSticky() { + handler.unimplementedError("sticky bit detection"); + + return false; + } + + public int major(long dev) { + handler.unimplementedError("major device"); + + return -1; + } + + public int minor(long dev) { + handler.unimplementedError("minor device"); + + return -1; + } + + public int nlink() { + handler.unimplementedError("stat.nlink"); + + return -1; + } + + public long rdev() { + handler.unimplementedError("stat.rdev"); + + return -1; + } + + // Limitation: We have no pure-java way of getting uid. RubyZip needs this defined to work. + public int uid() { + return -1; + } + + public long blocks() { + handler.unimplementedError("stat.st_blocks"); + + return -1; + } + + public long blockSize() { + // Limitation: We cannot determine, so always return 4096 (better than blowing up) + return 4096; + } + + public long dev() { + handler.unimplementedError("stat.st_dev"); + + return -1; + } + + public String ftype() { + if (isFile()) { + return "file"; + } else if (isDirectory()) { + return "directory"; + } + + return "unknown"; + } + + public int gid() { + handler.unimplementedError("stat.st_gid"); + + return -1; + } + + public boolean groupMember(int gid) { + return posix.getgid() == gid || posix.getegid() == gid; + } + + /** + * Limitation: We have no pure-java way of getting inode. webrick needs this defined to work. + */ + public long ino() { + return 0; + } +}
diff --git a/src/main/java/jnr/posix/AixFileStat.java b/src/main/java/jnr/posix/AixFileStat.java new file mode 100644 index 0000000..c797373 --- /dev/null +++ b/src/main/java/jnr/posix/AixFileStat.java
@@ -0,0 +1,150 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.NativeType; +import jnr.ffi.StructLayout; + +/** + * This corresponds with struct stat64x on AIX + */ +public final class AixFileStat extends BaseFileStat implements NanosecondFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final Unsigned64 st_dev = new Unsigned64(); + public final Signed64 st_ino = new Signed64(); + public final Unsigned32 st_mode = new Unsigned32(); + public final Signed16 st_nlink = new Signed16(); + public final Unsigned16 st_flag = new Unsigned16(); + public final Unsigned32 st_uid = new Unsigned32(); + public final Unsigned32 st_gid = new Unsigned32(); + public final Unsigned64 st_rdev = new Unsigned64(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_atime = new Signed64(); + public final Signed32 st_atime_n = new Signed32(); + public final Signed32 st_pad1 = new Signed32(); + + public final Signed64 st_mtime = new Signed64(); + public final Signed32 st_mtime_n = new Signed32(); + public final Signed32 st_pad2 = new Signed32(); + + public final Signed64 st_ctime = new Signed64(); + public final Signed32 st_ctime_n = new Signed32(); + public final Signed32 st_pad3 = new Signed32(); + + public final Unsigned64 st_blksize = new Unsigned64(); + public final Unsigned64 st_blocks = new Unsigned64(); + public final Signed32 st_vfstype = new Signed32(); + + public final Unsigned32 st_vfs = new Unsigned32(); + public final Unsigned32 st_type = new Unsigned32(); + public final Unsigned32 st_gen = new Unsigned32(); + public final Padding st_reserved = new Padding(NativeType.UINT, 11); + /* total size should be 176 bytes */ + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public AixFileStat(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atime_n.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctime_n.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtime_n.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/AixFlock.java b/src/main/java/jnr/posix/AixFlock.java new file mode 100644 index 0000000..75f8aa2 --- /dev/null +++ b/src/main/java/jnr/posix/AixFlock.java
@@ -0,0 +1,55 @@ +package jnr.posix; + +public final class AixFlock extends Flock { + public final Signed16 l_type = new Signed16(); + public final Signed16 l_whence = new Signed16(); + public final Unsigned32 l_sysid = new Unsigned32(); + public final Signed32 l_pid = new Signed32(); + public final Signed32 l_vfs = new Signed32(); + public final SignedLong l_start = new SignedLong(); + public final SignedLong l_len = new SignedLong(); + + public AixFlock(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void type(short type) { + this.l_type.set(type); + } + + public void whence(short whence) { + this.l_whence.set(whence); + } + + public void start(long start) { + this.l_start.set(start); + } + + public void len(long len) { + this.l_len.set(len); + } + + public void pid(int pid) { + this.l_pid.set(pid); + } + + public short type() { + return this.l_type.get(); + } + + public short whence() { + return this.l_whence.get(); + } + + public long start() { + return this.l_start.get(); + } + + public long len() { + return this.l_len.get(); + } + + public int pid() { + return this.l_pid.get(); + } +}
diff --git a/src/main/java/jnr/posix/AixLibC.java b/src/main/java/jnr/posix/AixLibC.java new file mode 100644 index 0000000..b84abe4 --- /dev/null +++ b/src/main/java/jnr/posix/AixLibC.java
@@ -0,0 +1,38 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +public interface AixLibC extends UnixLibC { + public int stat64x(CharSequence path, AixFileStat stat); + public int fstat64x(int fd, AixFileStat stat); + public int lstat64x(CharSequence path, AixFileStat stat); +}
diff --git a/src/main/java/jnr/posix/AixPOSIX.java b/src/main/java/jnr/posix/AixPOSIX.java new file mode 100644 index 0000000..cb2d023 --- /dev/null +++ b/src/main/java/jnr/posix/AixPOSIX.java
@@ -0,0 +1,149 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.constants.platform.Sysconf; +import jnr.constants.platform.Fcntl; +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.mapper.FromNativeContext; +import jnr.posix.util.MethodName; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; + +final class AixPOSIX extends BaseNativePOSIX { + // These should probably be put into jnr-constants instead eventually, but + // they're here for now as a one-off to work around AIX flock issues + private enum FlockFlags { + LOCK_SH(1), + LOCK_EX(2), + LOCK_NB(4), + LOCK_UN(8); + private final int value; + FlockFlags(int value) { + this.value = value; + } + public final int intValue() { + return value; + } + } + + AixPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + } + + public FileStat allocateStat() { + return new AixFileStat(this); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new AixPasswd((Pointer) arg) : null; + } + }; + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 4); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 60); + } + + // AIX flock lives in libbsd instead of libc. AIX flock locks fully + // interact with fcntl locks, so we can implement flock in terms of fcntl, + // which is what we do here to avoid having to pull in that lib. + @Override + public int flock(int fd, int operation) { + int cmd = Fcntl.F_SETLKW.intValue(); + short type = 0; + + // Map the flock call flags to a fcntl flock type flag + if ((operation & FlockFlags.LOCK_SH.intValue()) != 0) { + type = (short)Fcntl.F_RDLCK.intValue(); + } else if ((operation & FlockFlags.LOCK_EX.intValue()) != 0) { + type = (short)Fcntl.F_WRLCK.intValue(); + } else if ((operation & FlockFlags.LOCK_UN.intValue()) != 0) { + type = (short)Fcntl.F_UNLCK.intValue(); + } + + // Switch to the fcntl non-blocking command + if ((operation & FlockFlags.LOCK_NB.intValue()) != 0) { + cmd = Fcntl.F_SETLK.intValue(); + } + + Flock flock = allocateFlock(); + flock.type(type); + flock.whence((short)0); + flock.start(0); + flock.len(0); + return libc().fcntl(fd, cmd, flock); + } + + @Override + public Timeval allocateTimeval() { return new AixTimeval(getRuntime()); } + + // This isn't an override yet, because Flock would have to be implemented + // for all platforms, or at least with a DefaultNative implementation. This + // is fine for now, because only AIX uses the flock structure + public Flock allocateFlock() { return new AixFlock(getRuntime()); } +}
diff --git a/src/main/java/jnr/posix/AixPasswd.java b/src/main/java/jnr/posix/AixPasswd.java new file mode 100644 index 0000000..b76a4b8 --- /dev/null +++ b/src/main/java/jnr/posix/AixPasswd.java
@@ -0,0 +1,97 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + + +import jnr.ffi.StructLayout; + +public class AixPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final uid_t pw_uid = new uid_t(); // user id + public final gid_t pw_gid = new gid_t(); // user id + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + AixPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public String getAccessClass() { + return "unknown"; + } + + public String getGECOS() { + return layout.pw_gecos.get(memory); + } + + public long getGID() { + return layout.pw_gid.get(memory); + } + + public String getHome() { + return layout.pw_dir.get(memory); + } + + public String getLoginName() { + return layout.pw_name.get(memory); + } + + public int getPasswdChangeTime() { + return 0; + } + + public String getPassword() { + return layout.pw_passwd.get(memory); + } + + public String getShell() { + return layout.pw_shell.get(memory); + } + + public long getUID() { + return layout.pw_uid.get(memory); + } + + public int getExpire() { + return Integer.MAX_VALUE; + } +}
diff --git a/src/main/java/jnr/posix/AixTimeval.java b/src/main/java/jnr/posix/AixTimeval.java new file mode 100644 index 0000000..cbc0ece --- /dev/null +++ b/src/main/java/jnr/posix/AixTimeval.java
@@ -0,0 +1,32 @@ +package jnr.posix; + +public final class AixTimeval extends Timeval { + public final SignedLong tv_sec = new SignedLong(); + public final Signed32 tv_usec = new Signed32(); + + public AixTimeval(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void setTime(long[] timeval) { + assert timeval.length == 2; + tv_sec.set(timeval[0]); + tv_usec.set((int)timeval[1]); + } + + public void sec(long sec) { + this.tv_sec.set(sec); + } + + public void usec(long usec) { + this.tv_usec.set((int)usec); + } + + public long sec() { + return tv_sec.get(); + } + + public long usec() { + return tv_usec.get(); + } +}
diff --git a/src/main/java/jnr/posix/BaseCmsgHdr.java b/src/main/java/jnr/posix/BaseCmsgHdr.java new file mode 100644 index 0000000..c0148fc --- /dev/null +++ b/src/main/java/jnr/posix/BaseCmsgHdr.java
@@ -0,0 +1,50 @@ +package jnr.posix; + +import jnr.ffi.Memory; +import jnr.ffi.Pointer; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +abstract class BaseCmsgHdr implements CmsgHdr { + + protected final NativePOSIX posix; + final Pointer memory; + + protected BaseCmsgHdr(NativePOSIX posix, Pointer memory) { + this.posix = posix; + this.memory = memory; + } + + protected BaseCmsgHdr(NativePOSIX posix, Pointer memory, int totalLen) { + this.posix = posix; + this.memory = memory; + setLen( totalLen ); + } + + public void setData(ByteBuffer data) { + byte[] bytes = new byte[data.capacity() - data.position()]; + data.get(bytes); + posix.socketMacros().CMSG_DATA(this.memory).put(0, bytes, 0, bytes.length); + } + + public ByteBuffer getData() { + int dataLen = getLen() - posix.socketMacros().CMSG_LEN(0); + if ( dataLen == 0 ) { + return null; + } + byte[] bytes = new byte[dataLen]; + + posix.socketMacros().CMSG_DATA(this.memory).get(0, bytes, 0, bytes.length); + + ByteBuffer buf = ByteBuffer.allocate(bytes.length); + buf.put(bytes); + buf.flip(); + return buf; + } + + abstract void setLen(int len); + +}
diff --git a/src/main/java/jnr/posix/BaseFileStat.java b/src/main/java/jnr/posix/BaseFileStat.java new file mode 100644 index 0000000..34fd10b --- /dev/null +++ b/src/main/java/jnr/posix/BaseFileStat.java
@@ -0,0 +1,193 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.StructLayout; + +/** + * + */ +public abstract class BaseFileStat implements FileStat { + protected final POSIX posix; + protected final Pointer memory; + + protected BaseFileStat(NativePOSIX posix, StructLayout layout) { + this.posix = posix; + this.memory = Memory.allocate(posix.getRuntime(), layout.size()); + } + + public java.lang.String ftype() { + if (isFile()) { + return "file"; + } else if (isDirectory()) { + return "directory"; + } else if (isCharDev()) { + return "characterSpecial"; + } else if (isBlockDev()) { + return "blockSpecial"; + } else if (isFifo()) { + return "fifo"; + } else if (isSymlink()) { + return "link"; + } else if (isSocket()) { + return "socket"; + } + + return "unknown"; + } + + public boolean groupMember(int gid) { + if (posix.getgid() == gid || posix.getegid() == gid) { + return true; + } + + // FIXME: Though not Posix, windows has different mechanism for this. + + return false; + } + + public boolean isBlockDev() { + return (mode() & S_IFMT) == S_IFBLK; + } + + public boolean isCharDev() { + return (mode() & S_IFMT) == S_IFCHR; + } + + public boolean isDirectory() { + return (mode() & S_IFMT) == S_IFDIR; + } + + public boolean isEmpty() { + return st_size() == 0; + } + + public boolean isExecutable() { + if (posix.geteuid() == 0) return (mode() & S_IXUGO) != 0; + if (isOwned()) return (mode() & S_IXUSR) != 0; + if (isGroupOwned()) return (mode() & S_IXGRP) != 0; + return (mode() & S_IXOTH) != 0; + } + + public boolean isExecutableReal() { + if (posix.getuid() == 0) return (mode() & S_IXUGO) != 0; + if (isROwned()) return (mode() & S_IXUSR) != 0; + if (groupMember(gid())) return (mode() & S_IXGRP) != 0; + return (mode() & S_IXOTH) != 0; + } + + public boolean isFile() { + return (mode() & S_IFMT) == S_IFREG; + } + + public boolean isFifo() { + return (mode() & S_IFMT) == S_IFIFO; + } + + public boolean isGroupOwned() { + return groupMember(gid()); + } + + public boolean isIdentical(FileStat other) { + return dev() == other.dev() && ino() == other.ino(); + } + + public boolean isNamedPipe() { + return (mode() & S_IFIFO) != 0; + } + + public boolean isOwned() { + return posix.geteuid() == uid(); + } + + public boolean isROwned() { + return posix.getuid() == uid(); + } + + public boolean isReadable() { + if (posix.geteuid() == 0) return true; + if (isOwned()) return (mode() & S_IRUSR) != 0; + if (isGroupOwned()) return (mode() & S_IRGRP) != 0; + return (mode() & S_IROTH) != 0; + } + + public boolean isReadableReal() { + if (posix.getuid() == 0) return true; + if (isROwned()) return (mode() & S_IRUSR) != 0; + if (groupMember(gid())) return (mode() & S_IRGRP) != 0; + return (mode() & S_IROTH) != 0; + } + + public boolean isSetgid() { + return (mode() & S_ISGID) != 0; + } + + public boolean isSetuid() { + return (mode() & S_ISUID) != 0; + } + + public boolean isSocket() { + return (mode() & S_IFMT) == S_IFSOCK; + } + + public boolean isSticky() { + return (mode() & S_ISVTX) != 0; + } + + public boolean isSymlink() { + return (mode() & S_IFMT) == S_IFLNK; + } + + public boolean isWritable() { + if (posix.geteuid() == 0) return true; + if (isOwned()) return (mode() & S_IWUSR) != 0; + if (isGroupOwned()) return (mode() & S_IWGRP) != 0; + return (mode() & S_IWOTH) != 0; + } + + public boolean isWritableReal() { + if (posix.getuid() == 0) return true; + if (isROwned()) return (mode() & S_IWUSR) != 0; + if (groupMember(gid())) return (mode() & S_IWGRP) != 0; + return (mode() & S_IWOTH) != 0; + } + + public int major(long dev) { + return (int) (dev >> 24) & 0xff; + } + + public int minor(long dev) { + return (int) (dev & 0xffffff); + } +}
diff --git a/src/main/java/jnr/posix/BaseIovec.java b/src/main/java/jnr/posix/BaseIovec.java new file mode 100644 index 0000000..0273096 --- /dev/null +++ b/src/main/java/jnr/posix/BaseIovec.java
@@ -0,0 +1,70 @@ +package jnr.posix; + +import jnr.ffi.Runtime; +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.StructLayout; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +public class BaseIovec implements Iovec { + + + public static class Layout extends StructLayout { + protected Layout(Runtime runtime) { + super(runtime); + } + + public final Pointer iov_base = new Pointer(); + public final size_t iov_len = new size_t(); + } + + public static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + private final NativePOSIX posix; + protected final Pointer memory; + + public String toString(String indent) { + StringBuffer buf = new StringBuffer(); + buf.append( indent ).append( "iovec {\n" ); + buf.append(indent).append( " iov_base=" ).append(layout.iov_base.get(this.memory)).append( ",\n" ); + buf.append( indent ).append( " iov_len=" ).append( layout.iov_len.get( this.memory ) ).append(",\n"); + buf.append(indent).append( "}" ); + + return buf.toString(); + } + + protected BaseIovec(NativePOSIX posix) { + this.posix = posix; + this.memory = Memory.allocate(posix.getRuntime(), layout.size()); + } + + BaseIovec(NativePOSIX posix, Pointer memory) { + this.posix = posix; + this.memory = memory; + } + + public ByteBuffer get() { + int len = getLen(); + byte[] bytes = new byte[len]; + layout.iov_base.get( this.memory ).get(0, bytes, 0, len ); + return ByteBuffer.wrap( bytes ); + } + + public void set(ByteBuffer buf) { + int len = buf.remaining(); + layout.iov_base.set( this.memory, Pointer.wrap( posix.getRuntime(), buf ) ); + setLen(len); + } + + protected void setLen(int len) { + layout.iov_len.set( this.memory, len ); + } + + protected int getLen() { + return (int) layout.iov_len.get( this.memory ); + } +}
diff --git a/src/main/java/jnr/posix/BaseMsgHdr.java b/src/main/java/jnr/posix/BaseMsgHdr.java new file mode 100644 index 0000000..a5398b8 --- /dev/null +++ b/src/main/java/jnr/posix/BaseMsgHdr.java
@@ -0,0 +1,150 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Bob McWhirter + */ +public abstract class BaseMsgHdr implements MsgHdr { + + protected final NativePOSIX posix; + protected final Pointer memory; + + protected BaseMsgHdr(NativePOSIX posix, StructLayout layout) { + this.posix = posix; + this.memory = posix.getRuntime().getMemoryManager().allocateTemporary(layout.size(), true); + } + + public void setName(String name) { + if (name == null) { + setNamePointer(null); + setNameLen(0); + return; + } + byte[] nameBytes = name.getBytes(Charset.forName("US-ASCII")); + Pointer p = Runtime.getSystemRuntime().getMemoryManager().allocateTemporary(nameBytes.length, true); + p.put(0, nameBytes, 0, nameBytes.length); + setNamePointer(p); + setNameLen(nameBytes.length); + } + + public String getName() { + Pointer ptr = getNamePointer(); + if (ptr == null) { + return null; + } + return ptr.getString(0, getNameLen(), Charset.forName( "US-ASCII" )); + } + + public CmsgHdr allocateControl(int dataLength) { + CmsgHdr[] controls = allocateControls(new int[]{dataLength}); + return controls[0]; + } + + public CmsgHdr[] allocateControls(int[] dataLengths) { + CmsgHdr[] cmsgs = new CmsgHdr[dataLengths.length]; + + int totalSize = 0; + for (int i = 0; i < dataLengths.length; ++i) { + totalSize += posix.socketMacros().CMSG_SPACE(dataLengths[i]); + } + + Pointer ptr = posix.getRuntime().getMemoryManager().allocateDirect(totalSize); + + int offset = 0; + for (int i = 0; i < dataLengths.length; ++i) { + int eachSpace = posix.socketMacros().CMSG_SPACE(dataLengths[i]); + int len = posix.socketMacros().CMSG_LEN(dataLengths[i]); + CmsgHdr each = allocateCmsgHdrInternal(posix, ptr.slice(offset, eachSpace), len); + cmsgs[i] = each; + offset += eachSpace; + } + + setControlPointer(ptr); + setControlLen(totalSize); + + return cmsgs; + } + + public CmsgHdr[] getControls() { + int len = getControlLen(); + if (len == 0) { + return new CmsgHdr[0]; + } + + List<CmsgHdr> control = new ArrayList<CmsgHdr>(); + + int offset = 0; + + Pointer controlPtr = getControlPointer(); + + while (offset < len) { + CmsgHdr each = allocateCmsgHdrInternal(posix, controlPtr.slice(offset), -1); + offset += posix.socketMacros().CMSG_SPACE(each.getLen()); + control.add(each); + } + + return control.toArray(new CmsgHdr[control.size()]); + } + + public void setIov(ByteBuffer[] buffers) { + Pointer iov = Runtime.getSystemRuntime().getMemoryManager().allocateDirect(BaseIovec.layout.size() * buffers.length); + + for (int i = 0; i < buffers.length; ++i) { + Pointer eachIovecPtr = iov.slice(BaseIovec.layout.size() * i); + BaseIovec eachIovec = new BaseIovec(posix, eachIovecPtr); + eachIovec.set(buffers[i]); + } + + setIovPointer(iov); + setIovLen(buffers.length); + } + + public ByteBuffer[] getIov() { + int len = getIovLen(); + + ByteBuffer[] buffers = new ByteBuffer[len]; + + Pointer iov = getIovPointer(); + + for (int i = 0; i < len; ++i) { + Pointer eachPtr = iov.slice(BaseIovec.layout.size() * i); + BaseIovec eachIov = new BaseIovec(posix, eachPtr); + buffers[i] = eachIov.get(); + } + + return buffers; + } + + abstract void setNamePointer(Pointer name); + + abstract Pointer getNamePointer(); + + abstract void setNameLen(int len); + + abstract int getNameLen(); + + abstract void setIovPointer(Pointer iov); + + abstract Pointer getIovPointer(); + + abstract int getIovLen(); + + abstract void setIovLen(int len); + + abstract CmsgHdr allocateCmsgHdrInternal(NativePOSIX posix, Pointer pointer, int len); + + abstract void setControlPointer(Pointer control); + + abstract Pointer getControlPointer(); + + abstract void setControlLen(int len); + +}
diff --git a/src/main/java/jnr/posix/BaseNativePOSIX.java b/src/main/java/jnr/posix/BaseNativePOSIX.java new file mode 100644 index 0000000..96ed7de --- /dev/null +++ b/src/main/java/jnr/posix/BaseNativePOSIX.java
@@ -0,0 +1,944 @@ +package jnr.posix; + +import jnr.constants.Constant; +import jnr.constants.platform.Errno; +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Signal; +import jnr.constants.platform.Sysconf; +import jnr.ffi.*; +import jnr.ffi.byref.NumberByReference; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.mapper.FromNativeConverter; +import jnr.ffi.mapper.ToNativeContext; +import jnr.ffi.mapper.ToNativeConverter; +import jnr.posix.util.Java5ProcessMaker; +import jnr.posix.util.MethodName; +import jnr.posix.util.ProcessMaker; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.ffi.annotations.Out; + +public abstract class BaseNativePOSIX extends NativePOSIX implements POSIX { + private final LibC libc; + private final Crypt crypt; + + protected final POSIXHandler handler; + protected final JavaLibCHelper helper; + + protected final Map<Signal, SignalHandler> signalHandlers = new HashMap(); + + protected BaseNativePOSIX(LibCProvider libcProvider, POSIXHandler handler) { + this.handler = handler; + this.libc = libcProvider.getLibC(); + this.crypt = libcProvider.getCrypt(); + this.helper = new JavaLibCHelper(handler); + } + + public ProcessMaker newProcessMaker(String... command) { + return new Java5ProcessMaker(handler, command); + } + + public ProcessMaker newProcessMaker() { + return new Java5ProcessMaker(handler); + } + + public final LibC libc() { + return libc; + } + + public final Crypt crypt() { + return crypt; + } + + POSIXHandler handler() { + return handler; + } + + protected <T> T unimplementedNull() { + handler().unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + protected int unimplementedInt() { + handler().unimplementedError(MethodName.getCallerMethodName()); + return -1; + } + + public int chmod(String filename, int mode) { + return libc().chmod(filename, mode); + } + + public int fchmod(int fd, int mode) { + return libc().fchmod(fd, mode); + } + + public int chown(String filename, int user, int group) { + return libc().chown(filename, user, group); + } + + public int fchown(int fd, int user, int group) { + return libc().fchown(fd, user, group); + } + + public CharSequence crypt(CharSequence key, CharSequence salt) { + Crypt crypt = crypt(); + + if (crypt == null) { + return JavaLibCHelper.crypt(key, salt); + } + + return crypt.crypt(key, salt); + } + + public byte[] crypt(byte[] key, byte[] salt) { + Crypt crypt = crypt(); + + if (crypt == null) { + return JavaLibCHelper.crypt(key, salt); + } + + Pointer ptr = crypt().crypt(key, salt); + if (ptr == null) return null; + int end = ptr.indexOf(0, (byte)0); + byte[] bytes = new byte[end + 1]; + ptr.get(0, bytes, 0, end); + + return bytes; + } + + public int exec(String path, String... args) { + handler.unimplementedError("exec unimplemented"); + return -1; + } + + public int exec(String path, String[] args, String[] envp) { + handler.unimplementedError("exec unimplemented"); + return -1; + } + + public int execv(String path, String[] args) { + return libc().execv(path, args); + } + + public int execve(String path, String[] args, String[] env) { + return libc().execve(path, args, env); + } + + public FileStat fstat(FileDescriptor fileDescriptor) { + FileStat stat = allocateStat(); + + if (fstat(fileDescriptor, stat) < 0) handler.error(Errno.valueOf(errno()), "fstat", "" + helper.getfd(fileDescriptor)); + + return stat; + } + + public FileStat fstat(int fd) { + FileStat stat = allocateStat(); + if (fstat(fd, stat) < 0) handler.error(Errno.valueOf(errno()), "fstat", "" + fd); + return stat; + } + + + public int fstat(FileDescriptor fileDescriptor, FileStat stat) { + int fd = helper.getfd(fileDescriptor); + return libc().fstat(fd, stat); + } + + public int fstat(int fd, FileStat stat) { + return libc().fstat(fd, stat); + } + + public Pointer environ() { + return getRuntime().getMemoryManager().newPointer(libc().environ().get()); + } + + public String getenv(String envName) { + return libc().getenv(envName); + } + + public int getegid() { + return libc().getegid(); + } + + public int geteuid() { + return libc().geteuid(); + } + + public int getgid() { + return libc().getgid(); + } + + public int getdtablesize() { + return libc().getdtablesize(); + } + + public String getlogin() { + return libc().getlogin(); + } + + public int getpgid() { + return libc().getpgid(); + } + + public int getpgrp() { + return libc().getpgrp(); + } + + public int getpid() { + return libc().getpid(); + } + + public int getppid() { + return libc().getppid(); + } + + public Passwd getpwent() { + return libc().getpwent(); + } + + public Passwd getpwuid(int which) { + return libc().getpwuid(which); + } + + public Passwd getpwnam(String which) { + return libc().getpwnam(which); + } + + public Group getgrent() { + return libc().getgrent(); + } + public Group getgrgid(int which) { + return libc().getgrgid(which); + } + public Group getgrnam(String which) { + return libc().getgrnam(which); + } + + public int setpwent() { + return libc().setpwent(); + } + + public int endpwent() { + return libc().endpwent(); + } + + public int setgrent() { + return libc().setgrent(); + } + + public int endgrent() { + return libc().endgrent(); + } + + public int getuid() { + return libc().getuid(); + } + + public int getrlimit(int resource, RLimit rlim) { + return libc().getrlimit(resource, rlim); + } + + public int getrlimit(int resource, Pointer rlim) { + return libc().getrlimit(resource, rlim); + } + + public RLimit getrlimit(int resource) { + RLimit rlim = new DefaultNativeRLimit(getRuntime()); + + if (getrlimit(resource, rlim) < 0) handler.error(Errno.valueOf(errno()), "rlim"); + + return rlim; + } + + public int setrlimit(int resource, RLimit rlim) { + return libc().setrlimit(resource, rlim); + } + + public int setrlimit(int resource, Pointer rlim) { + return libc().setrlimit(resource, rlim); + } + + public int setrlimit(int resource, long rlimCur, long rlimMax) { + RLimit rlim = new DefaultNativeRLimit(getRuntime()); + rlim.init(rlimCur, rlimMax); + + return libc().setrlimit(resource, rlim); + } + + public int setegid(int egid) { + return libc().setegid(egid); + } + + public int seteuid(int euid) { + return libc().seteuid(euid); + } + + public int setgid(int gid) { + return libc().setgid(gid); + } + + public int getfd(FileDescriptor descriptor) { + return helper.getfd(descriptor); + } + + public int getpgid(int pid) { + return libc().getpgid(pid); + } + + public int setpgid(int pid, int pgid) { + return libc().setpgid(pid, pgid); + } + + public int setpgrp(int pid, int pgrp) { + return libc().setpgrp(pid, pgrp); + } + + public int setsid() { + return libc().setsid(); + } + + public int setuid(int uid) { + return libc().setuid(uid); + } + + public int kill(int pid, int signal) { + return kill((long) pid, signal); + } + + public int kill(long pid, int signal) { + return libc().kill(pid, signal); + } + + public SignalHandler signal(Signal sig, final SignalHandler handler) { + synchronized (signalHandlers) { + SignalHandler old = signalHandlers.get(sig); + + long result = libc().signal(sig.intValue(), new LibC.LibCSignalHandler() { + public void signal(int sig) { + handler.handle(sig); + } + }); + + if (result != -1) { + signalHandlers.put(sig, handler); + } + + return old; + } + } + + public int raise(int sig) { + return libc().raise(sig); + } + + public int lchmod(String filename, int mode) { + try { + return libc().lchmod(filename, mode); + } catch (UnsatisfiedLinkError ule) { + return unimplementedInt(); + } + } + + public int lchown(String filename, int user, int group) { + try { + return libc().lchown(filename, user, group); + } catch (UnsatisfiedLinkError ule) { + return unimplementedInt(); + } + } + + public int link(String oldpath, String newpath) { + return libc().link(oldpath, newpath); + } + + public FileStat lstat(String path) { + FileStat stat = allocateStat(); + + if (lstat(path, stat) < 0) handler.error(Errno.valueOf(errno()), "lstat", path); + + return stat; + } + + public int lstat(String path, FileStat stat) { + return libc().lstat(path, stat); + } + + public int mkdir(String path, int mode) { + int res = libc().mkdir(path, mode); + if (res < 0) { + int errno = errno(); + handler.error(Errno.valueOf(errno), "mkdir", path); + } + return res; + } + + public int rmdir(String path) { + int res = libc().rmdir(path); + + if (res < 0) handler.error(Errno.valueOf(errno()), "rmdir", path); + + return res; + } + + public int setenv(String envName, String envValue, int overwrite) { + return libc().setenv(envName, envValue, overwrite); + } + + public FileStat stat(String path) { + FileStat stat = allocateStat(); + + if (stat(path, stat) < 0) handler.error(Errno.valueOf(errno()), "stat", path); + + return stat; + } + + public int stat(String path, FileStat stat) { + return libc().stat(path, stat); + } + + public int symlink(String oldpath, String newpath) { + return libc().symlink(oldpath, newpath); + } + + public String readlink(String oldpath) throws IOException { + // TODO: this should not be hardcoded to 1024 bytes + ByteBuffer buffer = ByteBuffer.allocate(1024); + int result = libc().readlink(oldpath, buffer, buffer.capacity()); + + if (result == -1) return null; + + buffer.position(0); + buffer.limit(result); + return Charset.defaultCharset().decode(buffer).toString(); + } + + public int readlink(CharSequence path, byte[] buf, int bufsize) { + return libc().readlink(path, buf, bufsize); + } + + public int readlink(CharSequence path, ByteBuffer buf, int bufsize) { + return libc().readlink(path, buf, bufsize); + } + + public int readlink(CharSequence path, Pointer bufPtr, int bufsize) { + return libc().readlink(path, bufPtr, bufsize); + } + + public int unsetenv(String envName) { + return libc().unsetenv(envName); + } + + public int umask(int mask) { + return libc().umask(mask); + } + + public int utimes(String path, long[] atimeval, long[] mtimeval) { + Timeval[] times = null; + if (atimeval != null && mtimeval != null) { + times = Struct.arrayOf(getRuntime(), DefaultNativeTimeval.class, 2); + times[0].setTime(atimeval); + times[1].setTime(mtimeval); + } + return libc().utimes(path, times); + } + + public int utimes(String path, Pointer times) { + return libc().utimes(path, times); + } + + public int futimes(int fd, long[] atimeval, long[] mtimeval) { + Timeval[] times = null; + if (atimeval != null && mtimeval != null) { + times = Struct.arrayOf(getRuntime(), DefaultNativeTimeval.class, 2); + times[0].setTime(atimeval); + times[1].setTime(mtimeval); + } + return libc().futimes(fd, times); + } + + public int lutimes(String path, long[] atimeval, long[] mtimeval) { + Timeval[] times = null; + if (atimeval != null && mtimeval != null) { + times = Struct.arrayOf(getRuntime(), DefaultNativeTimeval.class, 2); + times[0].setTime(atimeval); + times[1].setTime(mtimeval); + } + return libc().lutimes(path, times); + } + + public int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag) { + Timespec[] times = null; + if (atimespec != null && mtimespec != null) { + times = Struct.arrayOf(getRuntime(), DefaultNativeTimespec.class, 2); + times[0].setTime(atimespec); + times[1].setTime(mtimespec); + } + return libc().utimensat(dirfd, path, times, flag); + } + + public int utimensat(int dirfd, String path, Pointer times, int flag) { + return libc().utimensat(dirfd, path, times, flag); + } + + public int futimens(int fd, long[] atimespec, long[] mtimespec) { + Timespec[] times = null; + if (atimespec != null && mtimespec != null) { + times = Struct.arrayOf(getRuntime(), DefaultNativeTimespec.class, 2); + times[0].setTime(atimespec); + times[1].setTime(mtimespec); + } + return libc().futimens(fd, times); + } + + public int futimens(int fd, Pointer times) { + return libc().futimens(fd, times); + } + + public int fork() { + return libc().fork(); + } + + public int waitpid(int pid, int[] status, int flags) { + return waitpid((long)pid, status, flags); + } + + public int waitpid(long pid, int[] status, int flags) { + return libc().waitpid(pid, status, flags); + } + + public int wait(int[] status) { + return libc().wait(status); + } + + public int getpriority(int which, int who) { + return libc().getpriority(which, who); + } + + public int setpriority(int which, int who, int prio) { + return libc().setpriority(which, who, prio); + } + + public boolean isatty(FileDescriptor fd) { + return isatty(helper.getfd(fd)) != 0; + } + + public int isatty(int fd) { + return libc().isatty(fd); + } + + public int errno() { + return LastError.getLastError(getRuntime()); + } + + public void errno(int value) { + LastError.setLastError(getRuntime(), value); + } + + public int chdir(String path) { + return libc().chdir(path); + } + + public boolean isNative() { + return true; + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + CharSequence[] argv, CharSequence[] envp) { + return posix_spawnp(path, fileActions, null, argv, envp); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + return posix_spawnp(path, fileActions, null, argv, envp); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + + CharSequence[] nativeArgv = new CharSequence[argv.size()]; + argv.toArray(nativeArgv); + + CharSequence[] nativeEnv = new CharSequence[envp.size()]; + envp.toArray(nativeEnv); + + return posix_spawnp(path, fileActions, spawnAttributes, nativeArgv, nativeEnv); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + CharSequence[] argv, CharSequence[] envp) { +// AbstractNumberReference<? extends Number> pid = getRuntime().findType(TypeAlias.pid_t).size() == 4 +// ? new IntByReference(-1) : new LongLongByReference(-1); + NumberByReference pid = new NumberByReference(TypeAlias.pid_t); + Pointer nativeFileActions = fileActions != null && !fileActions.isEmpty() ? nativeFileActions(fileActions) : null; + Pointer nativeSpawnAttributes = spawnAttributes != null && !spawnAttributes.isEmpty() ? nativeSpawnAttributes(spawnAttributes) : null; + long result; + + try { + result = ((UnixLibC) libc()).posix_spawnp(pid, path, nativeFileActions, nativeSpawnAttributes, argv, envp); + } finally { + if (nativeFileActions != null) ((UnixLibC) libc()).posix_spawn_file_actions_destroy(nativeFileActions); + if (nativeSpawnAttributes != null) ((UnixLibC) libc()).posix_spawnattr_destroy(nativeSpawnAttributes); + } + + if (result != 0) return -1; // result will be errno, but we can't indicate error because we return pid + return pid.longValue(); + } + + public int flock(int fd, int mode) { + return libc().flock(fd, mode); + } + + public int dup(int fd) { + return libc().dup(fd); + } + + public int dup2(int oldFd, int newFd) { + return libc().dup2(oldFd, newFd); + } + + public int fcntlInt(int fd, Fcntl fcntl, int arg) { + return fcntl(fd, fcntl, arg); + } + + public int fcntl(int fd, Fcntl fcntl) { + return libc().fcntl(fd, fcntl.intValue()); + } + + public int fcntl(int fd, Fcntl fcntl, int arg) { + return libc().fcntl(fd, fcntl.intValue(), arg); + } + + @Deprecated + public int fcntl(int fd, Fcntl fcntl, int... args) { + if (args != null) { + if (args.length == 1) { + return fcntl(fd, fcntl, args[0]); + } + } + throw new IllegalArgumentException("fcntl with variadic int args is unsupported"); + } + + public int access(CharSequence path, int amode) { + return libc().access(path, amode); + } + + public int close(int fd) { + return libc().close(fd); + } + + private Pointer nativeFileActions(Collection<? extends SpawnFileAction> fileActions) { + Pointer nativeFileActions = allocatePosixSpawnFileActions(); + ((UnixLibC) libc()).posix_spawn_file_actions_init(nativeFileActions); + for (SpawnFileAction action : fileActions) { + action.act(this, nativeFileActions); + } + + return nativeFileActions; + } + + private Pointer nativeSpawnAttributes(Collection<? extends SpawnAttribute> spawnAttributes) { + Pointer nativeSpawnAttributes = allocatePosixSpawnattr(); + ((UnixLibC) libc()).posix_spawnattr_init(nativeSpawnAttributes); + for (SpawnAttribute action : spawnAttributes) { + action.set(this, nativeSpawnAttributes); + } + + return nativeSpawnAttributes; + } + + public abstract FileStat allocateStat(); + + public long sysconf(Sysconf name) { + switch (name) { + case _SC_CLK_TCK: + return JavaTimes.HZ; + + default: + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + + public int fpathconf(int fd, Pathconf name) { + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + + public Times times() { + return new JavaTimes(); + } + + public int unlink(CharSequence path) { + return libc().unlink(path); + } + + public int open(CharSequence path, int flags, int perm) { + return libc().open(path, flags, perm); + } + + public long read(int fd, byte[] buf, long n) { + return libc().read(fd, buf, n); + } + public long write(int fd, byte[] buf, long n) { + return libc().write(fd, buf, n); + } + public long read(int fd, ByteBuffer buf, long n) { + return libc().read(fd, buf, n); + } + public long write(int fd, ByteBuffer buf, long n) { + return libc().write(fd, buf, n); + } + public long pread(int fd, byte[] buf, long n, long offset) { + return libc().pread(fd, buf, n, offset); + } + public long pwrite(int fd, byte[] buf, long n, long offset) { + return libc().pwrite(fd, buf, n, offset); + } + public long pread(int fd, ByteBuffer buf, long n, long offset) { + return libc().pread(fd, buf, n, offset); + } + public long pwrite(int fd, ByteBuffer buf, long n, long offset) { + return libc().pwrite(fd, buf, n, offset); + } + + public int read(int fd, byte[] buf, int n) { + return libc().read(fd, buf, n); + } + public int write(int fd, byte[] buf, int n) { + return libc().write(fd, buf, n); + } + public int read(int fd, ByteBuffer buf, int n) { + return libc().read(fd, buf, n); + } + public int write(int fd, ByteBuffer buf, int n) { + return libc().write(fd, buf, n); + } + public int pread(int fd, byte[] buf, int n, int offset) { + return libc().pread(fd, buf, n, offset); + } + public int pwrite(int fd, byte[] buf, int n, int offset) { + return libc().pwrite(fd, buf, n, offset); + } + public int pread(int fd, ByteBuffer buf, int n, int offset) { + return libc().pread(fd, buf, n, offset); + } + public int pwrite(int fd, ByteBuffer buf, int n, int offset) { + return libc().pwrite(fd, buf, n, offset); + } + + public int lseek(int fd, long offset, int whence) { + return (int) libc().lseek(fd, offset, whence); + } + + public long lseekLong(int fd, long offset, int whence) { + return libc().lseek(fd, offset, whence); + } + + public int pipe(int[] fds) { + return libc().pipe(fds); + } + + public int socketpair(int domain, int type, int protocol, int[] fds) { + return libc().socketpair(domain, type, protocol, fds); + } + + public int sendmsg(int socket, MsgHdr message, int flags) { + return libc().sendmsg( socket, message, flags ); + } + + public int recvmsg(int socket, MsgHdr message, int flags) { + return libc().recvmsg(socket, message, flags); + } + + public int truncate(CharSequence path, long length) { + return libc().truncate(path, length); + } + + public int ftruncate(int fd, long offset) { + return libc().ftruncate(fd, offset); + } + + public int rename(CharSequence oldName, CharSequence newName) { + return libc().rename(oldName, newName); + } + + public String gethostname() { + ByteBuffer buffer = ByteBuffer.allocate(256); + int result; + try { + result = libc().gethostname(buffer, buffer.capacity() - 1); + } catch (java.lang.UnsatisfiedLinkError e) { + result = -1; + } + if (result == -1) return helper.gethostname(); + buffer.position(0); + while (buffer.hasRemaining() && buffer.get() != 0); + buffer.limit(buffer.position() - 1); + buffer.position(0); + return Charset.forName("US-ASCII").decode(buffer).toString(); + } + + public String getcwd() { + byte[] cwd = new byte[1024]; + long result = libc().getcwd(cwd, 1024); + if (result == -1) return null; + int len = 0; + for (; len < 1024; len++) if (cwd[len] == 0) break; + return new String(cwd, 0, len); + } + + public int fsync(int fd) { + return libc().fsync(fd); + } + + public int fdatasync(int fd) { + return libc().fdatasync(fd); + } + + public static abstract class PointerConverter implements FromNativeConverter { + public Class nativeType() { + return Pointer.class; + } + } + + public static final PointerConverter GROUP = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new DefaultNativeGroup((Pointer) arg) : null; + } + }; + + public static final ToNativeConverter<FileStat, Pointer> FileStatConverter = new ToNativeConverter<FileStat, Pointer>() { + + public Pointer toNative(FileStat value, ToNativeContext context) { + if (value instanceof BaseFileStat) { + return ((BaseFileStat) value).memory; + + } else if (value instanceof Struct) { + return Struct.getMemory((Struct) value); + + } else if (value == null) { + return null; + } + + throw new IllegalArgumentException("instance of " + value.getClass() + " is not a struct"); + } + + public Class<Pointer> nativeType() { + return Pointer.class; + } + + }; + + public static final ToNativeConverter<NativeTimes, Pointer> TimesConverter = new ToNativeConverter<NativeTimes, Pointer>() { + + public Pointer toNative(NativeTimes value, ToNativeContext context) { + return value.memory; + } + + public Class<Pointer> nativeType() { + return Pointer.class; + } + }; + + public static final ToNativeConverter<Constant, Integer> ConstantConverter = new ToNativeConverter<Constant, Integer>() { + + public Integer toNative(Constant value, ToNativeContext context) { + return value.intValue(); + } + + public Class<Integer> nativeType() { + return Integer.class; + } + }; + + public static final ToNativeConverter<MsgHdr, Pointer> MsgHdrConverter = new ToNativeConverter<MsgHdr, Pointer>() { + public Pointer toNative(MsgHdr value, ToNativeContext context) { + if ( value instanceof BaseMsgHdr ) { + return ((BaseMsgHdr) value).memory; + } else if ( value instanceof Struct ) { + return Struct.getMemory((Struct) value); + } else if ( value == null ) { + return null; + } + + throw new IllegalArgumentException("instance of " + value.getClass() + " is not a struct"); + } + + public Class<Pointer> nativeType() { + return Pointer.class; + } + }; + + public int mkfifo(String filename, int mode) { + return ((UnixLibC) libc()).mkfifo(filename, mode); + } + + public int daemon(int nochdir, int noclose) { + return libc().daemon(nochdir, noclose); + } + + @Override + public long[] getgroups() { + final int size = getgroups(0, null); + final int[] groups = new int[size]; + final long[] castGroups = new long[size]; + + final int actualSize = getgroups(size, groups); + + if (actualSize == -1) { + return null; + } + + for (int i = 0; i < actualSize; i++) { + castGroups[i] = groups[i] & 0xFFFFFFFFL; + } + + if (actualSize < size) { + return Arrays.copyOfRange(castGroups, 0, actualSize); + } + + return castGroups; + } + + @Override + public int getgroups(int size, int[] groups) { + return libc().getgroups(size, groups); + } + + @Override + public String nl_langinfo(int item) { + return libc().nl_langinfo(item); + } + + @Override + public String setlocale(int category, String locale) { + return libc().setlocale(category, locale); + } + + @Override + public String strerror(int code) { + return libc().strerror(code); + } + + @Override + public Timeval allocateTimeval() { return new DefaultNativeTimeval(getRuntime()); } + + @Override + public int gettimeofday(Timeval tv) { return libc().gettimeofday(tv, 0); } +}
diff --git a/src/main/java/jnr/posix/CheckedPOSIX.java b/src/main/java/jnr/posix/CheckedPOSIX.java new file mode 100644 index 0000000..887929d --- /dev/null +++ b/src/main/java/jnr/posix/CheckedPOSIX.java
@@ -0,0 +1,644 @@ +package jnr.posix; + +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Signal; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import jnr.posix.util.MethodName; +import jnr.posix.util.ProcessMaker; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collection; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; + +final class CheckedPOSIX implements POSIX { + private final POSIX posix; + private final POSIXHandler handler; + + CheckedPOSIX(POSIX posix, POSIXHandler handler) { + this.posix = posix; + this.handler = handler; + } + + private <T> T unimplementedNull() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + private int unimplementedInt() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return -1; + } + + private boolean unimplementedBool() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return false; + } + + private String unimplementedString() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public ProcessMaker newProcessMaker(String... command) { + try { return posix.newProcessMaker(command); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public ProcessMaker newProcessMaker() { + try { return posix.newProcessMaker(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public FileStat allocateStat() { + try { return posix.allocateStat(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public MsgHdr allocateMsgHdr() { + try { return posix.allocateMsgHdr(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int chdir(String path) { + try { return posix.chdir(path); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int chmod(String filename, int mode) { + try { return posix.chmod(filename, mode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fchmod(int fd, int mode) { + try { return posix.fchmod(fd, mode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int chown(String filename, int user, int group) { + try { return posix.chown(filename, user, group); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public CharSequence crypt(CharSequence key, CharSequence salt) { + try { return posix.crypt(key, salt); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public byte[] crypt(byte[] key, byte[] salt) { + try { return posix.crypt(key, salt); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int fchown(int fd, int user, int group) { + try { return posix.fchown(fd, user, group); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int endgrent() { + try { return posix.endgrent(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int endpwent() { + try { return posix.endpwent(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int errno() { + return posix.errno(); + } + + public void errno(int value) { + posix.errno(value); + } + + public int exec(String path, String... args) { + try { return posix.exec(path, args); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int exec(String path, String[] args, String[] envp) { + try { return posix.exec(path, args, envp); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int execv(String path, String[] argv) { + try { return posix.execv(path, argv); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int execve(String path, String[] argv, String[] envp) { + try { return posix.execve(path, argv, envp); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fork() { + try { return posix.fork(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public FileStat fstat(int fd) { + try { return posix.fstat(fd); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int fstat(int fd, FileStat stat) { + try { return posix.fstat(fd, stat); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public FileStat fstat(FileDescriptor descriptor) { + try { return posix.fstat(descriptor); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int fstat(FileDescriptor descriptor, FileStat stat) { + try { return posix.fstat(descriptor, stat); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getegid() { + try { return posix.getegid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int geteuid() { + try { return posix.geteuid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getgid() { + try { return posix.getgid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getdtablesize() { + try { return posix.getdtablesize(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public Group getgrent() { + try { return posix.getgrent(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public Group getgrgid(int which) { + try { return posix.getgrgid(which); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public Group getgrnam(String which) { + try { return posix.getgrnam(which); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public String getlogin() { + try { return posix.getlogin(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int getpgid() { + try { return posix.getpgid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getpgid(int pid) { + try { return posix.getpgid(pid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getpgrp() { + try { return posix.getpgrp(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getpid() { + try { return posix.getpid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getppid() { + try { return posix.getppid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getpriority(int which, int who) { + try { return posix.getpriority(which, who); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public Passwd getpwent() { + try { return posix.getpwent(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public Passwd getpwnam(String which) { + try { return posix.getpwnam(which); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public Passwd getpwuid(int which) { + try { return posix.getpwuid(which); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int getuid() { + try { return posix.getuid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getrlimit(int resource, RLimit rlim) { + try { return posix.getrlimit(resource, rlim); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int getrlimit(int resource, Pointer rlim) { + try { return posix.getrlimit(resource, rlim); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public RLimit getrlimit(int resource) { + try { return posix.getrlimit(resource); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int setrlimit(int resource, RLimit rlim) { + try { return posix.setrlimit(resource, rlim); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setrlimit(int resource, Pointer rlim) { + try { return posix.setrlimit(resource, rlim); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setrlimit(int resource, long rlimCur, long rlimMax) { + try { return posix.setrlimit(resource, rlimCur, rlimMax); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public boolean isatty(FileDescriptor descriptor) { + try { return posix.isatty(descriptor); } catch (UnsatisfiedLinkError ule) { return unimplementedBool(); } + } + + public int isatty(int descriptor) { + try { return posix.isatty(descriptor); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int kill(int pid, int signal) { + return kill((long) pid, signal); + } + + public int kill(long pid, int signal) { + try { return posix.kill(pid, signal); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public SignalHandler signal(Signal sig, SignalHandler handler) { + try { return posix.signal(sig, handler); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int raise(int sig) { + try { return posix.raise(sig); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int lchmod(String filename, int mode) { + try { return posix.lchmod(filename, mode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int lchown(String filename, int user, int group) { + try { return posix.lchown(filename, user, group); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int link(String oldpath, String newpath) { + try { return posix.link(oldpath, newpath); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public FileStat lstat(String path) { + try { return posix.lstat(path); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int lstat(String path, FileStat stat) { + try { return posix.lstat(path, stat); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int mkdir(String path, int mode) { + try { return posix.mkdir(path, mode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public String readlink(String path) throws IOException { + try { return posix.readlink(path); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int readlink(CharSequence path, byte[] buf, int bufsize) { + try { return posix.readlink(path, buf, bufsize); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int readlink(CharSequence path, ByteBuffer buf, int bufsize) { + try { return posix.readlink(path, buf, bufsize); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int readlink(CharSequence path, Pointer bufPtr, int bufsize) { + try { return posix.readlink(path, bufPtr, bufsize); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int rmdir(String path) { + try { return posix.rmdir(path); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setegid(int egid) { + try { return posix.setegid(egid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int seteuid(int euid) { + try { return posix.seteuid(euid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setgid(int gid) { + try { return posix.setgid(gid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setgrent() { + try { return posix.setgrent(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setpgid(int pid, int pgid) { + try { return posix.setpgid(pid, pgid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setpgrp(int pid, int pgrp) { + try { return posix.setpgrp(pid, pgrp); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setpriority(int which, int who, int prio) { + try { return posix.setpriority(which, who, prio); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setpwent() { + try { return posix.setpwent(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setsid() { + try { return posix.setsid(); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int setuid(int uid) { + try { return posix.setuid(uid); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public FileStat stat(String path) { + try { return posix.stat(path); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int stat(String path, FileStat stat) { + try { return posix.stat(path, stat); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int symlink(String oldpath, String newpath) { + try { return posix.symlink(oldpath, newpath); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int umask(int mask) { + try { return posix.umask(mask); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int utimes(String path, long[] atimeval, long[] mtimeval) { + try { return posix.utimes(path, atimeval, mtimeval); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int utimes(String path, Pointer times) { + try { return posix.utimes(path, times); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int futimes(int fd, long[] atimeval, long[] mtimeval) { + try { return posix.futimes(fd, atimeval, mtimeval); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int lutimes(String path, long[] atimeval, long[] mtimeval) { + try { return posix.lutimes(path, atimeval, mtimeval); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag) { + try { return posix.utimensat(dirfd, path, atimespec, mtimespec, flag); } catch (UnsatisfiedLinkError ule) { + return unimplementedInt(); } + } + + public int utimensat(int dirfd, String path, Pointer times, int flag) { + try { return posix.utimensat(dirfd, path, times, flag); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int futimens(int fd, long[] atimespec, long[] mtimespec) { + try { return posix.futimens(fd, atimespec, mtimespec); } catch (UnsatisfiedLinkError ule) { + return unimplementedInt(); } + } + + public int futimens(int fd, Pointer times) { + try { return posix.futimens(fd, times); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int wait(int[] status) { + try { return posix.wait(status); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int waitpid(int pid, int[] status, int flags) { + return waitpid((long)pid, status, flags); + } + + public int waitpid(long pid, int[] status, int flags) { + try { return posix.waitpid(pid, status, flags); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public boolean isNative() { + return posix.isNative(); + } + + public LibC libc() { + return posix.libc(); + } + + public Pointer environ() { + try { return posix.environ(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public String getenv(String envName) { + try { return posix.getenv(envName); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int setenv(String envName, String envValue, int overwrite) { + try { return posix.setenv(envName, envValue, overwrite); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int unsetenv(String envName) { + try { return posix.unsetenv(envName); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + try { return posix.posix_spawnp(path, fileActions, argv, envp); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + try { return posix.posix_spawnp(path, fileActions, spawnAttributes, argv, envp); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + + public long sysconf(Sysconf name) { + try { return posix.sysconf(name); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + try { return posix.confstr(name, buf, len); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fpathconf(int fd, Pathconf name) { + try { return posix.fpathconf(fd, name); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public Times times() { + try { return posix.times(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + public int flock(int fd, int mode) { + return posix.flock(fd, mode); + } + + public int dup(int fd) { + try { return posix.dup(fd); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int dup2(int oldFd, int newFd) { + try { return posix.dup2(oldFd, newFd); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fcntlInt(int fd, Fcntl fcntlConst, int arg) { + try { return posix.fcntlInt(fd, fcntlConst, arg); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fcntl(int fd, Fcntl fcntlConst) { + try { return posix.fcntl(fd, fcntlConst); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fcntl(int fd, Fcntl fcntlConst, int arg) { + try { return posix.fcntl(fd, fcntlConst, arg); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + @Deprecated + public int fcntl(int fd, Fcntl fcntlConst, int... arg) { + try { return posix.fcntl(fd, fcntlConst); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int access(CharSequence path, int amode) { + try { return posix.access(path, amode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int close(int fd) { + try { return posix.close(fd); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int unlink(CharSequence path) { + try { return posix.unlink(path); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int open(CharSequence path, int flags, int perm) { + try { return posix.open(path, flags, perm); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public long read(int fd, byte[] buf, long n) { + try { return posix.read(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long write(int fd, byte[] buf, long n) { + try { return posix.write(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long read(int fd, ByteBuffer buf, long n) { + try { return posix.read(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long write(int fd, ByteBuffer buf, long n) { + try { return posix.write(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long pread(int fd, byte[] buf, long n, long offset) { + try { return posix.pread(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long pwrite(int fd, byte[] buf, long n, long offset) { + try { return posix.pwrite(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long pread(int fd, ByteBuffer buf, long n, long offset) { + try { return posix.pread(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public long pwrite(int fd, ByteBuffer buf, long n, long offset) { + try { return posix.pwrite(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int read(int fd, byte[] buf, int n) { + try { return posix.read(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int write(int fd, byte[] buf, int n) { + try { return posix.write(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int read(int fd, ByteBuffer buf, int n) { + try { return posix.read(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int write(int fd, ByteBuffer buf, int n) { + try { return posix.write(fd, buf, n); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int pread(int fd, byte[] buf, int n, int offset) { + try { return posix.pread(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int pwrite(int fd, byte[] buf, int n, int offset) { + try { return posix.pwrite(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int pread(int fd, ByteBuffer buf, int n, int offset) { + try { return posix.pread(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + public int pwrite(int fd, ByteBuffer buf, int n, int offset) { + try { return posix.pwrite(fd, buf, n, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int lseek(int fd, long offset, int whence) { + try { return posix.lseek(fd, offset, whence); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public long lseekLong(int fd, long offset, int whence) { + try { return posix.lseekLong(fd, offset, whence); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int pipe(int[] fds) { + try {return posix.pipe(fds); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int socketpair(int domain, int type, int protocol, int[] fds) { + try {return posix.socketpair(domain, type, protocol, fds); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int sendmsg(int socket, MsgHdr message, int flags) { + try {return posix.sendmsg(socket, message, flags); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int recvmsg(int socket, MsgHdr message, int flags) { + try {return posix.recvmsg(socket, message, flags); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int truncate(CharSequence path, long length) { + try { return posix.truncate(path, length); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int ftruncate(int fd, long offset) { + try {return posix.ftruncate(fd, offset); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int rename(CharSequence oldName, CharSequence newName) { + try {return posix.rename(oldName, newName); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public String getcwd() { + try {return posix.getcwd(); } catch (UnsatisfiedLinkError ule) { return unimplementedString(); } + } + + public int fsync(int fd) { + try {return posix.fsync(fd); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int fdatasync(int fd) { + try {return posix.fsync(fd); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int mkfifo(String path, int mode) { + try {return posix.mkfifo(path, mode); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public int daemon(int nochdir, int noclose) { + try {return posix.daemon(nochdir, noclose); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public long[] getgroups() { + try {return posix.getgroups(); } catch (UnsatisfiedLinkError ule) { return null; } + } + + public int getgroups(int size, int[] groups) { + try {return posix.getgroups(size, groups); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public String nl_langinfo(int item) { + try {return posix.nl_langinfo(item); } catch (UnsatisfiedLinkError ule) { return unimplementedString(); } + } + + public String setlocale(int category, String locale) { + try {return posix.setlocale(category, locale); } catch (UnsatisfiedLinkError ule) { return unimplementedString(); } + } + + @Override + public String strerror(int code) { + try {return posix.strerror(code); } catch (UnsatisfiedLinkError ule) { return unimplementedString(); } + } + + @Override + public Timeval allocateTimeval() { + try {return posix.allocateTimeval(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } + + @Override + public int gettimeofday(Timeval tv) { + try {return posix.gettimeofday(tv); } catch (UnsatisfiedLinkError ule) { return unimplementedInt(); } + } + + public String gethostname() { + try {return posix.gethostname(); } catch (UnsatisfiedLinkError ule) { return unimplementedNull(); } + } +}
diff --git a/src/main/java/jnr/posix/CmsgHdr.java b/src/main/java/jnr/posix/CmsgHdr.java new file mode 100644 index 0000000..a20fab8 --- /dev/null +++ b/src/main/java/jnr/posix/CmsgHdr.java
@@ -0,0 +1,24 @@ +package jnr.posix; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +public interface CmsgHdr { + + void setLevel(int level); + + int getLevel(); + + void setType(int type); + + int getType(); + + void setData(ByteBuffer data); + + ByteBuffer getData(); + + int getLen(); + +}
diff --git a/src/main/java/jnr/posix/Crypt.java b/src/main/java/jnr/posix/Crypt.java new file mode 100644 index 0000000..34ef981 --- /dev/null +++ b/src/main/java/jnr/posix/Crypt.java
@@ -0,0 +1,8 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + +public interface Crypt { + CharSequence crypt(CharSequence key, CharSequence salt); + Pointer crypt(byte[] key, byte[] salt); +}
diff --git a/src/main/java/jnr/posix/DefaultNativeGroup.java b/src/main/java/jnr/posix/DefaultNativeGroup.java new file mode 100644 index 0000000..8bc6914 --- /dev/null +++ b/src/main/java/jnr/posix/DefaultNativeGroup.java
@@ -0,0 +1,86 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +package jnr.posix; + +import jnr.ffi.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * The default native group layout. + * + * <p> + * This implementation should work on Solaris, Linux and MacOS. + * </p> + */ +public final class DefaultNativeGroup extends NativeGroup implements Group { + static final class Layout extends StructLayout { + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef gr_name = new UTF8StringRef(); // name + public final UTF8StringRef gr_passwd = new UTF8StringRef(); // group password (encrypted) + public final Signed32 gr_gid = new Signed32(); // group id + public final Pointer gr_mem = new Pointer(); + } + + static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + private final Pointer memory; + + DefaultNativeGroup(jnr.ffi.Pointer memory) { + super(memory.getRuntime(), layout); + this.memory = memory; + } + + public java.lang.String getName() { + return layout.gr_name.get(memory); + } + + public java.lang.String getPassword() { + return layout.gr_passwd.get(memory); + } + + public long getGID() { + return layout.gr_gid.get(memory); + } + + public java.lang.String[] getMembers() { + List<java.lang.String> lst = new ArrayList<java.lang.String>(); + + jnr.ffi.Pointer ptr = layout.gr_mem.get(memory); + Pointer member; + int ptrSize = runtime.addressSize(); + for (int i = 0; (member = ptr.getPointer(i)) != null; i += ptrSize) { + lst.add(member.getString(0)); + } + + return lst.toArray(new java.lang.String[lst.size()]); + } + +}
diff --git a/src/main/java/jnr/posix/DefaultNativeRLimit.java b/src/main/java/jnr/posix/DefaultNativeRLimit.java new file mode 100644 index 0000000..f285572 --- /dev/null +++ b/src/main/java/jnr/posix/DefaultNativeRLimit.java
@@ -0,0 +1,26 @@ +package jnr.posix; + +public class DefaultNativeRLimit extends RLimit { + public final UnsignedLong rlim_cur = new UnsignedLong(); + public final UnsignedLong rlim_max = new UnsignedLong(); + + protected DefaultNativeRLimit(jnr.ffi.Runtime runtime) { + super(runtime); + } + + @Override + public void init(long rlimCur, long rlimMax) { + rlim_cur.set(rlimCur); + rlim_max.set(rlimMax); + } + + @Override + public long rlimCur() { + return rlim_cur.get(); + } + + @Override + public long rlimMax() { + return rlim_max.get(); + } +}
diff --git a/src/main/java/jnr/posix/DefaultNativeTimespec.java b/src/main/java/jnr/posix/DefaultNativeTimespec.java new file mode 100644 index 0000000..dda3b77 --- /dev/null +++ b/src/main/java/jnr/posix/DefaultNativeTimespec.java
@@ -0,0 +1,32 @@ +package jnr.posix; + +public final class DefaultNativeTimespec extends Timespec { + public final SignedLong tv_sec = new SignedLong(); + public final SignedLong tv_nsec = new SignedLong(); + + public DefaultNativeTimespec(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void setTime(long[] timespec) { + assert timespec.length == 2; + tv_sec.set(timespec[0]); + tv_nsec.set(timespec[1]); + } + + public void sec(long sec) { + this.tv_sec.set(sec); + } + + public void nsec(long usec) { + this.tv_nsec.set(usec); + } + + public long sec() { + return tv_sec.get(); + } + + public long nsec() { + return tv_nsec.get(); + } +}
diff --git a/src/main/java/jnr/posix/DefaultNativeTimeval.java b/src/main/java/jnr/posix/DefaultNativeTimeval.java new file mode 100644 index 0000000..0cb2aa6 --- /dev/null +++ b/src/main/java/jnr/posix/DefaultNativeTimeval.java
@@ -0,0 +1,32 @@ +package jnr.posix; + +public final class DefaultNativeTimeval extends Timeval { + public final SignedLong tv_sec = new SignedLong(); + public final SignedLong tv_usec = new SignedLong(); + + public DefaultNativeTimeval(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void setTime(long[] timeval) { + assert timeval.length == 2; + tv_sec.set(timeval[0]); + tv_usec.set(timeval[1]); + } + + public void sec(long sec) { + this.tv_sec.set(sec); + } + + public void usec(long usec) { + this.tv_usec.set(usec); + } + + public long sec() { + return tv_sec.get(); + } + + public long usec() { + return tv_usec.get(); + } +}
diff --git a/src/main/java/jnr/posix/DragonFlyFileStat.java b/src/main/java/jnr/posix/DragonFlyFileStat.java new file mode 100644 index 0000000..89dba35 --- /dev/null +++ b/src/main/java/jnr/posix/DragonFlyFileStat.java
@@ -0,0 +1,141 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class DragonFlyFileStat extends BaseFileStat implements NanosecondFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends SignedLong {} + public final class dev_t extends Unsigned32 {} + + public final Signed64 st_ino = new Signed64(); + public final Signed32 st_nlink = new Signed32(); + public final dev_t st_dev = new dev_t(); + public final Unsigned16 st_mode = new Unsigned16(); + public final Unsigned16 st_padding1 = new Unsigned16(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final dev_t st_rdev = new dev_t(); + public final time_t st_atim = new time_t(); + public final time_t st_atimnsec = new time_t(); + public final time_t st_mtim = new time_t(); + public final time_t st_mtimnsec = new time_t(); + public final time_t st_ctim = new time_t(); + public final time_t st_ctimnsec = new time_t(); + public final Signed32 st_size = new Signed32(); + public final Signed32 st_blocks = new Signed32(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_flags = new Signed32(); + public final Signed32 st_gen = new Signed32(); + public final Signed32 st_lspare = new Signed32(); + public final Signed64 st_qspare1 = new Signed64(); + public final Signed64 st_qspare2 = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public DragonFlyFileStat(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atim.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctim.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtim.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimnsec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimnsec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimnsec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/DragonFlyPOSIX.java b/src/main/java/jnr/posix/DragonFlyPOSIX.java new file mode 100644 index 0000000..a8ba316 --- /dev/null +++ b/src/main/java/jnr/posix/DragonFlyPOSIX.java
@@ -0,0 +1,92 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Memory; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.Pointer; +import jnr.posix.util.MethodName; + +final class DragonFlyPOSIX extends BaseNativePOSIX { + DragonFlyPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + } + + public FileStat allocateStat() { + return new DragonFlyFileStat(this); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new DragonFlyPasswd((Pointer) arg) : null; + } + }; + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 8); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 8); + } +}
diff --git a/src/main/java/jnr/posix/DragonFlyPasswd.java b/src/main/java/jnr/posix/DragonFlyPasswd.java new file mode 100644 index 0000000..8876b70 --- /dev/null +++ b/src/main/java/jnr/posix/DragonFlyPasswd.java
@@ -0,0 +1,101 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + + +import jnr.ffi.StructLayout; + +public class DragonFlyPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Signed32 pw_uid = new Signed32(); // user id + public final Signed32 pw_gid = new Signed32(); // user id + public final SignedLong pw_change = new SignedLong();// password change time + public final UTF8StringRef pw_class = new UTF8StringRef(); // user access class + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + public final SignedLong pw_expire = new SignedLong(); // account expiration + public final Signed32 pw_fields = new Signed32(); // internal: fields filled in + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + DragonFlyPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return layout.pw_class.get(memory); + } + + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + + public long getGID() { + return layout.pw_gid.get(memory); + } + + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + + public int getPasswdChangeTime() { + return layout.pw_change.intValue(memory); + } + + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + + public long getUID() { + return layout.pw_uid.get(memory); + } + + public int getExpire() { + return layout.pw_expire.intValue(memory); + } +}
diff --git a/src/main/java/jnr/posix/FileStat.java b/src/main/java/jnr/posix/FileStat.java new file mode 100644 index 0000000..992bae7 --- /dev/null +++ b/src/main/java/jnr/posix/FileStat.java
@@ -0,0 +1,73 @@ +package jnr.posix; + +public interface FileStat { + public static final int S_IFIFO = 0010000; // named pipe (fifo) + public static final int S_IFCHR = 0020000; // character special + public static final int S_IFDIR = 0040000; // directory + public static final int S_IFBLK = 0060000; // block special + public static final int S_IFREG = 0100000; // regular + public static final int S_IFLNK = 0120000; // symbolic link + public static final int S_IFSOCK = 0140000; // socket + public static final int S_IFMT = 0170000; // file mask for type checks + public static final int S_ISUID = 0004000; // set user id on execution + public static final int S_ISGID = 0002000; // set group id on execution + public static final int S_ISVTX = 0001000; // save swapped text even after use + public static final int S_IRUSR = 0000400; // read permission, owner + public static final int S_IWUSR = 0000200; // write permission, owner + public static final int S_IXUSR = 0000100; // execute/search permission, owner + public static final int S_IRGRP = 0000040; // read permission, group + public static final int S_IWGRP = 0000020; // write permission, group + public static final int S_IXGRP = 0000010; // execute/search permission, group + public static final int S_IROTH = 0000004; // read permission, other + public static final int S_IWOTH = 0000002; // write permission, other + public static final int S_IXOTH = 0000001; // execute permission, other + + public static final int ALL_READ = S_IRUSR | S_IRGRP | S_IROTH; + public static final int ALL_WRITE = S_IWUSR | S_IWGRP | S_IWOTH; + public static final int S_IXUGO = S_IXUSR | S_IXGRP | S_IXOTH; + + public long atime(); + public long blocks(); + public long blockSize(); + public long ctime(); + public long dev(); + public String ftype(); + public int gid(); + public boolean groupMember(int gid); + public long ino(); + public boolean isBlockDev(); + public boolean isCharDev(); + public boolean isDirectory(); + public boolean isEmpty(); + public boolean isExecutable(); + public boolean isExecutableReal(); + public boolean isFifo(); + public boolean isFile(); + public boolean isGroupOwned(); + public boolean isIdentical(FileStat other); + public boolean isNamedPipe(); + public boolean isOwned(); + public boolean isROwned(); + public boolean isReadable(); + public boolean isReadableReal(); + public boolean isWritable(); + public boolean isWritableReal(); + public boolean isSetgid(); + public boolean isSetuid(); + public boolean isSocket(); + public boolean isSticky(); + public boolean isSymlink(); + public int major(long dev); + public int minor(long dev); + public int mode(); + public long mtime(); + public int nlink(); + public long rdev(); + /** + * Note: Name 'st_size' since Structure has a 'size' method already + * + * @return size of the stat structure + */ + public long st_size(); + public int uid(); +}
diff --git a/src/main/java/jnr/posix/FileTime.java b/src/main/java/jnr/posix/FileTime.java new file mode 100644 index 0000000..ddd402f --- /dev/null +++ b/src/main/java/jnr/posix/FileTime.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import jnr.ffi.Struct; + +public class FileTime extends Struct { + public final Unsigned32 dwLowDateTime = new Unsigned32(); + public final Unsigned32 dwHighDateTime = new Unsigned32(); + + FileTime(jnr.ffi.Runtime runtime) { + super(runtime); + } +}
diff --git a/src/main/java/jnr/posix/Flock.java b/src/main/java/jnr/posix/Flock.java new file mode 100644 index 0000000..47855d8 --- /dev/null +++ b/src/main/java/jnr/posix/Flock.java
@@ -0,0 +1,20 @@ +package jnr.posix; + +import jnr.ffi.Struct; + +abstract public class Flock extends Struct { + public Flock(jnr.ffi.Runtime runtime) { + super(runtime); + } + public abstract void type(short type); + public abstract void whence(short whence); + public abstract void start(long start); + public abstract void len(long len); + public abstract void pid(int pid); + + public abstract short type(); + public abstract short whence(); + public abstract long start(); + public abstract long len(); + public abstract int pid(); +}
diff --git a/src/main/java/jnr/posix/FreeBSDCmsgHdr.java b/src/main/java/jnr/posix/FreeBSDCmsgHdr.java new file mode 100644 index 0000000..b9ae98c --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDCmsgHdr.java
@@ -0,0 +1,72 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +/** + * @author Bob McWhirter + */ +class FreeBSDCmsgHdr extends BaseCmsgHdr { + + public static class Layout extends StructLayout { + + protected Layout(Runtime runtime) { + super(runtime); + } + + public final socklen_t cmsg_len = new socklen_t(); + public final Signed32 cmsg_level = new Signed32(); + public final Signed32 cmsg_type = new Signed32(); + } + + public static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + public FreeBSDCmsgHdr(NativePOSIX posix, Pointer memory) { + super(posix, memory); + } + + public FreeBSDCmsgHdr(NativePOSIX posix, Pointer memory, int totalLen) { + super(posix, memory, totalLen); + } + + public void setLevel(int level) { + layout.cmsg_level.set(this.memory, level); + } + + public int getLevel() { + return layout.cmsg_level.get(this.memory); + } + + public void setType(int type) { + layout.cmsg_type.set(this.memory, type); + } + + public int getType() { + return layout.cmsg_type.get(this.memory); + } + + public int getLen() { + return (int) layout.cmsg_len.get(this.memory); + } + + void setLen(int len) { + layout.cmsg_len.set(this.memory, len); + } + + public String toString(String indent) { + StringBuffer buf = new StringBuffer(); + + buf.append(indent).append("cmsg {\n"); + buf.append(indent).append(" cmsg_len=").append(layout.cmsg_len.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_level=").append(layout.cmsg_level.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_type=").append(layout.cmsg_type.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_data=").append(getData()).append("\n"); + buf.append(indent).append("}"); + return buf.toString(); + } + + public String toString(){ + return toString( "" ); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDFileStat.java b/src/main/java/jnr/posix/FreeBSDFileStat.java new file mode 100644 index 0000000..ec01140 --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDFileStat.java
@@ -0,0 +1,142 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class FreeBSDFileStat extends BaseFileStat implements NanosecondFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends SignedLong {} + public final class dev_t extends Signed32 {} + + public final dev_t st_dev = new dev_t(); + public final Signed32 st_ino = new Signed32(); + public final Signed16 st_mode = new Signed16(); + public final Signed16 st_nlink = new Signed16(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final dev_t st_rdev = new dev_t(); + public final time_t st_atime = new time_t(); + public final SignedLong st_atimensec = new SignedLong(); + public final time_t st_mtime = new time_t(); + public final SignedLong st_mtimensec = new SignedLong(); + public final time_t st_ctime = new time_t(); + public final SignedLong st_ctimensec = new SignedLong(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_blocks = new Signed64(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_flags = new Signed32(); + public final Signed32 st_gen = new Signed32(); + public final Signed32 st_lspare = new Signed32(); + public final time_t st_birthtime = new time_t(); + public final SignedLong st_birthtimensec = new SignedLong(); + /* FIXME: This padding isn't quite correct */ + public final Signed64 st_qspare0 = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public FreeBSDFileStat(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDFileStat12.java b/src/main/java/jnr/posix/FreeBSDFileStat12.java new file mode 100644 index 0000000..8e4633f --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDFileStat12.java
@@ -0,0 +1,145 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class FreeBSDFileStat12 extends BaseFileStat implements NanosecondFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends SignedLong {} + public final class dev_t extends Signed32 {} + + public final dev_t st_dev = new dev_t(); + public final Signed64 st_ino = new Signed64(); + // FIXME: this should be a 64-bit field + public final Signed32 st_nlink_upper = new Signed32(); + public final Signed32 st_nlink = new Signed32(); + public final Signed16 st_mode = new Signed16(); + public final Signed16 st_padding0 = new Signed16(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final Signed32 st_padding1 = new Signed32(); + public final dev_t st_rdev = new dev_t(); + public final time_t st_atime = new time_t(); + public final SignedLong st_atimensec = new SignedLong(); + public final time_t st_mtime = new time_t(); + public final SignedLong st_mtimensec = new SignedLong(); + public final time_t st_ctime = new time_t(); + public final SignedLong st_ctimensec = new SignedLong(); + public final time_t st_birthtime = new time_t(); + public final SignedLong st_birthtimensec = new SignedLong(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_blocks = new Signed64(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_flags = new Signed32(); + public final Signed64 st_gen = new Signed64(); + /* FIXME: This padding isn't quite correct */ + public final Signed64 st_qspare0 = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public FreeBSDFileStat12(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDMsgHdr.java b/src/main/java/jnr/posix/FreeBSDMsgHdr.java new file mode 100644 index 0000000..92e7f20 --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDMsgHdr.java
@@ -0,0 +1,151 @@ +package jnr.posix; + +import java.util.ArrayList; +import java.util.List; +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +/** + * @author Bob McWhirter + */ +class FreeBSDMsgHdr extends BaseMsgHdr { + + public static class Layout extends StructLayout { + protected Layout(Runtime runtime) { + super(runtime); + } + + public final Pointer msg_name = new Pointer(); + public final socklen_t msg_namelen = new socklen_t(); + public final Pointer msg_iov = new Pointer(); + public final Signed32 msg_iovlen = new Signed32(); + public final Pointer msg_control = new Pointer(); + public final socklen_t msg_controllen = new socklen_t(); + public final Signed32 msg_flags = new Signed32(); + } + + private static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + protected FreeBSDMsgHdr(NativePOSIX posix) { + super(posix, layout); + setName(null); + } + + CmsgHdr allocateCmsgHdrInternal(NativePOSIX posix, Pointer pointer, int len) { + if (len > 0) { + return new FreeBSDCmsgHdr(posix, pointer, len); + } else { + return new FreeBSDCmsgHdr(posix, pointer); + } + } + + @Override + void setControlPointer(Pointer control) { + layout.msg_control.set(this.memory, control); + } + + @Override + void setControlLen(int len) { + layout.msg_controllen.set(this.memory, len); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("msghdr {\n"); + buf.append(" msg_name=").append(getName()).append(",\n"); + buf.append(" msg_namelen=").append(getNameLen()).append(",\n"); + + buf.append(" msg_iov=[\n"); + Pointer iovp = layout.msg_iov.get(this.memory); + + int numIov = getIovLen(); + for (int i = 0; i < numIov; ++i) { + Pointer eachp = iovp.slice(i * BaseIovec.layout.size()); + buf.append(new BaseIovec(posix, eachp).toString(" ")); + if (i < (numIov - 1)) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + + buf.append(" msg_control=[\n"); + + CmsgHdr[] controls = getControls(); + for (int i = 0; i < controls.length; ++i) { + buf.append(((FreeBSDCmsgHdr) controls[i]).toString(" ")); + if (i < controls.length - 1) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + buf.append(" msg_controllen=").append(layout.msg_controllen.get(this.memory)).append("\n"); + + buf.append(" msg_iovlen=").append(getIovLen()).append(",\n"); + buf.append(" msg_flags=").append(getFlags()).append(",\n"); + buf.append("}"); + return buf.toString(); + } + + @Override + void setNamePointer(Pointer name) { + layout.msg_name.set( this.memory, name ); + } + + @Override + Pointer getNamePointer() { + return layout.msg_name.get( this.memory ); + } + + + @Override + void setNameLen(int len) { + layout.msg_namelen.set(this.memory, len); + } + + @Override + int getNameLen() { + return (int) layout.msg_namelen.get(this.memory); + } + + @Override + void setIovPointer(Pointer iov) { + layout.msg_iov.set(this.memory, iov); + } + + @Override + Pointer getIovPointer() { + return layout.msg_iov.get( this.memory ); + } + + @Override + void setIovLen(int len) { + layout.msg_iovlen.set(this.memory, len); + } + + @Override + int getIovLen() { + return (int) layout.msg_iovlen.get(this.memory); + } + + @Override + Pointer getControlPointer() { + return layout.msg_control.get(this.memory); + } + + public int getControlLen() { + return (int) layout.msg_controllen.get(this.memory); + } + + public void setFlags(int flags) { + layout.msg_flags.set(this.memory, flags); + } + + public int getFlags() { + return layout.msg_flags.get(this.memory); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDPOSIX.java b/src/main/java/jnr/posix/FreeBSDPOSIX.java new file mode 100644 index 0000000..ebb05d8 --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDPOSIX.java
@@ -0,0 +1,121 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.constants.platform.Sysconf; +import jnr.ffi.Memory; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.Pointer; +import jnr.posix.util.MethodName; + +import java.lang.Runtime; +import java.io.InputStreamReader; +import java.io.BufferedReader; +import java.nio.ByteBuffer; +import java.text.NumberFormat; +import java.text.ParsePosition; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; + +final class FreeBSDPOSIX extends BaseNativePOSIX { + private final int freebsdVersion; + + FreeBSDPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + + int parsed_version = 0; + + // FreeBSD 12 introduces a new stat structure. Until jffi gets dlvsym() support + // to allow us to link explicitly to supported versions of functions, detect + // the current userspace version and cross our fingers. + try { + Process p = Runtime.getRuntime().exec("/bin/freebsd-version -u"); + String version = new BufferedReader(new InputStreamReader(p.getInputStream())).readLine(); + + if (p.waitFor() == 0 && version != null) { + NumberFormat fmt = NumberFormat.getIntegerInstance(); + fmt.setGroupingUsed(false); + + parsed_version = fmt.parse(version, new ParsePosition(0)).intValue(); + } + } catch (Exception e) { } + + freebsdVersion = parsed_version; + } + + public FileStat allocateStat() { + if (freebsdVersion >= 12) { + return new FreeBSDFileStat12(this); + } else { + return new FreeBSDFileStat(this); + } + } + + public MsgHdr allocateMsgHdr() { + return new FreeBSDMsgHdr(this); + } + + public SocketMacros socketMacros() { + return FreeBSDSocketMacros.INSTANCE; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new FreeBSDPasswd((Pointer) arg) : null; + } + }; + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 8); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 8); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDPasswd.java b/src/main/java/jnr/posix/FreeBSDPasswd.java new file mode 100644 index 0000000..3345162 --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDPasswd.java
@@ -0,0 +1,101 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + + +import jnr.ffi.StructLayout; + +public class FreeBSDPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Signed32 pw_uid = new Signed32(); // user id + public final Signed32 pw_gid = new Signed32(); // user id + public final SignedLong pw_change = new SignedLong();// password change time + public final UTF8StringRef pw_class = new UTF8StringRef(); // user access class + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + public final SignedLong pw_expire = new SignedLong(); // account expiration + public final Signed32 pw_fields = new Signed32(); // internal: fields filled in + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + FreeBSDPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return layout.pw_class.get(memory); + } + + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + + public long getGID() { + return layout.pw_gid.get(memory); + } + + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + + public int getPasswdChangeTime() { + return layout.pw_change.intValue(memory); + } + + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + + public long getUID() { + return layout.pw_uid.get(memory); + } + + public int getExpire() { + return layout.pw_expire.intValue(memory); + } +}
diff --git a/src/main/java/jnr/posix/FreeBSDSocketMacros.java b/src/main/java/jnr/posix/FreeBSDSocketMacros.java new file mode 100644 index 0000000..c254d38 --- /dev/null +++ b/src/main/java/jnr/posix/FreeBSDSocketMacros.java
@@ -0,0 +1,29 @@ +package jnr.posix; + +import jnr.ffi.*; +import jnr.ffi.Runtime; + +/** + * @author Bob McWhirter + */ +public class FreeBSDSocketMacros implements SocketMacros { + + public static final FreeBSDSocketMacros INSTANCE = new FreeBSDSocketMacros(); + + public int CMSG_ALIGN(int len) { + int sizeof_size_t = Runtime.getSystemRuntime().findType(TypeAlias.size_t).size(); + return (len + sizeof_size_t - 1) & ~(sizeof_size_t - 1); + } + + public int CMSG_SPACE(int l) { + return CMSG_ALIGN(FreeBSDCmsgHdr.layout.size()) + CMSG_ALIGN(l); + } + + public int CMSG_LEN(int l) { + return CMSG_ALIGN( FreeBSDCmsgHdr.layout.size() ) + (l); + } + + public Pointer CMSG_DATA(Pointer cmsg) { + return cmsg.slice(CMSG_ALIGN(FreeBSDCmsgHdr.layout.size())); + } +}
diff --git a/src/main/java/jnr/posix/Group.java b/src/main/java/jnr/posix/Group.java new file mode 100644 index 0000000..dd9621b --- /dev/null +++ b/src/main/java/jnr/posix/Group.java
@@ -0,0 +1,8 @@ +package jnr.posix; + +public interface Group { + public String getName(); + public String getPassword(); + public long getGID(); + public String[] getMembers(); +}
diff --git a/src/main/java/jnr/posix/HANDLE.java b/src/main/java/jnr/posix/HANDLE.java new file mode 100644 index 0000000..825f808 --- /dev/null +++ b/src/main/java/jnr/posix/HANDLE.java
@@ -0,0 +1,46 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.mapper.DataConverter; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.mapper.ToNativeContext; + +public final class HANDLE { + public static final long INVALID_HANDLE_VALUE = -1L; + private final Pointer pointer; + + public HANDLE(Pointer pointer) { + this.pointer = pointer; + } + + public final Pointer toPointer() { + return pointer; + } + + public final boolean isValid() { + return pointer.address() != (INVALID_HANDLE_VALUE & jnr.ffi.Runtime.getSystemRuntime().addressMask()); + } + + public static HANDLE valueOf(Pointer value) { + return new HANDLE(value); + } + + public static HANDLE valueOf(long value) { + return new HANDLE(jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().newPointer(value)); + } + + public static final DataConverter<HANDLE, Pointer> Converter = new DataConverter<HANDLE, Pointer>() { + + public Pointer toNative(HANDLE value, ToNativeContext context) { + return value != null ? value.pointer : null; + } + + public HANDLE fromNative(Pointer nativeValue, FromNativeContext context) { + return nativeValue != null ? new HANDLE(nativeValue) : null; + } + + public Class<Pointer> nativeType() { + return Pointer.class; + } + }; +}
diff --git a/src/main/java/jnr/posix/Iovec.java b/src/main/java/jnr/posix/Iovec.java new file mode 100644 index 0000000..310d878 --- /dev/null +++ b/src/main/java/jnr/posix/Iovec.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +public interface Iovec { + + ByteBuffer get(); + void set(ByteBuffer buf); +}
diff --git a/src/main/java/jnr/posix/JavaFileStat.java b/src/main/java/jnr/posix/JavaFileStat.java new file mode 100644 index 0000000..e6991ec --- /dev/null +++ b/src/main/java/jnr/posix/JavaFileStat.java
@@ -0,0 +1,317 @@ +package jnr.posix; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.DosFileAttributes; +import java.nio.file.attribute.FileTime; +import java.nio.file.attribute.PosixFileAttributes; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +public class JavaFileStat extends AbstractJavaFileStat { + short st_mode; + + BasicFileAttributes attrs; + PosixFileAttributes posixAttrs; + DosFileAttributes dosAttrs; + + public JavaFileStat(POSIX posix, POSIXHandler handler) { + super(posix, handler); + } + + public void setup(String filePath) { + File file = new JavaSecuredFile(filePath); + Path path = file.toPath(); + + try { + try { + // try POSIX + posixAttrs = Files.readAttributes(path, PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS); + attrs = posixAttrs; + } catch (UnsupportedOperationException uoe) { + try { + // try DOS + dosAttrs = Files.readAttributes(path, DosFileAttributes.class, LinkOption.NOFOLLOW_LINKS); + attrs = dosAttrs; + } catch (UnsupportedOperationException uoe2) { + attrs = Files.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS); + } + } + } catch (IOException ioe) { + // fall back on pre-NIO2 logic + attrs = new PreNIO2FileAttributes(file); + } + + // Simulated mode value + st_mode = calculateMode(file, (short) 0); + } + + private class PreNIO2FileAttributes implements BasicFileAttributes { + final long st_size; + final int st_ctime; + final int st_mtime; + final boolean regularFile; + final boolean directory; + + PreNIO2FileAttributes(File file) { + st_size = file.length(); + + st_mtime = (int) (file.lastModified() / 1000); + + // Parent file last modified will only represent when something was added or removed. + // This is not correct, but it is better than nothing and does work in one common use + // case. + if (file.getParentFile() != null) { + st_ctime = (int) (file.getParentFile().lastModified() / 1000); + } else { + st_ctime = st_mtime; + } + + regularFile = file.isFile(); + directory = file.isDirectory(); + } + + @Override + public FileTime lastModifiedTime() { + return FileTime.fromMillis(st_mtime); + } + + @Override + public FileTime lastAccessTime() { + return lastModifiedTime(); + } + + @Override + public FileTime creationTime() { + return FileTime.fromMillis(st_mtime); + } + + @Override + public boolean isRegularFile() { + return (st_mode & S_IFREG) != 0; + } + + @Override + public boolean isDirectory() { + return (st_mode & S_IFDIR) != 0; + } + + @Override + public boolean isSymbolicLink() { + return (st_mode & S_IFLNK) != 0; + } + + @Override + public boolean isOther() { + return !(isRegularFile() || isDirectory() || isSymbolicLink()); + } + + @Override + public long size() { + return st_size; + } + + @Override + public Object fileKey() { + return null; + } + } + + private short calculateMode(File file, short st_mode) { + // implementation to lowest common denominator... + // Windows has no file mode, but C ruby returns either 0100444 or 0100644 + + if (file.canRead()) { + st_mode |= ALL_READ; + } + + if (file.canWrite()) { + st_mode |= ALL_WRITE; + st_mode &= ~(S_IWGRP | S_IWOTH); + } + + if (file.isDirectory()) { + st_mode |= S_IFDIR; + } else if (file.isFile()) { + st_mode |= S_IFREG; + } + + if (posixAttrs != null && posixAttrs.isSymbolicLink()) { + st_mode |= S_IFLNK; + } else { + try { + st_mode = calculateSymlink(file, st_mode); + } catch (IOException e) { + // Not sure we can do much in this case... + } + } + + return st_mode; + } + + private static short calculateSymlink(File file, short st_mode) throws IOException { + if (file.getAbsoluteFile().getParentFile() == null) { + return st_mode; + } + + File absoluteParent = file.getAbsoluteFile().getParentFile(); + File canonicalParent = absoluteParent.getCanonicalFile(); + + if (canonicalParent.getAbsolutePath().equals(absoluteParent.getAbsolutePath())) { + // parent doesn't change when canonicalized, compare absolute and canonical file directly + if (!file.getAbsolutePath().equalsIgnoreCase(file.getCanonicalPath())) { + st_mode |= S_IFLNK; + return st_mode; + } + } + + // directory itself has symlinks (canonical != absolute), so build new path with canonical parent and compare + file = new JavaSecuredFile(canonicalParent.getAbsolutePath() + "/" + file.getName()); + if (!file.getAbsolutePath().equalsIgnoreCase(file.getCanonicalPath())) { + st_mode |= S_IFLNK; + } + + return st_mode; + } + + /** + * Limitation: Java has no access time support, so we return mtime as the next best thing. + */ + public long atime() { + return (int) (attrs.lastAccessTime().toMillis() / 1000); + } + + public long ctime() { + return (int) (attrs.creationTime().toMillis() / 1000); + } + + public boolean isDirectory() { + return attrs.isDirectory(); + } + + public boolean isEmpty() { + return attrs.size() == 0; + } + + public boolean isExecutable() { + if (posixAttrs != null) { + Set<PosixFilePermission> permissions = posixAttrs.permissions(); + + return permissions.contains(PosixFilePermission.OWNER_EXECUTE) || + permissions.contains(PosixFilePermission.GROUP_EXECUTE) || + permissions.contains(PosixFilePermission.OTHERS_EXECUTE); + } + + // silently return false, since it's likely an unusual filesystem + return false; + } + + public boolean isExecutableReal() { + return isExecutable(); + } + + public boolean isFile() { + return attrs.isRegularFile(); + } + + public boolean isGroupOwned() { + return groupMember(gid()); + } + + public boolean isIdentical(FileStat other) { + // if attrs supports file keys, we can compare them + Object key = attrs.fileKey(); + + if (key != null && other instanceof JavaFileStat) { + JavaFileStat otherStat = (JavaFileStat) other; + + return key.equals(otherStat.attrs.fileKey()); + } + + handler.unimplementedError("identical file detection"); + + return false; + } + + public boolean isOwned() { + return posix.geteuid() == uid(); + } + + public boolean isROwned() { + return posix.getuid() == uid(); + } + + public boolean isReadable() { + if (posixAttrs != null) { + Set<PosixFilePermission> permissions = posixAttrs.permissions(); + + return permissions.contains(PosixFilePermission.OWNER_READ) || + permissions.contains(PosixFilePermission.GROUP_READ) || + permissions.contains(PosixFilePermission.OTHERS_READ); + } + + int mode = mode(); + + if ((mode & S_IRUSR) != 0) return true; + if ((mode & S_IRGRP) != 0) return true; + if ((mode & S_IROTH) != 0) return true; + + return false; + } + + // We do both readable and readable_real through the same method because + public boolean isReadableReal() { + return isReadable(); + } + + public boolean isSymlink() { + if (posixAttrs != null) { + return posixAttrs.isSymbolicLink(); + } + + return (mode() & S_IFLNK) == S_IFLNK; + } + + public boolean isWritable() { + if (posixAttrs != null) { + Set<PosixFilePermission> permissions = posixAttrs.permissions(); + + return permissions.contains(PosixFilePermission.OWNER_WRITE) || + permissions.contains(PosixFilePermission.GROUP_WRITE) || + permissions.contains(PosixFilePermission.OTHERS_WRITE); + } else if (dosAttrs != null) { + return !dosAttrs.isReadOnly(); + } + + int mode = mode(); + + if ((mode & S_IWUSR) != 0) return true; + if ((mode & S_IWGRP) != 0) return true; + if ((mode & S_IWOTH) != 0) return true; + + return false; + } + + // We do both readable and readable_real through the same method because + // in our java process effective and real userid will always be the same. + public boolean isWritableReal() { + return isWritable(); + } + + public int mode() { + return st_mode & 0xffff; + } + + public long mtime() { + return (int) (attrs.lastModifiedTime().toMillis() / 1000); + } + + public long st_size() { + return attrs.size(); + } + +}
diff --git a/src/main/java/jnr/posix/JavaLibCHelper.java b/src/main/java/jnr/posix/JavaLibCHelper.java new file mode 100644 index 0000000..e8547ff --- /dev/null +++ b/src/main/java/jnr/posix/JavaLibCHelper.java
@@ -0,0 +1,528 @@ + /* + **** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2007 + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +package jnr.posix; + +import static jnr.constants.platform.Errno.*; + +import java.io.*; +import java.lang.management.ManagementFactory; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.nio.channels.Channel; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import java.util.regex.Pattern; + +import jnr.constants.platform.Errno; +import jnr.posix.util.Chmod; +import jnr.posix.util.ExecIt; +import jnr.posix.util.JavaCrypt; +import jnr.posix.util.Platform; + + /** + * This libc implementation is created one per runtime instance versus the others which + * are expected to be one static instance for whole JVM. Because of this it is no big + * deal to make reference to a POSIXHandler directly. + */ +// FIXME: we ignore all exceptions with shell launcher...should we do something better +public class JavaLibCHelper { + public static final int STDIN = 0; + public static final int STDOUT = 1; + public static final int STDERR = 2; + + private static final ThreadLocal<Integer> errno = new ThreadLocal<Integer>(); + + private final POSIXHandler handler; + private final Map<String, String> env; + + + public JavaLibCHelper(POSIXHandler handler) { + this.env = new HashMap<String, String>(); + this.handler = handler; + } + + private static class ReflectiveAccess { + private static final Class SEL_CH_IMPL; + private static final Method SEL_CH_IMPL_GET_FD; + private static final Class FILE_CHANNEL_IMPL; + private static final Field FILE_CHANNEL_IMPL_FD; + private static final Field FILE_DESCRIPTOR_FD; + private static final Field FILE_DESCRIPTOR_HANDLE; + + static { + try { + Method getModule = Class.class.getMethod("getModule"); + Class<?> Module = Class.forName("java.lang.Module"); + Method isOpen = Module.getMethod("isOpen", String.class, Module); + Method isNamed = Module.getMethod("isNamed"); + Method addOpens = Module.getMethod("addOpens", String.class, Module); + Object JNRPosixModule = getModule.invoke(ReflectiveAccess.class); + Object JavaBaseModule = getModule.invoke(FileDescriptor.class); + + if (!((Boolean) isOpen.invoke(JavaBaseModule, "java.io", JNRPosixModule))) { + // warn that many APIs will be broken without module access + System.err.println("Some JDK modules may not be open to jnr-posix, which will break file descriptor and process APIs. See https://github.com/jnr/jnr-posix/wiki/Using-POSIX-with-Java-Modules"); + } else if (!((Boolean) isNamed.invoke(JNRPosixModule))) { + // explicitly open them to avoid the implicitly open warning + addOpens.invoke(JavaBaseModule, "java.io", JNRPosixModule); + addOpens.invoke(JavaBaseModule, "sun.nio.ch", JNRPosixModule); + } + } catch (Exception e) { + // ignore, we're not on Java 9+ + } + + Method getFD; + Class selChImpl; + try { + selChImpl = Class.forName("sun.nio.ch.SelChImpl"); + try { + getFD = selChImpl.getMethod("getFD"); + getFD.setAccessible(true); + } catch (Exception e) { + getFD = null; + } + } catch (Exception e) { + selChImpl = null; + getFD = null; + } + SEL_CH_IMPL = selChImpl; + SEL_CH_IMPL_GET_FD = getFD; + + Field fd; + Class fileChannelImpl; + try { + fileChannelImpl = Class.forName("sun.nio.ch.FileChannelImpl"); + try { + fd = fileChannelImpl.getDeclaredField("fd"); + fd.setAccessible(true); + } catch (Exception e) { + fd = null; + } + } catch (Exception e) { + fileChannelImpl = null; + fd = null; + } + FILE_CHANNEL_IMPL = fileChannelImpl; + FILE_CHANNEL_IMPL_FD = fd; + + Field ffd; + try { + ffd = FileDescriptor.class.getDeclaredField("fd"); + ffd.setAccessible(true); + } catch (Exception e) { + ffd = null; + } + FILE_DESCRIPTOR_FD = ffd; + + if (Platform.IS_WINDOWS) { + Field handle; + try { + handle = FileDescriptor.class.getDeclaredField("handle"); + handle.setAccessible(true); + } catch (Exception e) { + handle = null; + } + FILE_DESCRIPTOR_HANDLE = handle; + } else { + FILE_DESCRIPTOR_HANDLE = null; + } + } + } + + public static FileDescriptor getDescriptorFromChannel(Channel channel) { + if (ReflectiveAccess.SEL_CH_IMPL_GET_FD != null && ReflectiveAccess.SEL_CH_IMPL.isInstance(channel)) { + // Pipe Source and Sink, Sockets, and other several other selectable channels + try { + return (FileDescriptor)ReflectiveAccess.SEL_CH_IMPL_GET_FD.invoke(channel); + } catch (Exception e) { + // return bogus below + } + } else if (ReflectiveAccess.FILE_CHANNEL_IMPL_FD != null && ReflectiveAccess.FILE_CHANNEL_IMPL.isInstance(channel)) { + // FileChannels + try { + return (FileDescriptor)ReflectiveAccess.FILE_CHANNEL_IMPL_FD.get(channel); + } catch (Exception e) { + // return bogus below + } + } else if (ReflectiveAccess.FILE_DESCRIPTOR_FD != null) { + // anything else that implements a getFD method that returns an int + FileDescriptor unixFD = new FileDescriptor(); + + try { + Method getFD = channel.getClass().getMethod("getFD"); + ReflectiveAccess.FILE_DESCRIPTOR_FD.set(unixFD, (Integer)getFD.invoke(channel)); + return unixFD; + } catch (Exception e) { + // return bogus below + } + } + return new FileDescriptor(); + } + + static int errno() { + Integer errno = JavaLibCHelper.errno.get(); + return errno != null ? errno : 0; + } + + static void errno(int errno) { + JavaLibCHelper.errno.set(errno); + } + + static void errno(Errno errno) { + JavaLibCHelper.errno.set(errno.intValue()); + } + + public int chmod(String filename, int mode) { + return Chmod.chmod(new JavaSecuredFile(filename), Integer.toOctalString(mode)); + } + + public int chown(String filename, int user, int group) { + PosixExec launcher = new PosixExec(handler); + int chownResult = -1; + int chgrpResult = -1; + + try { + if (user != -1) chownResult = launcher.runAndWait("chown", "" + user, filename); + if (group != -1) chgrpResult = launcher.runAndWait("chgrp ", "" + user, filename); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + } + + return chownResult != -1 && chgrpResult != -1 ? 0 : 1; + } + + public static CharSequence crypt(CharSequence original, CharSequence salt) { + return JavaCrypt.crypt(original, salt); + } + + // FIXME: This version has no idea what charset you want, so it just uses default. + public static byte[] crypt(byte[] original, byte[] salt) { + return JavaCrypt.crypt(new String(original), new String(salt)).toString().getBytes(); + } + + public int getfd(FileDescriptor descriptor) { + return getfdFromDescriptor(descriptor); + } + + public static int getfdFromDescriptor(FileDescriptor descriptor) { + if (descriptor == null || ReflectiveAccess.FILE_DESCRIPTOR_FD == null) return -1; + try { + return ReflectiveAccess.FILE_DESCRIPTOR_FD.getInt(descriptor); + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + + return -1; + } + + public static HANDLE gethandle(FileDescriptor descriptor) { + if (descriptor == null || ReflectiveAccess.FILE_DESCRIPTOR_HANDLE == null) return HANDLE.valueOf(-1); + try { + return gethandle(ReflectiveAccess.FILE_DESCRIPTOR_HANDLE.getLong(descriptor)); + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + + return HANDLE.valueOf(-1); + } + + public static HANDLE gethandle(long descriptor) { + return HANDLE.valueOf(descriptor); + } + + public String getlogin() { + return System.getProperty("user.name"); + } + + public String gethostname() { + String hn = System.getenv("HOSTNAME"); + if (hn == null) hn = System.getenv("COMPUTERNAME"); + return hn; + } + + public int getpid() { + try { + return handler.getPID(); + } catch (UnsupportedOperationException uoe) { + // if handler raises UOE, as our default handler does, try other ways + + // Java 9+ provide ProcessHandle.current + try { + Class processHandle = Class.forName("java.lang.ProcessHandle"); + Object current = processHandle.getMethod("current").invoke(null); // static + return (int) (long) (Long) processHandle.getMethod("pid").invoke(current); + } catch (Exception e) { + // ignore, try Java 8 logic below + } + + // Java 8- can use management beans to infer the pid + try { + String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); + int index = runtimeName.indexOf('@'); + + if (index > 0) { + return (int) Long.parseLong(runtimeName.substring(0, index)); + } + } catch (Exception e) { + // ignore, rethrow UOE below + } + + // couldn't do it, rethrow + throw uoe; + } + + } + ThreadLocal<Integer> pwIndex = new ThreadLocal<Integer>() { + @Override + protected Integer initialValue() { + return 0; + } + }; + public Passwd getpwent() { + Passwd retVal = pwIndex.get().intValue() == 0 ? new JavaPasswd(handler) : null; + pwIndex.set(pwIndex.get() + 1); + return retVal; + } + + public int setpwent() { + return 0; + } + + public int endpwent() { + pwIndex.set(0); + return 0; + } + public Passwd getpwuid(int which) { + return which == JavaPOSIX.LoginInfo.UID ? new JavaPasswd(handler) : null; + } + public int isatty(int fd) { + return (fd == STDOUT || fd == STDIN || fd == STDERR) ? 1 : 0; + } + + public int link(String oldpath, String newpath) { + try { + return new PosixExec(handler).runAndWait("ln", oldpath, newpath); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + } + errno(EINVAL); + return -1; // We tried and failed for some reason. Indicate error. + } + + public int lstat(String path, FileStat stat) { + File file = new JavaSecuredFile(path); + + if (!file.exists()) { + errno(ENOENT); + return -1; + } + + // FIXME: Bulletproof this or no? + JavaFileStat jstat = (JavaFileStat) stat; + + jstat.setup(path); + + // TODO: Add error reporting for cases we can calculate: ENOTDIR, ENAMETOOLONG, ENOENT + // EACCES, ELOOP, EFAULT, EIO + + return 0; + } + + public int mkdir(String path, int mode) { + File dir = new JavaSecuredFile(path); + + if (!dir.mkdir()) return -1; + + chmod(path, mode); + + return 0; + } + + public int rmdir(String path) { + return new JavaSecuredFile(path).delete() ? 0 : -1; + } + + public static int chdir(String path) { + System.setProperty("user.dir", path); + return 0; + } + + public int stat(String path, FileStat stat) { + // FIXME: Bulletproof this or no? + JavaFileStat jstat = (JavaFileStat) stat; + + try { + File file = new JavaSecuredFile(path); + + if (!file.exists()) { + errno(ENOENT); + return -1; + } + + jstat.setup(file.getCanonicalPath()); + } catch (IOException e) { + // TODO: Throw error when we have problems stat'ing canonicalizing + } + + // TODO: Add error reporting for cases we can calculate: ENOTDIR, ENAMETOOLONG, + // EACCES, ELOOP, EFAULT, EIO + + return 0; + } + + public int symlink(String oldpath, String newpath) { + try { + return new PosixExec(handler).runAndWait("ln", "-s", oldpath, newpath); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e) { + } + errno(EEXIST); + return -1; // We tried and failed for some reason. Indicate error. + + } + + public int readlink(String oldpath, ByteBuffer buffer, int length) throws IOException { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + new PosixExec(handler).runAndWait(baos, "readlink", oldpath); + + byte[] bytes = baos.toByteArray(); + + if (bytes.length > length || bytes.length == 0) return -1; + buffer.put(bytes, 0, bytes.length - 1); // trim off \n + + + return buffer.position(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + errno(ENOENT); + return -1; // We tried and failed for some reason. Indicate error. + } + + public Map<String, String> getEnv() { + return env; + } + + public static FileDescriptor toFileDescriptor(int fileDescriptor) { + FileDescriptor descriptor = new FileDescriptor(); + try { + ReflectiveAccess.FILE_DESCRIPTOR_FD.set(descriptor, fileDescriptor); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + return descriptor; + } + + public static FileDescriptor toFileDescriptor(HANDLE fileDescriptor) { + FileDescriptor descriptor = new FileDescriptor(); + try { + ReflectiveAccess.FILE_DESCRIPTOR_HANDLE.set(descriptor, fileDescriptor.toPointer().address()); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + return descriptor; + } + + private static class PosixExec extends ExecIt { + private final AtomicReference<Errno> errno = new AtomicReference<Errno>(Errno.EINVAL); + private final ErrnoParsingOutputStream errorStream = new ErrnoParsingOutputStream(errno); + + public PosixExec(POSIXHandler handler) { + super(handler); + } + + private int parseResult(int result) { + if (result == 0) { + return result; + } + errno(errno.get()); + return -1; + } + + public int runAndWait(String... args) throws IOException, InterruptedException { + return runAndWait(handler.getOutputStream(), errorStream, args); + } + + public int runAndWait(OutputStream output, String... args) throws IOException, InterruptedException { + return runAndWait(output, errorStream, args); + } + + public int runAndWait(OutputStream output, OutputStream error, String... args) throws IOException, InterruptedException { + return parseResult(super.runAndWait(output, error, args)); + } + } + + private static final class ErrnoParsingOutputStream extends OutputStream { + private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private final AtomicReference<Errno> errno; + + private ErrnoParsingOutputStream(AtomicReference<Errno> errno) { + this.errno = errno; + } + + @Override + public void write(int b) throws IOException { + if (b != '\r' && b != '\n' && b != -1) { + baos.write(b); + } else if (baos.size() > 0) { + String errorString = baos.toString(); + baos.reset(); + parseError(errorString); + } + } + + static Map<Pattern, Errno> errorPatterns = new HashMap<Pattern, Errno>(); + static { + errorPatterns.put(Pattern.compile("File exists"), Errno.EEXIST); + errorPatterns.put(Pattern.compile("Operation not permitted"), Errno.EPERM); + errorPatterns.put(Pattern.compile("No such file or directory"), Errno.ENOENT); + errorPatterns.put(Pattern.compile("Input/output error"), Errno.EIO); + errorPatterns.put(Pattern.compile("Not a directory"), Errno.ENOTDIR); + errorPatterns.put(Pattern.compile("No space left on device"), Errno.ENOSPC); + errorPatterns.put(Pattern.compile("Read-only file system"), Errno.EROFS); + errorPatterns.put(Pattern.compile("Too many links"), Errno.EMLINK); + } + + void parseError(String errorString) { + for (Map.Entry<Pattern, Errno> entry : errorPatterns.entrySet()) { + if (entry.getKey().matcher(errorString).find()) { + errno.set(entry.getValue()); + } + } + } + } +}
diff --git a/src/main/java/jnr/posix/JavaPOSIX.java b/src/main/java/jnr/posix/JavaPOSIX.java new file mode 100644 index 0000000..d934ebb --- /dev/null +++ b/src/main/java/jnr/posix/JavaPOSIX.java
@@ -0,0 +1,893 @@ +package jnr.posix; + +import jnr.constants.platform.Errno; +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Signal; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import jnr.posix.util.Java5ProcessMaker; +import jnr.posix.util.MethodName; +import jnr.posix.util.Platform; +import jnr.posix.util.ProcessMaker; +import jnr.posix.util.SunMiscSignal; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.Collection; +import java.util.Map; +import jnr.constants.platform.Confstr; + +import static jnr.constants.platform.Errno.EINVAL; +import static jnr.constants.platform.Errno.ENOENT; +import jnr.constants.platform.Pathconf; + +final class JavaPOSIX implements POSIX { + private final POSIXHandler handler; + private final JavaLibCHelper helper; + + JavaPOSIX(POSIXHandler handler) { + this.handler = handler; + this.helper = new JavaLibCHelper(handler); + } + + public ProcessMaker newProcessMaker(String... command) { + return new Java5ProcessMaker(handler, command); + } + + public ProcessMaker newProcessMaker() { + return new Java5ProcessMaker(handler); + } + + public FileStat allocateStat() { + return new JavaFileStat(this, handler); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public int chmod(String filename, int mode) { + return helper.chmod(filename, mode); + } + + public int fchmod(int fd, int mode) { + handler.unimplementedError("No fchmod in Java (yet)"); + return -1; + } + + public int chown(String filename, int user, int group) { + return helper.chown(filename, user, group); + } + + public int fchown(int fd, int user, int group) { + handler.unimplementedError("No fchown in Java (yet)"); + return -1; + } + + public CharSequence crypt(CharSequence key, CharSequence salt) { + return helper.crypt(key, salt); + } + + public byte[] crypt(byte[] key, byte[] salt) { + return helper.crypt(key, salt); + } + + public int exec(String path, String... argv) { + handler.unimplementedError("No exec in Java (yet)"); + + return -1; + } + + public int exec(String path, String[] argv, String[] envp) { + handler.unimplementedError("No exec in Java (yet)"); + + return -1; + } + + public int execv(String path, String[] argv) { + handler.unimplementedError("No execv in Java (yet)"); + + return -1; + } + + public int execve(String path, String[] argv, String[] envp) { + handler.unimplementedError("No execve in Java (yet)"); + + return -1; + } + + public FileStat fstat(FileDescriptor descriptor) { + handler.unimplementedError("fstat unimplemented"); + + return null; + } + + public FileStat fstat(int descriptor) { + handler.unimplementedError("fstat unimplemented"); + + return null; + } + + public int fstat(int fd, FileStat stat) { + handler.unimplementedError("fstat unimplemented"); + return -1; + } + + public int fstat(FileDescriptor descriptor, FileStat stat) { + handler.unimplementedError("fstat unimplemented"); + return -1; + } + + public int getegid() { + return LoginInfo.GID; + } + + public int geteuid() { + return LoginInfo.UID; + } + + public int getgid() { + return LoginInfo.GID; + } + + public int getdtablesize() { + handler.unimplementedError("getdtablesize unimplemented"); + return -1; + } + + public String getlogin() { + return helper.getlogin(); + } + + public int getpgid() { + return unimplementedInt("getpgid"); + } + + public int getpgrp() { + return unimplementedInt("getpgrp"); + } + + public int getpid() { + return helper.getpid(); + } + + public int getppid() { + return unimplementedInt("getppid"); + } + + public Passwd getpwent() { + return helper.getpwent(); + } + + public Passwd getpwuid(int which) { + return helper.getpwuid(which); + } + + public Group getgrgid(int which) { + handler.unimplementedError("getgrgid unimplemented"); + return null; + } + + public Passwd getpwnam(String which) { + handler.unimplementedError("getpwnam unimplemented"); + return null; + } + public Group getgrnam(String which) { + handler.unimplementedError("getgrnam unimplemented"); + return null; + } + + public Group getgrent() { + handler.unimplementedError("getgrent unimplemented"); + return null; + } + + public int setpwent() { + return helper.setpwent(); + } + + public int endpwent() { + return helper.endpwent(); + } + + public int setgrent() { + return unimplementedInt("setgrent"); + } + + public int endgrent() { + return unimplementedInt("endgrent"); + } + + public Pointer environ() { + handler.unimplementedError("environ"); + + return null; + } + + // @see setenv for more on the environment methods + public String getenv(String envName) { + return helper.getEnv().get(envName); + } + + public int getuid() { + return LoginInfo.UID; + } + + public int getrlimit(int resource, RLimit rlim) { + return unimplementedInt("getrlimit"); + } + + public int getrlimit(int resource, Pointer rlim) { + return unimplementedInt("getrlimit"); + } + + public RLimit getrlimit(int resource) { + handler.unimplementedError("getrlimit"); + + return null; + } + + public int setrlimit(int resource, RLimit rlim) { + return unimplementedInt("setrlimit"); + } + + public int setrlimit(int resource, Pointer rlim) { + return unimplementedInt("setrlimit"); + } + + public int setrlimit(int resource, long rlimCur, long rlimMax) { + return unimplementedInt("setrlimit"); + } + + public int fork() { + return -1; + } + + public boolean isatty(FileDescriptor fd) { + return (fd == FileDescriptor.in + || fd == FileDescriptor.out + || fd == FileDescriptor.err); + } + + public int isatty(int fd) { + return (fd == 0 + || fd == 1 + || fd == 2) ? 1 : 0; + } + + public int kill(int pid, int signal) { + return unimplementedInt("kill"); // FIXME: Can be implemented + } + + public int kill(long pid, int signal) { + return unimplementedInt("kill"); // FIXME: Can be implemented + } + + public SignalHandler signal(Signal sig, SignalHandler handler) { + return SunMiscSignal.signal(sig, handler); + } + + public int raise(int sig) { + return unimplementedInt("raise"); + } + + public int lchmod(String filename, int mode) { + return unimplementedInt("lchmod"); // FIXME: Can be implemented + } + + public int lchown(String filename, int user, int group) { + return unimplementedInt("lchown"); // FIXME: Can be implemented + } + + public int link(String oldpath, String newpath) { + return helper.link(oldpath, newpath); + } + + public FileStat lstat(String path) { + FileStat stat = allocateStat(); + + if (lstat(path, stat) < 0) handler.error(ENOENT, "lstat", path); + + return stat; + } + + public int lstat(String path, FileStat stat) { + return helper.lstat(path, stat); + } + + public int mkdir(String path, int mode) { + return helper.mkdir(path, mode); + } + + public int rmdir(String path) { + return helper.rmdir(path); + } + + public String readlink(String path) throws IOException { + // TODO: this should not be hardcoded to 256 bytes + ByteBuffer buffer = ByteBuffer.allocateDirect(256); + int result = helper.readlink(path, buffer, buffer.capacity()); + + if (result == -1) return null; + + buffer.position(0); + buffer.limit(result); + return Charset.forName("ASCII").decode(buffer).toString(); + } + + public int readlink(CharSequence path, byte[] buf, int bufsize) { + handler.unimplementedError("readlink"); + + return -1; + } + + public int readlink(CharSequence path, ByteBuffer buf, int bufsize) { + handler.unimplementedError("readlink"); + + return -1; + } + + public int readlink(CharSequence path, Pointer bufPtr, int bufsize) { + handler.unimplementedError("readlink"); + + return -1; + } + + // At this point the environment is not being used by any methods here. + // getenv/setenv/unsetenv do behave properly via POSIX definitions, but + // it is only a storage facility at the moment. In a future release, this + // map will be hooked up to the methods which depend on env. + public int setenv(String envName, String envValue, int overwrite) { + Map<String, String> env = helper.getEnv(); + + if (envName.contains("=")) { + handler.error(EINVAL, "setenv", envName); + return -1; + } + + // POSIX specified. Existence is success if overwrite is 0. + if (overwrite == 0 && env.containsKey(envName)) return 0; + + env.put(envName, envValue); + + return 0; + } + + public FileStat stat(String path) { + FileStat stat = allocateStat(); + + if (helper.stat(path, stat) < 0) handler.error(ENOENT, "stat", path); + + return stat; + } + + public int stat(String path, FileStat stat) { + return helper.stat(path, stat); + } + + public int symlink(String oldpath, String newpath) { + return helper.symlink(oldpath, newpath); + } + + public int setegid(int egid) { + return unimplementedInt("setegid"); + } + + public int seteuid(int euid) { + return unimplementedInt("seteuid"); + } + + public int setgid(int gid) { + return unimplementedInt("setgid"); + } + + public int getpgid(int pid) { + return unimplementedInt("getpgid"); + } + + public int setpgid(int pid, int pgid) { + return unimplementedInt("setpgid"); + } + + public int setpgrp(int pid, int pgrp) { + return unimplementedInt("setpgrp"); + } + + public int setsid() { + return unimplementedInt("setsid"); + } + + public int setuid(int uid) { + return unimplementedInt("setuid"); + } + + public int umask(int mask) { + // TODO: We can possibly maintain an internal mask and try and apply it to individual + // libc methods. + return 0; + } + + public int unsetenv(String envName) { + if (helper.getEnv().remove(envName) == null) { + handler.error(EINVAL, "unsetenv", envName); + return -1; + } + + return 0; + } + + public int utimes(String path, long[] atimeval, long[] mtimeval) { + long mtimeMillis; + if (mtimeval != null) { + assert mtimeval.length == 2; + mtimeMillis = (mtimeval[0] * 1000) + (mtimeval[1] / 1000); + } else { + mtimeMillis = System.currentTimeMillis(); + } + new File(path).setLastModified(mtimeMillis); + return 0; + } + + public int utimes(String path, Pointer times) { + return unimplementedInt("utimes"); + } + + public int futimes(int fd, long[] atimeval, long[] mtimeval) { + handler.unimplementedError("futimes"); + return unimplementedInt("futimes"); + } + + public int lutimes(String path, long[] atimeval, long[] mtimeval) { + handler.unimplementedError("lutimes"); + return unimplementedInt("lutimes"); + } + + public int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag) { + long mtimeMillis; + if (mtimespec != null) { + assert mtimespec.length == 2; + mtimeMillis = (mtimespec[0] * 1000) + (mtimespec[1] / 1000000); + } else { + mtimeMillis = System.currentTimeMillis(); + } + new File(path).setLastModified(mtimeMillis); + return 0; + } + + public int utimensat(int dirfd, String path, Pointer times, int flag) { + return unimplementedInt("utimensat"); + } + + public int futimens(int fd, long[] atimespec, long[] mtimespec) { + handler.unimplementedError("futimens"); + return unimplementedInt("futimens"); + } + + public int futimens(int fd, Pointer times) { + handler.unimplementedError("futimens"); + return unimplementedInt("futimens"); + } + + public int wait(int[] status) { + return unimplementedInt("wait"); + } + + public int waitpid(int pid, int[] status, int flags) { + return unimplementedInt("waitpid"); + } + + public int waitpid(long pid, int[] status, int flags) { + return unimplementedInt("waitpid"); + } + + public int getpriority(int which, int who) { + return unimplementedInt("getpriority"); + } + + public int setpriority(int which, int who, int prio) { + return unimplementedInt("setpriority"); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + return unimplementedInt("posix_spawnp"); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + return unimplementedInt("posix_spawnp"); + } + + public int errno() { + return JavaLibCHelper.errno(); + } + + public void errno(int value) { + JavaLibCHelper.errno(value); + } + + public int chdir(String path) { + return JavaLibCHelper.chdir(path); + } + + public boolean isNative() { + return false; + } + + public LibC libc() { + return null; + } + + private int unimplementedInt(String message) { + handler.unimplementedError(message); + + return -1; + } + + public long sysconf(Sysconf name) { + switch (name) { + case _SC_CLK_TCK: + return JavaTimes.HZ; + + default: + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + + public int fpathconf(int fd, Pathconf name) { + errno(Errno.EOPNOTSUPP.intValue()); + return -1; + } + + public Times times() { + return new JavaTimes(); + } + + public int flock(int fd, int mode) { + return unimplementedInt("flock"); + } + + public int dup(int fd) { + return unimplementedInt("dup"); + } + + public int dup2(int oldFd, int newFd) { + return unimplementedInt("dup2"); + } + + public int fcntlInt(int fd, Fcntl fcntlConst, int arg) { + return unimplementedInt("fcntl"); + } + + public int fcntl(int fd, Fcntl fcntlConst) { + return unimplementedInt("fcntl"); + } + + public int fcntl(int fd, Fcntl fcntlConst, int arg) { + return unimplementedInt("fcntl"); + } + + @Deprecated + public int fcntl(int fd, Fcntl fcntlConst, int... arg) { + return unimplementedInt("fcntl"); + } + + public int access(CharSequence path, int amode) { + handler.unimplementedError("access"); + + return -1; + } + + public int close(int fd) { + return unimplementedInt("close"); + } + + public int unlink(CharSequence path) { + handler.unimplementedError("unlink"); + + return -1; + } + + public int open(CharSequence path, int flags, int perm) { + handler.unimplementedError("open"); + + return -1; + } + + + public long read(int fd, byte[] buf, long n) { + handler.unimplementedError("read"); + + return -1; + } + public long write(int fd, byte[] buf, long n) { + handler.unimplementedError("write"); + + return -1; + } + public long read(int fd, ByteBuffer buf, long n) { + handler.unimplementedError("read"); + + return -1; + } + public long write(int fd, ByteBuffer buf, long n) { + handler.unimplementedError("write"); + + return -1; + } + public long pread(int fd, byte[] buf, long n, long offset) { + handler.unimplementedError("pread"); + + return -1; + } + public long pwrite(int fd, byte[] buf, long n, long offset) { + handler.unimplementedError("pwrite"); + + return -1; + } + public long pread(int fd, ByteBuffer buf, long n, long offset) { + handler.unimplementedError("pread"); + + return -1; + } + public long pwrite(int fd, ByteBuffer buf, long n, long offset) { + handler.unimplementedError("pwrite"); + + return -1; + } + + public int read(int fd, byte[] buf, int n) { + handler.unimplementedError("read"); + + return -1; + } + public int write(int fd, byte[] buf, int n) { + handler.unimplementedError("write"); + + return -1; + } + public int read(int fd, ByteBuffer buf, int n) { + handler.unimplementedError("read"); + + return -1; + } + public int write(int fd, ByteBuffer buf, int n) { + handler.unimplementedError("write"); + + return -1; + } + public int pread(int fd, byte[] buf, int n, int offset) { + handler.unimplementedError("pread"); + + return -1; + } + public int pwrite(int fd, byte[] buf, int n, int offset) { + handler.unimplementedError("pwrite"); + + return -1; + } + public int pread(int fd, ByteBuffer buf, int n, int offset) { + handler.unimplementedError("pread"); + + return -1; + } + public int pwrite(int fd, ByteBuffer buf, int n, int offset) { + handler.unimplementedError("pwrite"); + + return -1; + } + + public int lseek(int fd, long offset, int whence) { + handler.unimplementedError("lseek"); + + return -1; + } + + public long lseekLong(int fd, long offset, int whence) { + handler.unimplementedError("lseek"); + + return -1; + } + + public int pipe(int[] fds) { + handler.unimplementedError("pipe"); + + return -1; + } + + public int socketpair(int domain, int type, int protocol, int[] fds) { + handler.unimplementedError("socketpair"); + + return -1; + } + + public int sendmsg(int socket, MsgHdr message, int flags) { + handler.unimplementedError("sendmsg"); + + return -1; + } + + public int recvmsg(int socket, MsgHdr message, int flags) { + handler.unimplementedError("recvmsg"); + + return -1; + } + + public int truncate(CharSequence path, long length) { + handler.unimplementedError("truncate"); + + return -1; + } + + public int ftruncate(int fd, long offset) { + handler.unimplementedError("ftruncate"); + + return -1; + } + + public int rename(CharSequence oldName, CharSequence newName) { + // Very basic support. This might not work well with rename's semantics regarding symlinks. + + File oldFile = new File(oldName.toString()); + File newFile = new File(newName.toString()); + + if (oldFile.renameTo(newFile)) { + return 0; + } + + return -1; + } + + public String getcwd() { + return System.getProperty("user.dir"); + } + + public int fsync(int fd) { + handler.unimplementedError("fsync"); + return unimplementedInt("fsync not available for Java"); + } + + public int fdatasync(int fd) { + handler.unimplementedError("fdatasync"); + return unimplementedInt("fdatasync not available for Java"); + } + + public int mkfifo(String filename, int mode) { + handler.unimplementedError("mkfifo"); + return unimplementedInt("mkfifo not available for Java"); + } + + public int daemon(int nochdir, int noclose) { + handler.unimplementedError("daemon"); + return unimplementedInt("daemon not available for Java"); + } + + public long[] getgroups() { + handler.unimplementedError("getgroups"); + return null; + } + + public int getgroups(int size, int[] groups) { + handler.unimplementedError("getgroups"); + return unimplementedInt("getgroups not available for Java"); + } + + public String nl_langinfo(int item) { + handler.unimplementedError("nl_langinfo"); + return null; + } + + public String setlocale(int category, String locale) { + handler.unimplementedError("setlocale"); + return null; + } + + @Override + public String strerror(int code) { + handler.unimplementedError("strerror"); + return null; + } + + public Timeval allocateTimeval() { + handler.unimplementedError("allocateTimeval"); + return null; + } + + @Override + public int gettimeofday(Timeval tv) { + handler.unimplementedError("gettimeofday"); + return -1; + } + + public String gethostname() { + return helper.gethostname(); + } + + static final class LoginInfo { + public static final int UID = IDHelper.getInt("-u"); + public static final int GID = IDHelper.getInt("-g"); + public static final String USERNAME = IDHelper.getString("-un"); + } + private static final class IDHelper { + private static final String ID_CMD = Platform.IS_SOLARIS ? "/usr/xpg4/bin/id" : "/usr/bin/id"; + private static final int NOBODY = Platform.IS_WINDOWS ? 0 : Short.MAX_VALUE; + public static int getInt(String option) { + try { + Process p = Runtime.getRuntime().exec(new String[] { ID_CMD, option }); + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + return Integer.parseInt(r.readLine()); + } catch (IOException ex) { + return NOBODY; + } catch (NumberFormatException ex) { + return NOBODY; + } catch (SecurityException ex) { + return NOBODY; + } + } + public static String getString(String option) { + try { + Process p = Runtime.getRuntime().exec(new String[] { ID_CMD, option }); + BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); + return r.readLine(); + } catch (IOException ex) { + return null; + } + } + } + private static final class FakePasswd implements Passwd { + + public String getLoginName() { + return LoginInfo.USERNAME; + } + + public String getPassword() { + return ""; + } + + public long getUID() { + return LoginInfo.UID; + } + + public long getGID() { + return LoginInfo.GID; + } + + public int getPasswdChangeTime() { + return 0; + } + + public String getAccessClass() { + return ""; + } + + public String getGECOS() { + return getLoginName(); + } + + public String getHome() { + return "/"; + } + + public String getShell() { + return "/bin/sh"; + } + + public int getExpire() { + return ~0; + } + + } +}
diff --git a/src/main/java/jnr/posix/JavaPasswd.java b/src/main/java/jnr/posix/JavaPasswd.java new file mode 100644 index 0000000..cfd37b3 --- /dev/null +++ b/src/main/java/jnr/posix/JavaPasswd.java
@@ -0,0 +1,59 @@ +package jnr.posix; + +final class JavaPasswd implements Passwd { + private final POSIXHandler handler; + + public JavaPasswd(POSIXHandler handler) { + this.handler = handler; + } + + public String getAccessClass() { + handler.unimplementedError("passwd.pw_access unimplemented"); + + return null; + } + + public String getGECOS() { + return getLoginName(); + } + + public long getGID() { + return JavaPOSIX.LoginInfo.GID; + } + + public String getHome() { + return System.getProperty("user.home"); + } + + public String getLoginName() { + return System.getProperty("user.name"); + } + + public int getPasswdChangeTime() { + handler.unimplementedError("passwd.pw_change unimplemented"); + + return 0; + } + + public String getPassword() { + handler.unimplementedError("passwd.pw_passwd unimplemented"); + + return null; + } + + public String getShell() { + handler.unimplementedError("passwd.pw_env unimplemented"); + + return null; + } + + public long getUID() { + return JavaPOSIX.LoginInfo.UID; + } + + public int getExpire() { + handler.unimplementedError("passwd.expire unimplemented"); + + return ~0; + } +}
diff --git a/src/main/java/jnr/posix/JavaSecuredFile.java b/src/main/java/jnr/posix/JavaSecuredFile.java new file mode 100644 index 0000000..b7d9295 --- /dev/null +++ b/src/main/java/jnr/posix/JavaSecuredFile.java
@@ -0,0 +1,256 @@ +/** + * ** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * <p/> + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * <p/> + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * <p/> + * <p/> + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + * **** END LICENSE BLOCK **** + */ + +package jnr.posix; + +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URI; + +@SuppressWarnings("serial") +public class JavaSecuredFile extends File { + + public JavaSecuredFile(String pathname) { + super(pathname); + } + + public JavaSecuredFile(String parent, String child) { + super(parent, child); + } + + public JavaSecuredFile(File parent, String child) { + super(parent, child); + } + + public JavaSecuredFile(URI uri) { + super(uri); + } + + + @Override + public File getParentFile() { + String path = getParent(); + return path == null ? null : new JavaSecuredFile(path); + } + + @Override + public File getAbsoluteFile() { + String path = getAbsolutePath(); + return path == null ? null : new JavaSecuredFile(path); + } + + @Override + public File getCanonicalFile() throws IOException { + String path = getCanonicalPath(); + return path == null ? null : new JavaSecuredFile(path); + } + + @Override + public boolean canRead() { + try { + return super.canRead(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean canWrite() { + try { + return super.canWrite(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean exists() { + try { + return super.exists(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean isDirectory() { + try { + return super.isDirectory(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean isFile() { + try { + return super.isFile(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean isHidden() { + try { + return super.isHidden(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean delete() { + try { + return super.delete(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean mkdir() { + try { + return super.mkdir(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean mkdirs() { + try { + return super.mkdirs(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean renameTo(File dest) { + try { + return super.renameTo(dest); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean setLastModified(long time) { + try { + return super.setLastModified(time); + } catch (SecurityException e) { + return false; + } + } + + @Override + public boolean setReadOnly() { + try { + return super.setReadOnly(); + } catch (SecurityException e) { + return false; + } + } + + @Override + public String getCanonicalPath() throws IOException { + try { + return super.getCanonicalPath(); + } catch (SecurityException e) { + throw new IOException(e); + } + } + + @Override + public boolean createNewFile() throws IOException { + try { + return super.createNewFile(); + } catch (SecurityException e) { + throw new IOException(e); + } + } + + @Override + public String[] list() { + try { + return super.list(); + } catch (SecurityException e) { + return null; + } + } + + @Override + public String[] list(FilenameFilter filter) { + try { + return super.list(filter); + } catch (SecurityException e) { + return null; + } + } + + @Override + public File[] listFiles() { + try { + return super.listFiles(); + } catch (SecurityException e) { + return null; + } + } + + @Override + public File[] listFiles(FileFilter filter) { + try { + return super.listFiles(filter); + } catch (SecurityException e) { + return null; + } + } + + @Override + public long lastModified() { + try { + return super.lastModified(); + } catch (SecurityException e) { + return 0L; + } + } + + @Override + public long length() { + try { + return super.length(); + } catch (SecurityException e) { + return 0L; + } + } + +} \ No newline at end of file
diff --git a/src/main/java/jnr/posix/JavaTimes.java b/src/main/java/jnr/posix/JavaTimes.java new file mode 100644 index 0000000..44cb0d1 --- /dev/null +++ b/src/main/java/jnr/posix/JavaTimes.java
@@ -0,0 +1,22 @@ +package jnr.posix; + +final class JavaTimes implements Times { + private static final long startTime = System.currentTimeMillis(); + static final long HZ = 1000; + + public long utime() { + return Math.max(System.currentTimeMillis() - startTime, 1); + } + + public long stime() { + return 0; + } + + public long cutime() { + return 0; + } + + public long cstime() { + return 0; + } +}
diff --git a/src/main/java/jnr/posix/LazyPOSIX.java b/src/main/java/jnr/posix/LazyPOSIX.java new file mode 100644 index 0000000..14d5213 --- /dev/null +++ b/src/main/java/jnr/posix/LazyPOSIX.java
@@ -0,0 +1,635 @@ + +package jnr.posix; + +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import jnr.posix.util.ProcessMaker; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collection; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.constants.platform.Signal; + +final class LazyPOSIX implements POSIX { + + private final POSIXHandler handler; + private final boolean useNativePosix; + + // NOTE: because all implementations of POSIX that are loaded via loadPOSIX() + // are immutable, there is no need for 'posix' to be a volatile field. + // See http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html + // (but since volatile reads on x86 and x86_64 are cheap, do it anyway) + private volatile POSIX posix; + + LazyPOSIX(POSIXHandler handler, boolean useNativePosix) { + this.handler = handler; + this.useNativePosix = useNativePosix; + } + + private final POSIX posix() { + return posix != null ? posix : loadPOSIX(); + } + + private final synchronized POSIX loadPOSIX() { + return posix != null + ? posix + : (posix = POSIXFactory.loadPOSIX(handler, useNativePosix)); + } + + public ProcessMaker newProcessMaker(String... command) { + return posix().newProcessMaker(command); + } + + public ProcessMaker newProcessMaker() { + return posix().newProcessMaker(); + } + + public FileStat allocateStat() { + return posix().allocateStat(); + } + + public MsgHdr allocateMsgHdr() { + return posix().allocateMsgHdr(); + } + + public int chdir(String path) { + return posix().chdir(path); + } + + public int chmod(String filename, int mode) { + return posix().chmod(filename, mode); + } + + public int fchmod(int fd, int mode) { + return posix().fchmod(fd, mode); + } + + public int chown(String filename, int user, int group) { + return posix().chown(filename, user, group); + } + + public CharSequence crypt(CharSequence key, CharSequence salt) { + return posix().crypt(key, salt); + } + + public byte[] crypt(byte[] key, byte[] salt) { + return posix().crypt(key, salt); + } + + public int fchown(int fd, int user, int group) { + return posix().fchown(fd, user, group); + } + + public int endgrent() { + return posix().endgrent(); + } + + public int endpwent() { + return posix().endpwent(); + } + + public int errno() { + return posix().errno(); + } + + public void errno(int value) { + posix().errno(value); + } + + public int exec(String path, String... args) { + return posix().exec(path, args); + } + + public int exec(String path, String[] args, String[] envp) { + return posix().exec(path, args, envp); + } + + public int execv(String path, String[] argv) { + return posix().execv(path, argv); + } + + public int execve(String path, String[] argv, String[] envp) { + return posix().execve(path, argv, envp); + } + + public int fork() { + return posix().fork(); + } + + public FileStat fstat(int fd) { + return posix().fstat(fd); + } + + public int fstat(int fd, FileStat stat) { + return posix().fstat(fd, stat); + } + + public FileStat fstat(FileDescriptor descriptor) { + return posix().fstat(descriptor); + } + + public int fstat(FileDescriptor descriptor, FileStat stat) { + return posix().fstat(descriptor, stat); + } + + public int getegid() { + return posix().getegid(); + } + + public int geteuid() { + return posix().geteuid(); + } + + public int getgid() { + return posix().getgid(); + } + + public int getdtablesize() { + return posix().getdtablesize(); + } + + public Group getgrent() { + return posix().getgrent(); + } + + public Group getgrgid(int which) { + return posix().getgrgid(which); + } + + public Group getgrnam(String which) { + return posix().getgrnam(which); + } + + public String getlogin() { + return posix().getlogin(); + } + + public int getpgid() { + return posix().getpgid(); + } + + public int getpgid(int pid) { + return posix().getpgid(pid); + } + + public int getpgrp() { + return posix().getpgrp(); + } + + public int getpid() { + return posix().getpid(); + } + + public int getppid() { + return posix().getppid(); + } + + public int getpriority(int which, int who) { + return posix().getpriority(which, who); + } + + public Passwd getpwent() { + return posix().getpwent(); + } + + public Passwd getpwnam(String which) { + return posix().getpwnam(which); + } + + public Passwd getpwuid(int which) { + return posix().getpwuid(which); + } + + public int getuid() { + return posix().getuid(); + } + + public int getrlimit(int resource, RLimit rlim) { + return posix().getrlimit(resource, rlim); + } + + public int getrlimit(int resource, Pointer rlim) { + return posix().getrlimit(resource, rlim); + } + + public RLimit getrlimit(int resource) { + return posix().getrlimit(resource); + } + + public int setrlimit(int resource, RLimit rlim) { + return posix().setrlimit(resource, rlim); + } + + public int setrlimit(int resource, Pointer rlim) { + return posix().setrlimit(resource, rlim); + } + + public int setrlimit(int resource, long rlimCur, long rlimMax) { + return posix().setrlimit(resource, rlimCur, rlimMax); + } + + public boolean isatty(FileDescriptor descriptor) { + return posix().isatty(descriptor); + } + + public int isatty(int descriptor) { + return posix().isatty(descriptor); + } + + public int kill(int pid, int signal) { + return kill((long) pid, signal); + } + + public int kill(long pid, int signal) { + return posix().kill(pid, signal); + } + + public SignalHandler signal(Signal sig, SignalHandler handler) { + return posix().signal(sig, handler); + } + + public int raise(int sig) { + return posix().raise(sig); + } + + public int lchmod(String filename, int mode) { + return posix().lchmod(filename, mode); + } + + public int lchown(String filename, int user, int group) { + return posix().lchown(filename, user, group); + } + + public int link(String oldpath, String newpath) { + return posix().link(oldpath, newpath); + } + + public FileStat lstat(String path) { + return posix().lstat(path); + } + + public int lstat(String path, FileStat stat) { + return posix().lstat(path, stat); + } + + public int mkdir(String path, int mode) { + return posix().mkdir(path, mode); + } + + public String readlink(String path) throws IOException { + return posix().readlink(path); + } + + public int readlink(CharSequence path, byte[] buf, int bufsize) { + return posix().readlink(path, buf, bufsize); + } + + public int readlink(CharSequence path, ByteBuffer buf, int bufsize) { + return posix().readlink(path, buf, bufsize); + } + + public int readlink(CharSequence path, Pointer bufPtr, int bufsize) { + return posix().readlink(path, bufPtr, bufsize); + } + + public int rmdir(String path) { + return posix().rmdir(path); + } + + public int setegid(int egid) { + return posix().setegid(egid); + } + + public int seteuid(int euid) { + return posix().seteuid(euid); + } + + public int setgid(int gid) { + return posix().setgid(gid); + } + + public int setgrent() { + return posix().setgrent(); + } + + public int setpgid(int pid, int pgid) { + return posix().setpgid(pid, pgid); + } + + public int setpgrp(int pid, int pgrp) { + return posix().setpgrp(pid, pgrp); + } + + public int setpriority(int which, int who, int prio) { + return posix().setpriority(which, who, prio); + } + + public int setpwent() { + return posix().setpwent(); + } + + public int setsid() { + return posix().setsid(); + } + + public int setuid(int uid) { + return posix().setuid(uid); + } + + public FileStat stat(String path) { + return posix().stat(path); + } + + public int stat(String path, FileStat stat) { + return posix().stat(path, stat); + } + + public int symlink(String oldpath, String newpath) { + return posix().symlink(oldpath, newpath); + } + + public int umask(int mask) { + return posix().umask(mask); + } + + public int utimes(String path, long[] atimeval, long[] mtimeval) { + return posix().utimes(path, atimeval, mtimeval); + } + + public int utimes(String path, Pointer times) { + return posix().utimes(path, times); + } + + public int futimes(int fd, long[] atimeval, long[] mtimeval) { + return posix().futimes(fd, atimeval, mtimeval); + } + + public int lutimes(String path, long[] atimeval, long[] mtimeval) { + return posix().lutimes(path, atimeval, mtimeval); + } + + public int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag) { + return posix().utimensat(dirfd, path, atimespec, mtimespec, flag); + } + + public int utimensat(int dirfd, String path, Pointer times, int flag) { + return posix().utimensat(dirfd, path, times, flag); + } + + public int futimens(int fd, long[] atimespec, long[] mtimespec) { + return posix().futimens(fd, atimespec, mtimespec); + } + + public int futimens(int fd, Pointer times) { + return posix().futimens(fd, times); + } + + public int wait(int[] status) { + return posix().wait(status); + } + + public int waitpid(int pid, int[] status, int flags) { + return waitpid((long) pid, status, flags); + } + + public int waitpid(long pid, int[] status, int flags) { + return posix().waitpid(pid, status, flags); + } + + public boolean isNative() { + return posix().isNative(); + } + + public LibC libc() { + return posix().libc(); + } + + public Pointer environ() { + return posix().environ(); + } + + public String getenv(String envName) { + return posix().getenv(envName); + } + + public int setenv(String envName, String envValue, int overwrite) { + return posix().setenv(envName, envValue, overwrite); + } + + public int unsetenv(String envName) { + return posix().unsetenv(envName); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + return posix().posix_spawnp(path, fileActions, argv, envp); + } + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp) { + return posix().posix_spawnp(path, fileActions, spawnAttributes, argv, envp); + } + + public long sysconf(Sysconf name) { + return posix().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return posix().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return posix().fpathconf(fd, name); + } + + public Times times() { + return posix().times(); + } + + public int flock(int fd, int mode) { + return posix().flock(fd, mode); + } + + public int dup(int fd) { + return posix().dup(fd); + } + + public int dup2(int oldFd, int newFd) { + return posix().dup2(oldFd, newFd); + } + + public int fcntlInt(int fd, Fcntl fcntlConst, int arg) { + return posix().fcntlInt(fd, fcntlConst, arg); + } + + public int fcntl(int fd, Fcntl fcntlConst) { + return posix().fcntl(fd, fcntlConst); + } + + public int fcntl(int fd, Fcntl fcntlConst, int arg) { + return posix().fcntl(fd, fcntlConst, arg); + } + + @Deprecated + public int fcntl(int fd, Fcntl fcntlConst, int... arg) { + return posix().fcntl(fd, fcntlConst); + } + + public int access(CharSequence path, int amode) { + return posix().access(path, amode); + } + + public int close(int fd) { + return posix().close(fd); + } + + public int unlink(CharSequence path) { + return posix().unlink(path); + } + + public int open(CharSequence path, int flags, int perm) { + return posix().open(path, flags, perm); + } + + public long read(int fd, byte[] buf, long n) { + return posix().read(fd, buf, n); + } + public long write(int fd, byte[] buf, long n) { + return posix().write(fd, buf, n); + } + public long read(int fd, ByteBuffer buf, long n) { + return posix().read(fd, buf, n); + } + public long write(int fd, ByteBuffer buf, long n) { + return posix().write(fd, buf, n); + } + public long pread(int fd, byte[] buf, long n, long offset) { + return posix().pread(fd, buf, n, offset); + } + public long pwrite(int fd, byte[] buf, long n, long offset) { + return posix().pwrite(fd, buf, n, offset); + } + public long pread(int fd, ByteBuffer buf, long n, long offset) { + return posix().pread(fd, buf, n, offset); + } + public long pwrite(int fd, ByteBuffer buf, long n, long offset) { + return posix().pwrite(fd, buf, n, offset); + } + + public int read(int fd, byte[] buf, int n) + { + return posix().read(fd, buf, n); + } + public int write(int fd, byte[] buf, int n) { + return posix().write(fd, buf, n); + } + public int read(int fd, ByteBuffer buf, int n) { + return posix().read(fd, buf, n); + } + public int write(int fd, ByteBuffer buf, int n) { + return posix().write(fd, buf, n); + } + public int pread(int fd, byte[] buf, int n, int offset) { + return posix().pread(fd, buf, n, offset); + } + public int pwrite(int fd, byte[] buf, int n, int offset) { + return posix().pwrite(fd, buf, n, offset); + } + public int pread(int fd, ByteBuffer buf, int n, int offset) { + return posix().pread(fd, buf, n, offset); + } + public int pwrite(int fd, ByteBuffer buf, int n, int offset) { + return posix().pwrite(fd, buf, n, offset); + } + + public int lseek(int fd, long offset, int whence) { + return posix().lseek(fd, offset, whence); + } + + public long lseekLong(int fd, long offset, int whence) { + return posix().lseekLong(fd, offset, whence); + } + + public int pipe(int[] fds) { + return posix().pipe(fds); + } + + public int socketpair(int domain, int type, int protocol, int[] fds) { + return posix().socketpair(domain, type, protocol, fds); + } + + public int sendmsg(int socket, MsgHdr message, int flags) { + return posix().sendmsg(socket, message, flags); + } + + public int recvmsg(int socket, MsgHdr message, int flags) { + return posix().recvmsg(socket, message, flags); + } + + public int truncate(CharSequence path, long length) { + return posix().truncate(path, length); + } + + public int ftruncate(int fd, long offset) { + return posix().ftruncate(fd, offset); + } + + public int rename(CharSequence oldName, CharSequence newName) { + return posix().rename(oldName, newName); + } + + public String getcwd() { + return posix().getcwd(); + } + + public int fsync(int fd) { + return posix().fsync(fd); + } + + public int fdatasync(int fd) { + return posix().fdatasync(fd); + } + + public int mkfifo(String path, int mode) { + return posix().mkfifo(path, mode); + } + + public String gethostname() { + return posix().gethostname(); + } + + public int daemon(int nochdir, int noclose) { + return posix().daemon(nochdir, noclose); + } + + public long[] getgroups() { + return posix().getgroups(); + } + + public int getgroups(int size, int[] groups) { + return posix().getgroups(size, groups); + } + + public String nl_langinfo(int item) { + return posix().nl_langinfo(item); + } + + public String setlocale(int category, String locale) { + return posix().setlocale(category, locale); + } + + @Override + public String strerror(int code) { + return posix().strerror(code); + } + + @Override + public Timeval allocateTimeval() { return posix().allocateTimeval(); } + + @Override + public int gettimeofday(Timeval tv) { return posix().gettimeofday(tv); } +}
diff --git a/src/main/java/jnr/posix/LibC.java b/src/main/java/jnr/posix/LibC.java new file mode 100644 index 0000000..fb384e7 --- /dev/null +++ b/src/main/java/jnr/posix/LibC.java
@@ -0,0 +1,207 @@ +/* + **** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2007 Thomas E Enebo <enebo@acm.org> + * Copyright (C) 2007 Charles O Nutter <headius@headius.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +package jnr.posix; + +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import jnr.ffi.Variable; +import jnr.ffi.annotations.*; +import jnr.ffi.types.*; + +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.ffi.byref.IntByReference; + +public interface LibC { + int chmod(CharSequence filename, int mode); + int fchmod(int fd, int mode); + int chown(CharSequence filename, int user, int group); + int fchown(int fd, int user, int group); + int fstat(int fd, @Out @Transient FileStat stat); + int fstat64(int fd, @Out @Transient FileStat stat); + String getenv(CharSequence envName); + @IgnoreError int getegid(); + int setegid(int egid); + @IgnoreError int geteuid(); + int seteuid(int euid); + @IgnoreError int getgid(); + String getlogin(); + int setgid(int gid); + int getpgid(); + int getpgid(int pid); + int setpgid(int pid, int pgid); + int getpgrp(); + int setpgrp(int pid, int pgrp); + @IgnoreError int getppid(); + @IgnoreError int getpid(); + NativePasswd getpwent(); + NativePasswd getpwuid(int which); + NativePasswd getpwnam(CharSequence which); + NativeGroup getgrent(); + NativeGroup getgrgid(int which); + NativeGroup getgrnam(CharSequence which); + int setpwent(); + int endpwent(); + int setgrent(); + int endgrent(); + @IgnoreError int getuid(); + int setsid(); + int setuid(int uid); + int getrlimit(int resource, @Out RLimit rlim); + int getrlimit(int resource, Pointer rlim); + int setrlimit(int resource, @In RLimit rlim); + int setrlimit(int resource, Pointer rlim); + int kill(int pid, int signal); + int kill(long pid, int signal); + + int dup(int fd); + int dup2(int oldFd, int newFd); + + @Variadic(fixedCount = 2) + int fcntl(int fd, int fnctl, Flock arg); + @Variadic(fixedCount = 2) + int fcntl(int fd, int fnctl, Pointer arg); + @Variadic(fixedCount = 2) + int fcntl(int fd, int fnctl); + @Variadic(fixedCount = 2) + int fcntl(int fd, int fnctl, @u_int64_t int arg); + @Deprecated + int fcntl(int fd, int fnctl, int... arg); + int access(CharSequence path, int amode); + int getdtablesize(); + + public interface LibCSignalHandler { + @Delegate void signal(int sig); + } + @intptr_t long signal(int sig, LibCSignalHandler handler); + int raise(int raise); + int lchmod(CharSequence filename, int mode); + int lchown(CharSequence filename, int user, int group); + int link(CharSequence oldpath, CharSequence newpath); + int lstat(CharSequence path, @Out @Transient FileStat stat); + int lstat64(CharSequence path, @Out @Transient FileStat stat); + int mkdir(CharSequence path, int mode); + int rmdir(CharSequence path); + int stat(CharSequence path, @Out @Transient FileStat stat); + int stat64(CharSequence path, @Out @Transient FileStat stat); + int symlink(CharSequence oldpath, CharSequence newpath); + int readlink(CharSequence oldpath, @Out ByteBuffer buffer, int len); + int readlink(CharSequence path, @Out byte[] buffer, int len); + int readlink(CharSequence path, Pointer bufPtr, int bufsize); + int setenv(CharSequence envName, CharSequence envValue, int overwrite); + @IgnoreError int umask(int mask); + int unsetenv(CharSequence envName); + int utimes(CharSequence path, @In Timeval[] times); + int utimes(String path, @In Pointer times); + int futimes(int fd, @In Timeval[] times); + int lutimes(CharSequence path, @In Timeval[] times); + int utimensat(int dirfd, String path, Timespec[] times, int flag); + int utimensat(int dirfd, String path, @In Pointer times, int flag); + int futimens(int fd, Timespec[] times); + int futimens(int fd, @In Pointer times); + int fork(); + int waitpid(long pid, @Out int[] status, int options); + int wait(@Out int[] status); + int getpriority(int which, int who); + int setpriority(int which, int who, int prio); + @IgnoreError int isatty(int fd); + + @ssize_t long read(int fd, @Out byte[] dst, @size_t long len); + @ssize_t long write(int fd, @In byte[] src, @size_t long len); + @ssize_t long read(int fd, @Out ByteBuffer dst, @size_t long len); + @ssize_t long write(int fd, @In ByteBuffer src, @size_t long len); + @ssize_t long pread(int fd, @Out byte[] dst, @size_t long len, @off_t long offset); + @ssize_t long pwrite(int fd, @In byte[] src, @size_t long len, @off_t long offset); + @ssize_t long pread(int fd, @Out ByteBuffer dst, @size_t long len, @off_t long offset); + @ssize_t long pwrite(int fd, @In ByteBuffer src, @size_t long len, @off_t long offset); + + int read(int fd, @Out byte[] dst, int len); + int write(int fd, @In byte[] src, int len); + int read(int fd, @Out ByteBuffer dst, int len); + int write(int fd, @In ByteBuffer src, int len); + int pread(int fd, @Out byte[] dst, int len, int offset); + int pwrite(int fd, @In byte[] src, int len, int offset); + int pread(int fd, @Out ByteBuffer dst, int len, int offset); + int pwrite(int fd, @In ByteBuffer src, int len, int offset); + + long lseek(int fd, long offset, int whence); + int close(int fd); + int execv(CharSequence path, @In CharSequence[] argv); + int execve(CharSequence path, @In CharSequence[] argv, @In CharSequence[] envp); + int chdir(CharSequence path); + + public long sysconf(Sysconf name); + + public int confstr(Confstr name, @Out ByteBuffer buf, int len); + + public int fpathconf(int fd, Pathconf name); + + public @clock_t long times(@Out @Transient NativeTimes tms); + + int flock(int fd, int mode); + int unlink(CharSequence path); + @Variadic(fixedCount = 2) + int open(CharSequence path, int flags, @u_int32_t int perm); + int pipe(@Out int[] fds); + int truncate(CharSequence path, long length); + int ftruncate(int fd, long offset); + int rename(CharSequence oldName, CharSequence newName); + long getcwd(byte[] cwd, int len); + int gethostname(@Out ByteBuffer buffer, int len); + int fsync(int fd); + int fdatasync(int fd); + + int socketpair(int domain, int type, int protocol, @Out int[] fds); + int sendmsg(int socket, @In MsgHdr message, int flags); + int recvmsg(int socket, @Direct MsgHdr message, int flags); + + int setsockopt(int s, int level, int optname, @In ByteBuffer optval, int optlen); + int getsockopt(int s, int level, int optname, @Out ByteBuffer optval, @In @Out IntByReference optlen); + + Variable<Long> environ(); + + int syscall(int number); + int syscall(int number, int arg1); + int syscall(int number, int arg1, int arg2); + int syscall(int number, int arg1, int arg2, int arg3); + + int daemon(int nochdir, int noclose); + + int getgroups(int size, int[] groups); + + String nl_langinfo(int item); + String setlocale(int category, String locale); + + String strerror(int errno); + + int gettimeofday(Timeval tv, long alwaysNull); +} +
diff --git a/src/main/java/jnr/posix/LibCProvider.java b/src/main/java/jnr/posix/LibCProvider.java new file mode 100644 index 0000000..a94df89 --- /dev/null +++ b/src/main/java/jnr/posix/LibCProvider.java
@@ -0,0 +1,7 @@ + +package jnr.posix; + +public interface LibCProvider { + public LibC getLibC(); + public Crypt getCrypt(); +}
diff --git a/src/main/java/jnr/posix/Linux.java b/src/main/java/jnr/posix/Linux.java new file mode 100644 index 0000000..b7e7cb2 --- /dev/null +++ b/src/main/java/jnr/posix/Linux.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import jnr.constants.platform.PosixFadvise; + +/** + * Linux-specific POSIX-like functions. + */ +public interface Linux extends POSIX { + int ioprio_get(int which, int who); + int ioprio_set(int which, int who, int ioprio); + int posix_fadvise(int fd, long offset, long len, PosixFadvise advise); +}
diff --git a/src/main/java/jnr/posix/LinuxCmsgHdr.java b/src/main/java/jnr/posix/LinuxCmsgHdr.java new file mode 100644 index 0000000..9854e9d --- /dev/null +++ b/src/main/java/jnr/posix/LinuxCmsgHdr.java
@@ -0,0 +1,73 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +/** + * @author Bob McWhirter + */ +class LinuxCmsgHdr extends BaseCmsgHdr { + + public static class Layout extends StructLayout { + + protected Layout(Runtime runtime) { + super(runtime); + } + + // contrary to man page + public final size_t cmsg_len = new size_t(); + public final Signed32 cmsg_level = new Signed32(); + public final Signed32 cmsg_type = new Signed32(); + } + + public static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + public LinuxCmsgHdr(NativePOSIX posix, Pointer memory) { + super(posix, memory); + } + + public LinuxCmsgHdr(NativePOSIX posix, Pointer memory, int totalLen) { + super(posix, memory, totalLen); + } + + public void setLevel(int level) { + layout.cmsg_level.set(this.memory, level); + } + + public int getLevel() { + return layout.cmsg_level.get(this.memory); + } + + public void setType(int type) { + layout.cmsg_type.set(this.memory, type); + } + + public int getType() { + return layout.cmsg_type.get(this.memory); + } + + public int getLen() { + return (int) layout.cmsg_len.get(this.memory); + } + + void setLen(int len) { + layout.cmsg_len.set(this.memory, len); + } + + public String toString(String indent) { + StringBuffer buf = new StringBuffer(); + + buf.append(indent).append("cmsg {\n"); + buf.append(indent).append(" cmsg_len=").append(layout.cmsg_len.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_level=").append(layout.cmsg_level.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_type=").append(layout.cmsg_type.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_data=").append(getData()).append("\n"); + buf.append(indent).append("}"); + return buf.toString(); + } + + public String toString(){ + return toString( "" ); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStat32.java b/src/main/java/jnr/posix/LinuxFileStat32.java new file mode 100644 index 0000000..333fee2 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStat32.java
@@ -0,0 +1,140 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.*; + +public final class LinuxFileStat32 extends BaseFileStat implements NanosecondFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final Signed64 st_dev = new Signed64(); + public final Signed16 __pad1 = new Signed16(); + public final Signed32 st_ino = new Signed32(); + public final Signed32 st_mode = new Signed32(); + public final Signed32 st_nlink = new Signed32(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final Signed64 st_rdev = new Signed64(); + public final Signed16 __pad2 = new Signed16(); + public final Signed64 st_size = new Signed64(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_blocks = new Signed32(); + public final Signed32 __unused4 = new Signed32(); + public final Signed32 st_atim_sec = new Signed32(); // Time of last access (time_t) + public final Signed32 st_atim_nsec = new Signed32(); // Time of last access (nanoseconds) + public final Signed32 st_mtim_sec = new Signed32(); // Last data modification time (time_t) + public final Signed32 st_mtim_nsec = new Signed32(); // Last data modification time (nanoseconds) + public final Signed32 st_ctim_sec = new Signed32(); // Time of last status change (time_t) + public final Signed32 st_ctim_nsec = new Signed32(); // Time of last status change (nanoseconds) + public final Signed64 __unused5 = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStat32() { + this(null); + } + + public LinuxFileStat32(BaseNativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atim_sec.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atim_nsec.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctim_sec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctim_nsec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtim_sec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtim_nsec.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStat64.java b/src/main/java/jnr/posix/LinuxFileStat64.java new file mode 100644 index 0000000..1a51523 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStat64.java
@@ -0,0 +1,102 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class LinuxFileStat64 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final dev_t st_dev = new dev_t(); + public final ino_t st_ino = new ino_t(); + public final nlink_t st_nlink = new nlink_t(); + public final mode_t st_mode = new mode_t(); + public final uid_t st_uid = new uid_t(); + public final gid_t st_gid = new gid_t(); + public final dev_t st_rdev = new dev_t(); + public final off_t st_size = new off_t(); + public final blksize_t st_blksize = new blksize_t(); + public final blkcnt_t st_blocks = new blkcnt_t(); + public final time_t st_atime = new time_t(); // Time of last access (time_t) + public final SignedLong st_atimensec = new SignedLong(); // Time of last access (nanoseconds) + public final time_t st_mtime = new time_t(); // Last data modification time (time_t) + public final SignedLong st_mtimensec = new SignedLong(); // Last data modification time (nanoseconds) + public final time_t st_ctime = new time_t(); // Time of last status change (time_t) + public final SignedLong st_ctimensec = new SignedLong(); // Time of last status change (nanoseconds) + public final Signed64 __unused4 = new Signed64(); + public final Signed64 __unused5 = new Signed64(); + public final Signed64 __unused6 = new Signed64(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStat64(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStatAARCH64.java b/src/main/java/jnr/posix/LinuxFileStatAARCH64.java new file mode 100644 index 0000000..d5df659 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStatAARCH64.java
@@ -0,0 +1,104 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; +import jnr.posix.util.Platform; + +public final class LinuxFileStatAARCH64 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final dev_t st_dev = new dev_t(); + public final ino_t st_ino = new ino_t(); + public final mode_t st_mode = new mode_t(); + public final nlink_t st_nlink = new nlink_t(); + public final uid_t st_uid = new uid_t(); + public final gid_t st_gid = new gid_t(); + public final dev_t st_rdev = new dev_t(); + public final dev_t __pad1 = new dev_t(); + public final off_t st_size = new off_t(); + public final blksize_t st_blksize = new blksize_t(); + public final Signed32 __pad2 = new Signed32(); + public final blkcnt_t st_blocks = new blkcnt_t(); + public final time_t st_atime = new time_t(); // Time of last access + public final SignedLong st_atimensec = new SignedLong(); // Time of last access (nanoseconds) + public final time_t st_mtime = new time_t(); // Last data modification time + public final SignedLong st_mtimensec = new SignedLong(); // Last data modification time (nanoseconds) + public final time_t st_ctime = new time_t(); // Time of last status change + public final SignedLong st_ctimensec = new SignedLong(); // Time of last status change (nanoseconds) + public final Signed32 __unused4 = new Signed32(); + public final Signed32 __unused5 = new Signed32(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStatAARCH64(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStatLOONGARCH64.java b/src/main/java/jnr/posix/LinuxFileStatLOONGARCH64.java new file mode 100644 index 0000000..54b1871 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStatLOONGARCH64.java
@@ -0,0 +1,104 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; +import jnr.posix.util.Platform; + +public final class LinuxFileStatLOONGARCH64 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final dev_t st_dev = new dev_t(); + public final ino_t st_ino = new ino_t(); + public final mode_t st_mode = new mode_t(); + public final nlink_t st_nlink = new nlink_t(); + public final uid_t st_uid = new uid_t(); + public final gid_t st_gid = new gid_t(); + public final dev_t st_rdev = new dev_t(); + public final dev_t __pad1 = new dev_t(); + public final off_t st_size = new off_t(); + public final blksize_t st_blksize = new blksize_t(); + public final Signed32 __pad2 = new Signed32(); + public final blkcnt_t st_blocks = new blkcnt_t(); + public final time_t st_atime = new time_t(); // Time of last access + public final SignedLong st_atimensec = new SignedLong(); // Time of last access (nanoseconds) + public final time_t st_mtime = new time_t(); // Last data modification time + public final SignedLong st_mtimensec = new SignedLong(); // Last data modification time (nanoseconds) + public final time_t st_ctime = new time_t(); // Time of last status change + public final SignedLong st_ctimensec = new SignedLong(); // Time of last status change (nanoseconds) + public final Signed32 __unused4 = new Signed32(); + public final Signed32 __unused5 = new Signed32(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStatLOONGARCH64(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStatMIPS64.java b/src/main/java/jnr/posix/LinuxFileStatMIPS64.java new file mode 100644 index 0000000..ac16548 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStatMIPS64.java
@@ -0,0 +1,110 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class LinuxFileStatMIPS64 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final Unsigned64 st_dev = new Unsigned64(); + public final Unsigned32 __pad01 = new Unsigned32(); + public final Unsigned32 __pad02 = new Unsigned32(); + public final Unsigned32 __pad03 = new Unsigned32(); + + public final Unsigned64 st_ino = new Unsigned64(); + public final Unsigned64 st_mode = new Unsigned64(); + public final Unsigned32 st_nlink = new Unsigned32(); + public final Unsigned32 st_uid = new Unsigned32(); + public final Unsigned32 st_gid = new Unsigned32(); + public final Unsigned64 st_rdev = new Unsigned64(); + public final Unsigned32 __pad11 = new Unsigned32(); + public final Unsigned32 __pad12 = new Unsigned32(); + public final Unsigned32 __pad13 = new Unsigned32(); + + public final Signed64 st_size = new Signed64(); + + public final Unsigned64 st_atime = new Unsigned64(); // Time of last access (time_t) + public final Unsigned64 st_atimensec = new Unsigned64(); // Time of last access (nanoseconds) + public final Unsigned64 st_mtime = new Unsigned64(); // Last data modification time (time_t) + public final Unsigned64 st_mtimensec = new Unsigned64(); // Last data modification time (nanoseconds) + public final Unsigned64 st_ctime = new Unsigned64(); // Time of last status change (time_t) + public final Unsigned64 st_ctimensec = new Unsigned64(); // Time of last status change (nanoseconds) + + public final Unsigned64 st_blksize = new Unsigned64(); + public final Unsigned32 __pad20 = new Unsigned32(); + public final Unsigned64 st_blocks = new Unsigned64(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStatMIPS64(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStatRISCV64.java b/src/main/java/jnr/posix/LinuxFileStatRISCV64.java new file mode 100644 index 0000000..94093ea --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStatRISCV64.java
@@ -0,0 +1,104 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; +import jnr.posix.util.Platform; + +public final class LinuxFileStatRISCV64 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final dev_t st_dev = new dev_t(); + public final ino_t st_ino = new ino_t(); + public final mode_t st_mode = new mode_t(); + public final nlink_t st_nlink = new nlink_t(); + public final uid_t st_uid = new uid_t(); + public final gid_t st_gid = new gid_t(); + public final dev_t st_rdev = new dev_t(); + public final dev_t __pad1 = new dev_t(); + public final off_t st_size = new off_t(); + public final blksize_t st_blksize = new blksize_t(); + public final Signed32 __pad2 = new Signed32(); + public final blkcnt_t st_blocks = new blkcnt_t(); + public final time_t st_atime = new time_t(); // Time of last access + public final SignedLong st_atimensec = new SignedLong(); // Time of last access (nanoseconds) + public final time_t st_mtime = new time_t(); // Last data modification time + public final SignedLong st_mtimensec = new SignedLong(); // Last data modification time (nanoseconds) + public final time_t st_ctime = new time_t(); // Time of last status change + public final SignedLong st_ctimensec = new SignedLong(); // Time of last status change (nanoseconds) + public final Signed32 __unused4 = new Signed32(); + public final Signed32 __unused5 = new Signed32(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStatRISCV64(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxFileStatSPARCV9.java b/src/main/java/jnr/posix/LinuxFileStatSPARCV9.java new file mode 100644 index 0000000..bc620c7 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxFileStatSPARCV9.java
@@ -0,0 +1,103 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; + +public class LinuxFileStatSPARCV9 extends BaseFileStat implements NanosecondFileStat { + public static final class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final dev_t st_dev = new dev_t(); + public final Unsigned16 __pad1 = new Unsigned16(); + public final ino_t st_ino = new ino_t(); + public final mode_t st_mode = new mode_t(); + public final nlink_t st_nlink = new nlink_t(); + public final uid_t st_uid = new uid_t(); + public final gid_t st_gid = new gid_t(); + public final dev_t st_rdev = new dev_t(); + public final Unsigned16 __pad2 = new Unsigned16(); + public final off_t st_size = new off_t(); + public final blksize_t st_blksize = new blksize_t(); + public final blkcnt_t st_blocks = new blkcnt_t(); + public final time_t st_atime = new time_t(); // Time of last access (time_t) + public final SignedLong st_atimensec = new SignedLong(); // Time of last access (nanoseconds) + public final time_t st_mtime = new time_t(); // Last data modification time (time_t) + public final SignedLong st_mtimensec = new SignedLong(); // Last data modification time (nanoseconds) + public final time_t st_ctime = new time_t(); // Time of last status change (time_t) + public final SignedLong st_ctimensec = new SignedLong(); // Time of last status change (nanoseconds) + public final Unsigned64 __unused4 = new Unsigned64(); + public final Unsigned64 __unused5 = new Unsigned64(); + } + + public static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public LinuxFileStatSPARCV9(LinuxPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int) layout.st_mode.get(memory); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } + + public int nlink() { + return (int) layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout. st_size.get(memory); + } + + public int uid() { + return (int) layout.st_uid.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/LinuxIoPrio.java b/src/main/java/jnr/posix/LinuxIoPrio.java new file mode 100644 index 0000000..3b09993 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxIoPrio.java
@@ -0,0 +1,24 @@ +package jnr.posix; + +public abstract class LinuxIoPrio { + public static int IOPRIO_WHO_PROCESS = 1; + public static int IOPRIO_WHO_PGRP = 2; + public static int IOPRIO_WHO_USER = 3; + + public static int IOPRIO_CLASS_NONE = 0; + public static int IOPRIO_CLASS_RT = 1; + public static int IOPRIO_CLASS_BE = 2; + public static int IOPRIO_CLASS_IDLE = 3; + + public static int IOPRIO_PRIO_VALUE(int _class, int data) { + return (_class << 13) | data; + } + + public static int IOPRIO_PRIO_CLASS(int mask) { + return mask >> 13; + } + + public static int IOPRIO_PRIO_DATA(int mask) { + return mask & 0x0f; + } +}
diff --git a/src/main/java/jnr/posix/LinuxLibC.java b/src/main/java/jnr/posix/LinuxLibC.java new file mode 100644 index 0000000..3275843 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxLibC.java
@@ -0,0 +1,22 @@ +package jnr.posix; + +import jnr.ffi.annotations.In; +import jnr.ffi.annotations.NulTerminate; +import jnr.ffi.annotations.Out; +import jnr.ffi.annotations.Transient; +import jnr.ffi.types.off_t; +import java.nio.ByteBuffer; + +public interface LinuxLibC extends UnixLibC { + public int __fxstat(int version, int fd, @Out @Transient FileStat stat); + public int __lxstat(int version, CharSequence path, @Out @Transient FileStat stat); + public int __lxstat(int version, @NulTerminate @In ByteBuffer path, @Out @Transient FileStat stat); + public int __xstat(int version, CharSequence path, @Out @Transient FileStat stat); + public int __xstat(int version, @NulTerminate @In ByteBuffer path, @Out @Transient FileStat stat); + public int __fxstat64(int version, int fd, @Out @Transient FileStat stat); + public int __lxstat64(int version, CharSequence path, @Out @Transient FileStat stat); + public int __lxstat64(int version, @NulTerminate @In ByteBuffer path, @Out @Transient FileStat stat); + public int __xstat64(int version, CharSequence path, @Out @Transient FileStat stat); + public int __xstat64(int version, @NulTerminate @In ByteBuffer path, @Out @Transient FileStat stat); + public int posix_fadvise(int fd, @off_t long offset, @off_t long len, int advice); +}
diff --git a/src/main/java/jnr/posix/LinuxMsgHdr.java b/src/main/java/jnr/posix/LinuxMsgHdr.java new file mode 100644 index 0000000..039479c --- /dev/null +++ b/src/main/java/jnr/posix/LinuxMsgHdr.java
@@ -0,0 +1,173 @@ +package jnr.posix; + +import java.util.ArrayList; +import java.util.List; +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +/** + * @author Bob McWhirter + */ +class LinuxMsgHdr extends BaseMsgHdr { + + public static class Layout extends StructLayout { + protected Layout(Runtime runtime) { + super(runtime); + } + + public final Pointer msg_name = new Pointer(); + public final socklen_t msg_namelen = new socklen_t(); + public final Pointer msg_iov = new Pointer(); + public final size_t msg_iovlen = new size_t(); + public final Pointer msg_control = new Pointer(); + public final size_t msg_controllen = new size_t(); + public final Signed32 msg_flags = new Signed32(); + } + + private static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + protected LinuxMsgHdr(NativePOSIX posix) { + super(posix, layout); + setName(null); + } + + CmsgHdr allocateCmsgHdrInternal(NativePOSIX posix, Pointer pointer, int len) { + if (len > 0) { + return new LinuxCmsgHdr(posix, pointer, len); + } else { + return new LinuxCmsgHdr(posix, pointer); + } + } + + @Override + void setControlPointer(Pointer control) { + layout.msg_control.set(this.memory, control); + } + + @Override + void setControlLen(int len) { + layout.msg_controllen.set(this.memory, len); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("msghdr {\n"); + buf.append(" msg_name=").append(getName()).append(",\n"); + buf.append(" msg_namelen=").append(getNameLen()).append(",\n"); + + buf.append(" msg_iov=[\n"); + Pointer iovp = layout.msg_iov.get(this.memory); + + int numIov = getIovLen(); + for (int i = 0; i < numIov; ++i) { + Pointer eachp = iovp.slice(i * BaseIovec.layout.size()); + buf.append(new BaseIovec(posix, eachp).toString(" ")); + if (i < (numIov - 1)) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + + buf.append(" msg_control=[\n"); + + CmsgHdr[] controls = getControls(); + for (int i = 0; i < controls.length; ++i) { + buf.append(((LinuxCmsgHdr) controls[i]).toString(" ")); + if (i < controls.length - 1) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + buf.append(" msg_controllen=").append(layout.msg_controllen.get(this.memory)).append("\n"); + + buf.append(" msg_iovlen=").append(getIovLen()).append(",\n"); + buf.append(" msg_flags=").append(getFlags()).append(",\n"); + buf.append("}"); + return buf.toString(); + } + + @Override + void setNamePointer(Pointer name) { + layout.msg_name.set( this.memory, name ); + } + + @Override + Pointer getNamePointer() { + return layout.msg_name.get( this.memory ); + } + + + @Override + void setNameLen(int len) { + layout.msg_namelen.set(this.memory, len); + } + + @Override + int getNameLen() { + return (int) layout.msg_namelen.get(this.memory); + } + + @Override + void setIovPointer(Pointer iov) { + layout.msg_iov.set(this.memory, iov); + } + + @Override + Pointer getIovPointer() { + return layout.msg_iov.get( this.memory ); + } + + @Override + void setIovLen(int len) { + layout.msg_iovlen.set(this.memory, len); + } + + @Override + int getIovLen() { + return (int) layout.msg_iovlen.get(this.memory); + } + + @Override + Pointer getControlPointer() { + return layout.msg_control.get(this.memory); + } + + public int getControlLen() { + return (int) layout.msg_controllen.get(this.memory); + } + + public void setFlags(int flags) { + layout.msg_flags.set(this.memory, flags); + } + + public int getFlags() { + return layout.msg_flags.get(this.memory); + } + + @Override + public CmsgHdr[] getControls() { + int len = getControlLen(); + if (len == 0) { + return new CmsgHdr[0]; + } + + List<CmsgHdr> control = new ArrayList<CmsgHdr>(); + + int offset = 0; + + Pointer controlPtr = getControlPointer(); + + while (offset < len) { + CmsgHdr each = allocateCmsgHdrInternal(posix, controlPtr.slice(offset), -1); + offset += LinuxSocketMacros.INSTANCE.CMSG_ALIGN( each.getLen() ); + control.add(each); + } + + return control.toArray(new CmsgHdr[control.size()]); + } +}
diff --git a/src/main/java/jnr/posix/LinuxPOSIX.java b/src/main/java/jnr/posix/LinuxPOSIX.java new file mode 100644 index 0000000..4a65400 --- /dev/null +++ b/src/main/java/jnr/posix/LinuxPOSIX.java
@@ -0,0 +1,357 @@ +package jnr.posix; + +import jnr.constants.platform.Errno; +import jnr.constants.platform.PosixFadvise; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.mapper.FromNativeContext; +import jnr.posix.util.Platform; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; + +final class LinuxPOSIX extends BaseNativePOSIX implements Linux { + private final boolean use_stat64; + private final int statVersion; + + LinuxPOSIX(LibCProvider libcProvider, POSIXHandler handler) { + super(libcProvider, handler); + + statVersion = getStatVersion(); + use_stat64 = statVersion >= 0; + } + + private int getStatVersion() { + if (Platform.IS_32_BIT || "sparcv9".equals(Platform.ARCH) || Platform.ARCH.contains("mips64")) { + return 3; + } else { + FileStat stat = allocateStat(); + try { + if (((LinuxLibC) libc()).__xstat64(0, "/dev/null", stat) < 0) { + return 1; + } + return 0; + } catch (UnsatisfiedLinkError ex) { + return -1; + } + } + } + + @Override + public FileStat allocateStat() { + if (Platform.IS_32_BIT) { + return new LinuxFileStat32(this); + } else { + if ("aarch64".equals(Platform.ARCH)) { + return new LinuxFileStatAARCH64(this); + } else if ("riscv64".equals(Platform.ARCH)) { + return new LinuxFileStatRISCV64(this); + } else if ("sparcv9".equals(Platform.ARCH)) { + return new LinuxFileStatSPARCV9(this); + } else if ("loongarch64".equals(Platform.ARCH)) { + return new LinuxFileStatLOONGARCH64(this); + } else { + if (Platform.ARCH.contains("mips64")) { + return new LinuxFileStatMIPS64(this); + } + return new LinuxFileStat64(this); + } + } + } + + public MsgHdr allocateMsgHdr() { + return new LinuxMsgHdr(this); + } + + @Override + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 80); + } + + @Override + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 336); + } + + public SocketMacros socketMacros() { + return LinuxSocketMacros.INSTANCE; + } + + private int old_fstat(int fd, FileStat stat) { + try { + return super.fstat(fd, stat); + } catch (UnsatisfiedLinkError ex2) { + handler.unimplementedError("fstat"); + return -1; + } + } + + @Override + public int fstat(int fd, FileStat stat) { + if (use_stat64) { + return ((LinuxLibC) libc()).__fxstat64(statVersion, fd, stat); + } else { + return old_fstat(fd, stat); + } + } + + @Override + public FileStat fstat(int fd) { + FileStat stat = allocateStat(); + int ret = fstat(fd, stat); + if (ret < 0) handler.error(Errno.valueOf(errno()), "fstat", Integer.toString(fd)); + return stat; + } + + @Override + public int fstat(FileDescriptor fileDescriptor, FileStat stat) { + return fstat(helper.getfd(fileDescriptor), stat); + } + + @Override + public FileStat fstat(FileDescriptor fileDescriptor) { + FileStat stat = allocateStat(); + int fd = helper.getfd(fileDescriptor); + int ret = fstat(fd, stat); + if (ret < 0) handler.error(Errno.valueOf(errno()), "fstat", Integer.toString(fd)); + return stat; + } + + private final int old_lstat(String path, FileStat stat) { + try { + return super.lstat(path, stat); + } catch (UnsatisfiedLinkError ex) { + handler.unimplementedError("lstat"); + return -1; + } + } + + @Override + public int lstat(String path, FileStat stat) { + if (use_stat64) { + return ((LinuxLibC) libc()).__lxstat64(statVersion, path, stat); + } else { + return old_lstat(path, stat); + } + } + + @Override + public FileStat lstat(String path) { + FileStat stat = allocateStat(); + int ret = lstat(path, stat); + if (ret < 0) handler.error(Errno.valueOf(errno()), "lstat", path); + return stat; + } + + private final int old_stat(String path, FileStat stat) { + try { + return super.stat(path, stat); + } catch (UnsatisfiedLinkError ex) { + handler.unimplementedError("stat"); + return -1; + } + } + + @Override + public int stat(String path, FileStat stat) { + + if (use_stat64) { + return ((LinuxLibC) libc()).__xstat64(statVersion, path, stat); + } else { + return old_stat(path, stat); + } + } + + @Override + public FileStat stat(String path) { + FileStat stat = allocateStat(); + int ret = stat(path, stat); + if (ret < 0) handler.error(Errno.valueOf(errno()), "stat", path); + return stat; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new LinuxPasswd((Pointer) arg) : null; + } + }; + + static final public class Syscall { + static final ABI _ABI_X86_32 = new ABI_X86_32(); + static final ABI _ABI_X86_64 = new ABI_X86_64(); + static final ABI _ABI_AARCH64 = new ABI_AARCH64(); + static final ABI _ABI_SPARCV9 = new ABI_SPARCV9(); + static final ABI _ABI_PPC64 = new ABI_PPC64(); + static final ABI _ABI_MIPS64 = new ABI_MIPS64(); + static final ABI _ABI_LOONGARCH64 = new ABI_LOONGARCH64(); + static final ABI _ABI_RISCV64 = new ABI_RISCV64(); + + public static ABI abi() { + if ("x86_64".equals(Platform.ARCH)) { + if (Platform.IS_64_BIT) { + return _ABI_X86_64; + } + } else if ("i386".equals(Platform.ARCH)) { + return _ABI_X86_32; + } else if ("aarch64".equals(Platform.ARCH)) { + return _ABI_AARCH64; + } else if ("sparcv9".equals(Platform.ARCH)) { + return _ABI_SPARCV9; + } else if (Platform.ARCH.contains("ppc64")) { + return _ABI_PPC64; + } else if (Platform.ARCH.contains("mips64")) { + return _ABI_MIPS64; + } else if (Platform.ARCH.contains("loongarch64")) { + return _ABI_LOONGARCH64; + } else if (Platform.ARCH.contains("riscv64")) { + return _ABI_RISCV64; + } + return null; + } + + interface ABI { + public int __NR_ioprio_set(); + public int __NR_ioprio_get(); + } + + /** @see /usr/include/asm/unistd_32.h */ + final static class ABI_X86_32 implements ABI { + @Override + public int __NR_ioprio_set() { + return 289; + } + @Override + public int __NR_ioprio_get() { + return 290; + } + } + + /** @see /usr/include/asm/unistd_64.h */ + final static class ABI_X86_64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 251; + } + @Override + public int __NR_ioprio_get() { + return 252; + } + } + + /** @see /usr/include/asm-generic/unistd.h */ + final static class ABI_AARCH64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 30; + } + @Override + public int __NR_ioprio_get() { + return 31 ; + } + } + + /** @see /usr/include/asm/unistd.h */ + final static class ABI_SPARCV9 implements ABI { + @Override + public int __NR_ioprio_set() { + return 196; + } + @Override + public int __NR_ioprio_get() { + return 218; + } + } + + /** @see /usr/include/asm-generic/unistd.h */ + final static class ABI_PPC64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 273; + } + @Override + public int __NR_ioprio_get() { + return 274 ; + } + } + + /** @see /usr/include/asm/unistd.h */ + final static class ABI_MIPS64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 5273; + } + @Override + public int __NR_ioprio_get() { + return 5274; + } + } + + /** @see /usr/include/asm-generic/unistd.h */ + final static class ABI_LOONGARCH64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 30; + } + @Override + public int __NR_ioprio_get() { + return 31; + } + } + + /** @see /usr/include/asm-generic/unistd.h */ + final static class ABI_RISCV64 implements ABI { + @Override + public int __NR_ioprio_set() { + return 30; + } + @Override + public int __NR_ioprio_get() { + return 31 ; + } + } + } + + + public int ioprio_get(int which, int who) { + Syscall.ABI abi = Syscall.abi(); + if (abi == null) { + handler.unimplementedError("ioprio_get"); + return -1; + } + + return libc().syscall(abi.__NR_ioprio_get(), which, who); + } + + public int ioprio_set(int which, int who, int ioprio) { + Syscall.ABI abi = Syscall.abi(); + if (abi == null) { + handler.unimplementedError("ioprio_set"); + return -1; + } + + return libc().syscall(abi.__NR_ioprio_set(), which, who, ioprio); + } + + public int posix_fadvise(int fd, long offset, long len, PosixFadvise advise) { + return ((LinuxLibC) libc()).posix_fadvise(fd, offset, len, advise.intValue()); + } +}
diff --git a/src/main/java/jnr/posix/LinuxPasswd.java b/src/main/java/jnr/posix/LinuxPasswd.java new file mode 100644 index 0000000..56669ba --- /dev/null +++ b/src/main/java/jnr/posix/LinuxPasswd.java
@@ -0,0 +1,57 @@ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class LinuxPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Signed32 pw_uid = new Signed32(); // user id + public final Signed32 pw_gid = new Signed32(); // user id + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + LinuxPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return ""; + } + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + public long getGID() { + return layout.pw_gid.get(memory); + } + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + public long getUID() { + return layout.pw_uid.get(memory); + } + public int getPasswdChangeTime() { + return 0; + } + public int getExpire() { + return Integer.MAX_VALUE; + } +}
diff --git a/src/main/java/jnr/posix/LinuxSocketMacros.java b/src/main/java/jnr/posix/LinuxSocketMacros.java new file mode 100644 index 0000000..d124f1c --- /dev/null +++ b/src/main/java/jnr/posix/LinuxSocketMacros.java
@@ -0,0 +1,29 @@ +package jnr.posix; + +import jnr.ffi.*; +import jnr.ffi.Runtime; + +/** + * @author Bob McWhirter + */ +public class LinuxSocketMacros implements SocketMacros { + + public static final LinuxSocketMacros INSTANCE = new LinuxSocketMacros(); + + public int CMSG_ALIGN(int len) { + int sizeof_size_t = Runtime.getSystemRuntime().findType(TypeAlias.size_t).size(); + return (len + sizeof_size_t - 1) & ~(sizeof_size_t - 1); + } + + public int CMSG_SPACE(int l) { + return CMSG_ALIGN(l) + CMSG_ALIGN(LinuxCmsgHdr.layout.size()); + } + + public int CMSG_LEN(int l) { + return CMSG_ALIGN( LinuxCmsgHdr.layout.size() ) + l; + } + + public Pointer CMSG_DATA(Pointer cmsg) { + return cmsg.slice(CMSG_ALIGN(LinuxCmsgHdr.layout.size())); + } +}
diff --git a/src/main/java/jnr/posix/MacOSCmsgHdr.java b/src/main/java/jnr/posix/MacOSCmsgHdr.java new file mode 100644 index 0000000..d75c934 --- /dev/null +++ b/src/main/java/jnr/posix/MacOSCmsgHdr.java
@@ -0,0 +1,69 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +/** + * @author Bob McWhirter + */ +class MacOSCmsgHdr extends BaseCmsgHdr { + + public static class Layout extends StructLayout { + + protected Layout(Runtime runtime) { + super(runtime); + } + + public final Unsigned32 cmsg_len = new Unsigned32(); + public final Signed32 cmsg_level = new Signed32(); + public final Signed32 cmsg_type = new Signed32(); + } + + public static final Layout layout = new Layout(Runtime.getSystemRuntime()); + + public MacOSCmsgHdr(NativePOSIX posix, Pointer memory) { + super(posix, memory); + } + + public MacOSCmsgHdr(NativePOSIX posix, Pointer memory, int totalLen) { + super(posix, memory, totalLen ); + } + + public void setLevel(int level) { + layout.cmsg_level.set(this.memory, level); + } + + public int getLevel() { + return layout.cmsg_level.get(this.memory); + } + + public void setType(int type) { + layout.cmsg_type.set(this.memory, type); + } + + public int getType() { + return layout.cmsg_type.get(this.memory); + } + + public int getLen() { + return (int) layout.cmsg_len.get(this.memory); + } + + void setLen(int len) { + layout.cmsg_len.set(this.memory, len); + } + + public String toString(String indent) { + StringBuffer buf = new StringBuffer(); + + buf.append(indent).append("cmsg {\n"); + buf.append(indent).append(" cmsg_len=").append(layout.cmsg_len.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_level=").append(layout.cmsg_level.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_type=").append(layout.cmsg_type.get(this.memory)).append("\n"); + buf.append(indent).append(" cmsg_data=").append(getData()).append("\n"); + buf.append(indent).append("}"); + return buf.toString(); + } + +}
diff --git a/src/main/java/jnr/posix/MacOSFileStat.java b/src/main/java/jnr/posix/MacOSFileStat.java new file mode 100644 index 0000000..e9f42f2 --- /dev/null +++ b/src/main/java/jnr/posix/MacOSFileStat.java
@@ -0,0 +1,139 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class MacOSFileStat extends BaseFileStat implements NanosecondFileStat { + public static class Layout extends StructLayout { + + public Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends SignedLong { + } + public final Signed32 st_dev = new Signed32(); + public final Signed32 st_ino = new Signed32(); + public final Signed16 st_mode = new Signed16(); + public final Signed16 st_nlink = new Signed16(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final Signed32 st_rdev = new Signed32(); + public final time_t st_atime = new time_t(); + public final SignedLong st_atimensec = new SignedLong(); + public final time_t st_mtime = new time_t(); + public final SignedLong st_mtimensec = new SignedLong(); + public final time_t st_ctime = new time_t(); + public final SignedLong st_ctimensec = new SignedLong(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_blocks = new Signed64(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_flags = new Signed32(); + public final Signed32 st_gen = new Signed32(); + public final Signed32 st_lspare = new Signed32(); + public final Signed64 st_qspare0 = new Signed64(); + public final Signed64 st_qspare1 = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public MacOSFileStat(MacOSPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/MacOSFileStat64Inode.java b/src/main/java/jnr/posix/MacOSFileStat64Inode.java new file mode 100644 index 0000000..703830a --- /dev/null +++ b/src/main/java/jnr/posix/MacOSFileStat64Inode.java
@@ -0,0 +1,144 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +/** + * An alternate stat layout when running with _DARWIN_FEATURE_64_BIT_INODE, which appears to be the default on M1. + */ +public final class MacOSFileStat64Inode extends BaseFileStat implements NanosecondFileStat { + public static class Layout64Inode extends StructLayout { + + public Layout64Inode(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends SignedLong { + } + public final Signed32 st_dev = new Signed32(); + public final Signed16 st_mode = new Signed16(); + public final Signed16 st_nlink = new Signed16(); + public final Signed64 st_ino = new Signed64(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final Signed32 st_rdev = new Signed32(); + public final time_t st_atime = new time_t(); + public final SignedLong st_atimensec = new SignedLong(); + public final time_t st_mtime = new time_t(); + public final SignedLong st_mtimensec = new SignedLong(); + public final time_t st_ctime = new time_t(); + public final SignedLong st_ctimensec = new SignedLong(); + public final time_t st_birthtime = new time_t(); + public final SignedLong st_birthtimensec = new SignedLong(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_blocks = new Signed64(); + public final Signed32 st_blksize = new Signed32(); + public final Signed32 st_flags = new Signed32(); + public final Signed32 st_gen = new Signed32(); + public final Signed32 st_lspare = new Signed32(); + public final Signed64 st_qspare0 = new Signed64(); + public final Signed64 st_qspare1 = new Signed64(); + } + private static final Layout64Inode layout = new Layout64Inode(jnr.ffi.Runtime.getSystemRuntime()); + + public MacOSFileStat64Inode(MacOSPOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/MacOSMsgHdr.java b/src/main/java/jnr/posix/MacOSMsgHdr.java new file mode 100644 index 0000000..b8a1f36 --- /dev/null +++ b/src/main/java/jnr/posix/MacOSMsgHdr.java
@@ -0,0 +1,151 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Runtime; +import jnr.ffi.StructLayout; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +class MacOSMsgHdr extends BaseMsgHdr { + + public static class Layout extends StructLayout { + protected Layout(Runtime runtime) { + super(runtime); + } + + public final Pointer msg_name = new Pointer(); + public final socklen_t msg_namelen = new socklen_t(); + public final Pointer msg_iov = new Pointer(); + public final Signed32 msg_iovlen = new Signed32(); + public final Pointer msg_control = new Pointer(); + public final socklen_t msg_controllen = new socklen_t(); + public final Signed32 msg_flags = new Signed32(); + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + protected MacOSMsgHdr(NativePOSIX posix) { + super(posix, layout); + setName(null); + } + + CmsgHdr allocateCmsgHdrInternal(NativePOSIX posix, Pointer pointer, int len) { + if (len > 0) { + return new MacOSCmsgHdr(posix, pointer, len); + } else { + return new MacOSCmsgHdr(posix, pointer); + } + } + + @Override + void setControlPointer(Pointer control) { + layout.msg_control.set(this.memory, control); + } + + @Override + void setControlLen(int len) { + layout.msg_controllen.set(this.memory, len); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("msghdr {\n"); + buf.append(" msg_name=").append(getName()).append(",\n"); + buf.append(" msg_namelen=").append(getNameLen()).append(",\n"); + + buf.append(" msg_iov=[\n"); + Pointer iovp = layout.msg_iov.get(this.memory); + + int numIov = getIovLen(); + for (int i = 0; i < numIov; ++i) { + Pointer eachp = iovp.slice(i * BaseIovec.layout.size()); + buf.append(new BaseIovec(posix, eachp).toString(" ")); + if (i < (numIov - 1)) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + + buf.append(" msg_control=[\n"); + + CmsgHdr[] controls = getControls(); + for (int i = 0; i < controls.length; ++i) { + buf.append(((MacOSCmsgHdr) controls[i]).toString(" ")); + if (i < controls.length - 1) { + buf.append(",\n"); + } else { + buf.append("\n"); + } + } + buf.append(" ],\n"); + buf.append(" msg_controllen=").append(layout.msg_controllen.get(this.memory)).append("\n"); + + buf.append(" msg_iovlen=").append(getIovLen()).append(",\n"); + buf.append(" msg_flags=").append(getFlags()).append(",\n"); + buf.append("}"); + return buf.toString(); + } + + @Override + void setNamePointer(Pointer name) { + layout.msg_name.set( this.memory, name ); + } + + @Override + Pointer getNamePointer() { + return layout.msg_name.get( this.memory ); + } + + + @Override + void setNameLen(int len) { + layout.msg_namelen.set(this.memory, len); + } + + @Override + int getNameLen() { + return (int) layout.msg_namelen.get(this.memory); + } + + @Override + void setIovPointer(Pointer iov) { + layout.msg_iov.set(this.memory, iov); + } + + @Override + Pointer getIovPointer() { + return layout.msg_iov.get( this.memory ); + } + + @Override + void setIovLen(int len) { + layout.msg_iovlen.set(this.memory, len); + } + + @Override + int getIovLen() { + return layout.msg_iovlen.get(this.memory); + } + + @Override + Pointer getControlPointer() { + return layout.msg_control.get(this.memory); + } + + public int getControlLen() { + return (int) layout.msg_controllen.get(this.memory); + } + + public void setFlags(int flags) { + layout.msg_flags.set(this.memory, flags); + } + + public int getFlags() { + return layout.msg_flags.get(this.memory); + } +}
diff --git a/src/main/java/jnr/posix/MacOSPOSIX.java b/src/main/java/jnr/posix/MacOSPOSIX.java new file mode 100644 index 0000000..d505317 --- /dev/null +++ b/src/main/java/jnr/posix/MacOSPOSIX.java
@@ -0,0 +1,75 @@ +package jnr.posix; + +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.constants.platform.Sysconf; +import jnr.ffi.*; +import jnr.ffi.mapper.FromNativeContext; + + +final class MacOSPOSIX extends BaseNativePOSIX { + + private final NSGetEnviron environ; + + MacOSPOSIX(LibCProvider libcProvider, POSIXHandler handler) { + super(libcProvider, handler); + + final LibraryLoader<NSGetEnviron> loader = LibraryLoader.create(NSGetEnviron.class); + loader.library("libSystem.B.dylib"); + environ = loader.load(); + } + + public FileStat allocateStat() { + if (Platform.getNativePlatform().getCPU() == Platform.CPU.AARCH64) { + return new MacOSFileStat64Inode(this); + } + + return new MacOSFileStat(this); + } + + public MsgHdr allocateMsgHdr() { + return new MacOSMsgHdr(this); + } + + @Override + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 8); + } + + @Override + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 8); + } + + public SocketMacros socketMacros() { + return MacOSSocketMacros.INSTANCE; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + @Override + public Pointer environ() { + return environ._NSGetEnviron().getPointer(0); + } + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new MacOSPasswd((Pointer) arg) : null; + } + }; +}
diff --git a/src/main/java/jnr/posix/MacOSPasswd.java b/src/main/java/jnr/posix/MacOSPasswd.java new file mode 100644 index 0000000..16f21ee --- /dev/null +++ b/src/main/java/jnr/posix/MacOSPasswd.java
@@ -0,0 +1,74 @@ + + +package jnr.posix; + + +import jnr.ffi.StructLayout; + +/** + * + */ +public final class MacOSPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Signed32 pw_uid = new Signed32(); // user id + public final Signed32 pw_gid = new Signed32(); // user id + public final SignedLong pw_change = new SignedLong(); // password change time + public final UTF8StringRef pw_class = new UTF8StringRef(); // user access class + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + public final SignedLong pw_expire = new SignedLong(); // account expiration + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + MacOSPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return layout.pw_class.get(memory); + } + + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + + public long getGID() { + return layout.pw_gid.get(memory); + } + + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + + public int getPasswdChangeTime() { + return layout.pw_change.intValue(memory); + } + + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + + public long getUID() { + return layout.pw_uid.get(memory); + } + + public int getExpire() { + return layout.pw_expire.intValue(memory); + } +}
diff --git a/src/main/java/jnr/posix/MacOSSocketMacros.java b/src/main/java/jnr/posix/MacOSSocketMacros.java new file mode 100644 index 0000000..c33f239 --- /dev/null +++ b/src/main/java/jnr/posix/MacOSSocketMacros.java
@@ -0,0 +1,27 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + +/** + * @author Bob McWhirter + */ +public class MacOSSocketMacros implements SocketMacros { + + public static final SocketMacros INSTANCE = new MacOSSocketMacros(); + + public int __DARWIN_ALIGN32(int x) { + return ((x + 3) & ~3); + } + + public int CMSG_SPACE(int l) { + return __DARWIN_ALIGN32(MacOSCmsgHdr.layout.size()) + __DARWIN_ALIGN32(l); + } + + public int CMSG_LEN(int l) { + return (__DARWIN_ALIGN32(MacOSCmsgHdr.layout.size())) + (l); + } + + public Pointer CMSG_DATA(Pointer cmsg) { + return cmsg.slice(__DARWIN_ALIGN32(MacOSCmsgHdr.layout.size())); + } +}
diff --git a/src/main/java/jnr/posix/MsgHdr.java b/src/main/java/jnr/posix/MsgHdr.java new file mode 100644 index 0000000..ffac87e --- /dev/null +++ b/src/main/java/jnr/posix/MsgHdr.java
@@ -0,0 +1,25 @@ +package jnr.posix; + +import java.nio.ByteBuffer; + +/** + * @author Bob McWhirter + */ +public interface MsgHdr { + + void setName(String name); + String getName(); + + void setIov(ByteBuffer[] buffers); + ByteBuffer[] getIov(); + + + void setFlags(int flags); + int getFlags(); + + CmsgHdr allocateControl(int dataLength); + CmsgHdr[] allocateControls(int[] dataLengths); + + CmsgHdr[] getControls(); + int getControlLen(); +}
diff --git a/src/main/java/jnr/posix/NSGetEnviron.java b/src/main/java/jnr/posix/NSGetEnviron.java new file mode 100644 index 0000000..4abe8c4 --- /dev/null +++ b/src/main/java/jnr/posix/NSGetEnviron.java
@@ -0,0 +1,9 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + +public interface NSGetEnviron { + + Pointer _NSGetEnviron(); + +}
diff --git a/src/main/java/jnr/posix/NanosecondFileStat.java b/src/main/java/jnr/posix/NanosecondFileStat.java new file mode 100644 index 0000000..00f1e96 --- /dev/null +++ b/src/main/java/jnr/posix/NanosecondFileStat.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +/** + * Represents the additional nsec resolution on the stat struct in Linux 2.6+. + */ +public interface NanosecondFileStat extends FileStat { + long aTimeNanoSecs(); + + long cTimeNanoSecs(); + + long mTimeNanoSecs(); +}
diff --git a/src/main/java/jnr/posix/NativeGroup.java b/src/main/java/jnr/posix/NativeGroup.java new file mode 100644 index 0000000..964f3b4 --- /dev/null +++ b/src/main/java/jnr/posix/NativeGroup.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; + +public abstract class NativeGroup implements Group { + protected final jnr.ffi.Runtime runtime; + protected final StructLayout structLayout; + protected NativeGroup(jnr.ffi.Runtime runtime, StructLayout structLayout) { + this.runtime = runtime; + this.structLayout = structLayout; + } +}
diff --git a/src/main/java/jnr/posix/NativePOSIX.java b/src/main/java/jnr/posix/NativePOSIX.java new file mode 100644 index 0000000..6c32fc5 --- /dev/null +++ b/src/main/java/jnr/posix/NativePOSIX.java
@@ -0,0 +1,26 @@ +package jnr.posix; + +import jnr.ffi.Memory; +import jnr.ffi.Pointer; + +/** + * + */ +public abstract class NativePOSIX implements POSIX { + + + jnr.ffi.Runtime getRuntime() { + return jnr.ffi.Runtime.getRuntime(libc()); + } + + public abstract SocketMacros socketMacros(); + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 128); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 128); + } + +}
diff --git a/src/main/java/jnr/posix/NativePasswd.java b/src/main/java/jnr/posix/NativePasswd.java new file mode 100644 index 0000000..49a7dd4 --- /dev/null +++ b/src/main/java/jnr/posix/NativePasswd.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + + +public abstract class NativePasswd implements Passwd { + protected final Pointer memory; + + NativePasswd(jnr.ffi.Pointer pointer) { + this.memory = pointer; + } +}
diff --git a/src/main/java/jnr/posix/NativeTimes.java b/src/main/java/jnr/posix/NativeTimes.java new file mode 100644 index 0000000..68a4252 --- /dev/null +++ b/src/main/java/jnr/posix/NativeTimes.java
@@ -0,0 +1,51 @@ +package jnr.posix; + +import jnr.constants.platform.Errno; +import jnr.ffi.LastError; +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.StructLayout; + +/** + * + */ +public final class NativeTimes implements Times { + static final class Layout extends StructLayout { + public final clock_t tms_utime = new clock_t(); + public final clock_t tms_stime = new clock_t(); + public final clock_t tms_cutime = new clock_t(); + public final clock_t tms_cstime = new clock_t(); + + Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + } + + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + final Pointer memory; + + static NativeTimes times(BaseNativePOSIX posix) { + NativeTimes tms = new NativeTimes(posix); + return posix.libc().times(tms) == -1 ? null : tms; + } + + NativeTimes(NativePOSIX posix) { + this.memory = Memory.allocate(posix.getRuntime(), layout.size()); + } + + public long utime() { + return layout.tms_utime.get(memory); + } + + public long stime() { + return layout.tms_stime.get(memory); + } + + public long cutime() { + return layout.tms_cutime.get(memory); + } + + public long cstime() { + return layout.tms_cstime.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/OpenBSDFileStat.java b/src/main/java/jnr/posix/OpenBSDFileStat.java new file mode 100644 index 0000000..fc4732d --- /dev/null +++ b/src/main/java/jnr/posix/OpenBSDFileStat.java
@@ -0,0 +1,138 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public final class OpenBSDFileStat extends BaseFileStat implements NanosecondFileStat{ + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final class time_t extends Signed64 {} + public final class dev_t extends Signed32 {} + + public final Unsigned32 st_mode = new Unsigned32(); + public final dev_t st_dev = new dev_t(); + public final Unsigned64 st_ino = new Unsigned64(); + public final Unsigned32 st_nlink = new Unsigned32(); + public final Unsigned32 st_uid = new Unsigned32(); + public final Unsigned32 st_gid = new Unsigned32(); + public final dev_t st_rdev = new dev_t(); + public final time_t st_atime = new time_t(); + public final SignedLong st_atimensec = new SignedLong(); + public final time_t st_mtime = new time_t(); + public final SignedLong st_mtimensec = new SignedLong(); + public final time_t st_ctime = new time_t(); + public final SignedLong st_ctimensec = new SignedLong(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_blocks = new Signed64(); + public final Unsigned32 st_blksize = new Unsigned32(); + public final Unsigned32 st_flags = new Unsigned32(); + public final Unsigned32 st_gen = new Unsigned32(); + public final time_t st_birthtime = new time_t(); + public final SignedLong st_birthtimensec = new SignedLong(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + public OpenBSDFileStat(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return (int) layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return (int)(layout.st_mode.get(memory) & 0xffff); + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return (int)layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return (int)layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atimensec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctimensec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtimensec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/OpenBSDPOSIX.java b/src/main/java/jnr/posix/OpenBSDPOSIX.java new file mode 100644 index 0000000..e3ca82e --- /dev/null +++ b/src/main/java/jnr/posix/OpenBSDPOSIX.java
@@ -0,0 +1,103 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Memory; +import jnr.ffi.Struct; +import jnr.ffi.mapper.FromNativeContext; +import jnr.ffi.Pointer; +import jnr.posix.util.MethodName; + +final class OpenBSDPOSIX extends BaseNativePOSIX { + OpenBSDPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + } + + public FileStat allocateStat() { + return new OpenBSDFileStat(this); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new OpenBSDPasswd((Pointer) arg) : null; + } + }; + + @Override + public int utimes(String path, long[] atimeval, long[] mtimeval) { + Timeval[] times = null; + if (atimeval != null && mtimeval != null) { + times = Struct.arrayOf(getRuntime(), OpenBSDTimeval.class, 2); + times[0].setTime(atimeval); + times[1].setTime(mtimeval); + } + return libc().utimes(path, times); + } + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 8); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 8); + } +}
diff --git a/src/main/java/jnr/posix/OpenBSDPasswd.java b/src/main/java/jnr/posix/OpenBSDPasswd.java new file mode 100644 index 0000000..4c61681 --- /dev/null +++ b/src/main/java/jnr/posix/OpenBSDPasswd.java
@@ -0,0 +1,100 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + + +import jnr.ffi.StructLayout; + +public class OpenBSDPasswd extends NativePasswd implements Passwd { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Unsigned32 pw_uid = new Unsigned32(); // user id + public final Unsigned32 pw_gid = new Unsigned32(); // user id + public final Signed64 pw_change = new Signed64(); // password change time + public final UTF8StringRef pw_class = new UTF8StringRef(); // user access class + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + public final Signed64 pw_expire = new Signed64(); // account expiration + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + OpenBSDPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return layout.pw_class.get(memory); + } + + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + + public long getGID() { + return layout.pw_gid.get(memory); + } + + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + + public int getPasswdChangeTime() { + return layout.pw_change.intValue(memory); + } + + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + + public long getUID() { + return layout.pw_uid.get(memory); + } + + public int getExpire() { + return layout.pw_expire.intValue(memory); + } +}
diff --git a/src/main/java/jnr/posix/OpenBSDTimeval.java b/src/main/java/jnr/posix/OpenBSDTimeval.java new file mode 100644 index 0000000..734d456 --- /dev/null +++ b/src/main/java/jnr/posix/OpenBSDTimeval.java
@@ -0,0 +1,32 @@ +package jnr.posix; + +public final class OpenBSDTimeval extends Timeval { + public final Signed64 tv_sec = new Signed64(); + public final SignedLong tv_usec = new SignedLong(); + + public OpenBSDTimeval(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void setTime(long[] timeval) { + assert timeval.length == 2; + tv_sec.set(timeval[0]); + tv_usec.set(timeval[1]); + } + + public void sec(long sec) { + this.tv_sec.set(sec); + } + + public void usec(long usec) { + this.tv_usec.set(usec); + } + + public long sec() { + return tv_sec.get(); + } + + public long usec() { + return tv_usec.get(); + } +}
diff --git a/src/main/java/jnr/posix/POSIX.java b/src/main/java/jnr/posix/POSIX.java new file mode 100644 index 0000000..941067d --- /dev/null +++ b/src/main/java/jnr/posix/POSIX.java
@@ -0,0 +1,237 @@ +package jnr.posix; + +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Signal; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import jnr.posix.util.ProcessMaker; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collection; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Pathconf; +import jnr.ffi.annotations.Out; + +public interface POSIX { + CharSequence crypt(CharSequence key, CharSequence salt); + + /** + * Call the crypt function with the given key and salt as raw null-terminated byte (C char) strings. + * + * @param key null-terminated key bytes + * @param salt null-terminated salt bytes + * @return null-terminated crypted bytes, or null if there was an error + */ + byte[] crypt(byte[] key, byte[] salt); + + FileStat allocateStat(); + int chmod(String filename, int mode); + int fchmod(int fd, int mode); + int chown(String filename, int user, int group); + int fchown(int fd, int user, int group); + /** + * Shell expanding and escaping version of exec which handles all the + * preparation of a command line or command list. + * + * @param path the path to execute + * @param argv the arguments to pass, with arg0 equal to the desired process name + * @return does not return if successful; -1 if failed + */ + int exec(String path, String... argv); + + /** + * Shell expanding and escaping version of exec which handles all the + * preparation of a command line or command list. + * + * @param path the path to execute + * @param argv the arguments to pass, with arg0 equal to the desired process name + * @param envp a set of KEY=VALUE environment strings to set for the new execution + * @return does not return if successful; -1 if failed + */ + int exec(String path, String[] argv, String[] envp); + + int execv(String path, String[] argv); + int execve(String path, String[] argv, String[] envp); + int fork(); + FileStat fstat(FileDescriptor descriptor); + FileStat fstat(int descriptor); + int fstat(FileDescriptor descriptor, FileStat stat); + int fstat(int fd, FileStat stat); + Pointer environ(); + String getenv(String envName); + int getegid(); + int geteuid(); + int seteuid(int euid); + int getgid(); + int getdtablesize(); + String getlogin(); + int getpgid(); + int getpgid(int pid); + int getpgrp(); + int getpid(); + int getppid(); + int getpriority(int which, int who); + Passwd getpwent(); + Passwd getpwuid(int which); + Passwd getpwnam(String which); + Group getgrgid(int which); + Group getgrnam(String which); + Group getgrent(); + int endgrent(); + int setgrent(); + int endpwent(); + int setpwent(); + int getuid(); + int getrlimit(int resource, RLimit rlim); + int getrlimit(int resource, Pointer rlim); + RLimit getrlimit(int resource); + int setrlimit(int resource, RLimit rlim); + int setrlimit(int resource, Pointer rlim); + int setrlimit(int resource, long rlimCur, long rlimMax); + boolean isatty(FileDescriptor descriptor); + int isatty(int descriptor); + int kill(int pid, int signal); + int kill(long pid, int signal); + SignalHandler signal(Signal sig, SignalHandler handler); + int raise(int sig); + int lchmod(String filename, int mode); + int lchown(String filename, int user, int group); + int link(String oldpath,String newpath); + FileStat lstat(String path); + int lstat(String path, FileStat stat); + int mkdir(String path, int mode); + String readlink(String path) throws IOException; + int readlink(CharSequence path, byte[] buf, int bufsize); + int readlink(CharSequence path, ByteBuffer buf, int bufsize); + int readlink(CharSequence path, Pointer bufPtr, int bufsize); + int rmdir(String path); + int setenv(String envName, String envValue, int overwrite); // 0 no !0 yes + int setsid(); + int setgid(int gid); + int setegid(int egid); + int setpgid(int pid, int pgid); + int setpgrp(int pid, int pgrp); + int setpriority(int which, int who, int prio); + int setuid(int uid); + FileStat stat(String path); + int stat(String path, FileStat stat); + int symlink(String oldpath,String newpath); + int umask(int mask); + int unsetenv(String envName); + int utimes(String path, long[] atimeval, long[] mtimeval); + int utimes(String path, Pointer times); + int futimes(int fd, long[] atimeval, long[] mtimeval); + int lutimes(String path, long[] atimeval, long[] mtimeval); + int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag); + int utimensat(int dirfd, String path, Pointer times, int flag); + int futimens(int fd, long[] atimespec, long[] mtimespec); + int futimens(int fd, Pointer times); + int waitpid(int pid, int[] status, int flags); + int waitpid(long pid, int[] status, int flags); + int wait(int[] status); + int errno(); + void errno(int value); + String strerror(int code); + int chdir(String path); + boolean isNative(); + /** + * Returns null if isNative returns false. + * + * @return the LibC implementation for this POSIX + */ + LibC libc(); + ProcessMaker newProcessMaker(String... command); + ProcessMaker newProcessMaker(); + + public long sysconf(Sysconf name); + + public int confstr(Confstr name, @Out ByteBuffer buf, int len); + + public int fpathconf(int fd, Pathconf name); + + public Times times(); + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp); + + public long posix_spawnp(String path, Collection<? extends SpawnFileAction> fileActions, + Collection<? extends SpawnAttribute> spawnAttributes, + Collection<? extends CharSequence> argv, Collection<? extends CharSequence> envp); + + public int flock(int fd, int operation); + + int dup(int fd); + + int dup2(int oldFd, int newFd); + + int fcntlInt(int fd, Fcntl fcntlConst, int arg); + int fcntl(int fd, Fcntl fcntlConst, int arg); + int fcntl(int fd, Fcntl fcntlConst); + int access(CharSequence path, int amode); + int close(int fd); + int unlink(CharSequence path); + int open(CharSequence path, int flags, int perm); + + long read(int fd, byte[] buf, long n); + long write(int fd, byte[] buf, long n); + long read(int fd, ByteBuffer buf, long n); + long write(int fd, ByteBuffer buf, long n); + long pread(int fd, byte[] buf, long n, long offset); + long pwrite(int fd, byte[] buf, long n, long offset); + long pread(int fd, ByteBuffer buf, long n, long offset); + long pwrite(int fd, ByteBuffer buf, long n, long offset); + + int read(int fd, byte[] buf, int n); + int write(int fd, byte[] buf, int n); + int read(int fd, ByteBuffer buf, int n); + int write(int fd, ByteBuffer buf, int n); + int pread(int fd, byte[] buf, int n, int offset); + int pwrite(int fd, byte[] buf, int n, int offset); + int pread(int fd, ByteBuffer buf, int n, int offset); + int pwrite(int fd, ByteBuffer buf, int n, int offset); + + int lseek(int fd, long offset, int whence); + long lseekLong(int fd, long offset, int whence); + int pipe(int[] fds); + int truncate(CharSequence path, long length); + int ftruncate(int fd, long offset); + int rename(CharSequence oldName, CharSequence newName); + String getcwd(); + String gethostname(); + + int socketpair(int domain, int type, int protocol, int[] fds); + int sendmsg(int socket, MsgHdr message, int flags); + int recvmsg(int socket, MsgHdr message, int flags); + + MsgHdr allocateMsgHdr(); + + /** + * fcntl(2) + * + * @deprecated This version does not pass args because jnr-ffi does not support variadic invocation. + * @see jnr.posix.POSIX#fcntlInt(int, jnr.constants.platform.Fcntl, int) + * + * @param fd the file descriptor on which to act + * @param fcntlConst the {@link Fcntl} enum value for the flag to set + * @param arg arguments for the flag or null if none + * @return 0 if success, -1 if error + */ + @Deprecated + int fcntl(int fd, Fcntl fcntlConst, int... arg); + int fsync(int fd); + int fdatasync(int fd); + int mkfifo(String filename, int mode); + + int daemon(int nochdir, int noclose); + + long[] getgroups(); + int getgroups(int size, int[] groups); + + String nl_langinfo(int item); + String setlocale(int category, String locale); + + Timeval allocateTimeval(); + int gettimeofday(Timeval tv); +}
diff --git a/src/main/java/jnr/posix/POSIXFactory.java b/src/main/java/jnr/posix/POSIXFactory.java new file mode 100644 index 0000000..a1ea703 --- /dev/null +++ b/src/main/java/jnr/posix/POSIXFactory.java
@@ -0,0 +1,342 @@ +package jnr.posix; + +import jnr.ffi.Library; +import jnr.ffi.LibraryLoader; +import jnr.ffi.LibraryOption; +import jnr.ffi.Struct; + +import java.util.Collections; +import java.util.HashMap; + +import jnr.ffi.mapper.FunctionMapper; +import jnr.posix.util.DefaultPOSIXHandler; +import jnr.posix.util.Platform; + +import java.util.Map; + +public class POSIXFactory { + // Weird inner-class resolution problem work-around FIXME: JRUBY-5889. Someone fix JAFFL! + private static final Class<Struct> BOGUS_HACK = Struct.class; + public static final jnr.ffi.Platform NATIVE_PLATFORM = jnr.ffi.Platform.getNativePlatform(); + public static final String STANDARD_C_LIBRARY_NAME = NATIVE_PLATFORM.getStandardCLibraryName(); + + /** + * Get a POSIX instance. If useNativePosix is true, this works just like + * POSIXFactory#getPOSIX(). If useNativePosix is false, this works like + * POSIXFactory#getJavaPOSIX() + * + * @param handler a POSIXHandler implementation + * @param useNativePOSIX whether to attempt to use native code for better functionality + * @return a POSIX implementation, attempting to use native code if useNativePosix is true + */ + public static POSIX getPOSIX(POSIXHandler handler, boolean useNativePOSIX) { + return new LazyPOSIX(handler, useNativePOSIX); + } + + /** + * This will use {@link DefaultPOSIXHandler} and the native POSIX implementation, + * falling back on the pure-Java implementation if native support is not available. + * + * @return a POSIX implementation, native if possible and pure-Java otherwise. + */ + public static POSIX getPOSIX() { + return getPOSIX(new DefaultPOSIXHandler(), true); + } + + /** + * Get a pure-Java POSIX instance. Functionality will be limited to that which can + * be provided by pure-Java/JDK features or shelling out to external commands. + * + * @param handler a POSIXHandler implementation + * @return a pure-Java POSIX implementation + */ + public static POSIX getJavaPOSIX(POSIXHandler handler) { + return new JavaPOSIX(handler); + } + + /** + * Get a pure-Java POSIX instance. Functionality will be limited to that which can + * be provided by pure-Java/JDK features or shelling out to external commands. + * + * @return a pure-Java POSIX implementation + */ + public static POSIX getJavaPOSIX() { + return getJavaPOSIX(new DefaultPOSIXHandler()); + } + + /** + * Get a POSIX instance. If a true native implementation can't be loaded, allow that + * error to propagate rather than falling back on the pure-Java version. + * + * @param handler a POSIXHandler implementation + * @return a native POSIX implementation, raising errors if the native version can't load + */ + public static POSIX getNativePOSIX(POSIXHandler handler) { + return loadNativePOSIX(handler); + } + + /** + * Get a POSIX instance. If a true native implementation can't be loaded, allow that + * error to propagate rather than falling back on the pure-Java version. + * + * @return a native POSIX implementation, raising errors if the native version can't load + */ + public static POSIX getNativePOSIX() { + return getNativePOSIX(new DefaultPOSIXHandler()); + } + + static POSIX loadPOSIX(POSIXHandler handler, boolean useNativePOSIX) { + POSIX posix = null; + + if (useNativePOSIX) { + try { + posix = loadNativePOSIX(handler); + posix = posix != null ? new CheckedPOSIX(posix, handler) : null; + // ENEBO: Should printing be done through a handler+log method? + if (handler.isVerbose()) { + if (posix != null) { + System.err.println("Successfully loaded native POSIX impl."); + } else { + System.err.println("Failed to load native POSIX impl; falling back on Java impl. Unsupported OS."); + } + } + } catch (Throwable t) { + if (handler.isVerbose()) { + System.err.println("Failed to load native POSIX impl; falling back on Java impl. Stacktrace follows."); + t.printStackTrace(); + } + } + } + + if (posix == null) { + posix = getJavaPOSIX(handler); + } + + return posix; + } + + private static POSIX loadNativePOSIX(POSIXHandler handler) { + switch (NATIVE_PLATFORM.getOS()) { + case DARWIN: + return loadMacOSPOSIX(handler); + + case LINUX: + return loadLinuxPOSIX(handler); + + case FREEBSD: + return loadFreeBSDPOSIX(handler); + + case DRAGONFLY: + return loadDragonFlyPOSIX(handler); + + case OPENBSD: + return loadOpenBSDPOSIX(handler); + + case SOLARIS: + return loadSolarisPOSIX(handler); + + case AIX: + return loadAixPOSIX(handler); + + case WINDOWS: + return loadWindowsPOSIX(handler); + } + + return null; + } + + public static POSIX loadLinuxPOSIX(POSIXHandler handler) { + return new LinuxPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadMacOSPOSIX(POSIXHandler handler) { + return new MacOSPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadSolarisPOSIX(POSIXHandler handler) { + return new SolarisPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadFreeBSDPOSIX(POSIXHandler handler) { + return new FreeBSDPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadDragonFlyPOSIX(POSIXHandler handler) { + return new DragonFlyPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadOpenBSDPOSIX(POSIXHandler handler) { + return new OpenBSDPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadWindowsPOSIX(POSIXHandler handler) { + return new WindowsPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + public static POSIX loadAixPOSIX(POSIXHandler handler) { + return new AixPOSIX(DefaultLibCProvider.INSTANCE, handler); + } + + private static String[] libraries() { + switch (NATIVE_PLATFORM.getOS()) { + case LINUX: + return new String[] {STANDARD_C_LIBRARY_NAME}; + + case SOLARIS: + return new String[] { "socket", "nsl", STANDARD_C_LIBRARY_NAME}; + + case DRAGONFLY: + case FREEBSD: + case NETBSD: + return new String[] {STANDARD_C_LIBRARY_NAME}; + + case AIX: + return jnr.ffi.Runtime.getSystemRuntime().addressSize() == 4 + ? new String[] { "libc.a(shr.o)" } + : new String[] { "libc.a(shr_64.o)" }; + + case WINDOWS: + return new String[] { "msvcrt", "kernel32" }; + + default: + return new String[] {STANDARD_C_LIBRARY_NAME}; + } + } + + private static Class<? extends LibC> libraryInterface() { + switch (NATIVE_PLATFORM.getOS()) { + case LINUX: + return LinuxLibC.class; + + case AIX: + return AixLibC.class; + + case SOLARIS: + return SolarisLibC.class; + + case WINDOWS: + return WindowsLibC.class; + + default: + return UnixLibC.class; + } + } + + private static FunctionMapper functionMapper() { + switch (NATIVE_PLATFORM.getOS()) { + case AIX: + return new SimpleFunctionMapper.Builder() + .map("stat", "stat64x") + .map("fstat", "fstat64x") + .map("lstat", "lstat64x") + .map("stat64", "stat64x") + .map("fstat64", "fstat64x") + .map("lstat64", "lstat64x") + .build(); + + case WINDOWS: + return new SimpleFunctionMapper.Builder() + .map("getpid", "_getpid") + .map("chmod", "_chmod") + .map("fstat", "_fstat64") + .map("stat", "_stat64") + .map("umask", "_umask") + .map("isatty", "_isatty") + .map("read", "_read") + .map("write", "_write") + .map("close", "_close") + .map("getcwd", "_getcwd") + .map("unlink", "_unlink") + .map("access", "_access") + .map("open", "_open") + .map("dup", "_dup") + .map("dup2", "_dup2") + .map("lseek", "_lseek") + .map("ftruncate", "_chsize") + .build(); + + case SOLARIS: + return Platform.IS_32_BIT + ? new SimpleFunctionMapper.Builder() + .map("stat", "stat64") + .map("fstat", "fstat64") + .map("lstat", "lstat64") + .build() + : null; + default: + return null; + } + } + + private static Map<LibraryOption, Object> options() { + Map<LibraryOption, Object> options = new HashMap<LibraryOption, Object>(); + + FunctionMapper functionMapper = functionMapper(); + if (functionMapper != null) { + options.put(LibraryOption.FunctionMapper, functionMapper); + } + + options.put(LibraryOption.TypeMapper, POSIXTypeMapper.INSTANCE); + options.put(LibraryOption.LoadNow, Boolean.TRUE); + + return Collections.unmodifiableMap(options); + } + + private static final class DefaultLibCProvider implements LibCProvider { + public static final LibCProvider INSTANCE = new DefaultLibCProvider(); + + private static final class SingletonHolder { + public static LibC libc; + public static Crypt crypt; + static { + LibraryLoader<? extends LibC> libcLoader = LibraryLoader.create(libraryInterface()); + + // always do a default search + libcLoader.searchDefault(); + + for (String library : libraries()) { + libcLoader.library(library); + } + + for (Map.Entry<LibraryOption, Object> entry : options().entrySet()) { + libcLoader.option(entry.getKey(), entry.getValue()); + } + + libcLoader.failImmediately(); + + libc = libcLoader.load(); + + Crypt c = null; + + // FIXME: This is kinda gross but there's no way to tell jnr-ffi that some libraries are ok to fail + // See jruby/jruby#5447. + try { + LibraryLoader<Crypt> loader = LibraryLoader.create(Crypt.class).failImmediately(); + c = loader.load("libcrypt.so.1"); + } catch (UnsatisfiedLinkError ule) { + try { + LibraryLoader<Crypt> loader = LibraryLoader.create(Crypt.class).failImmediately(); + c = loader.load("crypt"); + } catch (UnsatisfiedLinkError ule2) { + try { + LibraryLoader<Crypt> loader = LibraryLoader.create(Crypt.class).failImmediately(); + c = loader.load(STANDARD_C_LIBRARY_NAME); + } catch (UnsatisfiedLinkError ule3) { + // TODO: log somewhere? Warning? + } + } + } + + crypt = c; + } + } + + public final LibC getLibC() { + return SingletonHolder.libc; + } + + public final Crypt getCrypt() { + return SingletonHolder.crypt; + } + } +}
diff --git a/src/main/java/jnr/posix/POSIXFunctionMapper.java b/src/main/java/jnr/posix/POSIXFunctionMapper.java new file mode 100644 index 0000000..94d30bf --- /dev/null +++ b/src/main/java/jnr/posix/POSIXFunctionMapper.java
@@ -0,0 +1,28 @@ + +package jnr.posix; + +import jnr.ffi.mapper.FunctionMapper; + +/** + * No longer used. It used to map function names from libc names to + * msvcrt names. + * + * @deprecated Use SimpleFunctionMapper instead. + */ +@Deprecated +final class POSIXFunctionMapper implements FunctionMapper { + public static final FunctionMapper INSTANCE = new POSIXFunctionMapper(); + + private POSIXFunctionMapper() {} + + public String mapFunctionName(String name, Context ctx) { + if (ctx.getLibrary().getName().equals("msvcrt")) { + // FIXME: We should either always _ name for msvcrt or get good list of _ methods + if (name.equals("getpid") || name.equals("chmod")) { + name = "_" + name; + } + } + return name; + } + +}
diff --git a/src/main/java/jnr/posix/POSIXHandler.java b/src/main/java/jnr/posix/POSIXHandler.java new file mode 100644 index 0000000..46fb4c0 --- /dev/null +++ b/src/main/java/jnr/posix/POSIXHandler.java
@@ -0,0 +1,81 @@ +package jnr.posix; + +import jnr.constants.platform.Errno; + +import java.io.File; +import java.io.InputStream; +import java.io.PrintStream; + +/** + * The POSIXHandler class allows you do implement the runtime-specific behavior you need in + * such a way that it is insulated from the implementation of the POSIX library. Implementing + * each of the methods in this interface should give you are working POSIX implementation. + * + */ +public interface POSIXHandler { + public enum WARNING_ID { + DUMMY_VALUE_USED("DUMMY_VALUE_USED"); + + private String messageID; + + WARNING_ID(String messageID) { + this.messageID = messageID; + } + } + public void error(Errno error, String extraData); + public void error(Errno error, String methodName, String extraData); + + /** + * Specify that posix method is unimplemented. In JRuby we generate an + * exception with this. + * + * @param methodName the POSIX method that failed + */ + public void unimplementedError(String methodName); + + public void warn(WARNING_ID id, String message, Object... data); + + /** + * @return should we provide verbose output about POSIX activities + */ + public boolean isVerbose(); + + /** + * @return current working directory of your runtime. + */ + public File getCurrentWorkingDirectory(); + + /** + * @return current set of environment variables of your runtime. + */ + public String[] getEnv(); + + /** + * @return your runtime's current input stream + */ + public InputStream getInputStream(); + + /** + * @return your runtime's current output stream + */ + public PrintStream getOutputStream(); + + /** + * Get your runtime's process ID. This is only intended for non-native POSIX support (e.g. + * environments where JNA cannot load or security restricted environments). In JRuby we + * found a number of packages which would rather have some identity for the runtime than + * nothing. + * + * Note: If you do not want this to work you impl can just call {@link #unimplementedError(String)}. + * + * @return your runtime's process ID + */ + public int getPID(); + + /** + * Get your runtime's current ErrorStream + * + * @return your runtime's current error stream + */ + public PrintStream getErrorStream(); +}
diff --git a/src/main/java/jnr/posix/POSIXTypeMapper.java b/src/main/java/jnr/posix/POSIXTypeMapper.java new file mode 100644 index 0000000..da76d08 --- /dev/null +++ b/src/main/java/jnr/posix/POSIXTypeMapper.java
@@ -0,0 +1,72 @@ +package jnr.posix; + + +import jnr.constants.Constant; +import jnr.ffi.mapper.*; +import jnr.posix.util.Platform; + +final class POSIXTypeMapper implements TypeMapper { + public static final TypeMapper INSTANCE = new POSIXTypeMapper(); + + private POSIXTypeMapper() {} + + public FromNativeConverter getFromNativeConverter(Class klazz) { + if (Passwd.class.isAssignableFrom(klazz)) { + if (Platform.IS_MAC) { + return MacOSPOSIX.PASSWD; + } else if (Platform.IS_LINUX) { + return LinuxPOSIX.PASSWD; + } else if (Platform.IS_SOLARIS) { + return SolarisPOSIX.PASSWD; + } else if (Platform.IS_FREEBSD) { + return FreeBSDPOSIX.PASSWD; + } else if (Platform.IS_DRAGONFLY) { + return DragonFlyPOSIX.PASSWD; + } else if (Platform.IS_OPENBSD) { + return OpenBSDPOSIX.PASSWD; + } else if (Platform.IS_WINDOWS) { + return WindowsPOSIX.PASSWD; + } else if (jnr.ffi.Platform.getNativePlatform().getOS().equals(jnr.ffi.Platform.OS.AIX)) { + return AixPOSIX.PASSWD; + } + return null; + } else if (Group.class.isAssignableFrom(klazz)) { + return BaseNativePOSIX.GROUP; + + } else if (HANDLE.class.isAssignableFrom(klazz)) { + return HANDLE.Converter; + } + + return null; + } + + public ToNativeConverter getToNativeConverter(Class klazz) { + if (FileStat.class.isAssignableFrom(klazz)) { + return BaseNativePOSIX.FileStatConverter; + + } else if (NativeTimes.class.isAssignableFrom(klazz)) { + return BaseNativePOSIX.TimesConverter; + + } else if (Constant.class.isAssignableFrom(klazz)) { + return BaseNativePOSIX.ConstantConverter; + + } else if (WString.class.isAssignableFrom(klazz)) { + return WString.Converter; + + } else if (HANDLE.class.isAssignableFrom(klazz)) { + return HANDLE.Converter; + } else if (MsgHdr.class.isAssignableFrom(klazz)) { + return BaseNativePOSIX.MsgHdrConverter; + } + + return null; + } + + public final ToNativeConverter getToNativeConverter(Class klazz, ToNativeContext context) { + return getToNativeConverter(klazz); + } + + public final FromNativeConverter getFromNativeConverter(Class klazz, FromNativeContext context) { + return getFromNativeConverter(klazz); + } +}
diff --git a/src/main/java/jnr/posix/Passwd.java b/src/main/java/jnr/posix/Passwd.java new file mode 100644 index 0000000..63cff5f --- /dev/null +++ b/src/main/java/jnr/posix/Passwd.java
@@ -0,0 +1,14 @@ +package jnr.posix; + +public interface Passwd { + public String getLoginName(); + public String getPassword(); + public long getUID(); + public long getGID(); + public int getPasswdChangeTime(); + public String getAccessClass(); + public String getGECOS(); + public String getHome(); + public String getShell(); + public int getExpire(); +}
diff --git a/src/main/java/jnr/posix/RLimit.java b/src/main/java/jnr/posix/RLimit.java new file mode 100644 index 0000000..0a0018c --- /dev/null +++ b/src/main/java/jnr/posix/RLimit.java
@@ -0,0 +1,13 @@ +package jnr.posix; + +import jnr.ffi.*; + +public abstract class RLimit extends Struct { + protected RLimit(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public abstract void init(long current, long max); + public abstract long rlimCur(); + public abstract long rlimMax(); +}
diff --git a/src/main/java/jnr/posix/SignalHandler.java b/src/main/java/jnr/posix/SignalHandler.java new file mode 100644 index 0000000..33ab5de --- /dev/null +++ b/src/main/java/jnr/posix/SignalHandler.java
@@ -0,0 +1,5 @@ +package jnr.posix; + +public interface SignalHandler { + public void handle(int signal); +}
diff --git a/src/main/java/jnr/posix/SimpleFunctionMapper.java b/src/main/java/jnr/posix/SimpleFunctionMapper.java new file mode 100644 index 0000000..6894d5d --- /dev/null +++ b/src/main/java/jnr/posix/SimpleFunctionMapper.java
@@ -0,0 +1,31 @@ +package jnr.posix; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class SimpleFunctionMapper implements jnr.ffi.mapper.FunctionMapper { + private final Map<String, String> functionNameMap; + + private SimpleFunctionMapper(Map<String, String> map) { + functionNameMap = Collections.unmodifiableMap(new HashMap<String, String>(map)); + } + + public String mapFunctionName(String functionName, Context context) { + String nativeFunction = functionNameMap.get(functionName); + return nativeFunction != null ? nativeFunction : functionName; + } + + public static class Builder { + private final Map<String, String> functionNameMap = Collections.synchronizedMap(new HashMap<String, String>()); + + public Builder map(String posixName, String nativeFunction) { + functionNameMap.put(posixName, nativeFunction); + return this; + } + + public SimpleFunctionMapper build() { + return new SimpleFunctionMapper(functionNameMap); + } + } +}
diff --git a/src/main/java/jnr/posix/SocketMacros.java b/src/main/java/jnr/posix/SocketMacros.java new file mode 100644 index 0000000..10de54a --- /dev/null +++ b/src/main/java/jnr/posix/SocketMacros.java
@@ -0,0 +1,12 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + +/** + * @author Bob McWhirter + */ +public interface SocketMacros { + public int CMSG_SPACE(int l); + public int CMSG_LEN(int l); + public Pointer CMSG_DATA(Pointer cmsg); +}
diff --git a/src/main/java/jnr/posix/SolarisFileStat32.java b/src/main/java/jnr/posix/SolarisFileStat32.java new file mode 100644 index 0000000..ce22476 --- /dev/null +++ b/src/main/java/jnr/posix/SolarisFileStat32.java
@@ -0,0 +1,107 @@ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public class SolarisFileStat32 extends BaseFileStat implements NanosecondFileStat { + static final class Layout extends StructLayout { + + Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + public static final int _ST_FSTYPSZ = 16; /* array size for file system type name */ + + public final Signed32 st_dev = new Signed32(); + public final SignedLong[] st_pad1 = array(new SignedLong[3]); + public final Signed64 st_ino = new Signed64(); + public final Signed32 st_mode = new Signed32(); + public final Signed32 st_nlink = new Signed32(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final Signed32 st_rdev = new Signed32(); + public final SignedLong[] st_pad2 = array(new SignedLong[2]); + public final Signed64 st_size = new Signed64(); + public final Signed32 st_atim_sec = new Signed32(); + public final Signed32 st_atim_nsec = new Signed32(); + public final Signed32 st_mtim_sec = new Signed32(); + public final Signed32 st_mtim_nsec = new Signed32(); + public final Signed32 st_ctim_sec = new Signed32(); + public final Signed32 st_ctim_nsec = new Signed32(); + public final Signed32 st_blksize = new Signed32(); + public final Signed64 st_blocks = new Signed64(); + public final Signed8[] st_fstype = array(new Signed8[_ST_FSTYPSZ]); + public final SignedLong[] st_pad4 = array(new SignedLong[8]); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public SolarisFileStat32(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atim_sec.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctim_sec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtim_sec.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atim_nsec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctim_nsec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtim_nsec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/SolarisFileStat64.java b/src/main/java/jnr/posix/SolarisFileStat64.java new file mode 100644 index 0000000..a965451 --- /dev/null +++ b/src/main/java/jnr/posix/SolarisFileStat64.java
@@ -0,0 +1,108 @@ + +package jnr.posix; + + +import jnr.ffi.*; + +public class SolarisFileStat64 extends BaseFileStat implements NanosecondFileStat { + static final class Layout extends StructLayout { + + Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public static final int _ST_FSTYPSZ = 16; /* array size for file system type name */ + public final UnsignedLong st_dev = new UnsignedLong(); + public final Signed64 st_ino = new Signed64(); + public final Signed32 st_mode = new Signed32(); + public final Signed32 st_nlink = new Signed32(); + public final Signed32 st_uid = new Signed32(); + public final Signed32 st_gid = new Signed32(); + public final UnsignedLong st_rdev = new UnsignedLong(); + public final Signed64 st_size = new Signed64(); + public final SignedLong st_atim_sec = new SignedLong(); + public final SignedLong st_atim_nsec = new SignedLong(); + public final SignedLong st_mtim_sec = new SignedLong(); + public final SignedLong st_mtim_nsec = new SignedLong(); + public final SignedLong st_ctim_sec = new SignedLong(); + public final SignedLong st_ctim_nsec = new SignedLong(); + public final Signed32 st_blksize = new Signed32(); + public final Signed64 st_blocks = new Signed64(); + public final Signed8[] st_fstype = array(new Signed8[_ST_FSTYPSZ]); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public SolarisFileStat64() { + this(null); + } + public SolarisFileStat64(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atim_sec.get(memory); + } + + public long blocks() { + return layout.st_blocks.get(memory); + } + + public long blockSize() { + return layout.st_blksize.get(memory); + } + + public long ctime() { + return layout.st_ctim_sec.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & 0xffff; + } + + public long mtime() { + return layout.st_mtim_sec.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + @Override + public long aTimeNanoSecs() { + return layout.st_atim_nsec.get(memory); + } + + @Override + public long cTimeNanoSecs() { + return layout.st_ctim_nsec.get(memory); + } + + @Override + public long mTimeNanoSecs() { + return layout.st_mtim_nsec.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/SolarisLibC.java b/src/main/java/jnr/posix/SolarisLibC.java new file mode 100644 index 0000000..7efd010 --- /dev/null +++ b/src/main/java/jnr/posix/SolarisLibC.java
@@ -0,0 +1,4 @@ +package jnr.posix; + +public interface SolarisLibC extends UnixLibC { +}
diff --git a/src/main/java/jnr/posix/SolarisPOSIX.java b/src/main/java/jnr/posix/SolarisPOSIX.java new file mode 100644 index 0000000..46c7367 --- /dev/null +++ b/src/main/java/jnr/posix/SolarisPOSIX.java
@@ -0,0 +1,110 @@ +package jnr.posix; + +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Sysconf; +import jnr.ffi.*; +import jnr.ffi.mapper.FromNativeContext; +import jnr.posix.util.MethodName; +import jnr.posix.util.Platform; + +import static jnr.constants.platform.Errno.EINVAL; +import jnr.constants.platform.Pathconf; + +final class SolarisPOSIX extends BaseNativePOSIX { + SolarisPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + } + + public FileStat allocateStat() { + return Platform.IS_32_BIT ? new SolarisFileStat32(this) : new SolarisFileStat64(this); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public long sysconf(Sysconf name) { + return libc().sysconf(name); + } + + public int confstr(Confstr name, ByteBuffer buf, int len) { + return libc().confstr(name, buf, len); + } + + public int fpathconf(int fd, Pathconf name) { + return libc().fpathconf(fd, name); + } + + public Times times() { + return NativeTimes.times(this); + } + + public static final int LOCK_SH = 1; + public static final int LOCK_EX = 2; + public static final int LOCK_NB = 4; + public static final int LOCK_UN = 8; + + public static final int SEEK_SET = 0; + + public static class Layout extends StructLayout { + protected Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final int16_t l_type = new int16_t(); // short + public final int16_t l_whence = new int16_t(); // short + public final off_t l_start = new off_t(); + public final off_t l_len = new off_t(); + public final int32_t l_sysid = new int32_t(); // int + public final pid_t l_pid = new pid_t(); + public final int32_t[] l_pad = new int32_t[4]; // int[4] + } + + private static final Layout FLOCK_LAYOUT = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public int flock(int fd, int operation) { + Pointer lock = getRuntime().getMemoryManager().allocateTemporary(FLOCK_LAYOUT.size(), true); + + switch (operation & ~LOCK_NB) { + case LOCK_SH: + FLOCK_LAYOUT.l_type.set(lock, (short) Fcntl.F_RDLCK.intValue()); + break; + case LOCK_EX: + FLOCK_LAYOUT.l_type.set(lock, (short) Fcntl.F_WRLCK.intValue()); + break; + case LOCK_UN: + FLOCK_LAYOUT.l_type.set(lock, (short) Fcntl.F_UNLCK.intValue()); + break; + default: + errno(EINVAL.intValue()); + return -1; + } + FLOCK_LAYOUT.l_whence.set(lock, (short) SEEK_SET); + FLOCK_LAYOUT.l_start.set(lock, 0); + FLOCK_LAYOUT.l_len.set(lock, 0); + + return libc().fcntl(fd, (operation & LOCK_NB) != 0 ? Fcntl.F_SETLK.intValue() : Fcntl.F_SETLKW.intValue(), lock); + } + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + return arg != null ? new SolarisPasswd((Pointer) arg) : null; + } + }; + + public Pointer allocatePosixSpawnFileActions() { + return Memory.allocateDirect(getRuntime(), 8); + } + + public Pointer allocatePosixSpawnattr() { + return Memory.allocateDirect(getRuntime(), 8); + } +}
diff --git a/src/main/java/jnr/posix/SolarisPasswd.java b/src/main/java/jnr/posix/SolarisPasswd.java new file mode 100644 index 0000000..e2c8337 --- /dev/null +++ b/src/main/java/jnr/posix/SolarisPasswd.java
@@ -0,0 +1,59 @@ + +package jnr.posix; + +import jnr.ffi.StructLayout; + +public class SolarisPasswd extends NativePasswd implements Passwd { + static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final UTF8StringRef pw_name = new UTF8StringRef(); // user name + public final UTF8StringRef pw_passwd = new UTF8StringRef(); // password (encrypted) + public final Signed32 pw_uid = new Signed32(); // user id + public final Signed32 pw_gid = new Signed32(); // user id + public final Pointer pw_age = new Pointer(); // unused + public final Pointer pw_comment = new Pointer();// unused + public final UTF8StringRef pw_gecos = new UTF8StringRef(); // login info + public final UTF8StringRef pw_dir = new UTF8StringRef(); // home directory + public final UTF8StringRef pw_shell = new UTF8StringRef(); // default shell + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public SolarisPasswd(jnr.ffi.Pointer memory) { + super(memory); + } + + public java.lang.String getAccessClass() { + return "unknown"; + } + public java.lang.String getGECOS() { + return layout.pw_gecos.get(memory); + } + public long getGID() { + return layout.pw_gid.get(memory); + } + public java.lang.String getHome() { + return layout.pw_dir.get(memory); + } + public java.lang.String getLoginName() { + return layout.pw_name.get(memory); + } + public int getPasswdChangeTime() { + return 0; + } + public java.lang.String getPassword() { + return layout.pw_passwd.get(memory); + } + public java.lang.String getShell() { + return layout.pw_shell.get(memory); + } + public long getUID() { + return layout.pw_uid.get(memory); + } + public int getExpire() { + return Integer.MAX_VALUE; + } +}
diff --git a/src/main/java/jnr/posix/SpawnAttribute.java b/src/main/java/jnr/posix/SpawnAttribute.java new file mode 100644 index 0000000..e9fb913 --- /dev/null +++ b/src/main/java/jnr/posix/SpawnAttribute.java
@@ -0,0 +1,99 @@ +package jnr.posix; + +import jnr.ffi.*; +import jnr.ffi.byref.NumberByReference; + +public abstract class SpawnAttribute { + public static final int RESETIDS = 0x0001; /* [SPN] R[UG]ID not E[UG]ID */ + public static final int SETPGROUP = 0x0002; /* [SPN] set non-parent PGID */ + public static final int SETSIGDEF = 0x0004; /* [SPN] reset sigset default */ + public static final int SETSIGMASK = 0x0008; /* [SPN] set signal mask */ + + abstract boolean set(POSIX posix, Pointer nativeFileActions); + + public static SpawnAttribute pgroup(long pgroup) { + return new PGroup(pgroup); + } + + public static SpawnAttribute flags(short flags) { + return new SetFlags(flags); + } + + public static SpawnAttribute sigdef(long sigdef) { + throw new RuntimeException("sigdefault not yet supported"); +// return new Sigdef(sigdef); + } + + public static SpawnAttribute sigmask(long sigmask) { + throw new RuntimeException("sigmask not yet supported"); +// return new Sigmask(sigmask); + } + + + private static final class PGroup extends SpawnAttribute { + final long pgroup; + + public PGroup(long pgroup) { + this.pgroup = pgroup; + } + + final boolean set(POSIX posix, Pointer nativeSpawnAttr) { + return ((UnixLibC) posix.libc()).posix_spawnattr_setpgroup(nativeSpawnAttr, pgroup) == 0; + } + + public String toString() { + return "SpawnAttribute::PGroup(pgroup = " + pgroup + ")"; + } + } + + private static final class SetFlags extends SpawnAttribute { + final short flags; + + public SetFlags(short flags) { + this.flags = flags; + } + + final boolean set(POSIX posix, Pointer nativeSpawnAttr) { + return ((UnixLibC) posix.libc()).posix_spawnattr_setflags(nativeSpawnAttr, flags) == 0; + } + + public String toString() { + return "SpawnAttribute::SetFlags(flags = " + Integer.toHexString(flags) + ")"; + } + } + + private static final class Sigmask extends SpawnAttribute { + final long sigmask; + + public Sigmask(long sigmask) { + this.sigmask = sigmask; + } + + final boolean set(POSIX posix, Pointer nativeSpawnAttr) { + throw new RuntimeException("sigmask not yet supported"); +// return ((UnixLibC) posix.libc()).posix_spawnattr_setsigmask(nativeSpawnAttr, mask) == 0; + } + + public String toString() { + return "SpawnAttribute::Sigmask(mask = " + Long.toHexString(sigmask) + ")"; + } + } + + private static final class Sigdef extends SpawnAttribute { + final long sigdef; + + public Sigdef(long sigdef) { + this.sigdef = sigdef; + } + + final boolean set(POSIX posix, Pointer nativeSpawnAttr) { + throw new RuntimeException("sigdefault not yet supported"); +// return ((UnixLibC) posix.libc()).posix_spawnattr_setsigdefault(nativeSpawnAttr, sigdef) == 0; + } + + public String toString() { + return "SpawnAttribute::Sigdef(def = " + Long.toHexString(sigdef) + ")"; + } + } + +}
diff --git a/src/main/java/jnr/posix/SpawnFileAction.java b/src/main/java/jnr/posix/SpawnFileAction.java new file mode 100644 index 0000000..1657b3f --- /dev/null +++ b/src/main/java/jnr/posix/SpawnFileAction.java
@@ -0,0 +1,106 @@ +package jnr.posix; + +import jnr.ffi.Pointer; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +public abstract class SpawnFileAction { + abstract boolean act(POSIX posix, Pointer nativeFileActions); + + public static SpawnFileAction dup(int fd, int newfd) { + return new Dup(fd, newfd); + } + + public static SpawnFileAction open(String path, int fd, int flags, int mode) { + return new Open(path, fd, flags, mode); + } + + public static SpawnFileAction close(int fd) { + return new Close(fd); + } + + private static final class Dup extends SpawnFileAction { + final int fd, newfd; + + public Dup(int fd, int newfd) { + this.fd = fd; + this.newfd = newfd; + } + + final boolean act(POSIX posix, Pointer nativeFileActions) { + return ((UnixLibC) posix.libc()).posix_spawn_file_actions_adddup2(nativeFileActions, fd, newfd) == 0; + } + + public String toString() { + return "SpawnFileAction::Dup(old = " + fd + ", new = " + newfd + ")"; + } + } + + private static final class Open extends SpawnFileAction { + final String path; + final int fd; + final int flags, mode; + final ByteBuffer nativePath; + + public Open(String path, int fd, int flags, int mode) { + this.path = path; + this.fd = fd; + this.flags = flags; + this.mode = mode; + this.nativePath = defensiveCopy(path); + } + + private ByteBuffer defensiveCopy(String path) { + /* + This logic allocates a direct ByteBuffer to use for the path in order to work around systems that have not + patched CVE-2014-4043, in which older glibc versions do not make a defensive copy of the file path passed to + posix_spawn_file_actions_addopen. The buffer may be freed by the caller before it can be used in an + eventual posix_spawn call. + + See https://bugzilla.redhat.com/show_bug.cgi?id=1983750 for a RHEL version of this issue. + */ + + // determine encoded byte array length + CharsetEncoder encoder = Charset.defaultCharset().newEncoder(); + int bpc = (int) encoder.maxBytesPerChar(); + int size = (path.length() + 1) * bpc; + + // transcode to native buffer + ByteBuffer nativePath = ByteBuffer.allocateDirect(size); + encoder.encode(CharBuffer.wrap(path), nativePath, true); + nativePath.flip(); + + // null terminate + nativePath.limit(nativePath.limit() + bpc); + + return nativePath; + } + + final boolean act(POSIX posix, Pointer nativeFileActions) { + return ((UnixLibC) posix.libc()).posix_spawn_file_actions_addopen(nativeFileActions, fd, nativePath, flags, mode) == 0; + } + + public String toString() { + return "SpawnFileAction::Open(path = '" + path + "', fd = " + fd + ", flags = " + Integer.toHexString(flags) + ", mode = " + Integer.toHexString(mode) + ")"; + } + } + + private static final class Close extends SpawnFileAction { + final int fd; + + public Close(int fd) { + this.fd = fd; + } + + final boolean act(POSIX posix, Pointer nativeFileActions) { + return ((UnixLibC) posix.libc()).posix_spawn_file_actions_addclose(nativeFileActions, fd) == 0; + } + + public String toString() { + return "SpawnFileAction::Close(fd = " + fd + ")"; + } + } +}
diff --git a/src/main/java/jnr/posix/Times.java b/src/main/java/jnr/posix/Times.java new file mode 100644 index 0000000..ed34fce --- /dev/null +++ b/src/main/java/jnr/posix/Times.java
@@ -0,0 +1,9 @@ +package jnr.posix; + + +public interface Times { + public abstract long utime(); + public abstract long stime(); + public abstract long cutime(); + public abstract long cstime(); +}
diff --git a/src/main/java/jnr/posix/Timespec.java b/src/main/java/jnr/posix/Timespec.java new file mode 100644 index 0000000..a092070 --- /dev/null +++ b/src/main/java/jnr/posix/Timespec.java
@@ -0,0 +1,14 @@ +package jnr.posix; + +import jnr.ffi.Struct; + +abstract public class Timespec extends Struct { + public Timespec(jnr.ffi.Runtime runtime) { + super(runtime); + } + abstract public void setTime(long[] timespec); + public abstract void sec(long sec); + public abstract void nsec(long nsec); + public abstract long sec(); + public abstract long nsec(); +}
diff --git a/src/main/java/jnr/posix/Timeval.java b/src/main/java/jnr/posix/Timeval.java new file mode 100644 index 0000000..e5942e4 --- /dev/null +++ b/src/main/java/jnr/posix/Timeval.java
@@ -0,0 +1,14 @@ +package jnr.posix; + +import jnr.ffi.Struct; + +abstract public class Timeval extends Struct { + public Timeval(jnr.ffi.Runtime runtime) { + super(runtime); + } + abstract public void setTime(long[] timeval); + public abstract void sec(long sec); + public abstract void usec(long usec); + public abstract long sec(); + public abstract long usec(); +}
diff --git a/src/main/java/jnr/posix/UTimBuf64.java b/src/main/java/jnr/posix/UTimBuf64.java new file mode 100644 index 0000000..f836e4e --- /dev/null +++ b/src/main/java/jnr/posix/UTimBuf64.java
@@ -0,0 +1,14 @@ +package jnr.posix; + +import jnr.ffi.Struct; + +public final class UTimBuf64 extends Struct { + public final Signed64 actime = new Signed64(); + public final Signed64 modtime = new Signed64(); + + public UTimBuf64(jnr.ffi.Runtime runtime, long actime, long modtime) { + super(runtime); + this.actime.set(actime); + this.modtime.set(modtime); + } +}
diff --git a/src/main/java/jnr/posix/UnixLibC.java b/src/main/java/jnr/posix/UnixLibC.java new file mode 100644 index 0000000..89666be --- /dev/null +++ b/src/main/java/jnr/posix/UnixLibC.java
@@ -0,0 +1,48 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.annotations.Direct; +import jnr.ffi.annotations.In; +import jnr.ffi.annotations.Out; +import jnr.ffi.byref.ByReference; +import jnr.ffi.byref.IntByReference; +import jnr.ffi.byref.NumberByReference; +import jnr.ffi.byref.ShortByReference; +import jnr.ffi.types.pid_t; + +import java.nio.ByteBuffer; + +public interface UnixLibC extends LibC { + public int posix_spawn(@Out ByReference pid, @In CharSequence path, @In Pointer fileActions, + @In Pointer attr, @In CharSequence[] argv, @In CharSequence[] envp); + + public int posix_spawnp(@Out ByReference pid, @In CharSequence path, @In Pointer fileActions, + @In Pointer attr, @In CharSequence[] argv, @In CharSequence[] envp); + + public int posix_spawn_file_actions_init(Pointer fileActions); + public int posix_spawn_file_actions_destroy(Pointer fileActions); + public int posix_spawn_file_actions_addclose(Pointer fileActions, int filedes); + + /** + * @deprecated due to CVE-2014-4043 (https://bugzilla.redhat.com/show_bug.cgi?id=1983750) + */ + @Deprecated + public int posix_spawn_file_actions_addopen(Pointer fileActions, int filedes, CharSequence path, + int oflag, int mode); + public int posix_spawn_file_actions_addopen(Pointer fileActions, int filedes, @Direct ByteBuffer path, + int oflag, int mode); + public int posix_spawn_file_actions_adddup2(Pointer fileActions, int filedes, int newfiledes); + public int posix_spawnattr_init(Pointer attr); + public int posix_spawnattr_destroy(Pointer attr); + public int posix_spawnattr_setflags(Pointer attr, short flags); + public int posix_spawnattr_getflags(Pointer attr, ShortByReference flags); + public int posix_spawnattr_setpgroup(Pointer attr, @pid_t long pgroup); + public int posix_spawnattr_getpgroup(Pointer attr, NumberByReference pgroup); + public int posix_spawnattr_setsigmask(Pointer attr, Pointer sigmask); + public int posix_spawnattr_getsigmask(Pointer attr, Pointer sigmask); + public int posix_spawnattr_setsigdefault(Pointer attr, Pointer sigdefault); + public int posix_spawnattr_getsigdefault(Pointer attr, Pointer sigdefault); + public int sigprocmask(int how, Pointer set, Pointer get); + + int mkfifo(CharSequence filename, int mode); +}
diff --git a/src/main/java/jnr/posix/WString.java b/src/main/java/jnr/posix/WString.java new file mode 100644 index 0000000..590a858 --- /dev/null +++ b/src/main/java/jnr/posix/WString.java
@@ -0,0 +1,60 @@ +package jnr.posix; + +import jnr.ffi.Memory; +import jnr.ffi.Pointer; +import jnr.ffi.mapper.ToNativeContext; +import jnr.ffi.mapper.ToNativeConverter; +import jnr.posix.util.WindowsHelpers; + +public final class WString { + static final jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); + + private final byte[] bytes; + + WString(String string) { + bytes = WindowsHelpers.toWString(string); + } + + private WString(byte[] bytes) { + this.bytes = bytes; + } + + public static WString path(String path) { + return new WString(path(path, false)); + } + + public static byte[] path(String path, boolean longPathExtensionNeeded) { + if (longPathExtensionNeeded && path.length() > 240) { // FIXME: This is not right value. Needs tests around actual char boundary. + if (path.startsWith("//")) { // UNC Path + path = "//?/UNC/" + path.substring(2); + } else if (path.startsWith("\\\\")) { + path = "\\\\?\\UNC\\" + path.substring(2); + } else if (WindowsHelpers.isDriveLetterPath(path)) { + if (path.contains("/")) { + path = "//?/" + path; + } else { + path = "\\\\?\\" + path; + } + } + } + + return WindowsHelpers.toWPath(path); + } + + public static final ToNativeConverter<WString, Pointer> Converter = new ToNativeConverter<WString, Pointer>() { + + public Pointer toNative(WString value, ToNativeContext context) { + if (value == null) { + return null; + } + + Pointer memory = Memory.allocateDirect(runtime, value.bytes.length + 1, true); + memory.put(0, value.bytes, 0, value.bytes.length); + return memory; + } + + public Class<Pointer> nativeType() { + return Pointer.class; + } + }; +}
diff --git a/src/main/java/jnr/posix/WindowsChildRecord.java b/src/main/java/jnr/posix/WindowsChildRecord.java new file mode 100644 index 0000000..d4442e6 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsChildRecord.java
@@ -0,0 +1,28 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +/** + * + * @author enebo + */ +public class WindowsChildRecord { + private final HANDLE process; + private final int pid; + + public WindowsChildRecord(HANDLE process, int pid) { + this.process = process; + this.pid = pid; + } + + public HANDLE getProcess() { + return process; + } + + public int getPid() { + return pid; + } +}
diff --git a/src/main/java/jnr/posix/WindowsFileStat.java b/src/main/java/jnr/posix/WindowsFileStat.java new file mode 100644 index 0000000..96120e7 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsFileStat.java
@@ -0,0 +1,169 @@ +package jnr.posix; + +import jnr.ffi.StructLayout; + +// http://msdn.microsoft.com/en-us/library/14h5k7ff.aspx +// This layout is meant to be used with stat64() family so _USE_32BIT_TIME_T is not in play. +public class WindowsFileStat extends BaseFileStat { + private static final class Layout extends StructLayout { + + private Layout(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public final Signed32 st_dev = new Signed32(); + public final Signed16 st_ino = new Signed16(); + public final Signed16 st_mode = new Signed16(); + public final Signed16 st_nlink = new Signed16(); + public final Signed16 st_uid = new Signed16(); + public final Signed16 st_gid = new Signed16(); + public final Signed32 st_rdev = new Signed32(); + public final Signed64 st_size = new Signed64(); + public final Signed64 st_atime = new Signed64(); + public final Signed64 st_mtime = new Signed64(); + public final Signed64 st_ctime = new Signed64(); + } + private static final Layout layout = new Layout(jnr.ffi.Runtime.getSystemRuntime()); + + public WindowsFileStat(NativePOSIX posix) { + super(posix, layout); + } + + public long atime() { + return layout.st_atime.get(memory); + } + + public long blockSize() { + return 512; + } + + public long blocks() { + return (layout.st_size.get(memory) + 512 - 1) / 512; + } + + public long ctime() { + return layout.st_ctime.get(memory); + } + + public long dev() { + return layout.st_dev.get(memory); + } + + public int gid() { + return layout.st_gid.get(memory); + } + + public long ino() { + return layout.st_ino.get(memory); + } + + public int mode() { + return layout.st_mode.get(memory) & ~(S_IWGRP | S_IWOTH) & 0xffff; + } + + public long mtime() { + return layout.st_mtime.get(memory); + } + + public int nlink() { + return layout.st_nlink.get(memory); + } + + public long rdev() { + return layout.st_rdev.get(memory); + } + + public long st_size() { + return layout.st_size.get(memory); + } + + public int uid() { + return layout.st_uid.get(memory); + } + + // FIXME: Implement + @Override + public boolean groupMember(int gid) { + return true; + } + + @Override + public boolean isExecutable() { + if (isOwned()) return (mode() & S_IXUSR) != 0; + if (isGroupOwned()) return (mode() & S_IXGRP) != 0; + if ((mode() & S_IXOTH) != 0) return false; + + return true; + } + + @Override + public boolean isExecutableReal() { + if (isROwned()) return (mode() & S_IXUSR) != 0; + if (groupMember(gid())) return (mode() & S_IXGRP) != 0; + if ((mode() & S_IXOTH) != 0) return false; + + return true; + } + + // FIXME: Implement + @Override + public boolean isOwned() { + return true; + } + + // FIXME: Implement + @Override + public boolean isROwned() { + return true; + } + @Override + public boolean isReadable() { + if (isOwned()) return (mode() & S_IRUSR) != 0; + if (isGroupOwned()) return (mode() & S_IRGRP) != 0; + if ((mode() & S_IROTH) != 0) return false; + + return true; + } + + @Override + public boolean isReadableReal() { + if (isROwned()) return (mode() & S_IRUSR) != 0; + if (groupMember(gid())) return (mode() & S_IRGRP) != 0; + if ((mode() & S_IROTH) != 0) return false; + + return true; + } + + @Override + public boolean isWritable() { + if (isOwned()) return (mode() & S_IWUSR) != 0; + if (isGroupOwned()) return (mode() & S_IWGRP) != 0; + if ((mode() & S_IWOTH) != 0) return false; + + return true; + } + + @Override + public boolean isWritableReal() { + if (isROwned()) return (mode() & S_IWUSR) != 0; + if (groupMember(gid())) return (mode() & S_IWGRP) != 0; + if ((mode() & S_IWOTH) != 0) return false; + + return true; + } + + @Override + public java.lang.String toString() { + return "st_dev: " + layout.st_dev.get(memory) + + ", st_mode: " + Integer.toOctalString(mode()) + + ", layout.st_nlink: " + layout.st_nlink.get(memory) + + ", layout.st_rdev: " + layout.st_rdev.get(memory) + + ", layout.st_size: " + layout.st_size.get(memory) + + ", layout.st_uid: " + layout.st_uid.get(memory) + + ", layout.st_gid: " + layout.st_gid.get(memory) + + ", layout.st_atime: " + layout.st_atime.get(memory) + + ", layout.st_ctime: " + layout.st_ctime.get(memory) + + ", layout.st_mtime: " + layout.st_mtime.get(memory) + + ", layout.st_ino: " + layout.st_ino.get(memory); + } +}
diff --git a/src/main/java/jnr/posix/WindowsLibC.java b/src/main/java/jnr/posix/WindowsLibC.java new file mode 100644 index 0000000..495f399 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsLibC.java
@@ -0,0 +1,130 @@ +package jnr.posix; + +import jnr.ffi.Pointer; +import jnr.ffi.Variable; +import jnr.ffi.annotations.In; +import jnr.ffi.annotations.Out; +import jnr.ffi.annotations.StdCall; +import jnr.ffi.annotations.Transient; +import jnr.ffi.byref.IntByReference; + +import java.nio.ByteBuffer; +import jnr.posix.windows.SystemTime; +import jnr.posix.windows.WindowsByHandleFileInformation; +import jnr.posix.windows.WindowsFileInformation; +import jnr.posix.windows.WindowsFindData; + +public interface WindowsLibC extends LibC { + public static final int STD_INPUT_HANDLE = -10; + public static final int STD_OUTPUT_HANDLE = -11; + public static final int STD_ERROR_HANDLE = -12; + + public static final int NORMAL_PRIORITY_CLASS = 0x00000020; + public static final int CREATE_UNICODE_ENVIRONMENT = 0x00000400; + + public static final int INFINITE = -1; + + public static final int FILE_TYPE_DISK = 0x0001; + public static final int FILE_TYPE_CHAR = 0x0002; + public static final int FILE_TYPE_PIPE = 0x0003; + public static final int FILE_TYPE_REMOTE = 0x8000; + public static final int FILE_TYPE_UNKNOWN = 0x0000; + + public static final int PROCESS_QUERY_INFORMATION = 0x0400; + + public int _open_osfhandle(HANDLE handle, int flags); + public HANDLE _get_osfhandle(int fd); + public int _close(int fd); + public int _getpid(); + int _stat64(CharSequence path, @Out @Transient FileStat stat); + + int _umask(int mask); + + public int _wmkdir(@In WString path); + public boolean RemoveDirectoryW(@In WString path); + public int _wchmod(@In WString path, int pmode); + public int _wchdir(@In WString path); + public int _wstat64(@In WString path, @Out @Transient FileStat stat); + public int _wstat64(@In byte[] path, @Out @Transient FileStat stat); + public int _pipe(int[] fds, int psize, int textmode); + + @StdCall + public boolean CreateProcessW(byte[] applicationName, + @In @Out ByteBuffer buffer, + WindowsSecurityAttributes processAttributes, + WindowsSecurityAttributes threadAttributes, + int inheritHandles, + int creationFlags, + @In Pointer envp, + @In byte[] currentDirectory, + WindowsStartupInfo startupInfo, + WindowsProcessInformation processInformation); + + public HANDLE OpenProcess(@In int desiredAccess, @In int inheritHandle, @In int processId); + + public int FileTimeToSystemTime(@In FileTime fileTime, @Out @Transient SystemTime systemTime); + public int GetFileAttributesW(@In WString path); + public int GetFileAttributesExW(@In WString path, @In int infoLevel, @Out @Transient WindowsFileInformation fileInformation); + public int GetFileAttributesExW(@In byte[] path, @In int infoLevel, @Out @Transient WindowsFileInformation fileInformation); + public int SetFileAttributesW(@In WString path, int flags); + public int GetFileInformationByHandle(@In HANDLE handle, @Out @Transient WindowsByHandleFileInformation fileInformation); + + public int FindClose(HANDLE handle); + public HANDLE FindFirstFileW(@In WString wpath, @Out WindowsFindData findData); + public HANDLE FindFirstFileW(@In byte[] wpath, @Out WindowsFindData findData); + + @StdCall + public boolean GetExitCodeProcess(HANDLE handle, @Out Pointer exitCode); + + @StdCall + public boolean GetExitCodeProcess(HANDLE handle, @Out IntByReference exitCode); + + @StdCall + public int GetFileType(HANDLE handle); + + @StdCall + public int GetFileSize(HANDLE handle, @Out IntByReference outSizeHigh); + + @StdCall + public HANDLE GetStdHandle(int stdHandle); + + @StdCall + public boolean CreateHardLinkW(@In WString oldname, @In WString newName, @In WString reserved); + + @StdCall + HANDLE CreateFileW( + byte[] lpFileName, + int dwDesiredAccess, + int dwShareMode, + Pointer lpSecurityAttributes, + int dwCreationDisposition, + int dwFlagsAndAttributes, + int hTemplateFile + ); + + @StdCall + boolean SetEnvironmentVariableW( + @In WString envName, + @In WString envValue); + + @StdCall + boolean GetComputerNameW( + @Out ByteBuffer lpBuffer, + IntByReference nSize); + + @StdCall + boolean SetFileTime( + HANDLE hFile, + FileTime lpCreationTime, + FileTime lpLastAccessTime, + FileTime lpLastWriteTime + ); + + @StdCall + boolean CloseHandle(HANDLE handle); + + @StdCall + int WaitForSingleObject(HANDLE handle, int milliseconds); + + Variable<Long> _environ(); +}
diff --git a/src/main/java/jnr/posix/WindowsPOSIX.java b/src/main/java/jnr/posix/WindowsPOSIX.java new file mode 100644 index 0000000..926a683 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsPOSIX.java
@@ -0,0 +1,921 @@ +package jnr.posix; + +import jnr.constants.platform.OpenFlags; +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Errno; +import jnr.constants.platform.WaitFlags; +import static jnr.constants.platform.Errno.*; +import static jnr.constants.platform.windows.LastError.*; + +import jnr.ffi.LastError; +import jnr.ffi.Pointer; +import jnr.ffi.byref.IntByReference; +import jnr.ffi.mapper.FromNativeContext; + +import java.io.FileDescriptor; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +import jnr.posix.util.MethodName; +import jnr.posix.util.Platform; +import jnr.posix.util.WindowsHelpers; +import jnr.posix.windows.CommonFileInformation; +import jnr.posix.windows.WindowsByHandleFileInformation; +import jnr.posix.windows.WindowsFileInformation; +import jnr.posix.windows.WindowsFindData; + +final public class WindowsPOSIX extends BaseNativePOSIX { + private final static int FILE_TYPE_CHAR = 0x0002; + + private final static Map<Integer, Errno> errorToErrnoMapper + = new HashMap<Integer, Errno>(); + + static { + errorToErrnoMapper.put(ERROR_INVALID_FUNCTION.value(), EINVAL); + errorToErrnoMapper.put(ERROR_FILE_NOT_FOUND.value(), ENOENT); + errorToErrnoMapper.put(ERROR_PATH_NOT_FOUND.value(), ENOENT); + errorToErrnoMapper.put(ERROR_TOO_MANY_OPEN_FILES.value(), EMFILE); + errorToErrnoMapper.put(ERROR_ACCESS_DENIED.value(), EACCES); + errorToErrnoMapper.put(ERROR_INVALID_HANDLE.value(), EBADF ); + errorToErrnoMapper.put(ERROR_ARENA_TRASHED.value(), ENOMEM); + errorToErrnoMapper.put(ERROR_NOT_ENOUGH_MEMORY.value(), ENOMEM); + errorToErrnoMapper.put(ERROR_INVALID_BLOCK.value(), ENOMEM); + errorToErrnoMapper.put(ERROR_BAD_ENVIRONMENT.value(), E2BIG ); + errorToErrnoMapper.put(ERROR_BAD_FORMAT.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_ACCESS.value(), EINVAL); + errorToErrnoMapper.put(ERROR_INVALID_DATA.value(), EINVAL); + errorToErrnoMapper.put(ERROR_INVALID_DRIVE.value(), ENOENT); + errorToErrnoMapper.put(ERROR_CURRENT_DIRECTORY.value(), EACCES); + errorToErrnoMapper.put(ERROR_NOT_SAME_DEVICE.value(), EXDEV ); + errorToErrnoMapper.put(ERROR_NO_MORE_FILES.value(), ENOENT); + errorToErrnoMapper.put(ERROR_WRITE_PROTECT.value(), EROFS ); + errorToErrnoMapper.put(ERROR_BAD_UNIT.value(), ENODEV); + errorToErrnoMapper.put(ERROR_NOT_READY.value(), ENXIO ); + errorToErrnoMapper.put(ERROR_BAD_COMMAND.value(), EACCES); + errorToErrnoMapper.put(ERROR_CRC.value(), EACCES); + errorToErrnoMapper.put(ERROR_BAD_LENGTH.value(), EACCES); + errorToErrnoMapper.put(ERROR_SEEK.value(), EIO); + errorToErrnoMapper.put(ERROR_NOT_DOS_DISK.value(), EACCES); + errorToErrnoMapper.put(ERROR_SECTOR_NOT_FOUND.value(), EACCES); + errorToErrnoMapper.put(ERROR_OUT_OF_PAPER.value(), EACCES); + errorToErrnoMapper.put(ERROR_WRITE_FAULT.value(), EIO); + errorToErrnoMapper.put(ERROR_READ_FAULT.value(), EIO); + errorToErrnoMapper.put(ERROR_GEN_FAILURE.value(), EACCES); + errorToErrnoMapper.put(ERROR_LOCK_VIOLATION.value(), EACCES); + errorToErrnoMapper.put(ERROR_SHARING_VIOLATION.value(), EACCES); + errorToErrnoMapper.put(ERROR_WRONG_DISK.value(), EACCES); + errorToErrnoMapper.put(ERROR_SHARING_BUFFER_EXCEEDED.value(), EACCES); + errorToErrnoMapper.put(ERROR_BAD_NETPATH.value(), ENOENT); + errorToErrnoMapper.put(ERROR_NETWORK_ACCESS_DENIED.value(), EACCES); + errorToErrnoMapper.put(ERROR_BAD_NET_NAME.value(), ENOENT); + errorToErrnoMapper.put(ERROR_FILE_EXISTS.value(), EEXIST); + errorToErrnoMapper.put(ERROR_CANNOT_MAKE.value(), EACCES); + errorToErrnoMapper.put(ERROR_FAIL_I24.value(), EACCES); + errorToErrnoMapper.put(ERROR_INVALID_PARAMETER.value(), EINVAL); + errorToErrnoMapper.put(ERROR_NO_PROC_SLOTS.value(), EAGAIN); + errorToErrnoMapper.put(ERROR_DRIVE_LOCKED.value(), EACCES); + errorToErrnoMapper.put(ERROR_BROKEN_PIPE.value(), EPIPE); + errorToErrnoMapper.put(ERROR_DISK_FULL.value(), ENOSPC); + errorToErrnoMapper.put(ERROR_INVALID_TARGET_HANDLE.value(), EBADF); + errorToErrnoMapper.put(ERROR_INVALID_HANDLE.value(), EINVAL); + errorToErrnoMapper.put(ERROR_WAIT_NO_CHILDREN.value(), ECHILD); + errorToErrnoMapper.put(ERROR_CHILD_NOT_COMPLETE.value(), ECHILD); + errorToErrnoMapper.put(ERROR_DIRECT_ACCESS_HANDLE.value(), EBADF); + errorToErrnoMapper.put(ERROR_NEGATIVE_SEEK.value(), EINVAL); + errorToErrnoMapper.put(ERROR_SEEK_ON_DEVICE.value(), EACCES); + errorToErrnoMapper.put(ERROR_DIR_NOT_EMPTY.value(), ENOTEMPTY); + errorToErrnoMapper.put(ERROR_DIRECTORY.value(), ENOTDIR); + errorToErrnoMapper.put(ERROR_NOT_LOCKED.value(), EACCES); + errorToErrnoMapper.put(ERROR_BAD_PATHNAME.value(), ENOENT); + errorToErrnoMapper.put(ERROR_MAX_THRDS_REACHED.value(), EAGAIN); + errorToErrnoMapper.put(ERROR_LOCK_FAILED.value(), EACCES); + errorToErrnoMapper.put(ERROR_ALREADY_EXISTS.value(), EEXIST); + errorToErrnoMapper.put(ERROR_INVALID_STARTING_CODESEG.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_STACKSEG.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_MODULETYPE.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_EXE_SIGNATURE.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_EXE_MARKED_INVALID.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_BAD_EXE_FORMAT.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_ITERATED_DATA_EXCEEDS_64k.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_MINALLOCSIZE.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_DYNLINK_FROM_INVALID_RING.value(),ENOEXEC); + errorToErrnoMapper.put(ERROR_IOPL_NOT_ENABLED.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INVALID_SEGDPL.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_AUTODATASEG_EXCEEDS_64k.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_RING2SEG_MUST_BE_MOVABLE.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_RELOC_CHAIN_XEEDS_SEGLIM.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_INFLOOP_IN_RELOC_CHAIN.value(), ENOEXEC); + errorToErrnoMapper.put(ERROR_FILENAME_EXCED_RANGE.value(), ENOENT); + errorToErrnoMapper.put(ERROR_NESTING_NOT_ALLOWED.value(), EAGAIN); + // ERROR_PIPE_LOCAL (in MRI) + errorToErrnoMapper.put(229, EPIPE); + errorToErrnoMapper.put(ERROR_BAD_PIPE.value(), EPIPE); + errorToErrnoMapper.put(ERROR_PIPE_BUSY.value(), EAGAIN); + errorToErrnoMapper.put(ERROR_NO_DATA.value(), EPIPE); + errorToErrnoMapper.put(ERROR_PIPE_NOT_CONNECTED.value(), EPIPE); + errorToErrnoMapper.put(ERROR_OPERATION_ABORTED.value(), EINTR); + errorToErrnoMapper.put(ERROR_NOT_ENOUGH_QUOTA.value(), ENOMEM); + errorToErrnoMapper.put(ERROR_MOD_NOT_FOUND.value(), ENOENT); + errorToErrnoMapper.put(WSAENAMETOOLONG.value(), ENAMETOOLONG); + errorToErrnoMapper.put(WSAENOTEMPTY.value(), ENOTEMPTY); + errorToErrnoMapper.put(WSAEINTR.value(), EINTR); + errorToErrnoMapper.put(WSAEBADF.value(), EBADF); + errorToErrnoMapper.put(WSAEACCES.value(), EACCES); + errorToErrnoMapper.put(WSAEFAULT.value(), EFAULT); + errorToErrnoMapper.put(WSAEINVAL.value(), EINVAL); + errorToErrnoMapper.put(WSAEMFILE.value(), EMFILE); + } + + private final FileStat checkFdStat; + + WindowsPOSIX(LibCProvider libc, POSIXHandler handler) { + super(libc, handler); + this.checkFdStat = new WindowsFileStat(this); + } + + @Override + public FileStat allocateStat() { + return new WindowsRawFileStat(this, handler); + } + + public MsgHdr allocateMsgHdr() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + public SocketMacros socketMacros() { + handler.unimplementedError(MethodName.getCallerMethodName()); + return null; + } + + @Override + public int kill(int pid, int signal) { + handler.unimplementedError("kill"); + + return -1; + } + + @Override + public int kill(long pid, int signal) { + handler.unimplementedError("kill"); + + return -1; + } + + @Override + public int chmod(String filename, int mode) { + return wlibc()._wchmod(WString.path(filename), mode); + } + + @Override + public int chdir(String path) { + return wlibc()._wchdir(WString.path(path)); + } + + @Override + public int chown(String filename, int user, int group) { + return 0; + } + + @Override + public int exec(String path, String[] argv) { + if (argv.length == 1) return spawn(true, argv[0], null, path, null); + + return aspawn(true, null, argv, path, null); + } + + @Override + public CharSequence crypt(CharSequence key, CharSequence salt) { + return JavaLibCHelper.crypt(key, salt); + } + + @Override + public byte[] crypt(byte[] key, byte[] salt) { + return JavaLibCHelper.crypt(key, salt); + } + + @Override + public int exec(String path, String[] argv, String[] envp) { + if (argv.length == 1) return spawn(true, argv[0], null, path, envp); + + return aspawn(true, null, argv, path, envp); + } + + @Override + public int execv(String path, String[] argv) { + handler.unimplementedError("egid"); + + return -1; + } + + @Override + public int getegid() { + handler.unimplementedError("egid"); + + return -1; + } + + @Override + public int setegid(int egid) { + handler.unimplementedError("setegid"); + + return -1; + } + + @Override + public int geteuid() { + return 0; + } + + @Override + public int seteuid(int euid) { + handler.unimplementedError("seteuid"); + + return -1; + } + + @Override + public int getuid() { + return 0; + } + + @Override + public int setuid(int uid) { + handler.unimplementedError("setuid"); + + return -1; + } + + @Override + public int getgid() { + return 0; + } + + @Override + public int setgid(int gid) { + handler.unimplementedError("setgid"); + + return -1; + } + + @Override + public int getpgid(int pid) { + handler.unimplementedError("getpgid"); + + return -1; + } + + @Override + public int getpgid() { + handler.unimplementedError("getpgid"); + + return -1; + } + + @Override + public int setpgid(int pid, int pgid) { + handler.unimplementedError("setpgid"); + + return -1; + } + + @Override + public int getpriority(int which, int who) { + handler.unimplementedError("getpriority"); + + return -1; + } + + @Override + public int setpriority(int which, int who, int prio) { + handler.unimplementedError("setpriority"); + + return -1; + } + + @Override + public int getpid(){ + return wlibc()._getpid(); + } + + @Override + public int getppid() { + return 0; + } + + @Override + public int lchmod(String filename, int mode) { + handler.unimplementedError("lchmod"); + + return -1; + } + + @Override + public int lchown(String filename, int user, int group) { + handler.unimplementedError("lchown"); + + return -1; + } + + @Override + public String gethostname() { + ByteBuffer buffer = ByteBuffer.allocate(64); + IntByReference len = new IntByReference(buffer.capacity() - 1); + if (!wlibc().GetComputerNameW(buffer, len)) return helper.gethostname(); + buffer.limit(len.intValue() * 2); + return Charset.forName("UTF-16LE").decode(buffer).toString(); + } + + public FileStat fstat(int fd) { + WindowsFileStat stat = new WindowsFileStat(this); + if (fstat(fd, stat) < 0) handler.error(Errno.valueOf(errno()), "fstat", "" + fd); + return stat; + } + + @Override + public int fstat(FileDescriptor fileDescriptor, FileStat stat) { + WindowsByHandleFileInformation info = new WindowsByHandleFileInformation(getRuntime()); + if (wlibc().GetFileInformationByHandle(JavaLibCHelper.gethandle(fileDescriptor), info) == 0) return -1; + + ((WindowsRawFileStat) stat).setup(info); + + return 0; + } + + @Override + public FileStat lstat(String path) { + return stat(path); + } + + @Override + public int lstat(String path, FileStat stat) { + return stat(path, stat); // windows stat honors windows equiv of softlinks and dangling ones. + } + + @Override + public int stat(String path, FileStat stat) { + WindowsFileInformation info = new WindowsFileInformation(getRuntime()); + byte[] wpath = WString.path(path, true); + + if (wlibc().GetFileAttributesExW(wpath, 0, info) != 0) { + ((WindowsRawFileStat) stat).setup(path, info); + } else { + int e = errno(); + + if (e == ERROR_FILE_NOT_FOUND.intValue() || e == ERROR_PATH_NOT_FOUND.intValue() + || e == ERROR_BAD_NETPATH.intValue()) { + return -1; + } + + return findFirstFile(path, stat); + } + + return 0; + } + + // Public so we can test this via unit-testing. This makes me wish we had a whole different interface for + // windows APIs user32/kernel32 that this class could consume easily. We are clearly missing an abstraction + // or project here. + public int findFirstFile(String path, FileStat stat) { + byte[] wpath = WString.path(path, true); + WindowsFindData findData = new WindowsFindData(getRuntime()); + HANDLE handle = wlibc().FindFirstFileW(wpath, findData); + if (!handle.isValid()) return -1; + wlibc().FindClose(handle); + ((WindowsRawFileStat) stat).setup(path, findData); + + return 0; + } + + @Override + public String readlink(String oldpath) { + handler.unimplementedError("readlink"); + + return null; + } + + @Override + public Pointer environ() { + return getRuntime().getMemoryManager().newPointer(wlibc()._environ().get()); + } + + @Override + public int setenv(String envName, String envValue, int overwrite) { + if (envName.contains("=")) { + handler.error(EINVAL, "setenv", envName); + return -1; + } + + // FIXME: We do not have getenv implemented yet. So we are ignoring for now + // POSIX specified. Existence is success if overwrite is 0. + // if (overwrite == 0 && getenv(envName) != null) return 0; + + if (!wlibc().SetEnvironmentVariableW(new WString(envName), new WString(envValue))) { + handler.error(EINVAL, "setenv", envName); + return -1; + } + + return 0; + } + + @Override + public int umask(int mask) { + return wlibc()._umask(mask); + } + + @Override + public int unsetenv(String envName) { + if (!wlibc().SetEnvironmentVariableW(new WString(envName), null)) { + handler.error(EINVAL, "unsetenv", envName); + return -1; + } + + return 0; + } + + + + private static final int GENERIC_ALL = 0x10000000; + private static final int GENERIC_READ = 0x80000000; + private static final int GENERIC_WRITE = 0x40000000; + private static final int GENERIC_EXECUTE = 0x2000000; + + private static final int FILE_SHARE_DELETE = 0x00000004; + private static final int FILE_SHARE_READ = 0x00000001; + private static final int FILE_SHARE_WRITE = 0x00000002; + + private static final int CREATE_ALWAYS = 2; + private static final int CREATE_NEW = 1; + private static final int OPEN_ALWAYS = 4; + private static final int OPEN_EXISTING = 3; + private static final int TRUNCATE_EXISTING = 5; + + public static final int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; + + @Override + public int utimes(String path, long[] atimeval, long[] mtimeval) { + FileTime aTime = timevalToFileTime(atimeval); + FileTime mTime = timevalToFileTime(mtimeval); + return setFileTime(path, aTime, mTime); + } + + @Override + public int utimensat(int dirfd, String path, long[] atimespec, long[] mtimespec, int flag) { + FileTime aTime = timespecToFileTime(atimespec); + FileTime mTime = timespecToFileTime(mtimespec); + return setFileTime(path, aTime, mTime); + } + + private FileTime timevalToFileTime(long[] timeval) { + if (timeval == null) { + return currentFileTime(); + } + + // timeval unit is (sec, microsec) + long unixEpochIn100ns = timeval[0] * 10000000 + timeval[1] * 10; + return unixTimeToFileTime(unixEpochIn100ns); + } + + private FileTime timespecToFileTime(long[] timespec) { + if (timespec == null) { + return currentFileTime(); + } + + // timespec unit is (sec, nanosec) + long unixEpochIn100ns = timespec[0] * 10000000 + timespec[1] / 100; + return unixTimeToFileTime(unixEpochIn100ns); + } + + private int setFileTime(String path, FileTime aTime, FileTime mTime) { + byte[] wpath = WindowsHelpers.toWPath(path); + HANDLE handle = wlibc().CreateFileW(wpath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + null, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + if (!handle.isValid()) { + return -1; // TODO proper error handling + } + + boolean timeSet = wlibc().SetFileTime(handle, null, aTime, mTime); + wlibc().CloseHandle(handle); + + return timeSet ? 0 : -1; + } + + /** + * + * @param unixEpochIn100ns epoch time in 100-ns precision + * @return associated FILETIME structure + */ + private FileTime unixTimeToFileTime(long unixEpochIn100ns) { + // FILETIME is a 64-bit unsigned integer representing + // the number of 100-nanosecond intervals since January 1, 1601 + // UNIX timestamp is number of seconds since January 1, 1970 + // 116444736000000000 = 10_000_000 * 60 * 60 * 24 * 365 * 369 + 89 leap days + long ft = 116444736000000000L + unixEpochIn100ns; + + //long ft = CommonFileInformation.asNanoSeconds(unixTimeSeconds); + FileTime fileTime = new FileTime(getRuntime()); + fileTime.dwLowDateTime.set(ft & 0xFFFFFFFFL); + fileTime.dwHighDateTime.set((ft >> 32) & 0xFFFFFFFFL); + return fileTime; + } + + private FileTime nullFileTime() { + FileTime fileTime = new FileTime(getRuntime()); + fileTime.dwLowDateTime.set(0); + fileTime.dwHighDateTime.set(0); + return fileTime; + } + + private FileTime currentFileTime() { + return unixTimeToFileTime(System.currentTimeMillis() * 10000); + } + + @Override + public int wait(int[] status) { + handler.unimplementedError("wait"); + + return -1; + } + + @Override + public int waitpid(int pid, int[] status, int flags) { + if (pid <= 0) { + handler.unimplementedError("waitpid"); + } + + HANDLE h = wlibc().OpenProcess(WindowsLibC.PROCESS_QUERY_INFORMATION, 0, pid); + if (h == null) { + return -1; // TODO: Throw exception + } + + // Block + if ((flags & WaitFlags.WNOHANG.intValue()) != 0) { + wlibc().WaitForSingleObject(h, WindowsLibC.INFINITE); + } + + IntByReference exitCode = new IntByReference(); + wlibc().GetExitCodeProcess(h, exitCode); + wlibc().CloseHandle(h); + int code = exitCode.getValue(); + if (code == 259) { + return 0; + } else { + status[0] = code; + return pid; + } + } + + @Override + public int waitpid(long pid, int[] status, int flags) { + if (pid > Integer.MAX_VALUE) { + throw new java.lang.IllegalArgumentException("waitpid"); + } + return waitpid((int) pid, status, flags); + } + + @Override + public String getlogin() { + return helper.getlogin(); + } + + @Override + public int endgrent() { + return 0; + } + + @Override + public int endpwent() { + return helper.endpwent(); + } + + @Override + public Group getgrent() { + return null; + } + + @Override + public Passwd getpwent() { + return null; + } + + @Override + public Group getgrgid(int which) { + return null; + } + + @Override + public Passwd getpwnam(String which) { + return null; + } + + @Override + public Group getgrnam(String which) { + return null; + } + + @Override + public int setgrent() { + return 0; + } + + @Override + public int setpwent() { + return helper.setpwent(); + } + + @Override + public Passwd getpwuid(int which) { + return null; + } + + @Override + public boolean isatty(FileDescriptor fd) { + HANDLE handle = JavaLibCHelper.gethandle(fd); + + int type = wlibc().GetFileType(handle); + return type == FILE_TYPE_CHAR; + } + + @Override + public int isatty(int fd) { + HANDLE handle = JavaLibCHelper.gethandle(fd); + + int type = wlibc().GetFileType(handle); + return type == FILE_TYPE_CHAR ? 1 : 0; + } + + @Override + public int mkdir(String path, int mode) { + WString widePath = WString.path(path); + int res = -1; + + if (wlibc()._wmkdir(widePath) == 0) { + res = wlibc()._wchmod(widePath, mode); + } + + if (res < 0) { + int errno = errno(); + handler.error(Errno.valueOf(errno), "mkdir", path); + } + return res; + } + + // FIXME: Should this and other fields be part of constantine/jnr-constants? + static final int FILE_ATTRIBUTE_READONLY = 1; + static final int INVALID_FILE_ATTRIBUTES = -1; + + /** + * The logic here is a bit strange and this copies MRI (Ruby) which may not be language + * agnostic, but windows (win7 and others) automatically mark folders as read-only when + * it contains other files and folders within it. This document explains more: + * http://support.microsoft.com/kb/326549 + * I think the logic is based around idea that if you removed all other files it would + * be empty but will stay marked as read-only. + * + * @param path the path to remove + * @return 0 if successful, -1 if failed + */ + @Override + public int rmdir(String path) { + WString pathW = WString.path(path); + int attr = wlibc().GetFileAttributesW(pathW); + boolean isReadOnly = attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_READONLY) != 0; + + if (isReadOnly) wlibc().SetFileAttributesW(pathW, attr & ~FILE_ATTRIBUTE_READONLY); + + if (!wlibc().RemoveDirectoryW(pathW)) { + int errno = errno(); + + if (isReadOnly) wlibc().SetFileAttributesW(pathW, attr & FILE_ATTRIBUTE_READONLY); + + handler.error(mapErrorToErrno(errno), "rmdir", path); + + return -1; + } + + return 0; + } + + @Override + public int link(String oldpath, String newpath) { + boolean linkCreated = wlibc().CreateHardLinkW(WString.path(newpath), WString.path(oldpath), null); + + if (!linkCreated) { + int error = errno(); + handler.error(mapErrorToErrno(error), "link", oldpath + " or " + newpath); + return error; + } else { + return 0; + } + } + + /** + * @param overlay is P_OVERLAY if true and P_NOWAIT if false + * @param program to be invoked + * @param argv is all args including argv0 being what is executed + * @param path is path to be searched when needed (delimited by ; on windows) + * @param envp is a set of KEY=VALUE strings to be set in the child process + * @return the pid + */ + public int aspawn(boolean overlay, String program, String[] argv, String path, String[] envp) { + try { + if (argv.length == 0) return -1; + + String[] cmds = WindowsHelpers.processCommandArgs(this, program, argv, path); + + return childResult(createProcess("aspawn", cmds[0], cmds[1], null, null, null, null, envp), overlay); + } catch (Exception e) { + return -1; + } + } + + public int pipe(int[] fds) { + // TODO (nirvdrum 06-May-15) Maybe not hard-code the psize value. But figure out a sensible way to handle textmode. + return ((WindowsLibC) libc())._pipe(fds, 512, 0); + } + + public int truncate(CharSequence path, long length) { + // Windows doesn't have a native truncate() equivalent, but it does have a native ftruncate() equivalent. + // In order to call the ftruncate() equivalent, we must convert a path to a FD. We do that by wrapping the + // ftruncate() call with open() and close(). + + // Permissions are ignored since we're not using O_CREAT. + int fd = libc().open(path, OpenFlags.O_WRONLY.intValue(), 0); + if (fd == -1) { + return -1; + } + + if (libc().ftruncate(fd, length) == -1) { + return -1; + } + + if (libc().close(fd) == -1) { + return -1; + } + + // truncate() returns 0 on success. + return 0; + } + + public int fcntlInt(int fd, Fcntl fcntl, int arg) { + switch(fcntl) { + case F_GETFD: { + if (checkFd(fd) == -1) { + return -1; + } else { + // This is a gigantic hack. Indicate that Windows does not support close-on-exec. + return 0; + } + } + + case F_SETFD: { + if (checkFd(fd) == -1) { + return -1; + } else { + // This is a gigantic hack. Indicate that Windows does not support close-on-exec by no-oping. + return 0; + } + } + + case F_GETFL: { + if (checkFd(fd) == -1) { + return -1; + } else { + // TODO (nirvdrum 06-May-15): Look up the actual flags rather than optimistically hard-coding this set. + return OpenFlags.O_RDWR.intValue(); + } + } + + default: { + handler.unimplementedError("fcntl"); + + return -1; + } + } + } + + private WindowsLibC wlibc() { + return (WindowsLibC) libc(); + } + + /** + * @param overlay is P_OVERLAY if true and P_NOWAIT if false + * @param command full command string + * @param program program to be invoked + * @param path is path to be searched when needed (delimited by ; on windows) + * @param envp is a set of KEY=VALUE strings to be set in the child process + * @return the pid + */ + public int spawn(boolean overlay, String command, String program, String path, String[] envp) { + if (command == null) return -1; + + String[] cmds = WindowsHelpers.processCommandLine(this, command, program, path); + + return childResult(createProcess("spawn", cmds[0], cmds[1], null, null, null, null, envp), overlay); + } + + private int childResult(WindowsChildRecord child, boolean overlay) { + if (child == null) return -1; + + if (overlay) { + IntByReference exitCode = new IntByReference(); + + WindowsLibC libc = (WindowsLibC) libc(); + HANDLE handle = child.getProcess(); + + libc.WaitForSingleObject(handle, WindowsLibC.INFINITE); + libc.GetExitCodeProcess(handle, exitCode); + libc.CloseHandle(handle); + System.exit(exitCode.getValue()); + } + + return child.getPid(); + } + + private static Errno mapErrorToErrno(int error) { + Errno errno = errorToErrnoMapper.get(error); + if (errno == null) { + errno = __UNKNOWN_CONSTANT__; + } + return errno; + } + + private static final int STARTF_USESTDHANDLES = 0x00000100; + + // Used by spawn and aspawn (Note: See fixme below...envp not hooked up yet) + private WindowsChildRecord createProcess(String callingMethodName, String command, String program, + WindowsSecurityAttributes securityAttributes, HANDLE input, + HANDLE output, HANDLE error, String[] envp) { + if (command == null && program == null) { + handler.error(EFAULT, callingMethodName, "no command or program specified"); + return null; + } + + if (securityAttributes == null) { + securityAttributes = new WindowsSecurityAttributes(getRuntime()); + } + + WindowsStartupInfo startupInfo = new WindowsStartupInfo(getRuntime()); + + startupInfo.setFlags(STARTF_USESTDHANDLES); + startupInfo.setStandardInput(input != null ? input : + wlibc().GetStdHandle(WindowsLibC.STD_INPUT_HANDLE)); + startupInfo.setStandardOutput(output != null ? output : + wlibc().GetStdHandle(WindowsLibC.STD_OUTPUT_HANDLE)); + startupInfo.setStandardError(error != null ? input : + wlibc().GetStdHandle(WindowsLibC.STD_ERROR_HANDLE)); + + int creationFlags = WindowsLibC.NORMAL_PRIORITY_CLASS | WindowsLibC.CREATE_UNICODE_ENVIRONMENT; + WindowsProcessInformation processInformation = new WindowsProcessInformation(getRuntime()); + + // FIXME: Convert envp into useful wideEnv + Pointer wideEnv = null; + byte[] programW = WindowsHelpers.toWString(program); + byte[] cwd = WindowsHelpers.toWString(WindowsHelpers.escapePath(handler.getCurrentWorkingDirectory().toString()) +"\\"); + ByteBuffer commandW = ByteBuffer.wrap(WindowsHelpers.toWString(command)); + boolean returnValue = wlibc().CreateProcessW(programW, commandW, + securityAttributes, securityAttributes, + securityAttributes.getInheritHandle() ? 1: 0, creationFlags, wideEnv, cwd, + startupInfo, processInformation); + + if (!returnValue) return null; + + wlibc().CloseHandle(processInformation.getThread()); + + // TODO: On winnt reverse sign of pid + return new WindowsChildRecord(processInformation.getProcess(), processInformation.getPid()); + } + + private int checkFd(int fd) { + // There might be a lighter-weight check, but we basically want to + // make sure the FD is valid and the effective user can access it, + // since we need to simulate fcntl semantics. + return libc().fstat(fd, checkFdStat); + } + + public static final PointerConverter PASSWD = new PointerConverter() { + public Object fromNative(Object arg, FromNativeContext ctx) { + throw new RuntimeException("no support for native passwd"); + } + }; + + public int mkfifo(String filename, int mode) { + handler.unimplementedError("mkfifo"); + + return -1; + } + + public Timeval allocateTimeval() { + return new DefaultNativeTimeval(getRuntime()); + } + + // TODO: Replace with Win32 calls. See jnr/jnr-posix#98. + public int gettimeofday(Timeval tv) { + long currentMillis = System.currentTimeMillis(); + tv.sec(currentMillis / 1000); + tv.usec(currentMillis % 1000 * 1000); + return 0; + } +}
diff --git a/src/main/java/jnr/posix/WindowsProcessInformation.java b/src/main/java/jnr/posix/WindowsProcessInformation.java new file mode 100644 index 0000000..e2a8035 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsProcessInformation.java
@@ -0,0 +1,33 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +/** + * + * @author enebo + */ +public class WindowsProcessInformation extends jnr.ffi.Struct { + final Pointer hProcess = new Pointer(); + final Pointer hThread = new Pointer(); + final Unsigned32 dwProcessId = new Unsigned32(); + final Unsigned32 dwThreadId = new Unsigned32(); + + public WindowsProcessInformation(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public HANDLE getThread() { + return new HANDLE(hThread.get()); + } + + public HANDLE getProcess() { + return new HANDLE(hProcess.get()); + } + + public int getPid() { + return dwProcessId.intValue(); + } +}
diff --git a/src/main/java/jnr/posix/WindowsRawFileStat.java b/src/main/java/jnr/posix/WindowsRawFileStat.java new file mode 100644 index 0000000..8c0a048 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsRawFileStat.java
@@ -0,0 +1,212 @@ +package jnr.posix; + +import jnr.posix.util.WindowsHelpers; +import jnr.posix.windows.CommonFileInformation; + +public class WindowsRawFileStat extends AbstractJavaFileStat implements NanosecondFileStat { + private int st_atime; + private long st_atimensec; + private long st_mtimensec; + private long st_ctimensec; + private int st_rdev; + private int st_dev; + private int st_nlink; + private int st_mode; + private long st_size; + private int st_ctime; + private int st_mtime; + + public WindowsRawFileStat(POSIX posix, POSIXHandler handler) { + super(posix, handler); + } + + public void setup(String path, CommonFileInformation fileInfo) { + st_mode = fileInfo.getMode(path); + setup(fileInfo); + + if (WindowsHelpers.isDriveLetterPath(path)) { + int letterAsNumber = Character.toUpperCase(path.charAt(0)) - 'A'; + st_rdev = letterAsNumber; + st_dev = letterAsNumber; + } + } + + public void setup(CommonFileInformation fileInfo) { + long atime = fileInfo.getLastAccessTimeNanoseconds(); + st_atimensec = atime % CommonFileInformation.NANOSECONDS; + st_atime = (int) (atime / CommonFileInformation.NANOSECONDS); + long mtime = fileInfo.getLastWriteTimeNanoseconds(); + st_mtimensec = mtime % CommonFileInformation.NANOSECONDS; + st_mtime = (int) (mtime / CommonFileInformation.NANOSECONDS); + long ctime = fileInfo.getCreationTimeNanoseconds(); + st_ctimensec = ctime % CommonFileInformation.NANOSECONDS; + st_ctime = (int) (ctime / CommonFileInformation.NANOSECONDS); + st_size = isDirectory() ? 0 : fileInfo.getFileSize(); + st_nlink = 1; + st_mode &= ~(S_IWGRP | S_IWOTH); + } + + public int mode() { + return st_mode; + } + + @Override + public long mtime() { + return st_mtime; + } + + public long atime() { + return st_atime; + } + + @Override + public long aTimeNanoSecs() { + return st_atimensec; + } + + @Override + public long cTimeNanoSecs() { + return st_ctimensec; + } + + @Override + public long mTimeNanoSecs() { + return st_mtimensec; + } + + public long dev() { + return st_dev; + } + + public int nlink() { + return st_nlink; + } + + public long rdev() { + return st_rdev; + } + + @Override + public long st_size() { + return st_size; + } + + @Override + public long ctime() { + return st_ctime; + } + + public boolean isDirectory() { + return (mode() & S_IFMT) == S_IFDIR; + } + + public boolean isEmpty() { + return st_size() == 0; + } + + @Override + public boolean isExecutable() { + if (isOwned()) return (mode() & S_IXUSR) != 0; + if (isGroupOwned()) return (mode() & S_IXGRP) != 0; + if ((mode() & S_IXOTH) != 0) return false; + + return true; + } + + @Override + public boolean isExecutableReal() { + if (isROwned()) return (mode() & S_IXUSR) != 0; + if (groupMember(gid())) return (mode() & S_IXGRP) != 0; + if ((mode() & S_IXOTH) != 0) return false; + + return true; + } + + public boolean isFile() { + return (mode() & S_IFMT) == S_IFREG; + } + + public boolean isFifo() { + return (mode() & S_IFMT) == S_IFIFO; + } + + public boolean isGroupOwned() { + return groupMember(gid()); + } + + public boolean isIdentical(FileStat other) { + return dev() == other.dev() && ino() == other.ino(); + } + + public boolean isNamedPipe() { + return (mode() & S_IFIFO) != 0; + } + + // FIXME: Implement + @Override + public boolean isOwned() { + return true; + } + + // FIXME: Implement + @Override + public boolean isROwned() { + return true; + } + + @Override + public boolean isReadable() { + if (isOwned()) return (mode() & S_IRUSR) != 0; + if (isGroupOwned()) return (mode() & S_IRGRP) != 0; + if ((mode() & S_IROTH) != 0) return false; + + return true; + } + + @Override + public boolean isReadableReal() { + if (isROwned()) return (mode() & S_IRUSR) != 0; + if (groupMember(gid())) return (mode() & S_IRGRP) != 0; + if ((mode() & S_IROTH) != 0) return false; + + return true; + } + + public boolean isSetgid() { + return (mode() & S_ISGID) != 0; + } + + public boolean isSetuid() { + return (mode() & S_ISUID) != 0; + } + + public boolean isSocket() { + return (mode() & S_IFMT) == S_IFSOCK; + } + + public boolean isSticky() { + return (mode() & S_ISVTX) != 0; + } + + public boolean isSymlink() { + return (mode() & S_IFMT) == S_IFLNK; + } + + @Override + public boolean isWritable() { + if (isOwned()) return (mode() & S_IWUSR) != 0; + if (isGroupOwned()) return (mode() & S_IWGRP) != 0; + if ((mode() & S_IWOTH) != 0) return false; + + return true; + } + + @Override + public boolean isWritableReal() { + if (isROwned()) return (mode() & S_IWUSR) != 0; + if (groupMember(gid())) return (mode() & S_IWGRP) != 0; + if ((mode() & S_IWOTH) != 0) return false; + + return true; + } +}
diff --git a/src/main/java/jnr/posix/WindowsSecurityAttributes.java b/src/main/java/jnr/posix/WindowsSecurityAttributes.java new file mode 100644 index 0000000..a2a4b33 --- /dev/null +++ b/src/main/java/jnr/posix/WindowsSecurityAttributes.java
@@ -0,0 +1,28 @@ +package jnr.posix; + +import jnr.ffi.*; + +/** + * + */ +public class WindowsSecurityAttributes extends jnr.ffi.Struct { + public final Unsigned32 length = new Unsigned32(); + public final Pointer securityDescriptor = new Pointer(); + public final WBOOL inheritHandle = new WBOOL(); + + public WindowsSecurityAttributes(jnr.ffi.Runtime runtime) { + super(runtime); + + // This seems like the sensible defaults for this. + length.set(Struct.size(this)); + inheritHandle.set(true); + } + + public long getLength() { + return length.get(); + } + + public boolean getInheritHandle() { + return inheritHandle.get(); + } +}
diff --git a/src/main/java/jnr/posix/WindowsStartupInfo.java b/src/main/java/jnr/posix/WindowsStartupInfo.java new file mode 100644 index 0000000..1058aff --- /dev/null +++ b/src/main/java/jnr/posix/WindowsStartupInfo.java
@@ -0,0 +1,51 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +/** + * + * @author enebo + */ +public class WindowsStartupInfo extends jnr.ffi.Struct { + public final Unsigned32 cb = new Unsigned32(); + public final Pointer lpReserved = new Pointer(); //new UTF8String(); + public final Pointer lpDesktop = new Pointer(); //UTF8String(); + public final Pointer lpTitle = new Pointer(); //new UTF8String(); + public final Unsigned32 dwX = new Unsigned32(); + public final Unsigned32 dwY = new Unsigned32(); + public final Unsigned32 dwXSize = new Unsigned32(); + public final Unsigned32 dwYSize = new Unsigned32(); + public final Unsigned32 dwXCountChars = new Unsigned32(); + public final Unsigned32 dwYCountChars = new Unsigned32(); + public final Unsigned32 dwFillAttribute = new Unsigned32(); + public final Unsigned32 dwFlags = new Unsigned32(); + public final Unsigned16 wShowWindow = new Unsigned16(); + public final Unsigned16 cbReserved2 = new Unsigned16(); + public final Pointer lpReserved2 = new Pointer(); + public final Pointer standardInput = new Pointer(); + public final Pointer standardOutput = new Pointer(); + public final Pointer standardError = new Pointer(); + + public WindowsStartupInfo(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public void setFlags(int value) { + dwFlags.set(value); + } + + public void setStandardInput(HANDLE standardInput) { + this.standardInput.set(standardInput.toPointer()); + } + + public void setStandardOutput(HANDLE standardOutput) { + this.standardOutput.set(standardOutput.toPointer()); + } + + public void setStandardError(HANDLE standardError) { + this.standardError.set(standardError.toPointer()); + } +}
diff --git a/src/main/java/jnr/posix/util/Chmod.java b/src/main/java/jnr/posix/util/Chmod.java new file mode 100644 index 0000000..202ea0a --- /dev/null +++ b/src/main/java/jnr/posix/util/Chmod.java
@@ -0,0 +1,101 @@ +package jnr.posix.util; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Honor semantics of chmod as best we can in pure Java. Note, this uses reflection to be + * more tolerant of different Java versions. + */ +public class Chmod { + private static final boolean CHMOD_API_AVAILABLE; + private static final Method setWritable; + private static final Method setReadable; + private static final Method setExecutable; + + static { + boolean apiAvailable = false; + Method setWritableVar = null; + Method setReadableVar = null; + Method setExecutableVar = null; + try { + setWritableVar = File.class.getMethod("setWritable", new Class[] {Boolean.TYPE, Boolean.TYPE}); + setReadableVar = File.class.getMethod("setReadable", new Class[] {Boolean.TYPE, Boolean.TYPE}); + setExecutableVar = File.class.getMethod("setExecutable", new Class[] {Boolean.TYPE, Boolean.TYPE}); + apiAvailable = true; + } catch (Exception e) { + // failed to load methods, no chmod API available + } + setWritable = setWritableVar; + setReadable = setReadableVar; + setExecutable = setExecutableVar; + CHMOD_API_AVAILABLE = apiAvailable; + } + + public static int chmod(File file, String mode) { + if (CHMOD_API_AVAILABLE) { + // fast version + char other = '0'; + if (mode.length() >= 1) { + other = mode.charAt(mode.length() - 1); + } + //char group = mode.charAt(mode.length() - 2); + char user = '0'; + if (mode.length() >= 3) { + user = mode.charAt(mode.length() - 3); + } + //char setuidgid = mode.charAt(mode.length() - 3); + + // group and setuid/gid are ignored, no way to do them fast. Should we fall back on slow? + if (!setPermissions(file, other, false)) return -1; + if (!setPermissions(file, user, true)) return -1; + return 0; + } else { + // slow version + try { + Process chmod = Runtime.getRuntime().exec("/bin/chmod " + mode + " " + file.getAbsolutePath()); + chmod.waitFor(); + return chmod.exitValue(); + } catch (IOException ioe) { + // FIXME: ignore? + } catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + return -1; + } + + private static boolean setPermissions(File file, char permChar, boolean userOnly) { + int permValue = Character.digit(permChar, 8); + + try { + if ((permValue & 1) != 0) { + setExecutable.invoke(file, new Object[] {Boolean.TRUE, Boolean.valueOf(userOnly)}); + } else { + setExecutable.invoke(file, new Object[] {Boolean.FALSE, Boolean.valueOf(userOnly)}); + } + + if ((permValue & 2) != 0) { + setWritable.invoke(file, new Object[] {Boolean.TRUE, Boolean.valueOf(userOnly)}); + } else { + setWritable.invoke(file, new Object[] {Boolean.FALSE, Boolean.valueOf(userOnly)}); + } + + if ((permValue & 4) != 0) { + setReadable.invoke(file, new Object[] {Boolean.TRUE, Boolean.valueOf(userOnly)}); + } else { + setReadable.invoke(file, new Object[] {Boolean.FALSE, Boolean.valueOf(userOnly)}); + } + + return true; + } catch (IllegalAccessException iae) { + // ignore, return false below + } catch (InvocationTargetException ite) { + // ignore, return false below + } + + return false; + } +}
diff --git a/src/main/java/jnr/posix/util/DefaultPOSIXHandler.java b/src/main/java/jnr/posix/util/DefaultPOSIXHandler.java new file mode 100644 index 0000000..a5ef603 --- /dev/null +++ b/src/main/java/jnr/posix/util/DefaultPOSIXHandler.java
@@ -0,0 +1,74 @@ +package jnr.posix.util; + +import jnr.constants.platform.Errno; +import jnr.posix.POSIXHandler; + +import java.io.File; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.IllegalFormatException; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A POSIXHandler with reasonable default behavior. + */ +public class DefaultPOSIXHandler implements POSIXHandler { + public void error(Errno error, String extraData) { + throw new RuntimeException("native error " + error.description() + " " + extraData); + } + + public void error(Errno error, String methodName, String extraData) { + throw new RuntimeException("native error calling " + methodName + ": " + error.description() + " " + extraData); + } + + public void unimplementedError(String methodName) { + throw new IllegalStateException(methodName + " is not implemented in jnr-posix"); + } + + public void warn(WARNING_ID id, String message, Object... data) { + String msg; + try { + msg = String.format(message, data); + } + catch (IllegalFormatException e) { + msg = message + " " + Arrays.toString(data); + } + Logger.getLogger("jnr-posix").log(Level.WARNING, msg); + } + + public boolean isVerbose() { + return false; + } + + public File getCurrentWorkingDirectory() { + return new File("."); + } + + public String[] getEnv() { + String[] envp = new String[System.getenv().size()]; + int i = 0; + for (Map.Entry<String, String> pair : System.getenv().entrySet()) { + envp[i++] = new StringBuilder(pair.getKey()).append("=").append(pair.getValue()).toString(); + } + return envp; + } + + public InputStream getInputStream() { + return System.in; + } + + public PrintStream getOutputStream() { + return System.out; + } + + public int getPID() { + return 0; + } + + public PrintStream getErrorStream() { + return System.err; + } +}
diff --git a/src/main/java/jnr/posix/util/ExecIt.java b/src/main/java/jnr/posix/util/ExecIt.java new file mode 100644 index 0000000..a79512f --- /dev/null +++ b/src/main/java/jnr/posix/util/ExecIt.java
@@ -0,0 +1,157 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Copyright (C) 2008 JRuby Community + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +package jnr.posix.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import jnr.posix.POSIXHandler; + +public class ExecIt { + protected final POSIXHandler handler; + + /** Creates a new instance of ShellLauncher + * + * @param handler the {@link POSIXHandler} to use + */ + public ExecIt(POSIXHandler handler) { + this.handler = handler; + } + + public int runAndWait(String... args) throws IOException, InterruptedException { + return runAndWait(handler.getOutputStream(), args); + } + + public int runAndWait(OutputStream output, String... args) throws IOException, InterruptedException { + return runAndWait(output, handler.getErrorStream(), args); + } + + public int runAndWait(OutputStream output, OutputStream error, String... args) throws IOException, InterruptedException { + Process process = run(args); + + handleStreams(process, handler.getInputStream(), output, error); + + return process.waitFor(); + } + + public Process run(String... args) throws IOException { + File cwd = handler.getCurrentWorkingDirectory(); + + return Runtime.getRuntime().exec(args, handler.getEnv(), cwd); + } + + private static class StreamPumper extends Thread { + private InputStream in; + private OutputStream out; + private boolean onlyIfAvailable; + private volatile boolean quit; + private final Object waitLock = new Object(); + StreamPumper(InputStream in, OutputStream out, boolean avail) { + this.in = in; + this.out = out; + this.onlyIfAvailable = avail; + } + + public void run() { + byte[] buf = new byte[1024]; + int numRead; + boolean hasReadSomething = false; + try { + while (!quit) { + // The problem we trying to solve below: STDIN in Java is blocked and + // non-interruptible, so if we invoke read on it, we might never be able to + // interrupt such thread. So, we use in.available() to see if there is any + // input ready, and only then read it. But this approach can't tell whether + // the end of stream reached or not, so we might end up looping right at the + // end of the stream. Well, at least, we can improve the situation by checking + // if some input was ever available, and if so, not checking for available + // anymore, and just go to read. + if (onlyIfAvailable && !hasReadSomething) { + if (in.available() == 0) { + synchronized (waitLock) { + waitLock.wait(10); + } + continue; + } else { + hasReadSomething = true; + } + } + + if ((numRead = in.read(buf)) == -1) { + break; + } + out.write(buf, 0, numRead); + } + } catch (Exception e) { + } finally { + if (onlyIfAvailable) { + // We need to close the out, since some + // processes would just wait for the stream + // to be closed before they process its content, + // and produce the output. E.g.: "cat". + try { out.close(); } catch (IOException ioe) {} + } + } + } + + public void quit() { + this.quit = true; + synchronized (waitLock) { + waitLock.notify(); + } + } + } + + private void handleStreams(Process p, InputStream in, OutputStream out, OutputStream err) throws IOException { + InputStream pOut = p.getInputStream(); + InputStream pErr = p.getErrorStream(); + OutputStream pIn = p.getOutputStream(); + + StreamPumper t1 = new StreamPumper(pOut, out, false); + StreamPumper t2 = new StreamPumper(pErr, err, false); + StreamPumper t3 = new StreamPumper(in, pIn, true); + t1.start(); + t2.start(); + t3.start(); + + try { t1.join(); } catch (InterruptedException ie) {} + try { t2.join(); } catch (InterruptedException ie) {} + t3.quit(); + + try { err.flush(); } catch (IOException io) {} + try { out.flush(); } catch (IOException io) {} + + try { pIn.close(); } catch (IOException io) {} + try { pOut.close(); } catch (IOException io) {} + try { pErr.close(); } catch (IOException io) {} + + } +}
diff --git a/src/main/java/jnr/posix/util/FieldAccess.java b/src/main/java/jnr/posix/util/FieldAccess.java new file mode 100644 index 0000000..bdbe093 --- /dev/null +++ b/src/main/java/jnr/posix/util/FieldAccess.java
@@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jnr.posix.util; + +import java.lang.reflect.Field; + +/** + * + * @author nicksieger + */ +public class FieldAccess { + public static Field getProtectedField(Class klass, String fieldName) { + Field field = null; + try { + field = klass.getDeclaredField(fieldName); + field.setAccessible(true); + } catch (Exception e) { + } + return field; + } + public static Object getProtectedFieldValue(Class klass, String fieldName, Object instance) { + try { + Field f = getProtectedField(klass, fieldName); + return f.get(instance); + } catch (Exception e) { + throw new IllegalArgumentException(e); + } + } +}
diff --git a/src/main/java/jnr/posix/util/Finder.java b/src/main/java/jnr/posix/util/Finder.java new file mode 100644 index 0000000..85cc34e --- /dev/null +++ b/src/main/java/jnr/posix/util/Finder.java
@@ -0,0 +1,131 @@ +package jnr.posix.util; + +import java.io.File; +import java.util.*; + +import jnr.posix.FileStat; +import jnr.posix.POSIX; + +public class Finder { + private static final Collection<String> EXECUTABLE_EXTENSIONS + = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(".exe", ".com", ".cmd", ".bat"))); + + public static String findFileInPath(POSIX posix, String name, String path) { + if (path == null || path.length() == 0) path = System.getenv("PATH"); + + // MRI sets up a bogus path which seems like it would violate security + // if nothing else since if I don't have /usr/bin in my path but I end + // up executing it anyways??? Returning original name and hoping for + // best. + if (path == null || path.length() == 0) return name; + + return findFileCommon(posix, name, path, true); + } + + public static String findFileCommon(POSIX posix, String name, String path, boolean executableOnly) { + // No point looking for nothing... + if (name == null || name.length() == 0) return name; + + int length = name.length(); + boolean isAbsolute = false; + boolean isPath = false; + int i = 0; + if (Platform.IS_WINDOWS) { + if (length > 1 && Character.isLetter(name.charAt(0)) && name.charAt(1) == ':') { + i = 2; + isAbsolute = true; + } + + int extensionIndex = -1; + char c = name.charAt(i); + if (i == '/' || i == '\\') { + i++; + c = name.charAt(i); + isAbsolute = true; + } + + // Is this a partial path and does it contain an explicit + // file extension? + for (; i < length; i++) { + switch (c) { + case '/': + case '\\': + isPath = true; + extensionIndex = -1; + break; + case '.': + extensionIndex = i - 1; + break; + } + c = name.charAt(i); + } + + if (extensionIndex >= 0 && !EXECUTABLE_EXTENSIONS.contains(name.substring(extensionIndex).toLowerCase())) { + extensionIndex = -1; + } + + if (!executableOnly) { + if (isAbsolute) return name; + } else if (isPath) { + if (extensionIndex >= 0) return name; + + if (executableOnly) { + return addExtension(name); + } else if (new File(name).exists()) { + return name; + } + + return null; + } + + String[] paths = path.split(File.pathSeparator); + for (int p = 0; p < paths.length; p++) { + String currentPath = paths[p]; + int currentPathLength = currentPath.length(); + + if (currentPath == null || currentPathLength == 0) continue; + + if (currentPath.charAt(0) == '~' && + (currentPathLength == 1 || + (currentPathLength > 1 && (currentPath.charAt(1) == '/' || currentPath.charAt(1) == '\\')))) { + String home = System.getenv("HOME"); + + if (home != null) { + currentPath = home + (currentPathLength == 1 ? "" : currentPath.substring(1)); + } + } + + if (!currentPath.endsWith("/") && !currentPath.endsWith("\\")) { + currentPath += "\\"; + } + + String filename = currentPath + name; + if (Platform.IS_WINDOWS) filename = filename.replace('/', '\\'); + + if (Platform.IS_WINDOWS && executableOnly && extensionIndex == -1) { + String extendedFilename = addExtension(filename); + + if (extendedFilename != null) return extendedFilename; + continue; + } + + try { + FileStat stat = posix.stat(filename); + if (!executableOnly || (!stat.isDirectory() && stat.isExecutable())) return filename; + } catch (Throwable t) {} + } + } + + return null; + } + + public static String addExtension(String path) { + for (String extension : EXECUTABLE_EXTENSIONS) { + String newPath = path + extension; + + if (new File(newPath).exists()) return newPath; + } + + return null; + } +}
diff --git a/src/main/java/jnr/posix/util/Java5ProcessMaker.java b/src/main/java/jnr/posix/util/Java5ProcessMaker.java new file mode 100644 index 0000000..5f7f2c0 --- /dev/null +++ b/src/main/java/jnr/posix/util/Java5ProcessMaker.java
@@ -0,0 +1,160 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +package jnr.posix.util; + +import jnr.posix.POSIXHandler; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class Java5ProcessMaker implements ProcessMaker { + private final ProcessBuilder builder; + private final POSIXHandler handler; + + public Java5ProcessMaker(POSIXHandler handler, String... command) { + this.handler = handler; + builder = new ProcessBuilder(command); + } + + public Java5ProcessMaker(POSIXHandler handler) { + this.handler = handler; + builder = new ProcessBuilder(); + } + + public List<String> command() { + return builder.command(); + } + + public ProcessMaker command(List<String> command) { + builder.command(command); + return this; + } + + public ProcessMaker command(String... command) { + builder.command(command); + return this; + } + + public File directory() { + return builder.directory(); + } + + public ProcessMaker directory(File dir) { + builder.directory(dir); + return this; + } + + public Map<String, String> environment() { + return builder.environment(); + } + + public ProcessMaker environment(String[] envLines) { + envIntoProcessBuilder(builder, envLines); + return this; + } + + public ProcessMaker inheritIO() { + handler.unimplementedError("inheritIO"); + return this; + } + + public Redirect redirectError() { + return Redirect.PIPE; // only option on Java 5/6 + } + + public ProcessMaker redirectError(File file) { + handler.unimplementedError("redirectError"); + return this; + } + + public ProcessMaker redirectError(Redirect destination) { + handler.unimplementedError("redirectError"); + return this; + } + + public boolean redirectErrorStream() { + return false; + } + + public ProcessMaker redirectErrorStream(boolean redirectErrorStream) { + handler.unimplementedError("redirectErrorStream"); + return this; + } + + public Redirect redirectInput() { + return Redirect.PIPE; // only option on Java 5/6 + } + + public ProcessMaker redirectInput(File file) { + handler.unimplementedError("redirectInput"); + return this; + } + + public ProcessMaker redirectInput(Redirect source) { + handler.unimplementedError("redirectInput"); + return this; + } + + public Redirect redirectOutput() { + return Redirect.PIPE; // only option on Java 5/6 + } + + public ProcessMaker redirectOutput(File file) { + handler.unimplementedError("redirectOutput"); + return this; + } + + public ProcessMaker redirectOutput(Redirect destination) { + handler.unimplementedError("redirectOutput"); + return this; + } + + public Process start() throws IOException { + return builder.start(); + } + + private static void envIntoProcessBuilder(ProcessBuilder pb, String[] env) { + if (env == null) return; + + pb.environment().clear(); + for (String envLine : env) { + if (envLine.indexOf(0) != -1) { + envLine = envLine.replaceFirst("\u0000.*", ""); + } + + int index = envLine.indexOf('='); + + if (index != -1) { + pb.environment().put( + envLine.substring(0, index), + envLine.substring(index + 1)); + } + } + } +}
diff --git a/src/main/java/jnr/posix/util/JavaCrypt.java b/src/main/java/jnr/posix/util/JavaCrypt.java new file mode 100644 index 0000000..dc7f5c1 --- /dev/null +++ b/src/main/java/jnr/posix/util/JavaCrypt.java
@@ -0,0 +1,232 @@ +package jnr.posix.util; + +public class JavaCrypt { + private static final int ITERATIONS = 16; + private static final int[] con_salt = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 0, 0, 0, 0, 0}; + private static final boolean[] shifts2 = {false, false, true, true, true, true, true, true, false, true, true, true, true, true, true, false}; + private static final int[][] skb = {{0, 16, 536870912, 536870928, 65536, 65552, 536936448, 536936464, 2048, 2064, 536872960, 536872976, 67584, 67600, 536938496, 536938512, 32, 48, 536870944, 536870960, 65568, 65584, 536936480, 536936496, 2080, 2096, 536872992, 536873008, 67616, 67632, 536938528, 536938544, 524288, 524304, 537395200, 537395216, 589824, 589840, 537460736, 537460752, 526336, 526352, 537397248, 537397264, 591872, 591888, 537462784, 537462800, 524320, 524336, 537395232, 537395248, 589856, 589872, 537460768, 537460784, 526368, 526384, 537397280, 537397296, 591904, 591920, 537462816, 537462832}, {0, 33554432, 8192, 33562624, 2097152, 35651584, 2105344, 35659776, 4, 33554436, 8196, 33562628, 2097156, 35651588, 2105348, 35659780, 1024, 33555456, 9216, 33563648, 2098176, 35652608, 2106368, 35660800, 1028, 33555460, 9220, 33563652, 2098180, 35652612, 2106372, 35660804, 268435456, 301989888, 268443648, 301998080, 270532608, 304087040, 270540800, 304095232, 268435460, 301989892, 268443652, 301998084, 270532612, 304087044, 270540804, 304095236, 268436480, 301990912, 268444672, 301999104, 270533632, 304088064, 270541824, 304096256, 268436484, 301990916, 268444676, 301999108, 270533636, 304088068, 270541828, 304096260}, {0, 1, 262144, 262145, 16777216, 16777217, 17039360, 17039361, 2, 3, 262146, 262147, 16777218, 16777219, 17039362, 17039363, 512, 513, 262656, 262657, 16777728, 16777729, 17039872, 17039873, 514, 515, 262658, 262659, 16777730, 16777731, 17039874, 17039875, 134217728, 134217729, 134479872, 134479873, 150994944, 150994945, 151257088, 151257089, 134217730, 134217731, 134479874, 134479875, 150994946, 150994947, 151257090, 151257091, 134218240, 134218241, 134480384, 134480385, 150995456, 150995457, 151257600, 151257601, 134218242, 134218243, 134480386, 134480387, 150995458, 150995459, 151257602, 151257603}, {0, 1048576, 256, 1048832, 8, 1048584, 264, 1048840, 4096, 1052672, 4352, 1052928, 4104, 1052680, 4360, 1052936, 67108864, 68157440, 67109120, 68157696, 67108872, 68157448, 67109128, 68157704, 67112960, 68161536, 67113216, 68161792, 67112968, 68161544, 67113224, 68161800, 131072, 1179648, 131328, 1179904, 131080, 1179656, 131336, 1179912, 135168, 1183744, 135424, 1184000, 135176, 1183752, 135432, 1184008, 67239936, 68288512, 67240192, 68288768, 67239944, 68288520, 67240200, 68288776, 67244032, 68292608, 67244288, 68292864, 67244040, 68292616, 67244296, 68292872}, {0, 268435456, 65536, 268500992, 4, 268435460, 65540, 268500996, 536870912, 805306368, 536936448, 805371904, 536870916, 805306372, 536936452, 805371908, 1048576, 269484032, 1114112, 269549568, 1048580, 269484036, 1114116, 269549572, 537919488, 806354944, 537985024, 806420480, 537919492, 806354948, 537985028, 806420484, 4096, 268439552, 69632, 268505088, 4100, 268439556, 69636, 268505092, 536875008, 805310464, 536940544, 805376000, 536875012, 805310468, 536940548, 805376004, 1052672, 269488128, 1118208, 269553664, 1052676, 269488132, 1118212, 269553668, 537923584, 806359040, 537989120, 806424576, 537923588, 806359044, 537989124, 806424580}, {0, 134217728, 8, 134217736, 1024, 134218752, 1032, 134218760, 131072, 134348800, 131080, 134348808, 132096, 134349824, 132104, 134349832, 1, 134217729, 9, 134217737, 1025, 134218753, 1033, 134218761, 131073, 134348801, 131081, 134348809, 132097, 134349825, 132105, 134349833, 33554432, 167772160, 33554440, 167772168, 33555456, 167773184, 33555464, 167773192, 33685504, 167903232, 33685512, 167903240, 33686528, 167904256, 33686536, 167904264, 33554433, 167772161, 33554441, 167772169, 33555457, 167773185, 33555465, 167773193, 33685505, 167903233, 33685513, 167903241, 33686529, 167904257, 33686537, 167904265}, {0, 256, 524288, 524544, 16777216, 16777472, 17301504, 17301760, 16, 272, 524304, 524560, 16777232, 16777488, 17301520, 17301776, 2097152, 2097408, 2621440, 2621696, 18874368, 18874624, 19398656, 19398912, 2097168, 2097424, 2621456, 2621712, 18874384, 18874640, 19398672, 19398928, 512, 768, 524800, 525056, 16777728, 16777984, 17302016, 17302272, 528, 784, 524816, 525072, 16777744, 16778000, 17302032, 17302288, 2097664, 2097920, 2621952, 2622208, 18874880, 18875136, 19399168, 19399424, 2097680, 2097936, 2621968, 2622224, 18874896, 18875152, 19399184, 19399440}, {0, 67108864, 262144, 67371008, 2, 67108866, 262146, 67371010, 8192, 67117056, 270336, 67379200, 8194, 67117058, 270338, 67379202, 32, 67108896, 262176, 67371040, 34, 67108898, 262178, 67371042, 8224, 67117088, 270368, 67379232, 8226, 67117090, 270370, 67379234, 2048, 67110912, 264192, 67373056, 2050, 67110914, 264194, 67373058, 10240, 67119104, 272384, 67381248, 10242, 67119106, 272386, 67381250, 2080, 67110944, 264224, 67373088, 2082, 67110946, 264226, 67373090, 10272, 67119136, 272416, 67381280, 10274, 67119138, 272418, 67381282}}; + private static final int[][] SPtrans = {{8520192, 131072, -2139095040, -2138963456, 8388608, -2147352064, -2147352576, -2139095040, -2147352064, 8520192, 8519680, -2147483136, -2139094528, 8388608, 0, -2147352576, 131072, -2147483648, 8389120, 131584, -2138963456, 8519680, -2147483136, 8389120, -2147483648, 512, 131584, -2138963968, 512, -2139094528, -2138963968, 0, 0, -2138963456, 8389120, -2147352576, 8520192, 131072, -2147483136, 8389120, -2138963968, 512, 131584, -2139095040, -2147352064, -2147483648, -2139095040, 8519680, -2138963456, 131584, 8519680, -2139094528, 8388608, -2147483136, -2147352576, 0, 131072, 8388608, -2139094528, 8520192, -2147483648, -2138963968, 512, -2147352064}, {268705796, 0, 270336, 268697600, 268435460, 8196, 268443648, 270336, 8192, 268697604, 4, 268443648, 262148, 268705792, 268697600, 4, 262144, 268443652, 268697604, 8192, 270340, 268435456, 0, 262148, 268443652, 270340, 268705792, 268435460, 268435456, 262144, 8196, 268705796, 262148, 268705792, 268443648, 270340, 268705796, 262148, 268435460, 0, 268435456, 8196, 262144, 268697604, 8192, 268435456, 270340, 268443652, 268705792, 8192, 0, 268435460, 4, 268705796, 270336, 268697600, 268697604, 262144, 8196, 268443648, 268443652, 4, 268697600, 270336}, {1090519040, 16842816, 64, 1090519104, 1073807360, 16777216, 1090519104, 65600, 16777280, 65536, 16842752, 1073741824, 1090584640, 1073741888, 1073741824, 1090584576, 0, 1073807360, 16842816, 64, 1073741888, 1090584640, 65536, 1090519040, 1090584576, 16777280, 1073807424, 16842752, 65600, 0, 16777216, 1073807424, 16842816, 64, 1073741824, 65536, 1073741888, 1073807360, 16842752, 1090519104, 0, 16842816, 65600, 1090584576, 1073807360, 16777216, 1090584640, 1073741824, 1073807424, 1090519040, 16777216, 1090584640, 65536, 16777280, 1090519104, 65600, 16777280, 0, 1090584576, 1073741888, 1090519040, 1073807424, 64, 16842752}, {1049602, 67109888, 2, 68158466, 0, 68157440, 67109890, 1048578, 68158464, 67108866, 67108864, 1026, 67108866, 1049602, 1048576, 67108864, 68157442, 1049600, 1024, 2, 1049600, 67109890, 68157440, 1024, 1026, 0, 1048578, 68158464, 67109888, 68157442, 68158466, 1048576, 68157442, 1026, 1048576, 67108866, 1049600, 67109888, 2, 68157440, 67109890, 0, 1024, 1048578, 0, 68157442, 68158464, 1024, 67108864, 68158466, 1049602, 1048576, 68158466, 2, 67109888, 1049602, 1048578, 1049600, 68157440, 67109890, 1026, 67108864, 67108866, 68158464}, {33554432, 16384, 256, 33571080, 33570824, 33554688, 16648, 33570816, 16384, 8, 33554440, 16640, 33554696, 33570824, 33571072, 0, 16640, 33554432, 16392, 264, 33554688, 16648, 0, 33554440, 8, 33554696, 33571080, 16392, 33570816, 256, 264, 33571072, 33571072, 33554696, 16392, 33570816, 16384, 8, 33554440, 33554688, 33554432, 16640, 33571080, 0, 16648, 33554432, 256, 16392, 33554696, 256, 0, 33571080, 33570824, 33571072, 264, 16384, 16640, 33570824, 33554688, 264, 8, 16648, 33570816, 33554440}, {536870928, 524304, 0, 537397248, 524304, 2048, 536872976, 524288, 2064, 537397264, 526336, 536870912, 536872960, 536870928, 537395200, 526352, 524288, 536872976, 537395216, 0, 2048, 16, 537397248, 537395216, 537397264, 537395200, 536870912, 2064, 16, 526336, 526352, 536872960, 2064, 536870912, 536872960, 526352, 537397248, 524304, 0, 536872960, 536870912, 2048, 537395216, 524288, 524304, 537397264, 526336, 16, 537397264, 526336, 524288, 536872976, 536870928, 537395200, 526352, 0, 2048, 536870928, 536872976, 537397248, 537395200, 2064, 16, 537395216}, {4096, 128, 4194432, 4194305, 4198529, 4097, 4224, 0, 4194304, 4194433, 129, 4198400, 1, 4198528, 4198400, 129, 4194433, 4096, 4097, 4198529, 0, 4194432, 4194305, 4224, 4198401, 4225, 4198528, 1, 4225, 4198401, 128, 4194304, 4225, 4198400, 4198401, 129, 4096, 128, 4194304, 4198401, 4194433, 4225, 4224, 0, 128, 4194305, 1, 4194432, 0, 4194433, 4194432, 4224, 129, 4096, 4198529, 4194304, 4198528, 1, 4097, 4198529, 4194305, 4198528, 4198400, 4097}, {136314912, 136347648, 32800, 0, 134250496, 2097184, 136314880, 136347680, 32, 134217728, 2129920, 32800, 2129952, 134250528, 134217760, 136314880, 32768, 2129952, 2097184, 134250496, 136347680, 134217760, 0, 2129920, 134217728, 2097152, 134250528, 136314912, 2097152, 32768, 136347648, 32, 2097152, 32768, 134217760, 136347680, 32800, 134217728, 0, 2129920, 136314912, 134250528, 134250496, 2097184, 136347648, 32, 2097184, 134250496, 136347680, 2097152, 136314880, 134217760, 2129920, 32800, 134250528, 136314880, 32, 136347648, 2129952, 0, 134217728, 136314912, 32768, 2129952}}; + private static final int[] cov_2char = {46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}; + + private static final int byteToUnsigned(byte b) { + return b & 255; + } + + private static int fourBytesToInt(byte[] b, int offset) { + int value; + value = byteToUnsigned(b[offset++]); + value |= (byteToUnsigned(b[offset++]) << 8); + value |= (byteToUnsigned(b[offset++]) << 16); + value |= (byteToUnsigned(b[offset++]) << 24); + return value; + } + + private static final void intToFourBytes(int iValue, byte[] b, int offset) { + b[offset++] = (byte) ((iValue) & 255); + b[offset++] = (byte) ((iValue >>> 8) & 255); + b[offset++] = (byte) ((iValue >>> 16) & 255); + b[offset++] = (byte) ((iValue >>> 24) & 255); + } + + private static final void PERM_OP(int a, int b, int n, int m, int[] results) { + int t; + + t = ((a >>> n) ^ b) & m; + a ^= t << n; + b ^= t; + + results[0] = a; + results[1] = b; + } + + private static final int HPERM_OP(int a, int n, int m) { + int t; + + t = ((a << (16 - n)) ^ a) & m; + a = a ^ t ^ (t >>> (16 - n)); + + return a; + } + + private static int[] des_set_key(byte[] key) { + int[] schedule = new int[ITERATIONS * 2]; + + int c = fourBytesToInt(key, 0); + int d = fourBytesToInt(key, 4); + + int[] results = new int[2]; + + PERM_OP(d, c, 4, 252645135, results); + d = results[0]; + c = results[1]; + + c = HPERM_OP(c, -2, -859045888); + d = HPERM_OP(d, -2, -859045888); + + PERM_OP(d, c, 1, 1431655765, results); + d = results[0]; + c = results[1]; + + PERM_OP(c, d, 8, 16711935, results); + c = results[0]; + d = results[1]; + + PERM_OP(d, c, 1, 1431655765, results); + d = results[0]; + c = results[1]; + + d = (((d & 255) << 16) | (d & 65280) | ((d & 16711680) >>> 16) | ((c & -268435456) >>> 4)); + c &= 268435455; + + int s; + int t; + int j = 0; + + for (int i = 0; i < ITERATIONS; i++) { + if (shifts2[i]) { + c = (c >>> 2) | (c << 26); + d = (d >>> 2) | (d << 26); + } else { + c = (c >>> 1) | (c << 27); + d = (d >>> 1) | (d << 27); + } + + c &= 268435455; + d &= 268435455; + + s = skb[0][(c) & 63] | skb[1][((c >>> 6) & 3) | ((c >>> 7) & 60)] | skb[2][((c >>> 13) & 15) | ((c >>> 14) & 48)] | skb[3][((c >>> 20) & 1) | ((c >>> 21) & 6) | ((c >>> 22) & 56)]; + + t = skb[4][(d) & 63] | skb[5][((d >>> 7) & 3) | ((d >>> 8) & 60)] | skb[6][(d >>> 15) & 63] | skb[7][((d >>> 21) & 15) | ((d >>> 22) & 48)]; + + schedule[j++] = ((t << 16) | (s & 65535)) & -1; + s = ((s >>> 16) | (t & -65536)); + + s = (s << 4) | (s >>> 28); + schedule[j++] = s & -1; + } + return schedule; + } + + private static final int D_ENCRYPT(int L, int R, int S, int E0, int E1, int[] s) { + int t; + int u; + int v; + + v = R ^ (R >>> 16); + u = v & E0; + v = v & E1; + u = (u ^ (u << 16)) ^ R ^ s[S]; + t = (v ^ (v << 16)) ^ R ^ s[S + 1]; + t = (t >>> 4) | (t << 28); + + L ^= SPtrans[1][(t) & 63] | SPtrans[3][(t >>> 8) & 63] | SPtrans[5][(t >>> 16) & 63] | SPtrans[7][(t >>> 24) & 63] | SPtrans[0][(u) & 63] | SPtrans[2][(u >>> 8) & 63] | SPtrans[4][(u >>> 16) & 63] | SPtrans[6][(u >>> 24) & 63]; + + return L; + } + + private static final int[] body(int[] schedule, int Eswap0, int Eswap1) { + int left = 0; + int right = 0; + int t = 0; + + for (int j = 0; j < 25; j++) { + for (int i = 0; i < ITERATIONS * 2; i += 4) { + left = D_ENCRYPT(left, right, i, Eswap0, Eswap1, schedule); + right = D_ENCRYPT(right, left, i + 2, Eswap0, Eswap1, schedule); + } + t = left; + left = right; + right = t; + } + + t = right; + + right = (left >>> 1) | (left << 31); + left = (t >>> 1) | (t << 31); + + left &= -1; + right &= -1; + + int[] results = new int[2]; + + PERM_OP(right, left, 1, 1431655765, results); + right = results[0]; + left = results[1]; + + PERM_OP(left, right, 8, 16711935, results); + left = results[0]; + right = results[1]; + + PERM_OP(right, left, 2, 858993459, results); + right = results[0]; + left = results[1]; + + PERM_OP(left, right, 16, 65535, results); + left = results[0]; + right = results[1]; + + PERM_OP(right, left, 4, 252645135, results); + right = results[0]; + left = results[1]; + + int[] out = new int[2]; + + out[0] = left; + out[1] = right; + + return out; + } + + public static final CharSequence crypt(CharSequence original, CharSequence salt) { + char[] buffer = new char[]{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; + + char charZero = salt.charAt(0); + char charOne = salt.charAt(1); + + buffer[0] = charZero; + buffer[1] = charOne; + + int Eswap0 = con_salt[charZero & 127]; + int Eswap1 = con_salt[charOne & 127] << 4; + + byte[] key = new byte[8]; + + for (int i = 0; i < key.length; i++) { + key[i] = (byte) 0; + } + + for (int i = 0; i < key.length && i < original.length(); i++) { + int iChar = original.charAt(i) & 255; + + key[i] = (byte) (iChar << 1); + } + + int[] schedule = des_set_key(key); + int[] out = body(schedule, Eswap0, Eswap1); + + byte[] b = new byte[9]; + + intToFourBytes(out[0], b, 0); + intToFourBytes(out[1], b, 4); + b[8] = 0; + + for (int i = 2, y = 0, u = 128; i < 13; i++) { + for (int j = 0, c = 0; j < 6; j++) { + c <<= 1; + + if (((int) b[y] & u) != 0) { + c |= 1; + } + + u >>>= 1; + + if (u == 0) { + y++; + u = 128; + } + buffer[i] = (char) cov_2char[c]; + } + } + return new String(buffer); + } +}
diff --git a/src/main/java/jnr/posix/util/MethodName.java b/src/main/java/jnr/posix/util/MethodName.java new file mode 100644 index 0000000..f993af6 --- /dev/null +++ b/src/main/java/jnr/posix/util/MethodName.java
@@ -0,0 +1,25 @@ +package jnr.posix.util; + +public class MethodName { + private static final int CLIENT_CODE_STACK_INDEX; + + static { + // Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6 + int i = 0; + for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { + i++; + if (ste.getClassName().equals(MethodName.class.getName())) { + break; + } + } + CLIENT_CODE_STACK_INDEX = i; + } + + public static String getMethodName() { + return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName(); + } + + public static String getCallerMethodName() { + return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX + 1].getMethodName(); + } +}
diff --git a/src/main/java/jnr/posix/util/Platform.java b/src/main/java/jnr/posix/util/Platform.java new file mode 100644 index 0000000..e961a23 --- /dev/null +++ b/src/main/java/jnr/posix/util/Platform.java
@@ -0,0 +1,128 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ +package jnr.posix.util; + +import java.util.HashMap; +import java.util.Map; + +public class Platform { + public static final String OS_NAME = System.getProperty("os.name"); + public static final String OS_NAME_LC = OS_NAME.toLowerCase(); + + // Generic Windows designation + private static final String WINDOWS = "windows"; + // For Windows 95, 98... Would these platforms actually work? + private static final String WINDOWS_9X = "windows 9"; + // TODO: Windows ME? + private static final String WINDOWS_NT = "nt"; + private static final String WINDOWS_20X = "windows 2"; + private static final String WINDOWS_XP = "windows xp"; + private static final String WINDOWS_SERVER = "server"; + private static final String WINDOWS_VISTA = "vista"; + private static final String WINDOWS_7 = "windows 7"; + private static final String MAC_OS = "mac os"; + private static final String DARWIN = "darwin"; + private static final String FREEBSD = "freebsd"; + private static final String DRAGONFLY = "dragonfly"; + private static final String OPENBSD = "openbsd"; + private static final String LINUX = "linux"; + private static final String SOLARIS = "sunos"; + + // TODO: investigate supported platforms for OpenJDK7? + + public static final boolean IS_WINDOWS = OS_NAME_LC.indexOf(WINDOWS) != -1; + public static final boolean IS_WINDOWS_9X = OS_NAME_LC.indexOf(WINDOWS_9X) > -1; + public static final boolean IS_WINDOWS_NT = IS_WINDOWS && OS_NAME_LC.indexOf(WINDOWS_NT) > -1; + public static final boolean IS_WINDOWS_20X = OS_NAME_LC.indexOf(WINDOWS_20X) > -1; + public static final boolean IS_WINDOWS_XP = OS_NAME_LC.indexOf(WINDOWS_XP) > -1; + public static final boolean IS_WINDOWS_VISTA = IS_WINDOWS && OS_NAME_LC.indexOf(WINDOWS_VISTA) > -1; + public static final boolean IS_WINDOWS_SERVER = IS_WINDOWS && OS_NAME_LC.indexOf(WINDOWS_SERVER) > -1; + public static final boolean IS_WINDOWS_7 = IS_WINDOWS && OS_NAME_LC.indexOf(WINDOWS_7) > -1; + public static final boolean IS_MAC = OS_NAME_LC.startsWith(MAC_OS) || OS_NAME_LC.startsWith(DARWIN); + public static final boolean IS_FREEBSD = OS_NAME_LC.startsWith(FREEBSD); + public static final boolean IS_DRAGONFLY = OS_NAME_LC.startsWith(DRAGONFLY); + public static final boolean IS_OPENBSD = OS_NAME_LC.startsWith(OPENBSD); + public static final boolean IS_LINUX = OS_NAME_LC.startsWith(LINUX); + public static final boolean IS_SOLARIS = OS_NAME_LC.startsWith(SOLARIS); + public static final boolean IS_BSD = IS_MAC || IS_FREEBSD || IS_OPENBSD || IS_DRAGONFLY; + + public static final String envCommand() { + if (IS_WINDOWS) { + if (IS_WINDOWS_9X) { + return "command.com /c set"; + } else if (IS_WINDOWS_NT || IS_WINDOWS_20X || IS_WINDOWS_XP || + IS_WINDOWS_SERVER || IS_WINDOWS_VISTA || IS_WINDOWS_7) { + return "cmd.exe /c set"; + } + } + return "env"; + } + + public static final boolean IS_32_BIT = "32".equals(getProperty("sun.arch.data.model", "32")); + public static final boolean IS_64_BIT = "64".equals(getProperty("sun.arch.data.model", "64")); + + public static final String ARCH; + static { + String arch = System.getProperty("os.arch"); + if (arch.equals("amd64")) arch = "x86_64"; + ARCH = arch; + } + + public static final Map<String, String> OS_NAMES = new HashMap<String, String>(); + static { + OS_NAMES.put("Mac OS X", DARWIN); + OS_NAMES.put("Darwin", DARWIN); + OS_NAMES.put("Linux", LINUX); + } + + public static String getOSName() { + String theOSName = OS_NAMES.get(OS_NAME); + + return theOSName == null ? OS_NAME : theOSName; + } + + /** + * An extension over <code>System.getProperty</code> method. + * Handles security restrictions, and returns the default + * value if the access to the property is restricted. + * @param property The system property name. + * @param defValue The default value. + * @return The value of the system property, + * or the default value. + */ + public static String getProperty(String property, String defValue) { + try { + return System.getProperty(property, defValue); + } catch (SecurityException se) { + return defValue; + } + } +}
diff --git a/src/main/java/jnr/posix/util/ProcessMaker.java b/src/main/java/jnr/posix/util/ProcessMaker.java new file mode 100644 index 0000000..2dd5aac --- /dev/null +++ b/src/main/java/jnr/posix/util/ProcessMaker.java
@@ -0,0 +1,103 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ + +package jnr.posix.util; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * Abstract interface for building a process on various JVM versions. + */ +public interface ProcessMaker { + public static class Redirect { + public static final Redirect INHERIT = new Redirect(Type.INHERIT); + public static final Redirect PIPE = new Redirect(Type.PIPE); + + private enum Type { + APPEND, + INHERIT, + PIPE, + READ, + WRITE + } + + private final Type type; + private final File file; + + private Redirect(Type type) { + this(type, null); + } + + private Redirect(Type type, File file) { + this.type = type; + this.file = file; + } + + public static Redirect appendTo(File file) { + return new Redirect(Type.APPEND, file); + } + + public static Redirect from(File file) { + return new Redirect(Type.READ, file); + } + + public static Redirect to(File file) { + return new Redirect(Type.WRITE, file); + } + + public File file() { + return file; + } + + public Type type() { + return type; + } + } + + public List<String> command(); + public ProcessMaker command(List<String> command); + public ProcessMaker command(String... command); + public File directory(); + public ProcessMaker directory(File dir); + public Map<String, String> environment(); + public ProcessMaker environment(String[] envLines); + public ProcessMaker inheritIO(); + public Redirect redirectError(); + public ProcessMaker redirectError(File file); + public ProcessMaker redirectError(Redirect destination); + public boolean redirectErrorStream(); + public ProcessMaker redirectErrorStream(boolean redirectErrorStream); + public Redirect redirectInput(); + public ProcessMaker redirectInput(File file); + public ProcessMaker redirectInput(Redirect source); + public Redirect redirectOutput(); + public ProcessMaker redirectOutput(File file); + public ProcessMaker redirectOutput(Redirect destination); + public Process start() throws IOException; +}
diff --git a/src/main/java/jnr/posix/util/SunMiscSignal.java b/src/main/java/jnr/posix/util/SunMiscSignal.java new file mode 100644 index 0000000..164a52e --- /dev/null +++ b/src/main/java/jnr/posix/util/SunMiscSignal.java
@@ -0,0 +1,36 @@ +package jnr.posix.util; + +import jnr.posix.SignalHandler; +import sun.misc.Signal; + +public class SunMiscSignal { + public static SignalHandler signal(jnr.constants.platform.Signal sig, final SignalHandler handler) { + Signal s = new Signal(sig.name().substring("SIG".length())); + + sun.misc.SignalHandler oldHandler = Signal.handle(s, new SunMiscSignalHandler(handler)); + + if (oldHandler instanceof SunMiscSignalHandler) { + return ((SunMiscSignalHandler)oldHandler).handler; + } else if (oldHandler != null) { + return new SignalHandler() { + @Override + public void handle(int signal) { + oldHandler.handle(s); + } + }; + } else { + return null; + } + } + + private static class SunMiscSignalHandler implements sun.misc.SignalHandler { + final SignalHandler handler; + public SunMiscSignalHandler(SignalHandler handler) { + this.handler = handler; + } + + public void handle(Signal signal) { + handler.handle(signal.getNumber()); + } + } +}
diff --git a/src/main/java/jnr/posix/util/WindowsHelpers.java b/src/main/java/jnr/posix/util/WindowsHelpers.java new file mode 100644 index 0000000..705a111 --- /dev/null +++ b/src/main/java/jnr/posix/util/WindowsHelpers.java
@@ -0,0 +1,422 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package jnr.posix.util; + +import jnr.ffi.*; + +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import jnr.posix.POSIX; + +/** + * + * @author enebo + */ +public class WindowsHelpers { + static final jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); + static final int WORDSIZE = jnr.ffi.Runtime.getSystemRuntime().addressSize(); + + public static byte[] toWPath(String path) { + return toWString(path); + } + + public static byte[] toWString(String string) { + if (string == null) return null; + + string += (char) 0; + + try { + return string.getBytes("UTF-16LE"); + } catch (UnsupportedEncodingException e) { + return null; // JVM mandates this encoding. Not reached + } + } + + // FIXME: This does not work and I am unsure if it is because I am violating something + // CreateProcess requires OR because there are weird requirements in how env needs to be + // setup for CreateProcess (e.g. =C:=C:/ vars). + public static Pointer createWideEnv(String[] envp) { + if (envp == null) return null; + byte[] marker = {0}; + int envLength = envp.length; + + // Allocate pointer for env pointer entries plus last \0\0 marker + Pointer result = Memory.allocateDirect(runtime, WORDSIZE * (envLength + 1)); + + for (int i = 0; i < envLength; i++) { + byte[] bytes = toWString(envp[i]); + Pointer envElement = Memory.allocateDirect(runtime, bytes.length + 1); + envElement.put(0, bytes, 0, bytes.length); + envElement.put(bytes.length, marker, 0, marker.length); + result.putPointer(i * WORDSIZE, envElement); + } + + Pointer nullMarker = Memory.allocateDirect(runtime, marker.length); + nullMarker.put(0, marker, 0, marker.length); + result.putPointer(WORDSIZE * envLength, nullMarker); + + + return result; + } + // Windows cmd strings have various escaping: + // 1. <>|^ can all be escaped with ^ (e.g. ^<) + // 2. \s\t must be quoted if not already + // 3. Any arguments with double quotes must be escaped with a double + // quote around whole cmd + private static void joinSingleArgv(StringBuilder buffer, String arg, + boolean quote, boolean escape) { + int backslashCount = 0; + int start = 0; + + if (quote) buffer.append('"'); + + for (int i = 0; i < arg.length(); i++) { + char c = arg.charAt(i); + switch(c) { + case '\\': + backslashCount++; + break; + case '"': { + buffer.append(arg.substring(start, i)); + for (int j = 0; j < backslashCount + 1; j++) { + buffer.append('\\'); + } + backslashCount = 0; + start = i; + } + case '<': case '>': case '|': case '^': { + if (escape && !quote) { + buffer.append(arg.substring(start, i)); + buffer.append('^'); + start = i; + break; + } + } + default: { + backslashCount = 0; + break; + } + } + } + buffer.append(arg.substring(start)); + + if (quote) buffer.append('"'); + } + + public static String joinArgv(String command, String[] argv, boolean escape) { + StringBuilder buffer = new StringBuilder(); + + if (command != null) { + buffer.append(command); + buffer.append(' '); + } + + int last_index = argv.length - 1; + for (int i = 0; i <= last_index; i++) { + joinSingleArgv(buffer, argv[i], quotable(argv[i]), escape); + if (i != last_index) buffer.append(' '); // Add space between arguments + } + + return buffer.toString(); + } + + + public static boolean quotable(String value) { + if (value == null) return false; + StringTokenizer toker = new StringTokenizer(value, " \t\"'"); + toker.nextToken(); // We know a string with no delimeters will return self + return toker.hasMoreTokens(); + } + + public static boolean isBatch(String value) { + if (value == null) return false; + int length = value.length(); + + if (length < 5) return false; + + String end = value.substring(length - 4); + + return end.equalsIgnoreCase(".bat") || end.equalsIgnoreCase(".cmd"); + } + + public static String[] processCommandLine(POSIX posix, String command, + String program, String path) { + String shell = null; + + if (program != null) { + String fullPath = Finder.findFileInPath(posix, program, path); + + shell = fullPath == null ? program : fullPath.replace('/', '\\'); + } else { + // Strip off leading whitespace + command = command.substring(firstNonWhitespaceIndex(command)); + + // FIXME: Ruby first looks for RUBYSHELL, but this only applies for + // JRuby (I doubt Jython wants to honor that env). We need a generic + // hook for other envs to look for? + shell = System.getenv("COMSPEC"); + boolean notHandledYet = true; + if (shell != null) { + boolean commandDotCom = isCommandDotCom(shell); + if (hasBuiltinSpecialNeeds(command) || isInternalCommand(command, commandDotCom)) { + String quote = commandDotCom ? "\"" : ""; + command = shell + " /c " + quote + command + quote; + notHandledYet = false; + } + } + + if (notHandledYet) { + char firstChar = command.charAt(0); + char quote = firstChar == '"' ? firstChar : (firstChar == '\'' ? firstChar : (char) 0); + int commandLength = command.length(); + + int i = quote == 0 ? 0 : 1; + + for(;; i++) { + if (i == commandLength) { + shell = command; + break; + } + + char c = command.charAt(i); + + if (c == quote) { + shell = command.substring(1, i); + break; + } + if (quote != 0) continue; + + if (Character.isSpaceChar(c) || isFunnyChar(c)) { + shell = command.substring(0, i); + break; + } + } + shell = Finder.findFileInPath(posix, shell, path); + + if (shell == null) { + shell = command.substring(0, i); + } else { + if (!shell.contains(" ")) quote = 0; + + shell = shell.replace('/', '\\'); + } + } + } + + return new String[] { command, shell }; + } + + public static String[] processCommandArgs(POSIX posix, String program, + String[] argv, String path) { + if (program == null || program.length() == 0) program = argv[0]; + + boolean addSlashC = false; + boolean isNotBuiltin = false; + boolean notHandledYet = true; + String shell = System.getenv("COMSPEC"); + String command = null; + if (shell != null) { + boolean commandDotCom = isCommandDotCom(shell); + if (isInternalCommand(program, commandDotCom)) { + isNotBuiltin = !commandDotCom; + program = shell; + addSlashC = true; + notHandledYet = false; + } + } + if (notHandledYet) { + command = Finder.findFileInPath(posix, program, path); + if (command != null) { + program = command.replace('/', '\\'); + } else if (program.contains("/")) { + command = program.replace('/', '\\'); + program = command; + } + } + + if (addSlashC || isBatch(program)) { + if (addSlashC) { + command = program + " /c "; + } else { + String[] newArgv = new String[argv.length - 1]; + System.arraycopy(argv, 1, newArgv, 0, argv.length - 1); + argv = newArgv; + } + + if (argv.length > 0) { + command = WindowsHelpers.joinArgv(command, argv, isNotBuiltin); + } + program = addSlashC ? shell : null; + } else { + command = WindowsHelpers.joinArgv(null, argv, false); + } + + return new String[] { command, program }; + } + + private static boolean isFunnyChar(char c) { + return c == '<' || c == '>' || c == '|' || c == '*' || c == '?' || + c == '"'; + } + + private static boolean hasBuiltinSpecialNeeds(String value) { + int length = value.length(); + char quote = '\0'; + + for (int i = 0; i < length; i++) { + char c = value.charAt(i); + switch (c) { + case '\'': case '\"': + if (quote == '\0') { + quote = c; + } else if (quote == c) { + quote = '\0'; + } + break; + case '>': case '<': case '|': case '\n': + if (quote != '\0') return true; + break; + case '%': // %FOO% check + if (i + 1 < length) { + i += 1; + char c2 = value.charAt(i); + if (c2 != ' ' && !Character.isLetter(c2)) break; + for (int j = i; j < length; j++) { + c2 = value.charAt(j); + if (c2 != ' ' && !Character.isLetterOrDigit(c2)) break; + } + if (c2 == '%') return true; + } + break; + } + } + return false; + } + + private static int firstNonWhitespaceIndex(String value) { + int length = value.length(); + int i = 0; + for (; i < length && Character.isSpaceChar(value.charAt(i)); i++) {} + return i; + } + + public static String escapePath(String path) { + StringBuilder buf = new StringBuilder(); + + for (int i = 0; i < path.length(); i++) { + char c = path.charAt(i); + + buf.append(c); + if (c == '\\') buf.append(c); + } + return buf.toString() + "\\\\"; + } + + private final static String COMMAND_DOT_COM = "command.com"; + private final static int CDC_LENGTH = COMMAND_DOT_COM.length(); + private enum InternalType { SHELL, COMMAND, BOTH }; + private static Map<String, InternalType> INTERNAL_COMMANDS = new HashMap<String, InternalType>() {{ + put("assoc", InternalType.COMMAND); + put("break", InternalType.BOTH); + put("call", InternalType.BOTH); + put("cd", InternalType.BOTH); + put("chcp", InternalType.SHELL); + put("chdir", InternalType.BOTH); + put("cls", InternalType.BOTH); + put("color", InternalType.COMMAND); + put("copy", InternalType.BOTH); + put("ctty", InternalType.SHELL); + put("date", InternalType.BOTH); + put("del", InternalType.BOTH); + put("dir", InternalType.BOTH); + put("echo", InternalType.BOTH); + put("endlocal", InternalType.COMMAND); + put("erase", InternalType.BOTH); + put("exit", InternalType.BOTH); + put("for", InternalType.BOTH); + put("ftype", InternalType.COMMAND); + put("goto", InternalType.BOTH); + put("if", InternalType.BOTH); + put("lfnfor", InternalType.SHELL); + put("lh", InternalType.SHELL); + put("lock", InternalType.SHELL); + put("md", InternalType.BOTH); + put("mkdir", InternalType.BOTH); + put("move", InternalType.COMMAND); + put("path", InternalType.BOTH); + put("pause", InternalType.BOTH); + put("popd", InternalType.COMMAND); + put("prompt", InternalType.BOTH); + put("pushd", InternalType.COMMAND); + put("rd", InternalType.BOTH); + put("rem", InternalType.BOTH); + put("ren", InternalType.BOTH); + put("rename", InternalType.BOTH); + put("rmdir", InternalType.BOTH); + put("set", InternalType.BOTH); + put("setlocal", InternalType.COMMAND); + put("shift", InternalType.BOTH); + put("start", InternalType.COMMAND); + put("time", InternalType.BOTH); + put("title", InternalType.COMMAND); + put("truename", InternalType.SHELL); + put("type", InternalType.BOTH); + put("unlock", InternalType.SHELL); + put("ver", InternalType.BOTH); + put("verify", InternalType.BOTH); + put("vol", InternalType.BOTH); + }}; + + private static boolean isDirectorySeparator(char value) { + return value == '/' || value == '\\'; + } + private static boolean isCommandDotCom(String command) { + int length = command.length(); + int i = length - CDC_LENGTH; + + return i == 0 || i > 0 && isDirectorySeparator(command.charAt(i - 1)) && + command.regionMatches(true, i, COMMAND_DOT_COM, 0, CDC_LENGTH); + } + + private static boolean isInternalCommand(String command, boolean hasCommandDotCom) { + assert command != null && !Character.isSpaceChar(command.charAt(0)) : "Spaces should have been stripped off already"; + + int length = command.length(); + + StringBuilder buf = new StringBuilder(); + int i = 0; + char c = 0; + for (; i < length; i++) { + c = command.charAt(i); + if (!Character.isLetter(c)) break; + buf.append(Character.toLowerCase(c)); + } + + if (i < length) { + if (c == '.' && i + 1 < length) i++; + + switch (command.charAt(i)) { + case '<': case '>': case '|': + return true; + case '\0': case ' ': case '\t': case '\n': + break; + default: + return false; + } + } + + InternalType kindOf = INTERNAL_COMMANDS.get(buf.toString()); + return kindOf == InternalType.BOTH || + (hasCommandDotCom ? kindOf == InternalType.COMMAND : kindOf == InternalType.SHELL); + } + + public static boolean isDriveLetterPath(String path) { + return path.length() >= 2 && Character.isLetter(path.charAt(0)) && path.charAt(1) == ':'; + } + +}
diff --git a/src/main/java/jnr/posix/windows/CommonFileInformation.java b/src/main/java/jnr/posix/windows/CommonFileInformation.java new file mode 100644 index 0000000..9932163 --- /dev/null +++ b/src/main/java/jnr/posix/windows/CommonFileInformation.java
@@ -0,0 +1,101 @@ +package jnr.posix.windows; + +import static jnr.posix.FileStat.*; + +/** + * Shared logic between by handle and file path FILE_INFORMATION. + */ +public abstract class CommonFileInformation extends jnr.ffi.Struct { + public static int FILE_ATTRIBUTE_READONLY = 0x01; + public static int FILE_ATTRIBUTE_DIRECTORY = 0x10; + + public class HackyFileTime { + private final UnsignedLong dwHighDateTime; + private final UnsignedLong dwLowDateTime; + + public HackyFileTime(UnsignedLong high, UnsignedLong low) { + this.dwHighDateTime = high; + this.dwLowDateTime = low; + } + + public long getLowDateTime() { + return dwLowDateTime.longValue(); + } + + public long getHighDateTime() { + return dwHighDateTime.longValue(); + } + + public long getLongValue() { + return (getHighDateTime() & 0xFFFFFFFFL) << 32 | (getLowDateTime() & 0xFFFFFFFFL); + } + } + + + protected CommonFileInformation(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public abstract int getFileAttributes(); + public abstract HackyFileTime getCreationTime(); + public abstract HackyFileTime getLastAccessTime(); + public abstract HackyFileTime getLastWriteTime(); + public abstract long getFileSizeHigh(); + public abstract long getFileSizeLow(); + + public int getMode(java.lang.String path) { + int attr = getFileAttributes(); + int mode = S_IRUSR; + + if ((attr & FILE_ATTRIBUTE_READONLY) == 0) { + mode |= S_IWUSR; + + } + mode |= (attr & FILE_ATTRIBUTE_DIRECTORY) != 0 ? (S_IFDIR | S_IXUSR) : S_IFREG; + + path = path.toLowerCase(); + if (path != null && (mode & S_IFREG) != 0 && + (path.endsWith(".bat") || path.endsWith(".cmd") || path.endsWith(".com") || path.endsWith(".exe"))) { + mode |= S_IXUSR; + } + + mode |= (mode & 0700) >> 3; + mode |= (mode & 0700) >> 6; + + return mode; + } + + public long getLastWriteTimeNanoseconds() { + return epochNanos(getLastWriteTime().getLongValue()); + } + + public long getLastAccessTimeNanoseconds() { + return epochNanos(getLastAccessTime().getLongValue()); + } + + public long getCreationTimeNanoseconds() { + return epochNanos(getCreationTime().getLongValue()); + } + + public long getFileSize() { + return (getFileSizeHigh() << 32) | getFileSizeLow(); + } + + // FIXME: I used same equation in C to get number. I did something wrong with the math here in Java + //private static final int HOURS = 24; + //private static final int MINUTES = 60; + // private static final int SECONDS = 60; + public static final int NANOSECONDS = 1000 * 1000 * 1000; + // on number of days a year: https://imicrothinking.wordpress.com/tag/365-2425-days/ + private static final double DAYS_BETWEEN_WINDOWS_AND_UNIX = (1970 - 1601) * 365.2425; + private static final long NANOSECONDS_TO_UNIX_EPOCH_FROM_WINDOWS = 11644473600L * NANOSECONDS; + // (long) (DAYS_BETWEEN_WINDOWS_AND_UNIX * HOURS * SECONDS * MINUTES * MICROSECONDS); + + private long epochNanos(long windowsNanoChunks) { + return (windowsNanoChunks * 100) - NANOSECONDS_TO_UNIX_EPOCH_FROM_WINDOWS; + } + + public static long asNanoSeconds(long seconds) { + return (seconds * 1000 + NANOSECONDS_TO_UNIX_EPOCH_FROM_WINDOWS / 1000) * 10; + } +}
diff --git a/src/main/java/jnr/posix/windows/SystemTime.java b/src/main/java/jnr/posix/windows/SystemTime.java new file mode 100644 index 0000000..2dfae63 --- /dev/null +++ b/src/main/java/jnr/posix/windows/SystemTime.java
@@ -0,0 +1,25 @@ +package jnr.posix.windows; + +import jnr.ffi.*; + +/** + * Created by enebo on 9/18/2015. + */ +public class SystemTime extends jnr.ffi.Struct { + Unsigned16 wYear = new Unsigned16(); + Unsigned16 wMonth = new Unsigned16(); + Unsigned16 wDayOfWeek = new Unsigned16(); + Unsigned16 wDay = new Unsigned16(); + Unsigned16 wHour = new Unsigned16(); + Unsigned16 wMinute = new Unsigned16(); + Unsigned16 wSecond = new Unsigned16(); + Unsigned16 wMilliseconds = new Unsigned16(); + + public SystemTime(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public java.lang.String toString() { + return "" + wYear + "/" + wMonth + "/" + wDay + " " + wHour + ":" + wMinute + ":" + wSecond; + } +}
diff --git a/src/main/java/jnr/posix/windows/WindowsByHandleFileInformation.java b/src/main/java/jnr/posix/windows/WindowsByHandleFileInformation.java new file mode 100644 index 0000000..2b9b820 --- /dev/null +++ b/src/main/java/jnr/posix/windows/WindowsByHandleFileInformation.java
@@ -0,0 +1,50 @@ +package jnr.posix.windows; + +/** + * BY_HANDLE_FILE_INFORMATION + */ +public class WindowsByHandleFileInformation extends CommonFileInformation { + final Unsigned32 dwFileAttributes = new Unsigned32(); + // FIXME: I have no idea why I could not include FileTime here but having it do its own layout seems to change + // something. + final UnsignedLong chigh = new UnsignedLong(); + final UnsignedLong clow = new UnsignedLong(); + final UnsignedLong ahigh = new UnsignedLong(); + final UnsignedLong alow = new UnsignedLong(); + final UnsignedLong uhigh = new UnsignedLong(); + final UnsignedLong ulow = new UnsignedLong(); + final Unsigned32 dwVolumeSerialNumber = new Unsigned32(); + final Unsigned32 nFileSizeHigh = new Unsigned32(); + final Unsigned32 nFileSizeLow = new Unsigned32(); + final Unsigned32 nNumberOfLinks = new Unsigned32(); + final Unsigned32 nFileIndexHigh = new Unsigned32(); + final Unsigned32 nFileIndexLow = new Unsigned32(); + + public WindowsByHandleFileInformation(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public HackyFileTime getCreationTime() { + return new HackyFileTime(chigh, clow); + } + + public HackyFileTime getLastAccessTime() { + return new HackyFileTime(ahigh, alow); + } + + public HackyFileTime getLastWriteTime() { + return new HackyFileTime(uhigh, ulow); + } + + public int getFileAttributes() { + return dwFileAttributes.intValue(); + } + + public long getFileSizeHigh() { + return nFileSizeHigh.intValue(); + } + + public long getFileSizeLow() { + return nFileSizeLow.intValue(); + } +}
diff --git a/src/main/java/jnr/posix/windows/WindowsFileInformation.java b/src/main/java/jnr/posix/windows/WindowsFileInformation.java new file mode 100644 index 0000000..d719e41 --- /dev/null +++ b/src/main/java/jnr/posix/windows/WindowsFileInformation.java
@@ -0,0 +1,58 @@ +package jnr.posix.windows; + +/** + * WIN32_FILE_ATTRIBUTE_DATA + */ + +public class WindowsFileInformation extends CommonFileInformation { + + final UnsignedLong dwFileAttributes; + // FIXME: I have no idea why I could not include FileTime here but having it do its own layout seems to change + // something. + final UnsignedLong chigh; + final UnsignedLong clow; + final UnsignedLong ahigh; + final UnsignedLong alow; + final UnsignedLong uhigh; + final UnsignedLong ulow; + final UnsignedLong nFileSizeHigh; + final UnsignedLong nFileSizeLow; + + public WindowsFileInformation(jnr.ffi.Runtime runtime) { + super(runtime); + + dwFileAttributes = new UnsignedLong(); + clow = new UnsignedLong(); + chigh = new UnsignedLong(); + alow = new UnsignedLong(); + ahigh = new UnsignedLong(); + ulow = new UnsignedLong(); + uhigh = new UnsignedLong(); + nFileSizeHigh = new UnsignedLong(); + nFileSizeLow = new UnsignedLong(); + } + + public HackyFileTime getCreationTime() { + return new HackyFileTime(chigh, clow); + } + + public HackyFileTime getLastAccessTime() { + return new HackyFileTime(ahigh, alow); + } + + public HackyFileTime getLastWriteTime() { + return new HackyFileTime(uhigh, ulow); + } + + public int getFileAttributes() { + return dwFileAttributes.intValue(); + } + + public long getFileSizeHigh() { + return nFileSizeHigh.longValue(); + } + + public long getFileSizeLow() { + return nFileSizeLow.longValue(); + } +}
diff --git a/src/main/java/jnr/posix/windows/WindowsFileTime.java b/src/main/java/jnr/posix/windows/WindowsFileTime.java new file mode 100644 index 0000000..86b21d0 --- /dev/null +++ b/src/main/java/jnr/posix/windows/WindowsFileTime.java
@@ -0,0 +1,25 @@ +package jnr.posix.windows; + +/** + * FILETIME + */ +public class WindowsFileTime extends jnr.ffi.Struct { + final Unsigned32 lowDateTime = new Unsigned32(); + final Unsigned32 highDateTime = new Unsigned32(); + + public WindowsFileTime(jnr.ffi.Runtime runtime) { + super(runtime); + } + + public int getLowDateTime() { + return lowDateTime.intValue(); + } + + public int getHighDateTime() { + return highDateTime.intValue(); + } + + public long getLongValue() { + return getHighDateTime() << 32 + getLowDateTime(); + } +}
diff --git a/src/main/java/jnr/posix/windows/WindowsFindData.java b/src/main/java/jnr/posix/windows/WindowsFindData.java new file mode 100644 index 0000000..1a5de7a --- /dev/null +++ b/src/main/java/jnr/posix/windows/WindowsFindData.java
@@ -0,0 +1,77 @@ +package jnr.posix.windows; + +import jnr.ffi.*; + +/** + * WIN32_FIND_DATA. For use with FindFirstFileW and friends (since this is for W methods + * the filename fields are wchar_t (or on windows usigned short) in width - TCHAR is an ambiguously + * sized type depending on which variant of method calls it). + */ +public class WindowsFindData extends CommonFileInformation { + public static final int MAX_PATH = 260; + + final UnsignedLong dwFileAttributes; + // FIXME: I have no idea why I could not include FileTime here but having it do its own layout seems to change + // something. + final UnsignedLong chigh; + final UnsignedLong clow; + final UnsignedLong ahigh; + final UnsignedLong alow; + final UnsignedLong uhigh; + final UnsignedLong ulow; + final UnsignedLong nFileSizeHigh; + final UnsignedLong nFileSizeLow; + final UnsignedLong dwReserved0; + final UnsignedLong dwReserved1; + final Padding cFileName; + final Padding cAlternateFileName; + + public WindowsFindData(jnr.ffi.Runtime runtime) { + super(runtime); + + dwFileAttributes = new UnsignedLong(); + clow = new UnsignedLong(); + chigh = new UnsignedLong(); + alow = new UnsignedLong(); + ahigh = new UnsignedLong(); + ulow = new UnsignedLong(); + uhigh = new UnsignedLong(); + nFileSizeHigh = new UnsignedLong(); + nFileSizeLow = new UnsignedLong(); + dwReserved0 = new UnsignedLong(); + dwReserved1 = new UnsignedLong(); + // This is epically large but any paths with //?/ can get a long name. Also even if you do not + // and depend on MAX_PATH (original constant this struct is supposedly defined on) then you can + // get overflows from FindFirstFileW on reparse points. So we will waste memory on allocation + // to avoid the potential for buffer overflows. + // This number specifically is the actual physical limit of a file size in NTFS. So although this + // the functions using this struct cannot handle something this long the internet seems to think + // it is possible to get these long values copied into this field. + cFileName = new Padding(NativeType.USHORT, 32767); + cAlternateFileName = new Padding(NativeType.USHORT, 14); + } + + public HackyFileTime getCreationTime() { + return new HackyFileTime(chigh, clow); + } + + public HackyFileTime getLastAccessTime() { + return new HackyFileTime(ahigh, alow); + } + + public HackyFileTime getLastWriteTime() { + return new HackyFileTime(uhigh, ulow); + } + + public int getFileAttributes() { + return dwFileAttributes.intValue(); + } + + public long getFileSizeHigh() { + return nFileSizeHigh.longValue(); + } + + public long getFileSizeLow() { + return nFileSizeLow.longValue(); + } +}
diff --git a/src/test/java/jnr/posix/ConfstrTest.java b/src/test/java/jnr/posix/ConfstrTest.java new file mode 100644 index 0000000..b616496 --- /dev/null +++ b/src/test/java/jnr/posix/ConfstrTest.java
@@ -0,0 +1,34 @@ +package jnr.posix; + +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import java.nio.ByteBuffer; +import jnr.constants.platform.Confstr; +import jnr.constants.platform.Errno; +import jnr.posix.util.Platform; + +public class ConfstrTest { + private static POSIX posix; + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void confstr() { + if (Platform.IS_WINDOWS) { + int len = posix.confstr(Confstr._CS_PATH, null, 0); + assertEquals(-1, len); + assertEquals(Errno.EOPNOTSUPP.intValue(), posix.errno()); + } else { + int len = posix.confstr(Confstr._CS_PATH, null, 0); + assertTrue("bad strlen", len > 0); + + ByteBuffer buf = ByteBuffer.allocate(len); + posix.confstr(Confstr._CS_PATH, buf, len); + String str = new String(buf.array()); + assertTrue("CS_PATH is blank", str.length() > 0); + } + } +}
diff --git a/src/test/java/jnr/posix/CryptTest.java b/src/test/java/jnr/posix/CryptTest.java new file mode 100644 index 0000000..f73c7b0 --- /dev/null +++ b/src/test/java/jnr/posix/CryptTest.java
@@ -0,0 +1,40 @@ +package jnr.posix; + +import jnr.posix.util.Platform; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.Arrays; + +/** + * Created by headius on 3/24/15. + */ +public class CryptTest { + @Before + public void before() { + posix = POSIXFactory.getPOSIX(); + } + @Test + public void testCrypt() { + if (!Platform.IS_WINDOWS) { + String str1 = "blahblahblah"; + String salt1 = "saltysalty"; + + CharSequence result1 = posix.crypt(str1, salt1); + Assert.assertNotNull(result1); + + byte[] str1bytes = Arrays.copyOfRange(str1.getBytes(), 0, str1.length() + 1); + byte[] salt1bytes = Arrays.copyOfRange(salt1.getBytes(), 0, salt1.length() + 1); + byte[] result2 = posix.crypt(str1bytes, salt1bytes); + + Assert.assertNotNull(result2); + + String result2str = new String(result2, 0, result2.length - 1); + + Assert.assertEquals(result1, result2str); + } + } + + private POSIX posix; +}
diff --git a/src/test/java/jnr/posix/DTableSizeTest.java b/src/test/java/jnr/posix/DTableSizeTest.java new file mode 100644 index 0000000..7b05d27 --- /dev/null +++ b/src/test/java/jnr/posix/DTableSizeTest.java
@@ -0,0 +1,22 @@ +package jnr.posix; + +import jnr.posix.util.Platform; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; +import static org.junit.Assume.assumeTrue; + +public class DTableSizeTest { + @Test + public void testGetDtableSize() throws Exception + { + if (!Platform.IS_WINDOWS) { // FIXME: I have seen window's impl so this can be impld + POSIX posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + assumeTrue("getdtablesize only supported on native posix", posix.isNative()); + + int dtablesize = posix.getdtablesize(); + assertThat(dtablesize, not(-1)); + } + } +}
diff --git a/src/test/java/jnr/posix/DummyPOSIXHandler.java b/src/test/java/jnr/posix/DummyPOSIXHandler.java new file mode 100644 index 0000000..737c915 --- /dev/null +++ b/src/test/java/jnr/posix/DummyPOSIXHandler.java
@@ -0,0 +1,64 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +import jnr.constants.platform.Errno; + +import java.io.File; +import java.io.InputStream; +import java.io.PrintStream; + +/** + * + * @author wayne + */ +public class DummyPOSIXHandler implements POSIXHandler { + + public void error(Errno error, String extraData) { + throw new UnsupportedOperationException("error: " + error); + } + + public void error(Errno error, String methodName, String extraData) { + throw new UnsupportedOperationException("error: " + error); + } + + public void unimplementedError(String methodName) { + throw new UnsupportedOperationException("unimplemented method: " + methodName); + } + + public void warn(WARNING_ID id, String message, Object... data) { + throw new UnsupportedOperationException("warning: " + id); + } + + public boolean isVerbose() { + return true; + } + + public File getCurrentWorkingDirectory() { + return new File("/tmp"); + } + + public String[] getEnv() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public InputStream getInputStream() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public PrintStream getOutputStream() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public int getPID() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public PrintStream getErrorStream() { + throw new UnsupportedOperationException("Not supported yet."); + } + +}
diff --git a/src/test/java/jnr/posix/EnvTest.java b/src/test/java/jnr/posix/EnvTest.java new file mode 100644 index 0000000..47280c1 --- /dev/null +++ b/src/test/java/jnr/posix/EnvTest.java
@@ -0,0 +1,83 @@ +package jnr.posix; + +import com.kenai.jffi.MemoryIO; +import jnr.ffi.Pointer; +import jnr.posix.util.Platform; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class EnvTest { + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void testGetenv() throws Throwable { + assertNotNull(posix.getenv("PATH")); + assertNull(posix.getenv("SOME_NON_EXISTENT_ENV")); + } + + @Test + public void testSetenvNonOverwrite() throws Throwable { + final String path = posix.getenv("PATH"); + int result = posix.setenv("PATH", "new value", 0); + + assertEquals(0, result); + assertEquals(path, posix.getenv("PATH")); + } + + @Test + public void testSetenvOverwrite() throws Throwable { + if (!Platform.IS_WINDOWS) { + final String path = posix.getenv("PATH"); + int result = posix.setenv("PATH", "new value", 1); + + assertEquals(0, result); + assertNotEquals(path, posix.getenv("PATH")); + posix.setenv("PATH", path, 1); + } + } + + @Test + public void testSetEnvNewVar() throws Throwable { + if (!Platform.IS_WINDOWS) { + int result = posix.setenv("MY_NEW_SETENV_VAR", "Yo", 0); + + assertEquals(0, result); + assertEquals("Yo", posix.getenv("MY_NEW_SETENV_VAR")); + } + } + + @Test + public void testUnsetenv() throws Throwable { + if (!Platform.IS_WINDOWS) { + posix.setenv("MY_UNSETENV_VAR", "Yo", 1); + assertEquals("Yo", posix.getenv("MY_UNSETENV_VAR")); + + int result = posix.unsetenv("MY_UNSETENV_VAR"); + assertEquals(0, result); + + assertNull(posix.getenv("MY_UNSETENV_VAR")); + } + } + + @Test + public void testEnv() throws Throwable { + final Pointer env = posix.environ(); + + int offset = 0; + while (env.getPointer(offset) != null) { + final Pointer entryPointer = env.getPointer(offset); + final String entry = new String(MemoryIO.getInstance().getZeroTerminatedByteArray(entryPointer.address())); + + assertTrue(entry.contains("=")); + + offset += jnr.ffi.Runtime.getSystemRuntime().addressSize(); + } + } +}
diff --git a/src/test/java/jnr/posix/FileStatTest.java b/src/test/java/jnr/posix/FileStatTest.java new file mode 100644 index 0000000..3db2331 --- /dev/null +++ b/src/test/java/jnr/posix/FileStatTest.java
@@ -0,0 +1,202 @@ + +package jnr.posix; + +import java.io.FileOutputStream; +import java.io.IOException; +import jnr.posix.util.FieldAccess; +import jnr.posix.util.Platform; +import org.junit.*; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.lang.reflect.Field; + +import static org.junit.Assert.*; + +public class FileStatTest { + + public FileStatTest() { + } + + private void addNBytes(File file, int amount) { + FileOutputStream fis = null; + + try { + fis = new FileOutputStream(file); + byte[] buf = new byte[amount]; + fis.write(buf); + } catch (IOException e) { + if (fis != null) { try { fis.close(); } catch (IOException e2) {} } + } + } + + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void filestat() throws Throwable { + File f = File.createTempFile("stat", null); + int size = 1567; + //Thread.sleep(2000); + addNBytes(f, size); + try { + FileStat stat = posix.stat(f.getAbsolutePath()); + assertNotNull("posix.stat failed", stat); + assertEquals(size, stat.st_size()); + assertEquals(1, stat.nlink()); + //assertNotEquals(stat.mtime(), stat.ctime()); + + stat = posix.allocateStat(); + int result = posix.stat(f.getAbsolutePath(), stat); + assertNotNull("posix.stat failed", stat); + assertEquals(0, result); + assertEquals(size, stat.st_size()); + } finally { + f.delete(); + } + } + + @Test + public void filestatDescriptor() throws Throwable { + File f = File.createTempFile("stat", null); + + try { + FileInputStream fis = new FileInputStream(f); + FileStat stat = posix.allocateStat(); + int result = posix.fstat(fis.getFD(), stat); + assertEquals(0, result); + assertEquals(0, stat.st_size()); + } finally { + f.delete(); + } + + } + + @Test + public void filestatInt() throws Throwable { + // Windows does not store fd in FileDescriptor so this test wll not work + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + File f = File.createTempFile("stat", null); + try { + FileInputStream fis = new FileInputStream(f); + FileDescriptor desc = fis.getFD(); + int fd = -1; + try { + Field fdField = FieldAccess.getProtectedField(FileDescriptor.class, "fd"); + fd = fdField.getInt(desc); + } catch (SecurityException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + FileStat stat = posix.allocateStat(); + int result = posix.fstat(fd, stat); + assertTrue(fd > 2); // should not be stdin, stdout, stderr + assertEquals(0, result); + } finally { + f.delete(); + } + } else { + FileStat stat = posix.fstat(0); + assertTrue(stat != null); + } + } + + // FIXME: I could guarantee this does not exist but this was very very quick :) + private static final String NON_EXISTENT_FILENAME = "skdjlfklfsdjk"; + @Test + public void filestatFailed() throws Throwable { + FileStat stat = null; + + // A little wonky without adding a new posixhandler but we are using dummy so this is ok for now + // the default handler raises on a problem in stat so we are only verifying this at the moment. + try { + stat = posix.stat(NON_EXISTENT_FILENAME); + } catch (UnsupportedOperationException e) {} + + assertTrue(stat == null); + } + + + @Test + public void fileStatNanoTime() throws Throwable { + // Currently only linux file stat support nano time resolution + jnr.ffi.Platform nativePlatform = jnr.ffi.Platform.getNativePlatform(); + if (nativePlatform.getOS() == jnr.ffi.Platform.OS.LINUX) { + File f = File.createTempFile("stat", null); + try { + FileStat st = posix.stat(f.getAbsolutePath()); + assertNotNull("posix.stat failed", st); + + FileStat stat = posix.allocateStat(); + int result = posix.stat(f.getAbsolutePath(), stat); + assertNotNull("posix.stat failed", st); + assertEquals(0, result); + + NanosecondFileStat fstat32 = (NanosecondFileStat) stat; + assertTrue(fstat32.cTimeNanoSecs() > 0); + assertTrue(fstat32.mTimeNanoSecs() > 0); + assertTrue(fstat32.aTimeNanoSecs() > 0); + assertEquals(fstat32.cTimeNanoSecs(), fstat32.mTimeNanoSecs()); + } finally { + f.delete(); + } + } + } + + @Test + public void structStatSize() throws Throwable { + if (Platform.IS_SOLARIS) { + jnr.ffi.Runtime runtime = jnr.ffi.Runtime.getSystemRuntime(); + if (Platform.IS_32_BIT) { + assertEquals("struct size is wrong", 144, new SolarisFileStat32.Layout(runtime).size()); + } else { + assertEquals("struct size is wrong", 128, new SolarisFileStat64.Layout(runtime).size()); + } + } + + if (Platform.IS_SOLARIS) { + File f = File.createTempFile("stat", null); + try { + FileStat st = posix.stat(f.getAbsolutePath()); + + if (Platform.IS_32_BIT) { + assertSame("incorrect stat instance returned", SolarisFileStat32.class, st.getClass()); + } else { + assertSame("incorrect stat instance returned", SolarisFileStat64.class, st.getClass()); + } + } finally { + f.delete(); + } + } + } + + @Test + public void filestatDirectory() throws Throwable { + File f = File.createTempFile("stat", null).getParentFile(); + try { + FileStat stat = posix.stat(f.getAbsolutePath()); + + assertTrue(stat.isDirectory()); + } finally { + f.delete(); + } + } +}
diff --git a/src/test/java/jnr/posix/FileTest.java b/src/test/java/jnr/posix/FileTest.java new file mode 100644 index 0000000..afadb07 --- /dev/null +++ b/src/test/java/jnr/posix/FileTest.java
@@ -0,0 +1,680 @@ +package jnr.posix; + +import jnr.constants.platform.Access; +import jnr.constants.platform.Fcntl; +import jnr.constants.platform.Errno; +import jnr.constants.platform.OpenFlags; +import jnr.ffi.Pointer; +import jnr.posix.util.Platform; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.Charset; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +public class FileTest { + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void utimesTest() throws Throwable { + // FIXME: On Windows this is working but providing wrong numbers and therefore getting wrong results. + if (!Platform.IS_WINDOWS) { + File f = File.createTempFile("utimes", null); + + int rval = posix.utimes(f.getAbsolutePath(), new long[]{800, 200}, new long[]{900, 300}); + assertEquals("utimes did not return 0", 0, rval); + + FileStat stat = posix.stat(f.getAbsolutePath()); + + assertEquals("atime seconds failed", 800, stat.atime()); + assertEquals("mtime seconds failed", 900, stat.mtime()); + + // The nano secs part is available in other stat implementations. We really just want to verify that the + // nsec portion of the timeval is passed through to the POSIX call. + // Mac seems to fail this test sporadically. + if (stat instanceof NanosecondFileStat && !Platform.IS_MAC) { + NanosecondFileStat linuxStat = (NanosecondFileStat) stat; + + assertEquals("atime useconds failed", 200000, linuxStat.aTimeNanoSecs()); + assertEquals("mtime useconds failed", 300000, linuxStat.mTimeNanoSecs()); + } + + f.delete(); + } + } + + @Test + public void utimesDefaultValuesTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File f = File.createTempFile("utimes", null); + + long oldTime = posix.stat(f.getAbsolutePath()).mtime(); + Thread.sleep(2000); + + int rval = posix.utimes(f.getAbsolutePath(), null, null); + assertEquals("utimes did not return 0", 0, rval); + + FileStat stat = posix.stat(f.getAbsolutePath()); + + assertTrue("atime failed", stat.atime() > oldTime); + assertTrue("mtime failed", stat.mtime() > oldTime); + + f.delete(); + } + } + + @Test + public void utimesPointerTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File f = File.createTempFile("utimes", null); + + Pointer times = jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().allocateDirect(8 * 4); // long[2][2] == 4 longs. + times.putLong(0, 800); + times.putLong(8, 200); + times.putLong(16, 900); + times.putLong(24, 300); + + int rval = posix.utimes(f.getAbsolutePath(), times); + assertEquals("utimes did not return 0", 0, rval); + + FileStat stat = posix.stat(f.getAbsolutePath()); + + assertEquals("atime seconds failed", 800, stat.atime()); + assertEquals("mtime seconds failed", 900, stat.mtime()); + + // The nano secs part is available in other stat implementations. We use Linux x86_64 because it's + // representative. We really just want to verify that the usec portion of the timeval is passed throug + // to the POSIX call. + if (hasNanosecondPrecision(stat)) { + NanosecondFileStat linuxStat = (NanosecondFileStat) stat; + +// assertEquals("atime useconds failed", 200000, linuxStat.aTimeNanoSecs()); + assertEquals("mtime useconds failed", 300000, linuxStat.mTimeNanoSecs()); + } + + f.delete(); + } + } + + @Test + public void utimensatAbsolutePath() throws Throwable { + File file = File.createTempFile("utimensat", null); + utimensat(file, 0); + } + + @Test + public void utimensatRelativePath() throws Throwable { + String path = "utimensat"; + File file = new File(path); + file.createNewFile(); + int parentFd = posix.open(".", OpenFlags.O_DIRECTORY.intValue(), 0444); + utimensat(file, parentFd); + } + + @Test + public void futimens() throws Throwable { + File file = File.createTempFile("futimens", null); + FileStat fileStat = posix.stat(file.getPath()); + if (!hasNanosecondPrecision(fileStat)) { + file.delete(); + return; + } + + long atimeSeconds = fileStat.atime()+1; + long mtimeSeconds = fileStat.mtime()-1; + long atimeNanoSeconds = 123456789; + long mtimeNanoSeconds = 135; + int fd = posix.open(file.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0444); + posix.futimens(fd, + new long[] {atimeSeconds, atimeNanoSeconds}, + new long[] {mtimeSeconds, mtimeNanoSeconds}); + assertStatNanoSecond(file, atimeSeconds, atimeNanoSeconds, mtimeSeconds, mtimeNanoSeconds); + } + + @Test + public void lutimesTest() throws Throwable { + // FIXME: On Windows this is working but providing wrong numbers and therefore getting wrong results. + if (!Platform.IS_WINDOWS) { + File f1 = File.createTempFile("lutimes", null); + File f2 = new File(f1.getParentFile(), "lutimes-link"); + posix.symlink(f1.getAbsolutePath(), f2.getAbsolutePath()); + + int rval = posix.utimes(f1.getAbsolutePath(), new long[]{800, 0}, new long[]{900, 0}); + assertEquals("utimes did not return 0", 0, rval); + + rval = posix.lutimes(f2.getAbsolutePath(), new long[]{1800, 0}, new long[]{1900, 0}); + assertEquals("lutimes did not return 0", 0, rval); + + FileStat stat = posix.stat(f1.getAbsolutePath()); + assertEquals("atime seconds failed", 800, stat.atime()); + assertEquals("mtime seconds failed", 900, stat.mtime()); + + stat = posix.lstat(f2.getAbsolutePath()); + assertEquals("atime seconds failed", 1800, stat.atime()); + assertEquals("mtime seconds failed", 1900, stat.mtime()); + + f1.delete(); + f2.delete(); + } + } + + @Test + public void futimeTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File f = File.createTempFile("jnr-posix-futime", "tmp"); + long oldTime = posix.stat(f.getAbsolutePath()).mtime(); + Thread.sleep(2000); + int fd = posix.open(f.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0666); + int rval = posix.futimes(fd, null, null); + assertEquals("futime did not return 0", 0, rval); + long newTime = posix.stat(f.getAbsolutePath()).mtime(); + f.delete(); + assertTrue("mtime failed", newTime > oldTime); + } + } + + @Test + public void linkTest() throws Throwable { + File f1 = File.createTempFile("utime", null); + File f2 = new File(f1.getAbsolutePath() + "link"); + int rval = posix.link(f1.getAbsolutePath(), f2.getAbsolutePath()); + assertEquals("link did not return 0", 0, rval); + assertTrue("Link was not created", f2.exists()); + f1.delete(); + f2.delete(); + } + + @Test + public void mkdirRelativeTest() throws Throwable { + File dir = new File("tmp"); + int rval = posix.mkdir(dir.getPath(), 0); + assertEquals("mkdir did not return 0", 0, rval); + assertTrue("Directory was not created", dir.exists()); + dir.delete(); + } + + @Test + public void mkdirAbsoluteTest() throws Throwable { + File dir = new File("tmp"); + int rval = posix.mkdir(dir.getAbsolutePath(), 0); + assertEquals("mkdir did not return 0", 0, rval); + assertTrue("Directory was not created", dir.exists()); + dir.delete(); + } + + @Test + public void flockTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("flockTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + RandomAccessFile raf2 = new RandomAccessFile(tmp, "rw"); + FileChannel fc = raf.getChannel(); + FileChannel fc2 = raf2.getChannel(); + FileDescriptor FD = JavaLibCHelper.getDescriptorFromChannel(fc); + FileDescriptor FD2 = JavaLibCHelper.getDescriptorFromChannel(fc2); + int fd = JavaLibCHelper.getfdFromDescriptor(FD); + int fd2 = JavaLibCHelper.getfdFromDescriptor(FD2); + + assertEquals(0, posix.flock(fd, 1)); // LOCK_SH + assertEquals(0, posix.flock(fd, 8)); // LOCK_UN + assertEquals(0, posix.flock(fd, 2)); // LOCK_EX + assertEquals(-1, posix.flock(fd2, 2 | 4)); // LOCK_EX | LOCK_NB + assertEquals(0, posix.flock(fd, 8)); // LOCK_UN + } + } + + @Test + public void dupTest() throws Throwable { + File tmp = File.createTempFile("dupTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + FileChannel fileChannel = raf.getChannel(); + int fileDescriptor = getFdFromDescriptor(JavaLibCHelper.getDescriptorFromChannel(fileChannel)); + + byte[] outContent = "foo".getBytes(); + + FileDescriptor newFileDescriptor = toDescriptor(posix.dup(fileDescriptor)); + + new FileOutputStream(toDescriptor(fileDescriptor)).write(outContent); + raf.seek(0); + + byte[] inContent = new byte[outContent.length]; + new FileInputStream(newFileDescriptor).read(inContent, 0, 3); + + assertArrayEquals(inContent, outContent); + } + + public static final int SEEK_SET = 0; + + @Test + public void dup2Test() throws Throwable { + File tmp = File.createTempFile("dupTest", "tmp"); + int oldFd = posix.open(tmp.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0666); + int newFd = 1000; + + byte[] outContent = "foo".getBytes(); + + // NB: Windows differs a bit from POSIX's return value. Both will return -1 on failure, but Windows will return + // 0 upon success, while POSIX will return the new FD. Since we already know what the FD will be if the call + // is successful, it's easy to make code that works with both forms. But it is something to watch out for. + assertNotEquals(-1, posix.dup2(oldFd, newFd)); + FileDescriptor newFileDescriptor = toDescriptor(newFd); + + new FileOutputStream(toDescriptor(oldFd)).write(outContent); + posix.lseek(newFd, SEEK_SET, 0); + + byte[] inContent = new byte[outContent.length]; + new FileInputStream(newFileDescriptor).read(inContent, 0, 3); + + assertArrayEquals(inContent, outContent); + } + + @Test + public void fcntlDupfdTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("fcntlTest", "tmp"); + int fd = posix.open(tmp.getPath(), OpenFlags.O_RDWR.intValue(), 0444); + + byte[] outContent = "foo".getBytes(); + + // NOTE: This test used to call without the third argument, but this leads to undefined behavior. + // See https://github.com/jnr/jnr-posix/issues/144 + int newFd = posix.fcntl(fd, Fcntl.F_DUPFD, 0); + + new FileOutputStream(JavaLibCHelper.toFileDescriptor(fd)).write(outContent); + posix.lseek(fd, SEEK_SET, 0); + + byte[] inContent = new byte[outContent.length]; + new FileInputStream(JavaLibCHelper.toFileDescriptor(newFd)).read(inContent, 0, 3); + + assertArrayEquals(inContent, outContent); + } + } + + @Test + public void fcntlDupfdWithArgTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("dupTest", "tmp"); + int oldFd = JavaLibCHelper.getfdFromDescriptor(JavaLibCHelper.getDescriptorFromChannel( + new RandomAccessFile(tmp, "rw").getChannel())); + int newFd = JavaLibCHelper.getfdFromDescriptor(JavaLibCHelper.getDescriptorFromChannel( + new RandomAccessFile(tmp, "rw").getChannel())); + + byte[] outContent = "foo".getBytes(); + + int expectedFd = 100; + int dupFd = posix.fcntl(oldFd, Fcntl.F_DUPFD, expectedFd); + + new FileOutputStream(JavaLibCHelper.toFileDescriptor(newFd)).write(outContent); + + byte[] inContent = new byte[outContent.length]; + new FileInputStream(JavaLibCHelper.toFileDescriptor(dupFd)).read(inContent, 0, 3); + + assertTrue(dupFd >= expectedFd); + assertArrayEquals(inContent, outContent); + } + } + + @Test + public void closeTest() throws Throwable { + File tmp = File.createTempFile("closeTest", "tmp"); + int fd = getFdFromDescriptor(JavaLibCHelper.getDescriptorFromChannel(new RandomAccessFile(tmp, "rw").getChannel())); + + int result; + + result = posix.close(fd); + assertEquals(0, result); + + result = posix.close(fd); + assertEquals(-1, result); + + // TODO (nirvdrum 06-May-15) We're not getting the correct errno value from Windows currently, so we need to skip this test. + if (!Platform.IS_WINDOWS) { + assertEquals(Errno.EBADF.intValue(), posix.errno()); + } + } + + @Test + public void unlinkTestNonWindows() throws Throwable { + if (! Platform.IS_WINDOWS) { + File tmp = File.createTempFile("unlinkTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + + raf.write("hello".getBytes()); + + int res = posix.unlink(tmp.getCanonicalPath()); + + assertEquals(0, res); + assertFalse(tmp.exists()); + + raf.write("world".getBytes()); + raf.seek(0); + + byte[] actual = new byte[10]; + raf.read(actual); + + assertArrayEquals("helloworld".getBytes(), actual); + } + } + + @Test + public void openTest() throws Throwable { + int fd = posix.open("pom.xml", 0, 0666); + + assertNotEquals(-1, fd); + + int result = posix.close(fd); + assertEquals(0, result); + + result = posix.close(fd); + assertEquals(-1, result); + + fd = posix.open("jnr-posix-filetest.txt", OpenFlags.O_CREAT.intValue() | OpenFlags.O_RDWR.intValue(), 0600); + + assertEquals(0600, posix.stat("jnr-posix-filetest.txt").mode() & 0777); + + result = posix.close(fd); + assertEquals(0, result); + + new File("jnr-posix-filetest.txt").delete(); + } + + @Test + public void writeTest() throws Throwable { + String str = "To thine own self be true"; + File tmp = File.createTempFile("writeTest", "tmp"); + ByteBuffer buffer = ByteBuffer.wrap(str.getBytes()); + + int fd = posix.open(tmp.getAbsolutePath(), 1, 066); + posix.write(fd, buffer, str.length()); + posix.close(fd); + + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + assertEquals(raf.readLine(), new String(buffer.array())); + posix.unlink(tmp.getAbsolutePath()); + } + + @Test + public void pwriteTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + String str = "Now is the winter of our discontent"; + File tmp = File.createTempFile("pwriteTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + raf.write(str.getBytes()); + raf.close(); + + String str2 = "summer"; + ByteBuffer buffer = ByteBuffer.wrap(str2.getBytes()); + + int fd = posix.open(tmp.getAbsolutePath(), 1, 066); + posix.pwrite(fd, buffer, str2.length(), 11); + posix.close(fd); + + raf = new RandomAccessFile(tmp, "r"); + assertEquals(raf.readLine(), "Now is the summer of our discontent"); + posix.unlink(tmp.getAbsolutePath()); + } + } + + @Test + public void truncateTest() throws Throwable { + String str = "Beware the Jabberwock, my son!"; + File tmp = File.createTempFile("truncateTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + raf.write(str.getBytes()); + raf.close(); + + int shorterLength = str.length() - 10; + int longerLength = shorterLength * 2; + + // Truncate should make a file shorter if the new length is less than the old length. + posix.truncate(tmp.getAbsolutePath(), shorterLength); + assertEquals(shorterLength, tmp.length()); + + // Truncate should extend a file if the new length is greater than the old length. + posix.truncate(tmp.getAbsolutePath(), longerLength); + assertEquals(longerLength, tmp.length()); + } + + @Test + public void ftruncateTest() throws Throwable { + String str = "Beware the Jabberwock, my son!"; + File tmp = File.createTempFile("ftruncateTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + raf.write(str.getBytes()); + raf.close(); + + int fd = posix.open(tmp.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0666); + posix.ftruncate(fd, 21); + posix.lseekLong(fd, 0, 0); + byte[] buf = new byte[21]; + int read = posix.read(fd, buf, 31); + assertEquals(21, read); + assertArrayEquals(buf, "Beware the Jabberwock".getBytes()); + } + + @Test + public void fcntlIntTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + int[] fds = new int[2]; + int ret = posix.pipe(fds); + assertEquals(0, ret); + int flags = posix.fcntlInt(fds[0], Fcntl.F_GETFD, 0); + posix.fcntlInt(fds[0], Fcntl.F_SETFD, flags | 1); // FD_CLOEXEC + assertEquals(flags | 1, posix.fcntlInt(fds[0], Fcntl.F_GETFD, 0)); + } + } + + @Test + public void fchmodTest() throws IOException { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("jnr-posix-chmod-test", "tmp"); + int fd = posix.open(tmp.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0600); + + assertEquals("chmod: ", 0, posix.fchmod(fd, 0)); + assertEquals("chmod: ", 0, posix.fchmod(fd, 0777)); + tmp.delete(); + } + } + + + @Test + public void renameTest() throws IOException { + File oldFile = File.createTempFile("jnr-posix-rename-test", "tmp"); + File newFile = new File(oldFile.getParent() + File.separatorChar + "jnr-posix-rename-test-new"); + + assertTrue(oldFile.exists()); + assertFalse(newFile.exists()); + + posix.rename(oldFile.getCanonicalPath(), newFile.getCanonicalPath()); + + assertFalse(oldFile.exists()); + assertTrue(newFile.exists()); + + newFile.delete(); + } + + @Test + public void accessTest() throws IOException { + File tmp = File.createTempFile("jnr-posix-access-test", "tmp"); + + jnr.constants.platform.Access.F_OK.intValue(); + + // Set permissions to read-only and verify we don't have permissions to write. + String canonicalPath = tmp.getCanonicalPath(); + assertEquals("chmod 0400: ", 0, posix.chmod(canonicalPath, 0400)); + assertEquals("access " + canonicalPath + " for write: ", -1, posix.access(canonicalPath, Access.W_OK.intValue())); + assertEquals("access " + canonicalPath + " for read: ", 0, posix.access(canonicalPath, Access.R_OK.intValue())); + + // Reset the permissions to read-write and verify we now have permissions to write. + assertEquals("chmod 0600: ", 0, posix.chmod(canonicalPath, 0600)); + assertEquals("access " + canonicalPath + " for write: ", 0, posix.access(canonicalPath, Access.W_OK.intValue())); + assertEquals("access " + canonicalPath + " for read: ", 0, posix.access(canonicalPath, Access.R_OK.intValue())); + + // F_OK just checks the file exists and should pass. + assertEquals("access " + canonicalPath + " exists: ", 0, posix.access(canonicalPath, Access.F_OK.intValue())); + } + + @Test + public void readlinkTest() throws IOException { + if (!Platform.IS_WINDOWS) { + File file = File.createTempFile("jnr-pøsix-réådlînk-tést", "tmp"); + File link = new File(file.getAbsolutePath() + "link"); + + posix.symlink(file.getAbsolutePath(), link.getAbsolutePath()); + + byte[] fileBytes = file.getAbsolutePath().getBytes(); + int fileLength = fileBytes.length; + + byte[] buffer = new byte[fileLength]; + + assertEquals(fileLength, posix.readlink(link.getAbsolutePath(), buffer, buffer.length)); + + assertArrayEquals(fileBytes, buffer); + + link.delete(); + file.delete(); + } + } + + @Test + public void readlinkByteBufferTest() throws IOException { + if (!Platform.IS_WINDOWS) { + File file = File.createTempFile("jnr-pøsix-réådlînk-tést", "tmp"); + File link = new File(file.getAbsolutePath() + "link"); + + posix.symlink(file.getAbsolutePath(), link.getAbsolutePath()); + + byte[] fileBytes = file.getAbsolutePath().getBytes(); + int fileLength = fileBytes.length; + ByteBuffer buffer = ByteBuffer.allocate(fileLength); + + assertEquals(fileLength, posix.readlink(link.getAbsolutePath(), buffer, buffer.capacity())); + + assertArrayEquals(buffer.array(), file.getAbsolutePath().getBytes()); + + link.delete(); + file.delete(); + } + } + + @Test + public void readlinkPointerTest() throws IOException { + if (!Platform.IS_WINDOWS) { + File file = File.createTempFile("jnr-pøsix-réådlînk-tést", "tmp"); + File link = new File(file.getAbsolutePath() + "link"); + + int bufSize = 1024; + + Pointer buffer = jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().allocateDirect(bufSize); + + posix.symlink(file.getAbsolutePath(), link.getAbsolutePath()); + + byte[] fileBytes = file.getAbsolutePath().getBytes(); + int fileLength = fileBytes.length; + + assertEquals(fileLength, posix.readlink(link.getAbsolutePath(), buffer, bufSize)); + + assertEquals(file.getAbsolutePath(), buffer.getString(0, fileLength, Charset.defaultCharset())); + + link.delete(); + file.delete(); + } + } + + @Test + public void mkfifoTest() throws Throwable { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("mkfifoTest", "tmp"); + tmp.deleteOnExit(); + + int ret = posix.mkfifo(tmp.getAbsolutePath(), 0666); + + FileInputStream fis = new FileInputStream(tmp); + FileOutputStream fos = new FileOutputStream(tmp); + + byte[] content = "hello".getBytes(); + + fos.write(content); + fis.read(content); + + assertArrayEquals("hello".getBytes(), content); + } + } + + @Test + public void lseekTest() throws Throwable { + if (Platform.IS_MAC) { + int fd = posix.open("/dev/zero", 0, 0); + + // use 2^33 to ensure we're out of int range + long offset = (long) Math.pow(2, 33); + long seek = posix.lseekLong(fd, offset, 0); + + assertEquals(seek, offset); + } + } + + private int getFdFromDescriptor(FileDescriptor descriptor) { + if (Platform.IS_WINDOWS) { + HANDLE handle = JavaLibCHelper.gethandle(descriptor); + return ((WindowsLibC) posix.libc())._open_osfhandle(handle, 0); + } else { + return JavaLibCHelper.getfdFromDescriptor(descriptor); + } + } + + private FileDescriptor toDescriptor(int fd) { + if (Platform.IS_WINDOWS) { + HANDLE handle = ((WindowsLibC) posix.libc())._get_osfhandle(fd); + return JavaLibCHelper.toFileDescriptor(handle); + } else { + return JavaLibCHelper.toFileDescriptor(fd); + } + } + + private boolean hasNanosecondPrecision(FileStat fileStat) { + return fileStat instanceof NanosecondFileStat && !Platform.IS_MAC; + } + + private void utimensat(File file, int parentFd) { + String path = file.getAbsolutePath(); + FileStat fileStat = posix.stat(path); + if (!hasNanosecondPrecision(fileStat)) { + file.delete(); + return; + } + + long atimeSeconds = fileStat.atime()+2; + long mtimeSeconds = fileStat.mtime()-2; + long atimeNanoSeconds = 123456789; + long mtimeNanoSeconds = 135; + posix.utimensat(parentFd, + path, + new long[] {atimeSeconds, atimeNanoSeconds}, + new long[] {mtimeSeconds, mtimeNanoSeconds}, + 0); + assertStatNanoSecond(file, atimeSeconds, atimeNanoSeconds, mtimeSeconds, mtimeNanoSeconds); + } + + private void assertStatNanoSecond(File file, long atimeSeconds, long atimeNanoSeconds, long mtimeSeconds, long mtimeNanoSeconds) { + NanosecondFileStat nanosecondFileStat = (NanosecondFileStat) posix.stat(file.getPath()); + assertEquals("Access timestamp should be updated", atimeSeconds, nanosecondFileStat.atime()); + assertEquals("Modification timestamp should be updated", mtimeSeconds, nanosecondFileStat.mtime()); + assertEquals("Access time precision should be in ns", atimeNanoSeconds, nanosecondFileStat.aTimeNanoSecs()); + assertEquals("Modification time precision should be in ns", mtimeNanoSeconds, nanosecondFileStat.mTimeNanoSecs()); + file.delete(); + } +}
diff --git a/src/test/java/jnr/posix/GroupTest.java b/src/test/java/jnr/posix/GroupTest.java new file mode 100644 index 0000000..6ede36a --- /dev/null +++ b/src/test/java/jnr/posix/GroupTest.java
@@ -0,0 +1,149 @@ + +package jnr.posix; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Arrays; + +import jnr.constants.platform.LangInfo; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + */ +public class GroupTest { + + public GroupTest() { + } + + private static POSIX posix; + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + // TODO add test methods here. + // The methods must be annotated with annotation @Test. For example: + // + // @Test + // public void hello() {} + @Test + public void getgrnam() { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + final String LOGIN = "daemon"; + Group grp = posix.getgrnam(LOGIN); + assertNotNull(grp); + assertEquals("Login name not equal", LOGIN, grp.getName()); + } + } + + @Test + public void nonExistantGroupReturnsNull() { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + final String LOGIN = "dkjhfjkdsfhjksdhfsdjkhfsdkjhfdskj"; + assertNull("getpwnam for non-existant group should return null", posix.getgrnam(LOGIN)); + } + } + + @Test + public void getgrent() { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + ArrayList<Group> grps = new ArrayList<Group>(); + while (true) { + Group grp = posix.getgrent(); + if (grp == null) { + break; + } + grps.add(grp); + } + for (Group grp : grps) { + assertNotNull(grp.getName()); + assertNotNull(grp.getPassword()); + assertNotNull(grp.getGID()); + for (String member : grp.getMembers()) { + assertNotNull(member); + } + } + } + } + + @Test + public void getgroups() throws Throwable { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + String[] groupIdsAsStrings = exec("id", "-G").split(" "); + long[] expectedGroupIds = new long[groupIdsAsStrings.length]; + + for (int i = 0; i < groupIdsAsStrings.length; i++) { + expectedGroupIds[i] = Long.parseLong(groupIdsAsStrings[i]); + } + + long[] actualGroupIds = posix.getgroups(); + + // getgroups does not specify whether the effective group ID is included along with the supplementary + // group IDs. However, `id -G` always includes all group IDs. So, we must do something of a fuzzy match. + // If the actual list is shorter than the expected list by 1, alter the expected list by removing the + // effective group ID before comparing the two arrays. + if (actualGroupIds.length == expectedGroupIds.length - 1) { + long effectiveGroupId = Long.parseLong(exec("id", "-g")); + expectedGroupIds = removeElement(expectedGroupIds, effectiveGroupId); + } + + Arrays.sort(expectedGroupIds); + Arrays.sort(actualGroupIds); + + assertArrayEquals(expectedGroupIds, actualGroupIds); + } + } + + private String exec(String... command) throws IOException { + InputStreamReader isr = null; + BufferedReader reader = null; + + try { + isr = new InputStreamReader(Runtime.getRuntime().exec(command).getInputStream()); + reader = new BufferedReader(isr); + + return reader.readLine(); + } finally { + if (reader != null) { + reader.close(); + } + + if (isr != null) { + isr.close(); + } + } + } + + private long[] removeElement(long[] array, long value) { + for (int i = 0; i < array.length; i++) { + if (array[i] == value) { + long[] ret = new long[array.length - 1]; + System.arraycopy(array, 0, ret, 0, i); + System.arraycopy(array, i + 1, ret, i, array.length - i - 1); + return ret; + } + } + + return array; + } +}
diff --git a/src/test/java/jnr/posix/HANDLETest.java b/src/test/java/jnr/posix/HANDLETest.java new file mode 100644 index 0000000..eceeadd --- /dev/null +++ b/src/test/java/jnr/posix/HANDLETest.java
@@ -0,0 +1,57 @@ +package jnr.posix; + +import jnr.posix.util.Platform; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +public class HANDLETest { + + private static POSIX posix; + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void invalidHandleIsInValid() { + assertFalse(HANDLE.valueOf(-1L).isValid()); + } + + private static WindowsLibC kernel32() { + return (WindowsLibC) posix.libc(); + } + + // This really is matching pipe for the sake of these unit tests but in general the + // in/out/error handle will vary depending on how a CLI supplies it: + // http://stackoverflow.com/questions/9021916/how-do-i-check-if-my-delphi-console-app-is-redirected-to-a-file-or-pipe + private boolean isValidHandleType(HANDLE handle) { + int type = kernel32().GetFileType(handle); + + return type == WindowsLibC.FILE_TYPE_DISK || type == WindowsLibC.FILE_TYPE_PIPE; + } + + @Test + public void stdinHandle() { + if (Platform.IS_WINDOWS) { + assertTrue(kernel32().GetStdHandle(WindowsLibC.STD_INPUT_HANDLE).isValid()); + assertTrue(isValidHandleType(kernel32().GetStdHandle(WindowsLibC.STD_INPUT_HANDLE))); + } + } + + @Test + public void stdoutHandle() { + if (Platform.IS_WINDOWS) { + assertTrue(kernel32().GetStdHandle(WindowsLibC.STD_OUTPUT_HANDLE).isValid()); + assertTrue(isValidHandleType(kernel32().GetStdHandle(WindowsLibC.STD_OUTPUT_HANDLE))); + } + } + + @Test + public void stderrHandle() { + if (Platform.IS_WINDOWS) { + assertTrue(kernel32().GetStdHandle(WindowsLibC.STD_ERROR_HANDLE).isValid()); + assertTrue(isValidHandleType(kernel32().GetStdHandle(WindowsLibC.STD_ERROR_HANDLE))); + } + } +}
diff --git a/src/test/java/jnr/posix/HostnameTest.java b/src/test/java/jnr/posix/HostnameTest.java new file mode 100644 index 0000000..cb094ce --- /dev/null +++ b/src/test/java/jnr/posix/HostnameTest.java
@@ -0,0 +1,47 @@ +package jnr.posix; + +import org.hamcrest.Matcher; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.*; +import static org.junit.Assume.*; + +import java.io.IOException; +import java.util.Scanner; + +public class HostnameTest { + private static POSIX posix; + private static POSIX jPosix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + jPosix = POSIXFactory.getJavaPOSIX(); + } + + @Test + public void testHostnameWorks() { + assertNotNull(posix.gethostname()); + } + + @Test + public void jPosixIsReasonable() { + // cast here works around a generic resolution problem in Java 11+ + assumeThat(System.getenv().keySet(), (Matcher) anyOf(hasItem("HOSTNAME"), hasItem("COMPUTERNAME"))); + assertNotNull(jPosix.gethostname()); + } + + @Test + public void testHostnameIsResonable() throws IOException { + String hostname = ""; + try { + hostname = new Scanner(Runtime.getRuntime().exec("hostname").getInputStream()).next(); + } catch (IOException e) { + assumeNoException(e); + } + assumeThat(hostname, is(not(equalTo("")))); + assertThat(posix.gethostname().toLowerCase(), equalTo(hostname.toLowerCase())); + } +}
diff --git a/src/test/java/jnr/posix/IDTest.java b/src/test/java/jnr/posix/IDTest.java new file mode 100644 index 0000000..c98c2e6 --- /dev/null +++ b/src/test/java/jnr/posix/IDTest.java
@@ -0,0 +1,70 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ + +package jnr.posix; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +public class IDTest { + + public IDTest() { + } + private static POSIX nativePosix, javaPosix; + @BeforeClass + public static void setUpClass() throws Exception { + nativePosix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + javaPosix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), false); + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test public void getuid() { + assertEquals("Java posix did not return same value as native posix", nativePosix.getuid(), javaPosix.getuid()); + } + @Test public void getgid() { + assertEquals("Java posix did not return same value as native posix", nativePosix.getgid(), javaPosix.getgid()); + } +} \ No newline at end of file
diff --git a/src/test/java/jnr/posix/IOTest.java b/src/test/java/jnr/posix/IOTest.java new file mode 100644 index 0000000..b0c0c98 --- /dev/null +++ b/src/test/java/jnr/posix/IOTest.java
@@ -0,0 +1,231 @@ +package jnr.posix; + +import jnr.constants.platform.*; +import jnr.posix.util.Platform; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.IntBuffer; + +/** + * Created by headius on 5/31/14. + */ +public class IOTest { + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void testOpenReadWrite() throws Throwable { + if (!Platform.IS_WINDOWS) { + File tmp = File.createTempFile("IOTest", "testOpen"); + int fd = posix.open(tmp.getPath(), OpenFlags.O_RDWR.intValue(), 0666); + Assert.assertTrue(fd > 0); + + byte[] hello = "hello".getBytes(); + int written = posix.write(fd, hello, 5); + Assert.assertEquals(5, written); + + byte[] buf = new byte[5]; + posix.lseekLong(fd, 0, 0); // no jnr-constants for SEEK_SET + int read = posix.read(fd, buf, 5); + Assert.assertEquals(5, read); + Assert.assertArrayEquals(hello, buf); + + byte[] goodbye = "goodbye".getBytes(); + written = posix.pwrite(fd, goodbye, 7, 3); + Assert.assertEquals(7, written); + Assert.assertEquals(5, posix.lseekLong(fd, 0, 1)); // SEEK_CUR + + byte[] bye = new byte[3]; + read = posix.pread(fd, bye, 3, 7); + Assert.assertEquals(3, read); + Assert.assertEquals(5, posix.lseekLong(fd, 0, 1)); // SEEK_CUR + Assert.assertArrayEquals("bye".getBytes(), bye); + } + } + + @Test + public void testPipe() throws Throwable { + int[] fds = {0, 0}; + int ret = posix.pipe(fds); + Assert.assertTrue(ret >= 0); + Assert.assertTrue(fds[0] > 0); + Assert.assertTrue(fds[1] > 0); + + byte[] hello = "hello".getBytes(); + int written = posix.write(fds[1], hello, 5); + Assert.assertEquals(5, written); + + byte[] buf = new byte[5]; + int read = posix.read(fds[0], buf, 5); + Assert.assertEquals(5, read); + Assert.assertArrayEquals(buf, hello); + } + + @Test + public void testPathconf() { + if (Platform.IS_WINDOWS) { + int res = posix.fpathconf(-1, Pathconf._PC_PIPE_BUF); + Assert.assertEquals(-1, res); + Assert.assertEquals(Errno.EOPNOTSUPP.intValue(), posix.errno()); + } else { + int res = posix.fpathconf(-1, Pathconf._PC_PIPE_BUF); + Assert.assertEquals(-1, res); + + int[] fds = {0, 0}; + posix.pipe(fds); + res = posix.fpathconf(fds[1], Pathconf._PC_PIPE_BUF); + if (Platform.IS_LINUX) { + Assert.assertEquals(4096, res); + } else { + Assert.assertTrue(res > 0); + } + } + } + + @Test + public void testSocketPair() throws Throwable { + if (!Platform.IS_WINDOWS) { + int[] fds = {0, 0}; + + int ret = posix.socketpair(AddressFamily.AF_UNIX.intValue(), Sock.SOCK_STREAM.intValue(), 0, fds); + + Assert.assertTrue(ret >= 0); + Assert.assertTrue(fds[0] > 0); + Assert.assertTrue(fds[1] > 0); + + byte[] hello = "hello".getBytes(); + int written = posix.write(fds[1], hello, 5); + Assert.assertEquals(5, written); + + byte[] buf = new byte[5]; + int read = posix.read(fds[0], buf, 5); + Assert.assertEquals(5, read); + Assert.assertArrayEquals(buf, hello); + + hello = "goodbye".getBytes(); + written = posix.write(fds[0], hello, 7); + Assert.assertEquals(7, written); + + buf = new byte[7]; + read = posix.read(fds[1], buf, 7); + Assert.assertEquals(7, read); + Assert.assertArrayEquals(buf, hello); + } + } + + @Test + public void testSendRecvMsg_NoControl() throws Throwable { + if (!Platform.IS_WINDOWS) { + int[] fds = {0, 0}; + + int ret = posix.socketpair(AddressFamily.AF_UNIX.intValue(), Sock.SOCK_STREAM.intValue(), 0, fds); + + Assert.assertTrue(ret >= 0); + Assert.assertTrue(fds[0] > 0); + Assert.assertTrue(fds[1] > 0); + + MsgHdr outMessage = posix.allocateMsgHdr(); + + String data = "does this work?"; + byte[] dataBytes = data.getBytes(); + + ByteBuffer[] outIov = new ByteBuffer[1]; + outIov[0] = ByteBuffer.allocateDirect(dataBytes.length); + outIov[0].put(dataBytes); + outIov[0].flip(); + + outMessage.setIov(outIov); + + int sendStatus = posix.sendmsg(fds[0], outMessage, 0); + + Assert.assertTrue(sendStatus == dataBytes.length); + + // ---------------- + + MsgHdr inMessage = posix.allocateMsgHdr(); + ByteBuffer[] inIov = new ByteBuffer[1]; + inIov[0] = ByteBuffer.allocateDirect(1024); + inMessage.setIov(inIov); + + int recvStatus = posix.recvmsg(fds[1], inMessage, 0); + + Assert.assertTrue(recvStatus == dataBytes.length); + + for (int i = 0; i < recvStatus; ++i) { + Assert.assertEquals(dataBytes[i], outIov[0].get(i)); + } + } + } + + @Test + public void testSendRecvMsg_WithControl() throws Throwable { + if (!Platform.IS_WINDOWS) { + int[] fds = {0, 0}; + + int ret = posix.socketpair(AddressFamily.AF_UNIX.intValue(), Sock.SOCK_STREAM.intValue(), 0, fds); + + String data = "does this work?"; + byte[] dataBytes = data.getBytes(); + + + Assert.assertTrue(ret >= 0); + Assert.assertTrue(fds[0] > 0); + Assert.assertTrue(fds[1] > 0); + + MsgHdr outMessage = posix.allocateMsgHdr(); + + ByteBuffer[] outIov = new ByteBuffer[1]; + outIov[0] = ByteBuffer.allocateDirect(dataBytes.length); + outIov[0].put(dataBytes); + outIov[0].flip(); + + outMessage.setIov(outIov); + + CmsgHdr outControl = outMessage.allocateControl(4); + outControl.setLevel(SocketLevel.SOL_SOCKET.intValue()); + outControl.setType(0x01); + + ByteBuffer fdBuf = ByteBuffer.allocateDirect(4); + fdBuf.order(ByteOrder.nativeOrder()); + fdBuf.putInt(0, fds[0]); + outControl.setData(fdBuf); + + int sendStatus = posix.sendmsg(fds[0], outMessage, 0); + + Assert.assertTrue(sendStatus == dataBytes.length); + + // ---------------- + + MsgHdr inMessage = posix.allocateMsgHdr(); + ByteBuffer[] inIov = new ByteBuffer[1]; + inIov[0] = ByteBuffer.allocateDirect(1024); + inMessage.setIov(inIov); + + inMessage.allocateControl(4); + int recvStatus = posix.recvmsg(fds[1], inMessage, 0); + + Assert.assertTrue(recvStatus == dataBytes.length); + + ByteBuffer inFdBuf = inMessage.getControls()[0].getData(); + inFdBuf.order(ByteOrder.nativeOrder()); + + int fd = inFdBuf.getInt(); + + Assert.assertTrue(fd != 0); + + for (int i = 0; i < recvStatus; ++i) { + Assert.assertEquals(dataBytes[i], outIov[0].get(i)); + } + + } + } +}
diff --git a/src/test/java/jnr/posix/JavaFileStatTest.java b/src/test/java/jnr/posix/JavaFileStatTest.java new file mode 100644 index 0000000..88ebc05 --- /dev/null +++ b/src/test/java/jnr/posix/JavaFileStatTest.java
@@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +import jnr.posix.JavaFileStat; +import junit.framework.TestCase; + +import jnr.posix.util.Platform; + +/** + * + * @author nicksieger + */ +public class JavaFileStatTest extends TestCase { + public void testSetup() { + JavaFileStat fs = new JavaFileStat(null, null); + if (Platform.IS_WINDOWS) { + fs.setup("c:/"); + } else { + fs.setup("/"); + } + assertFalse(fs.isSymlink()); + } +}
diff --git a/src/test/java/jnr/posix/JavaPOSIXTest.java b/src/test/java/jnr/posix/JavaPOSIXTest.java new file mode 100644 index 0000000..c5b93fd --- /dev/null +++ b/src/test/java/jnr/posix/JavaPOSIXTest.java
@@ -0,0 +1,119 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package jnr.posix; + +import java.io.File; +import java.io.IOException; + +import jnr.constants.platform.Errno; +import jnr.posix.JavaPOSIX; +import jnr.posix.POSIX; +import jnr.posix.Passwd; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author wayne + */ +public class JavaPOSIXTest { + POSIX posix; + public JavaPOSIXTest() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + posix = new JavaPOSIX(new DummyPOSIXHandler()); + } + + @After + public void tearDown() { + posix = null; + } + + // TODO add test methods here. + // The methods must be annotated with annotation @Test. For example: + // + // @Test + // public void hello() {} + @Test public void uid() { + + } + + @Test public void lstatTest() throws IOException { + File file = createTestFile(); + + FileStat stat = posix.lstat(file.getName()); + + assertTrue(stat.isEmpty()); + + stat = posix.allocateStat(); + int ret = posix.lstat(file.getPath(), stat); + + assertTrue(ret >= 0); + assertTrue(stat.isEmpty()); + + file.delete(); + + stat = posix.allocateStat(); + ret = posix.lstat(file.getPath(), stat); + + assertTrue(ret < 0); + } + + @Test public void statMissingFileTest() throws IOException { + FileStat stat = posix.allocateStat(); + + int ret = posix.stat("does not exist", stat); + + assertEquals(-1, ret); + assertEquals(Errno.ENOENT.intValue(), posix.errno()); + } + + @Test + public void chmodTest() throws IOException { + File file = createTestFile(); + + assertEquals("chmod: ", 0, posix.chmod(file.getName(), 0)); + assertEquals("chmod: ", 0, posix.chmod(file.getName(), 0777)); + + file.delete(); + } + + @Test public void getpwuid() { + Passwd pwd = posix.getpwuid(posix.getuid()); + assertNotNull("getpwuid failed", pwd); + + } + @Test public void isNative() { + assertFalse("JavaPOSIX isNative should be false", posix.isNative()); + } + + private File createTestFile() throws IOException { + // create a tmp file + String fName = "test.dat"; + File file = new File(fName); + file.createNewFile(); + + return file; + } + + @Test public void getpid() { + assertEquals(POSIXFactory.getNativePOSIX().getpid(), posix.getpid()); + } +}
diff --git a/src/test/java/jnr/posix/LinuxPOSIXTest.java b/src/test/java/jnr/posix/LinuxPOSIXTest.java new file mode 100644 index 0000000..bdec625 --- /dev/null +++ b/src/test/java/jnr/posix/LinuxPOSIXTest.java
@@ -0,0 +1,199 @@ +package jnr.posix; + +import jnr.constants.platform.AddressFamily; +import jnr.constants.platform.PosixFadvise; +import jnr.constants.platform.OpenFlags; +import jnr.constants.platform.Sock; +import jnr.constants.platform.SocketLevel; +import jnr.constants.platform.SocketOption; +import jnr.ffi.Platform; +import jnr.posix.util.ConditionalTestRule; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.io.File; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RunnableFuture; +import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.Lock; + +import static jnr.posix.LinuxIoPrio.*; + +public class LinuxPOSIXTest { + + @ClassRule + public static RunningOnLinux rule = new RunningOnLinux(); + + private static Linux linuxPOSIX = null; + + @BeforeClass + public static void setUpClass() throws Exception { + POSIX posix = POSIXFactory.getNativePOSIX(); + + if (posix instanceof Linux) { + linuxPOSIX = (Linux) posix; + } + } + + /** + * Tests that IO priority can be set to a thread and that it doesn't change priority set on + * another thread + * @throws InterruptedException + * @throws ExecutionException + */ + @Test + public void ioprioThreadedTest() throws InterruptedException, ExecutionException { + linuxPOSIX.ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4)); + + Future<Integer> threadPriorityFuture = Executors.newFixedThreadPool(1).submit(new Callable<Integer>() { + @Override + public Integer call() throws Exception { + linuxPOSIX.ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 7)); + return linuxPOSIX.ioprio_get(IOPRIO_WHO_PROCESS, 0); + } + }); + + int threadPriority = threadPriorityFuture.get().intValue(); + + Assert.assertEquals(7, IOPRIO_PRIO_DATA(threadPriority)); + Assert.assertEquals(IOPRIO_CLASS_IDLE, IOPRIO_PRIO_CLASS(threadPriority)); + Assert.assertEquals(4, IOPRIO_PRIO_DATA(linuxPOSIX.ioprio_get(IOPRIO_WHO_PROCESS, 0))); + Assert.assertEquals(IOPRIO_CLASS_BE, IOPRIO_PRIO_CLASS(linuxPOSIX.ioprio_get(IOPRIO_WHO_PROCESS, 0))); + } + + @Test + public void testMessageHdrMultipleControl() { + if (jnr.posix.util.Platform.IS_WINDOWS) { + return; + } + + int[] fds = {0, 0}; + + int ret = linuxPOSIX.socketpair(AddressFamily.AF_UNIX.intValue(), + Sock.SOCK_STREAM.intValue(), + 0, + fds); + + + String data = "twoControlMessages"; + byte[] dataBytes = data.getBytes(); + + Assert.assertTrue(ret >= 0); + Assert.assertTrue(fds[0] > 0); + Assert.assertTrue(fds[1] > 0); + + ByteBuffer buf = ByteBuffer.allocate(4); + buf.order(ByteOrder.nativeOrder()); + buf.putInt(1).flip(); + + ret = linuxPOSIX.libc().setsockopt(fds[1], + SocketLevel.SOL_SOCKET.intValue(), + SocketOption.SO_PASSCRED.intValue(), + buf, + buf.remaining()); + + Assert.assertTrue(ret >= 0); + + MsgHdr outMessage = linuxPOSIX.allocateMsgHdr(); + + ByteBuffer[] outIov = new ByteBuffer[1]; + outIov[0] = ByteBuffer.allocateDirect(dataBytes.length); + outIov[0].put(dataBytes); + outIov[0].flip(); + + outMessage.setIov(outIov); + + CmsgHdr[] outControl = outMessage.allocateControls(new int[]{4}); + outControl[0].setLevel(SocketLevel.SOL_SOCKET.intValue()); + outControl[0].setType(0x01); + + ByteBuffer fdBuf = ByteBuffer.allocateDirect(4); + fdBuf.order(ByteOrder.nativeOrder()); + fdBuf.putInt(0, fds[0]); + outControl[0].setData(fdBuf); + + int sendStatus = linuxPOSIX.sendmsg(fds[0], outMessage, 0); + if (sendStatus == -1) { + String sendmsgError = "Error with sendmsg: " + linuxPOSIX.strerror(linuxPOSIX.errno()); + Assert.fail(sendmsgError); + return; + } + + Assert.assertEquals(dataBytes.length, sendStatus); + + // ---------------- + + MsgHdr inMessage = linuxPOSIX.allocateMsgHdr(); + ByteBuffer[] inIov = new ByteBuffer[1]; + inIov[0] = ByteBuffer.allocateDirect(1024); + inMessage.setIov(inIov); + + inMessage.allocateControls(new int[]{4, 12}); + int recvStatus = linuxPOSIX.recvmsg(fds[1], inMessage, 0); + + Assert.assertEquals(dataBytes.length, recvStatus); + + Assert.assertEquals(2, inMessage.getControls().length); + + CmsgHdr[] controls = inMessage.getControls(); + for (int x = 0; x < controls.length; x++) { + validateCmsghdr(controls[x]); + } + } + + private void validateCmsghdr(CmsgHdr control) { + if (control.getLevel() == SocketLevel.SOL_SOCKET.intValue() + && control.getType() == 0x01) { + // Passing a FD + ByteBuffer inFdBuf = control.getData(); + inFdBuf.order(ByteOrder.nativeOrder()); + + int fd = inFdBuf.getInt(); + + Assert.assertTrue(fd != 0); + } else if (control.getLevel() == SocketLevel.SOL_SOCKET.intValue() + && control.getType() == 0x02) { + //Credentials + ByteBuffer data = control.getData(); + data.order(ByteOrder.nativeOrder()); + + int got_pid = data.getInt(); + int got_uid = data.getInt(); + int got_gid = data.getInt(); + + Assert.assertEquals(linuxPOSIX.getpid(), got_pid); + Assert.assertEquals(linuxPOSIX.getuid(), got_uid); + Assert.assertEquals(linuxPOSIX.getgid(), got_gid); + } else { + Assert.fail("Unable to determine cmsghdr type"); + } + } + + @Test + public void testPosixFadvise() throws Throwable { + File file = File.createTempFile("posix_fadvise", null); + int fd = linuxPOSIX.open(file.getAbsolutePath(), OpenFlags.O_RDWR.intValue(), 0444); + + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_SEQUENTIAL)); + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_RANDOM)); + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_NOREUSE)); + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_WILLNEED)); + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_DONTNEED)); + Assert.assertEquals(0, linuxPOSIX.posix_fadvise(fd, 0, 0, PosixFadvise.POSIX_FADV_NORMAL)); // normal last to reset it + + linuxPOSIX.close(fd); + } +} + +class RunningOnLinux extends ConditionalTestRule { + public boolean isSatisfied() { + return jnr.ffi.Platform.getNativePlatform().getOS().equals(Platform.OS.LINUX); + } +}
diff --git a/src/test/java/jnr/posix/NlLanginfoTest.java b/src/test/java/jnr/posix/NlLanginfoTest.java new file mode 100644 index 0000000..2c13742 --- /dev/null +++ b/src/test/java/jnr/posix/NlLanginfoTest.java
@@ -0,0 +1,45 @@ +package jnr.posix; + +import jnr.constants.platform.LangInfo; +import jnr.posix.util.Platform; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import static org.junit.Assert.assertEquals; + +public class NlLanginfoTest { + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void testNlLanginfo() throws Throwable { + if (!Platform.IS_WINDOWS) { + InputStreamReader isr = null; + BufferedReader reader = null; + + try { + isr = new InputStreamReader(Runtime.getRuntime().exec("locale charmap").getInputStream()); + reader = new BufferedReader(isr); + + String localeCharmap = reader.readLine(); + assertEquals(localeCharmap, posix.nl_langinfo(LangInfo.CODESET.intValue())); + } finally { + if (reader != null) { + reader.close(); + } + + if (isr != null) { + isr.close(); + } + } + } + } + +}
diff --git a/src/test/java/jnr/posix/POSIXFactoryTest.java b/src/test/java/jnr/posix/POSIXFactoryTest.java new file mode 100644 index 0000000..c2ea3e7 --- /dev/null +++ b/src/test/java/jnr/posix/POSIXFactoryTest.java
@@ -0,0 +1,20 @@ +package jnr.posix; + +import org.junit.Assert; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class POSIXFactoryTest { + @Test + public void testGetNativePOSIX() throws Throwable { + POSIX posix = POSIXFactory.getNativePOSIX(); + assertTrue(posix.isNative()); + } + + @Test + public void testGetJavaPOSIX() throws Throwable { + POSIX posix = POSIXFactory.getJavaPOSIX(); + assertFalse(posix.isNative()); + } +}
diff --git a/src/test/java/jnr/posix/PasswdTest.java b/src/test/java/jnr/posix/PasswdTest.java new file mode 100644 index 0000000..623a7bf --- /dev/null +++ b/src/test/java/jnr/posix/PasswdTest.java
@@ -0,0 +1,69 @@ + +package jnr.posix; + +import jnr.posix.util.Platform; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + */ +public class PasswdTest { + + public PasswdTest() { + } + private static POSIX posix; + private static Class passwdClass; + @BeforeClass + public static void setUpClass() throws Exception { + if (Platform.IS_MAC) { + passwdClass = MacOSPasswd.class; + } else if (Platform.IS_LINUX) { + passwdClass = LinuxPasswd.class; + } else if (Platform.IS_FREEBSD) { + passwdClass = FreeBSDPasswd.class; + } else if (Platform.IS_OPENBSD) { + passwdClass = OpenBSDPasswd.class; + } else if (Platform.IS_SOLARIS) { + passwdClass = SolarisPasswd.class; + } else if (Platform.IS_WINDOWS) { + // Skipping these tests for windows + } else { + throw new IllegalArgumentException("Platform not supported"); + } + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test public void getpwnam() { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + final String LOGIN = "root"; + Passwd pwd = posix.getpwnam(LOGIN); + assertNotNull(pwd); + assertEquals("Login name not equal", LOGIN, pwd.getLoginName()); + + assertTrue(pwd.getClass().equals(passwdClass)); + } + } + @Test public void nonExistantUserReturnsNull() { + if (jnr.ffi.Platform.getNativePlatform().isUnix()) { + final String LOGIN = "dkjhfjkdsfhjksdhfsdjkhfsdkjhfdskj"; + assertNull("getpwnam for non-existant user should return null", posix.getpwnam(LOGIN)); + } + } +}
diff --git a/src/test/java/jnr/posix/ProcessTest.java b/src/test/java/jnr/posix/ProcessTest.java new file mode 100644 index 0000000..35a588f --- /dev/null +++ b/src/test/java/jnr/posix/ProcessTest.java
@@ -0,0 +1,136 @@ +package jnr.posix; + +import jnr.posix.DefaultNativeRLimit; +import jnr.posix.DummyPOSIXHandler; +import jnr.posix.POSIX; +import jnr.posix.POSIXFactory; +import jnr.posix.RLimit; +import jnr.posix.util.Platform; +import jnr.constants.platform.RLIMIT; +import jnr.constants.platform.Sysconf; +import jnr.ffi.Pointer; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class ProcessTest { + + + private static POSIX posix; + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + @Test + public void times() { + long hz = posix.sysconf(Sysconf._SC_CLK_TCK); + if (Platform.IS_MAC) { + assertEquals("incorrect HZ value", 100L, hz); + } + } + + @Test + public void getcwd() { + String propCwd = System.getProperty("user.dir"); + assertEquals(propCwd, posix.getcwd()); + } + + @Test + public void testGetRLimit() { + if (Platform.IS_LINUX) { + RLimit rlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + + // These tests may fail depending on how the system they're being run on is configured. Since they are + // system-defined limits that may even differ based on UID, it's hard to find something universally true. + // Limiting the number of processes a user can create is believed to be universally enabled since without it + // the system would be susceptible to fork bombs. + assertTrue("Bad soft limit for number of processes", rlim.rlimCur() > 0); + assertTrue("Bad hard limit for number of processes", rlim.rlimMax() > 0); + } + } + + @Test + public void testGetRLimitPreallocatedRlimit() { + if (Platform.IS_LINUX) { + RLimit rlim = new DefaultNativeRLimit(jnr.ffi.Runtime.getSystemRuntime()); + + int result = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue(), rlim); + assertEquals("getrlimit did not return 0", 0, result); + + // These tests may fail depending on how the system they're being run on is configured. Since they are + // system-defined limits that may even differ based on UID, it's hard to find something universally true. + // Limiting the number of processes a user can create is believed to be universally enabled since without it + // the system would be susceptible to fork bombs. + assertTrue("Bad soft limit for number of processes", rlim.rlimCur() > 0); + assertTrue("Bad hard limit for number of processes", rlim.rlimMax() > 0); + } + } + + @Test + public void testGetRLimitPointer() { + if (Platform.IS_LINUX) { + Pointer rlim = jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().allocateDirect(8 * 2); // 2 longs. + + int result = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue(), rlim); + assertEquals("getrlimit did not return 0", 0, result); + + // These tests may fail depending on how the system they're being run on is configured. Since they are + // system-defined limits that may even differ based on UID, it's hard to find something universally true. + // Limiting the number of processes a user can create is believed to be universally enabled since without it + // the system would be susceptible to fork bombs. + assertTrue("Bad soft limit for number of processes", rlim.getLong(0) > 0); + assertTrue("Bad hard limit for number of processes", rlim.getLong(8) > 0); + } + } + + @Test + public void testSetRlimitLinux() { + if (Platform.IS_LINUX) { + RLimit originalRlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + + int result = posix.setrlimit(RLIMIT.RLIMIT_NPROC.intValue(), originalRlim.rlimCur() - 1, originalRlim.rlimMax() - 1); + assertEquals("setrlimit did not return 0", 0, result); + + RLimit rlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + assertEquals("soft limit didn't update", originalRlim.rlimCur() - 1, rlim.rlimCur()); + assertEquals("hard limit didn't update", originalRlim.rlimMax() - 1, rlim.rlimMax()); + } + } + + @Test + public void testSetRlimitPreallocatedLinux() { + if (Platform.IS_LINUX) { + RLimit originalRlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + + RLimit updatedRlim = new DefaultNativeRLimit(jnr.ffi.Runtime.getSystemRuntime()); + updatedRlim.init(originalRlim.rlimCur() - 1, originalRlim.rlimMax() - 1); + + int result = posix.setrlimit(RLIMIT.RLIMIT_NPROC.intValue(), updatedRlim); + assertEquals("setrlimit did not return 0", 0, result); + + RLimit rlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + assertEquals("soft limit didn't update", originalRlim.rlimCur() - 1, rlim.rlimCur()); + assertEquals("hard limit didn't update", originalRlim.rlimMax() - 1, rlim.rlimMax()); + } + } + + @Test + public void testSetRlimitPointerLinux() { + if (Platform.IS_LINUX) { + RLimit originalRlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + + Pointer updatedRlim = jnr.ffi.Runtime.getSystemRuntime().getMemoryManager().allocateDirect(8 * 2); // 2 longs. + updatedRlim.putLong(0, originalRlim.rlimCur() - 1); + updatedRlim.putLong(8, originalRlim.rlimMax() - 1); + + int result = posix.setrlimit(RLIMIT.RLIMIT_NPROC.intValue(), updatedRlim); + assertEquals("setrlimit did not return 0", 0, result); + + RLimit rlim = posix.getrlimit(RLIMIT.RLIMIT_NPROC.intValue()); + assertEquals("soft limit didn't update", originalRlim.rlimCur() - 1, rlim.rlimCur()); + assertEquals("hard limit didn't update", originalRlim.rlimMax() - 1, rlim.rlimMax()); + } + } +}
diff --git a/src/test/java/jnr/posix/SignalTest.java b/src/test/java/jnr/posix/SignalTest.java new file mode 100644 index 0000000..01a8573 --- /dev/null +++ b/src/test/java/jnr/posix/SignalTest.java
@@ -0,0 +1,70 @@ +package jnr.posix; + +import jnr.constants.platform.Signal; +import jnr.posix.util.Platform; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class SignalTest { + private static POSIX posix; + private static POSIX javaPosix; + + @BeforeClass + public static void setupClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + javaPosix = new JavaPOSIX(new DummyPOSIXHandler()); + } + + private static void waitUntilTrue(AtomicBoolean var, long maxWait) { + long start = System.currentTimeMillis(); + while (!var.get() && (System.currentTimeMillis() - start) < maxWait) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + break; + } + } + } + + @Test + public void testBasicSignal() { + if (!Platform.IS_WINDOWS) { + Signal s = Signal.SIGHUP; + final AtomicBoolean fired = new AtomicBoolean(false); + posix.signal(s, new SignalHandler() { + public void handle(int signal) { + fired.set(true); + } + }); + + posix.kill(posix.getpid(), s.intValue()); + waitUntilTrue(fired, 200); + Assert.assertTrue(fired.get()); + } + } + + @Test + public void testJavaSignal() { + if (!Platform.IS_WINDOWS) { + Signal s = Signal.SIGHUP; + final AtomicBoolean fired = new AtomicBoolean(false); + SignalHandler previousHandler = javaPosix.signal(s, new SignalHandler() { + public void handle(int signal) { + fired.set(true); + } + }); + + Assert.assertNotNull(previousHandler); + + // have to use native here; no abstraction for kill in pure Java + // TODO: sun.misc.Signal.raise can be used to kill current pid + posix.kill(posix.getpid(), s.intValue()); + + waitUntilTrue(fired, 200); + Assert.assertTrue(fired.get()); + } + } +}
diff --git a/src/test/java/jnr/posix/SpawnTest.java b/src/test/java/jnr/posix/SpawnTest.java new file mode 100644 index 0000000..b98a098 --- /dev/null +++ b/src/test/java/jnr/posix/SpawnTest.java
@@ -0,0 +1,200 @@ +package jnr.posix; + +import jnr.constants.platform.windows.OpenFlags; +import jnr.ffi.Library; +import jnr.ffi.Platform; +import jnr.ffi.annotations.Out; +import org.junit.*; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.Assert.*; +import static jnr.posix.SpawnFileAction.*; + +public class SpawnTest { + private static POSIX posix; + private static LibC libc; + private static final List<String> emptyEnv = Arrays.asList(new String[0]); + private static final List<SpawnFileAction> emptyActions = Arrays.asList(new SpawnFileAction[0]); + + public static interface LibC { + int pipe(@Out int[] fds); + } + + @BeforeClass + public static void setUpClass() throws Exception { + if (Platform.getNativePlatform().isUnix()) { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + libc = Library.loadLibrary(LibC.class, jnr.ffi.Platform.getNativePlatform().getStandardCLibraryName()); + } + } + + @Test public void validPid() { + if (Platform.getNativePlatform().isUnix()) { + long pid = -1; + try { + pid = posix.posix_spawnp("true", emptyActions, Arrays.asList("true"), emptyEnv); + assertTrue(pid != -1); + } finally { + if (pid != -1) posix.libc().waitpid((int) pid, null, 0); + } + } + } + + private static void closePipe(int[] fds) { + posix.libc().close(fds[0]); + posix.libc().close(fds[1]); + } + + private static void killChild(long pid) { + if (pid > 0) { + posix.libc().kill((int) pid, 9); posix.libc().waitpid((int) pid, null, 0); + } + } + + @Test public void outputPipe() { + if (Platform.getNativePlatform().isUnix()) { + int[] outputPipe = { -1, -1 }; + long pid = -1; + try { + assertFalse(libc.pipe(outputPipe) < 0); + assertNotSame(-1, outputPipe[0]); + assertNotSame(-1, outputPipe[1]); + + List<SpawnFileAction> actions = Arrays.asList(dup(outputPipe[1], 1)); + pid = posix.posix_spawnp("echo", actions, Arrays.asList("echo", "bar"), emptyEnv); + assertTrue(pid != -1); + + // close the write side of the output pipe, so read() will return immediately once the process has exited + posix.libc().close(outputPipe[1]); + + ByteBuffer output = ByteBuffer.allocate(100); + long nbytes = posix.libc().read(outputPipe[0], output, output.remaining()); + assertEquals(4L, nbytes); + output.position((int) nbytes).flip(); + byte[] bytes = new byte[output.remaining()]; + output.get(bytes); + assertEquals("bar", new String(bytes).trim()); + } finally { + closePipe(outputPipe); + killChild(pid); + } + } + } + + @Test public void inputPipe() { + if (Platform.getNativePlatform().isUnix()) { + int[] outputPipe = { -1, -1 }; + int[] inputPipe = { -1, -1 }; + long pid = -1; + try { + assertFalse(libc.pipe(outputPipe) < 0); + assertFalse(libc.pipe(inputPipe) < 0); + assertNotSame(-1, outputPipe[0]); + assertNotSame(-1, outputPipe[1]); + assertNotSame(-1, inputPipe[0]); + assertNotSame(-1, inputPipe[1]); + + List<SpawnFileAction> actions = Arrays.asList(dup(inputPipe[0], 0), dup(outputPipe[1], 1)); + pid = posix.posix_spawnp("cat", actions, Arrays.asList("cat", "-"), emptyEnv); + assertTrue(pid != -1); + posix.libc().close(inputPipe[0]); + assertEquals(3, posix.libc().write(inputPipe[1], ByteBuffer.wrap("foo".getBytes(Charset.forName("US-ASCII"))), 3)); + posix.libc().close(inputPipe[1]); // send EOF to process + + // close the write side of the output pipe, so read() will return immediately once the process has exited + posix.libc().close(outputPipe[1]); + + ByteBuffer output = ByteBuffer.allocate(100); + long nbytes = posix.libc().read(outputPipe[0], output, output.remaining()); + assertEquals(3L, nbytes); + output.position((int) nbytes).flip(); + byte[] bytes = new byte[output.remaining()]; + output.get(bytes); + assertEquals("foo", new String(bytes).trim()); + } finally { + closePipe(outputPipe); + closePipe(inputPipe); + killChild(pid); + } + } + } + + @Test public void inputFile() throws IOException { + if (Platform.getNativePlatform().isUnix()) { + File inputFile = File.createTempFile("foo", null); + FileOutputStream inputStream = new FileOutputStream(inputFile); + inputStream.write("foo".getBytes("US-ASCII")); + inputStream.close(); + int[] outputPipe = { -1, -1 }; + long pid = -1; + try { + assertFalse(libc.pipe(outputPipe) < 0); + assertNotSame(-1, outputPipe[0]); + assertNotSame(-1, outputPipe[1]); + + List<SpawnFileAction> actions = Arrays.asList(open(inputFile.getAbsolutePath(), 0, OpenFlags.O_RDONLY.intValue(), 0444), + dup(outputPipe[1], 1), close(outputPipe[0])); + pid = posix.posix_spawnp("cat", actions, Arrays.asList("cat", "-"), emptyEnv); + assertTrue(pid != -1); + + // close the write side of the output pipe, so read() will return immediately once the process has exited + posix.libc().close(outputPipe[1]); + + ByteBuffer output = ByteBuffer.allocate(100); + long nbytes = posix.libc().read(outputPipe[0], output, output.remaining()); + assertEquals(3L, nbytes); + output.position((int) nbytes).flip(); + byte[] bytes = new byte[output.remaining()]; + output.get(bytes); + assertEquals("foo", new String(bytes).trim()); + } finally { + closePipe(outputPipe); + killChild(pid); + } + } + } + + @Test public void closeInput() throws IOException { + if (Platform.getNativePlatform().isUnix()) { + int[] outputPipe = { -1, -1 }; + int[] inputPipe = { -1, -1 }; + long pid = -1; + try { + assertFalse(libc.pipe(outputPipe) < 0); + assertFalse(libc.pipe(inputPipe) < 0); + assertNotSame(-1, outputPipe[0]); + assertNotSame(-1, outputPipe[1]); + assertNotSame(-1, inputPipe[0]); + assertNotSame(-1, inputPipe[1]); + + List<SpawnFileAction> actions = Arrays.asList(dup(outputPipe[1], 1), + open("/dev/null", 2, OpenFlags.O_WRONLY.intValue(), 0444), + close(inputPipe[0]), close(inputPipe[1])); + pid = posix.posix_spawnp("cat", actions, Arrays.asList("cat", "/dev/fd/" + inputPipe[0]), emptyEnv); + assertTrue(pid != -1); + assertEquals(3, posix.libc().write(inputPipe[1], ByteBuffer.wrap("foo".getBytes(Charset.forName("US-ASCII"))), 3)); + posix.libc().close(inputPipe[1]); // send EOF to process + + // close the write side of the output pipe, so read() will return immediately once the process has exited + posix.libc().close(outputPipe[1]); + + // Output from the process on stdout should be empty + ByteBuffer output = ByteBuffer.allocate(100); + long nbytes = posix.libc().read(outputPipe[0], output, output.remaining()); + assertEquals(0L, nbytes); + } finally { + closePipe(inputPipe); + closePipe(outputPipe); + killChild(pid); + } + } + } +}
diff --git a/src/test/java/jnr/posix/util/ConditionalTestRule.java b/src/test/java/jnr/posix/util/ConditionalTestRule.java new file mode 100644 index 0000000..aa44a3f --- /dev/null +++ b/src/test/java/jnr/posix/util/ConditionalTestRule.java
@@ -0,0 +1,23 @@ +package jnr.posix.util; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +public abstract class ConditionalTestRule implements TestRule { + public Statement apply(Statement base, Description description) { + return statement(base); + } + + private Statement statement(final Statement base) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + if (isSatisfied()) { + base.evaluate(); + } + } + }; + } + public abstract boolean isSatisfied(); +}
diff --git a/src/test/java/jnr/posix/util/DefaultPOSIXHandlerTest.java b/src/test/java/jnr/posix/util/DefaultPOSIXHandlerTest.java new file mode 100644 index 0000000..f4ff76e --- /dev/null +++ b/src/test/java/jnr/posix/util/DefaultPOSIXHandlerTest.java
@@ -0,0 +1,25 @@ +package jnr.posix.util; + +import jnr.posix.POSIX; +import jnr.posix.POSIXFactory; +import org.junit.Test; + +import java.lang.management.ManagementFactory; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class DefaultPOSIXHandlerTest +{ + @Test + public void testGetPid() throws Exception + { + int pid_from_jmx = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]); + + POSIX posix = POSIXFactory.getPOSIX(new DefaultPOSIXHandler(), true); + int pid = posix.getpid(); + assertThat(pid, equalTo(pid_from_jmx)); + } +}
diff --git a/src/test/java/jnr/posix/util/PlatformTest.java b/src/test/java/jnr/posix/util/PlatformTest.java new file mode 100644 index 0000000..7ae91ef --- /dev/null +++ b/src/test/java/jnr/posix/util/PlatformTest.java
@@ -0,0 +1,59 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ +package jnr.posix.util; + +import jnr.posix.util.Platform; +import junit.framework.TestCase; + +/* + * Admittedly, there is a lot of cyclomatic complexity and system-dependent + * testing going on here. At least it's in one place. + */ + +public class PlatformTest extends TestCase { + + public void testBitLengths() { + assertTrue("Not 32 or 64-bit platform?", Platform.IS_32_BIT ^ Platform.IS_64_BIT); + } + + public void testEnvCommand() { + String command =Platform.envCommand(); + if (Platform.IS_WINDOWS_9X) { + assertEquals("Fails on Windows 95/98", "command.com /c set", command); + } + if (Platform.IS_WINDOWS & !Platform.IS_WINDOWS_9X) { + assertEquals("Fails on Windows other than 95/98", "cmd.exe /c set", command); + } + if (!Platform.IS_WINDOWS) { + assertEquals("Fails on Non-Windows platform", "env", command); + } + } +}
diff --git a/src/test/java/jnr/posix/windows/WindowsFileTest.java b/src/test/java/jnr/posix/windows/WindowsFileTest.java new file mode 100644 index 0000000..1f540ef --- /dev/null +++ b/src/test/java/jnr/posix/windows/WindowsFileTest.java
@@ -0,0 +1,317 @@ +package jnr.posix.windows; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.text.NumberFormat; +import jnr.posix.DummyPOSIXHandler; +import jnr.posix.FileStat; +import jnr.posix.POSIX; +import jnr.posix.POSIXFactory; +import jnr.posix.WindowsPOSIX; +import org.junit.BeforeClass; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +public class WindowsFileTest { + private static POSIX posix; + + @BeforeClass + public static void setUpClass() throws Exception { + posix = POSIXFactory.getPOSIX(new DummyPOSIXHandler(), true); + } + + private class Pair { + public File base; + public File leaf; + public Pair(File base, File leaf) { + this.base = base; + this.leaf = leaf; + } + + public void cleanup() { + cleanup(base); + } + + public void cleanup(File node) { + if (node.isDirectory()) { + File[] files = node.listFiles(); + if (files != null) { + for(File file: files) { + cleanup(file); + } + } + } + node.delete(); + } + } + // FIXME: This is a broken method since it does not delete any of the generated dirs. + private static final String DIR_NAME = "0123456789"; + private Pair makeLongPath() throws IOException { + File tmp = Files.createTempDirectory("temp" + Long.toHexString(System.nanoTime())).toFile(); + + StringBuilder buf = new StringBuilder(DIR_NAME); + for (int i = 0; i < 30; i++) { + buf.append(DIR_NAME).append('/'); + } + File tmp2 = new File(tmp, buf.toString()); + tmp2.mkdirs(); + + return new Pair(tmp, tmp2); + } + + @Test + public void testLowercaseDriveLetter() throws Throwable { + // FIXME: Not all systems have a C drive but nearly all do + FileStat st = posix.stat("c:/"); + assertTrue(st.dev() == 2); + assertTrue(st.rdev() == 2); + } + + @Test + public void testFakeUIDGUID() throws Throwable { + File f = File.createTempFile("stat", null); + + try { + FileStat st = posix.stat(f.getAbsolutePath()); + assertTrue(st.uid() == 0); + assertTrue(st.gid() == 0); + } finally { + f.delete(); + } + } + + @Test + public void testExecutableSuffixesAreExecutable() throws Throwable { + File f = File.createTempFile("stat", ".exe"); + + try { + FileStat st = posix.stat(f.getAbsolutePath()); + assertEquals("100755", Integer.toOctalString(st.mode())); + assertTrue(st.isExecutable()); + } finally { + f.delete(); + } + + f = File.createTempFile("STAT", ".EXE"); + + try { + FileStat st = posix.stat(f.getAbsolutePath()); + assertEquals("100755", Integer.toOctalString(st.mode())); + assertTrue(st.isExecutable()); + } finally { + f.delete(); + } + + } + + @Test + public void testBlocksAndBlockSizeReturn() throws Throwable { + File f = File.createTempFile("stat", null); + + try { + FileStat st = posix.stat(f.getAbsolutePath()); + assertTrue(st.blocks() == -1); + assertTrue(st.blockSize() == -1); + } finally { + f.delete(); + } + } + + @Test + public void testLongFileRegular() throws Throwable { + Pair pair = makeLongPath(); + String path = pair.leaf.getAbsolutePath(); + try { + FileStat st = posix.stat(path); + assertNotNull("posix.stat failed", st); + + FileStat stat = posix.allocateStat(); + int result = posix.stat(path, stat); + assertNotNull("posix.stat failed", stat); + assertEquals(0, result); + } finally { + pair.cleanup(); + } + } + + @Test + public void testLongFileUNC() throws Throwable { + Pair pair = makeLongPath(); + String absolutePath = pair.leaf.getAbsolutePath(); + char letter = absolutePath.charAt(0); + String path = absolutePath.replace(absolutePath.substring(0,2), "\\\\localhost\\" + letter + "$"); + try { + FileStat st = posix.stat(path); + assertNotNull("posix.stat failed", st); + + FileStat stat = posix.allocateStat(); + int result = posix.stat(path, stat); + assertNotNull("posix.stat failed", stat); + assertEquals(0, result); + } finally { + pair.cleanup(); + } + } + + @Test + public void statUNCFile() throws Throwable { + File f = File.createTempFile("stat", null); + String absolutePath = f.getAbsolutePath(); + char letter = absolutePath.charAt(0); + String path = absolutePath.replace(absolutePath.substring(0,2), "\\\\localhost\\" + letter + "$"); + try { + FileStat st = posix.stat(path); + assertNotNull("posix.stat failed", st); + + FileStat stat = posix.allocateStat(); + int result = posix.stat(path, stat); + assertNotNull("posix.stat failed", stat); + assertEquals(0, result); + } finally { + f.delete(); + } + } + + @Test + public void unlinkTestWindows() throws Throwable { + File tmp = File.createTempFile("unlinkTest", "tmp"); + RandomAccessFile raf = new RandomAccessFile(tmp, "rw"); + + raf.write("hello".getBytes()); + + // Windows won't allow you to delete open files, so we must + // close the handle before trying to delete it. Unfortunately, + // this also means we're unable to write to the handle afterwards + // as we do with the non-Windows test. + raf.close(); + + int res = posix.unlink(tmp.getCanonicalPath()); + + assertEquals(0, res); + assertFalse(tmp.exists()); + } + + @Test + public void testFindFirstFile() throws Throwable { + File f = File.createTempFile("stat", null); + try { + + POSIX posix = POSIXFactory.getNativePOSIX(); + FileStat stat = posix.allocateStat(); + int result = ((WindowsPOSIX) posix).findFirstFile(f.getAbsolutePath(), stat); + + assertEquals(0, result); + assertTrue(stat.isFile()); + } finally { + f.delete(); + } + } + + @Test + public void testFindFirstFileBogusFile() throws Throwable { + POSIX posix = POSIXFactory.getNativePOSIX(); + FileStat stat = posix.allocateStat(); + int result = ((WindowsPOSIX) posix).findFirstFile("sdjfhjfsdfhdsdfhsdj", stat); + assertTrue(result < 0); + } + + @Test + public void utimensatWindows() throws Throwable { + File file = File.createTempFile("utimensat", null); + try { + FileStat fileStat = posix.stat(file.getPath()); + + long atimeSeconds = fileStat.atime() + 1; + long mtimeSeconds = fileStat.mtime() - 1; + + // Windows precision is 100 ns + long atimeNanoSeconds = 123456700; + long mtimeNanoSeconds = 987654300; + + // dirfd is ignored when passing an absolute path + // flag can be used to update symlinks + posix.utimensat(0, + file.getAbsolutePath(), + new long[]{atimeSeconds, atimeNanoSeconds}, + new long[]{mtimeSeconds, mtimeNanoSeconds}, + 0); + + fileStat = posix.stat(file.getPath()); + assertEquals("access time should be updated", atimeSeconds, fileStat.atime()); + assertEquals("modification time should be updated", mtimeSeconds, fileStat.mtime()); + } finally { + file.delete(); + } + } + + @Test + public void utimensatWindowsCurrentTime() throws Throwable { + File file = File.createTempFile("file", null); + try { + FileStat fileStat = posix.stat(file.getPath()); + long atimeSeconds = fileStat.atime(); + long mtimeSeconds = fileStat.mtime(); + long atimeSecondsInPast = atimeSeconds - 1000; + long mtimeSecondsInPast = mtimeSeconds - 1000; + + posix.utimensat(0, + file.getAbsolutePath(), + new long[]{atimeSecondsInPast, 0}, + new long[]{mtimeSecondsInPast, 0}, 0); + fileStat = posix.stat(file.getPath()); + assertEquals("access time should be updated", fileStat.atime(), atimeSecondsInPast); + assertEquals("modification time should be updated", fileStat.mtime(), mtimeSecondsInPast); + + posix.utimensat(0, file.getAbsolutePath(), null, null, 0); + + fileStat = posix.stat(file.getPath()); + assertTrue("access time should be updated to current time", + timeWithinRange(fileStat.atime(), atimeSeconds, 10)); + assertTrue("modification time should be updated to current time", + timeWithinRange(fileStat.mtime(), mtimeSeconds, 10)); + } finally { + file.delete(); + } + } + + @Test + public void utimenWindowsCurrentTime() throws Throwable { + File file = File.createTempFile("file", null); + try { + FileStat fileStat = posix.stat(file.getPath()); + long atimeSeconds = fileStat.atime(); + long mtimeSeconds = fileStat.mtime(); + long atimeSecondsInPast = atimeSeconds - 1000; + long mtimeSecondsInPast = mtimeSeconds - 1000; + + posix.utimes(file.getAbsolutePath(), + new long[]{atimeSecondsInPast, 0}, + new long[]{mtimeSecondsInPast, 0}); + fileStat = posix.stat(file.getPath()); + assertEquals("access time should be updated", + fileStat.atime(), atimeSecondsInPast); + assertEquals("modification time should be updated", + fileStat.mtime(), mtimeSecondsInPast); + + posix.utimes(file.getAbsolutePath(), null, null); + + fileStat = posix.stat(file.getPath()); + assertTrue("access time should be updated to current time", + timeWithinRange(fileStat.atime(), atimeSeconds, 10)); + assertTrue("modification time should be updated to current time", + timeWithinRange(fileStat.mtime(), mtimeSeconds, 10)); + } finally { + file.delete(); + } + } + + private boolean timeWithinRange(long actual, long expected, long precision) { + return actual > (expected - precision) && actual < (expected + precision); + } +}
diff --git a/src/test/java/jnr/posix/windows/WindowsHelpersTest.java b/src/test/java/jnr/posix/windows/WindowsHelpersTest.java new file mode 100644 index 0000000..09e6d69 --- /dev/null +++ b/src/test/java/jnr/posix/windows/WindowsHelpersTest.java
@@ -0,0 +1,52 @@ +/***** BEGIN LICENSE BLOCK ***** + * Version: EPL 2.0/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Eclipse Public + * License Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.eclipse.org/legal/cpl-v10.html + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the CPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the CPL, the GPL or the LGPL. + ***** END LICENSE BLOCK *****/ +/** + * $Id: $ + */ +package jnr.posix.windows; + +import jnr.posix.util.WindowsHelpers; +import junit.framework.TestCase; + +public class WindowsHelpersTest extends TestCase { + + public void testIsBatch() { + assertTrue(WindowsHelpers.isBatch("file.bat")); + assertTrue(WindowsHelpers.isBatch("FILE.BAT")); + assertTrue(WindowsHelpers.isBatch("file.cmd")); + assertTrue(WindowsHelpers.isBatch("FILE.CMD")); + + assertFalse(WindowsHelpers.isBatch("file.exe")); + assertFalse(WindowsHelpers.isBatch("file.txt")); + assertFalse(WindowsHelpers.isBatch("file")); + assertFalse(WindowsHelpers.isBatch("filebat")); + assertFalse(WindowsHelpers.isBatch("filecmd")); + assertFalse(WindowsHelpers.isBatch("")); + assertFalse(WindowsHelpers.isBatch(null)); + } +}