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));
+ }
+}