From e1d5b394e2c7f170b188f8a895842bc3d2b1698a Mon Sep 17 00:00:00 2001 From: Iustin Pop Date: Sat, 28 Jun 2008 23:01:40 +0200 Subject: [PATCH] Imported Upstream version 0.4.0 --- COPYING | 504 +++++++++++++++++++++++++ IMPLEMENTATION | 67 ++-- MANIFEST | 11 - MANIFEST.in | 9 + Makefile | 18 + NEWS | 76 +++- PKG-INFO | 4 +- PLATFORMS | 31 +- README | 21 +- acl.c | 213 ++++++++--- os_linux.c | 6 - posix1e.html | 412 -------------------- posix1e.txt | 416 -------------------- pylibacl.egg-info/PKG-INFO | 12 + pylibacl.egg-info/SOURCES.txt | 15 + pylibacl.egg-info/dependency_links.txt | 1 + pylibacl.egg-info/top_level.txt | 1 + setup.cfg | 7 +- setup.py | 12 +- test/test_acls.py | 289 ++++++++++++++ 20 files changed, 1178 insertions(+), 947 deletions(-) create mode 100644 COPYING delete mode 100644 MANIFEST create mode 100644 MANIFEST.in create mode 100644 Makefile delete mode 100644 os_linux.c delete mode 100644 posix1e.html delete mode 100644 posix1e.txt create mode 100644 pylibacl.egg-info/PKG-INFO create mode 100644 pylibacl.egg-info/SOURCES.txt create mode 100644 pylibacl.egg-info/dependency_links.txt create mode 100644 pylibacl.egg-info/top_level.txt create mode 100644 test/test_acls.py diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..5ab7695 --- /dev/null +++ b/COPYING @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/IMPLEMENTATION b/IMPLEMENTATION index 64ad4a5..e065241 100644 --- a/IMPLEMENTATION +++ b/IMPLEMENTATION @@ -1,36 +1,49 @@ -The IEEE 1003.1e draft 17 ("POSIX.1e") describes a set of 28 -functions. These are grouped into three groups, based on their -portability: - - first group, the most portable one. All systems which claim to - support POSIX.1e should implement these: +Functionality level +------------------- + +The IEEE 1003.1e draft 17 ("POSIX.1e") describes a set of 28 functions. +These are grouped into three groups, based on their portability: + +- first group, the most portable one. All systems which claim to support + POSIX.1e should implement these: + acl_delete_def_file(3), acl_dup(3), acl_free(3), acl_from_text(3), acl_get_fd(3), acl_get_file(3), acl_init(3), acl_set_fd(3), acl_set_file(3), acl_to_text(3), acl_valid(3) - - second group, containing the rest of the POSIX ACL functions. Systems - which claim to fully implement POSIX.1e should implement these: - acl_add_perm(3), acl_calc_mask(3), acl_clear_perms(3), acl_copy_entry(3), - acl_copy_ext(3), acl_copy_int(3), acl_create_entry(3), - acl_delete_entry(3), acl_delete_perm(3), acl_get_entry(3), - acl_get_permset(3), acl_get_qualifier(3), acl_get_tag_type(3), - acl_set_permset(3), acl_set_qualifier(3), acl_set_tag_type(3), - acl_size(3) +- second group, containing the rest of the POSIX ACL functions. Systems + which claim to fully implement POSIX.1e should implement these: + + acl_add_perm(3), acl_calc_mask(3), acl_clear_perms(3), + acl_copy_entry(3), acl_copy_ext(3), acl_copy_int(3), + acl_create_entry(3), acl_delete_entry(3), acl_delete_perm(3), + acl_get_entry(3), acl_get_permset(3), acl_get_qualifier(3), + acl_get_tag_type(3), acl_set_permset(3), acl_set_qualifier(3), + acl_set_tag_type(3), acl_size(3) - - third group, containing extra functions implemented by each OS. These - are non-portable version. Both Linux and FreeBSD implement some extra - function. +- third group, containing extra functions implemented by each OS. These + are non-portable version. Both Linux and FreeBSD implement some extra + functions. Thus we have the level of compliance. Depending on whether the system -library support the second group, you get some extra methods for the -ACL object. +library support the second group, you get some extra methods for the ACL +object. + +The implementation of the second group of function can be tested by +checking the module-level constant HAS_ACL_ENTRY. The extra +functionality available on Linux can be tested by additional HAS_* +constants. Internal structure - The POSIX draft has the following stuff (correct me if I'm wrong): - - an ACL is denoted by acl_t - - an ACL contains many acl_entry_t, these are the individual entries - in the list; they always! belong to an acl_t - - each entry_t has a qualifier (think uid_t or gid_t), whose type is - denoted by the acl_tag_t type, and an acl_permset_t - - the acl_permset_t can contain acl_perm_t value (ACL_READ, ACL_WRITE, - ACL_EXECUTE, ACL_ADD, ACL_DELETE, ...) - - function to manipulate all these, and functions to manipulate files +------------------ + +The POSIX draft has the following stuff (correct me if I'm wrong): + +- an ACL is denoted by acl_t +- an ACL contains many acl_entry_t, these are the individual entries in + the list; they always(!) belong to an acl_t +- each entry_t has a qualifier (think uid_t or gid_t), whose type is + denoted by the acl_tag_t type, and an acl_permset_t +- the acl_permset_t can contain acl_perm_t value (ACL_READ, ACL_WRITE, + ACL_EXECUTE, ACL_ADD, ACL_DELETE, ...) +- functions to manipulate all these, and functions to manipulate files diff --git a/MANIFEST b/MANIFEST deleted file mode 100644 index 57f40a1..0000000 --- a/MANIFEST +++ /dev/null @@ -1,11 +0,0 @@ -IMPLEMENTATION -MANIFEST -NEWS -PLATFORMS -README -acl.c -os_linux.c -posix1e.html -posix1e.txt -setup.cfg -setup.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..04fba87 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,9 @@ +include COPYING +include IMPLEMENTATION +include MANIFEST +include Makefile +include NEWS +include PLATFORMS +include README +include acl.c +include setup.cfg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..354046f --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +.PHONY: doc test + +all: doc test + +posix1e.so: acl.c + ./setup.py build_ext --inplace + +doc: posix1e.so + epydoc -q -o html --name pylibacl \ + --url http://pylibacl.sourceforge.net/ \ + --show-frames \ + --docformat epytext \ + --no-sourcecode \ + posix1e + +test: + python2.4 ./setup.py test + python2.5 ./setup.py test diff --git a/NEWS b/NEWS index 41c538c..e018bbd 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,68 @@ -version 0.3 ------------ - - Under Linux, implement more functions from libacl: - - add ACL(mode=...), implementing acl_from_mode - - add ACL().to_any_text, implementing acl_to_any_text - - add ACL comparison, using acl_cmp - - add ACL().check, which is a more descriptive function than validate +Version 0.4 +=========== + +License +------- + +Starting with this version, pylibacl is licensed under LGPL 2.1, +Febryary 1999 or any later versions (see README and COPYING). + +Linux support +------------- + +A few more Linux-specific functions: + +- add the ACL.equiv_mode() method, which will return the equivalent + octal mode if this is a basic ACL and raise an IOError exception + otherwise + +- add the acl_extended(...) function, which will check if an fd or path + has an extended ACL + +FreeBSD support +--------------- + +FreeBSD 7.x will have almost all the acl manipulation functions that +Linux has, with the exception of __getstate__/__setstate__. As a +workaround, use the str() and ACL(text=...) methods to pass around +textual representations. + +Interface +--------- + +At module level there are now a few constants exported for easy-checking +at runtime what features have been compiled in: + +- HAS_ACL_FROM_MODE, denoting whether the ACL constructor supports the + mode=0xxx parameter + +- HAS_ACL_CHECK, denoting whether ACL instances support the check() + method + +- HAS_ACL_ENTRY, denoting whether ACL manipulation is possible and the + Entry and Permset classes are available + +- HAS_EXTENEDED_CHECK, denoting whether the acl_extended function is + supported + +- HAS_EQUIV_MODE, denoting whether ACL instances support the + equiv_mode() method + +Internals +--------- + +Many functions have now unittests, which is a good thing. + + +Version 0.3 +=========== + +Linux support +------------- + +Under Linux, implement more functions from libacl: + +- add ACL(mode=...), implementing acl_from_mode +- add ACL().to_any_text, implementing acl_to_any_text +- add ACL comparison, using acl_cmp +- add ACL().check, which is a more descriptive function than validate diff --git a/PKG-INFO b/PKG-INFO index 96bd276..0bf4e63 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,11 +1,11 @@ Metadata-Version: 1.0 Name: pylibacl -Version: 0.3.0 +Version: 0.4.0 Summary: POSIX.1e ACLs for python Home-page: http://pylibacl.sourceforge.net Author: Iustin Pop Author-email: iusty@k1024.org -License: GPL +License: LGPL Description: This is a C extension module for Python which implements POSIX ACLs manipulation. It is a wrapper on top of the systems's acl C library - see acl(5). diff --git a/PLATFORMS b/PLATFORMS index ab2d28b..6c05d1d 100644 --- a/PLATFORMS +++ b/PLATFORMS @@ -1,23 +1,30 @@ -The current supported platforms: +Current supported platforms +=========================== Linux +----- - It needs kernel 2.4 or higher and the libacl library installed (with - development headers, if installing from rpm). The url is - http://acl.bestbits.at if using for ext2/ext3 and JFS, and - http://oss.sgi.com/projects/xfs/ if using for XFS. +It needs kernel 2.4 or higher and the libacl library installed (with +development headers, if installing from rpm). This library is available +on all modern distributions. - The level of compliance is level 2 (see IMPLEMENTATION). +The level of compliance is level 2 (see IMPLEMENTATION), plus some extra +functions; and as my development is done on Linux, I try to implement +these extensions when it makes sense. FreeBSD +------- - The current tested version is 4.6. I hope to be able to test 5.0 after - it's released. +The current tested version is 7.0. FreeBSD supports all the standards +functions, but 7.0-RELEASE seems to have some issues regarding the +acl_valid() function when the qualifier of an ACL_USER or ACL_GROUP +entry is the same as the current uid. By my interpretation, this should +be a valid ACL, but FreeBSD declares the ACL invalid. As such, some +unittests fail on FreeBSD. - The level of compliance is level 1. I hope that in FreeBSD 5 they will - improve. +Other platforms +--------------- -For any other platform, volunteers are welcome. To add support, look -into setup.py at first and then into acl.c +For any other platforms, volunteers are welcome - read the PORTING file. diff --git a/README b/README index e17837d..992ad2b 100644 --- a/README +++ b/README @@ -1,6 +1,23 @@ +pylibacl +======== + +About +----- + This is an extension for Python which implements POSIX ACLs (POSIX.1e). -To see the supported platforms, look at PLATFORMS. -To see internal details, look at IMPLEMENTATION. +The supported platforms are detailed in the file PLATFORMS. + +A few internal details are in the file IMPLEMENTATION. + +License +------- + +pylibacl 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. + +See the COPYING file for the full license terms. Iustin Pop, diff --git a/acl.c b/acl.c index a477b73..d22af08 100644 --- a/acl.c +++ b/acl.c @@ -1,20 +1,47 @@ +/* + posix1e - a python module exposing the posix acl functions + + Copyright (C) 2002-2008 Iustin Pop + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA + +*/ + #include #include #include #ifdef HAVE_LINUX -#include "os_linux.c" +#include +#define get_perm acl_get_perm +#elif HAVE_FREEBSD +#define get_perm acl_get_perm_np #endif staticforward PyTypeObject ACL_Type; static PyObject* ACL_applyto(PyObject* obj, PyObject* args); static PyObject* ACL_valid(PyObject* obj, PyObject* args); -#ifdef HAVE_LEVEL2 +#ifdef HAVE_ACL_COPY_EXT static PyObject* ACL_get_state(PyObject *obj, PyObject* args); static PyObject* ACL_set_state(PyObject *obj, PyObject* args); +#endif +#ifdef HAVE_LEVEL2 staticforward PyTypeObject Entry_Type; staticforward PyTypeObject Permset_Type; static PyObject* Permset_new(PyTypeObject* type, PyObject* args, @@ -175,18 +202,18 @@ static char __to_any_text_doc__[] = " - separator: a single character (defaults to '\\n'); this will be\n" " user to separate the entries in the ACL\n" " - options: a bitwise combination of:\n" - " TEXT_ABBREVIATE: use 'u' instead of 'user', 'g' instead of \n" + " - TEXT_ABBREVIATE: use 'u' instead of 'user', 'g' instead of \n" " 'group', etc.\n" - " TEXT_NUMERIC_IDS: User and group IDs are included as decimal\n" - " numbers instead of names\n" - " TEXT_SOME_EFFECTIVE: Include comments denoting the effective\n" - " permissions when some are masked\n" - " TEXT_ALL_EFFECTIVE: Include comments after all ACL entries\n" - " affected by an ACL_MASK entry\n" - " TEXT_SMART_INDENT: Used in combination with the _EFFECTIVE\n" - " options, this will ensure that comments \n" - " are alligned to the fourth tab position\n" - " (assuming one tab equal eight spaces\n" + " - TEXT_NUMERIC_IDS: User and group IDs are included as decimal\n" + " numbers instead of names\n" + " - TEXT_SOME_EFFECTIVE: Include comments denoting the effective\n" + " permissions when some are masked\n" + " - TEXT_ALL_EFFECTIVE: Include comments after all ACL entries\n" + " affected by an ACL_MASK entry\n" + " - TEXT_SMART_INDENT: Used in combination with the _EFFECTIVE\n" + " options, this will ensure that comments \n" + " are alligned to the fourth tab position\n" + " (assuming one tab equals eight spaces)\n" ; /* Converts the acl to a custom text format */ @@ -284,6 +311,25 @@ static PyObject* ACL_richcompare(PyObject* o1, PyObject* o2, int op) { Py_INCREF(ret); return ret; } + +static char __equiv_mode_doc__[] = + "Return the octal mode the ACL is equivalent to.\n" + "\n" + "This is a non-portable, Linux specific extension that checks\n" + "if the ACL is a basic ACL and returns the corresponding mode.\n" + "\n" + "An IOerror exception will be raised if the ACL is an extended ACL\n" + ; + +/* The acl_equiv_mode method */ +static PyObject* ACL_equiv_mode(PyObject* obj, PyObject* args) { + ACL_Object *self = (ACL_Object*) obj; + mode_t mode; + + if(acl_equiv_mode(self->acl, &mode) == -1) + return PyErr_SetFromErrno(PyExc_IOError); + return PyInt_FromLong(mode); +} #endif /* Implementation of the compare for ACLs */ @@ -372,8 +418,7 @@ static PyObject* ACL_valid(PyObject* obj, PyObject* args) { } } -#ifdef HAVE_LEVEL2 - +#ifdef HAVE_ACL_COPY_EXT static PyObject* ACL_get_state(PyObject *obj, PyObject* args) { ACL_Object *self = (ACL_Object*) obj; PyObject *ret; @@ -422,6 +467,9 @@ static PyObject* ACL_set_state(PyObject *obj, PyObject* args) { Py_INCREF(Py_None); return Py_None; } +#endif + +#ifdef HAVE_LEVEL2 /* tp_iter for the ACL type; since it can be iterated only * destructively, the type is its iterator @@ -467,9 +515,9 @@ static char __ACL_delete_entry_doc__[] = "\n" "Note: Only with level 2\n" "Parameters:\n" - " - the Entry object which should be deleted; note that after\n" - " this function is called, that object is unusable any longer\n" - " and should be deleted\n" + " - the Entry object which should be deleted; note that after\n" + " this function is called, that object is unusable any longer\n" + " and should be deleted\n" ; /* Deletes an entry from the ACL */ @@ -946,10 +994,12 @@ static char __Permset_add_doc__[] = "the argument perm to the permission set. An attempt \n" "to add a permission that is already contained in the \n" "permission set is not considered an error.\n" - "Parameters:\n" - " - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" - "Return value:\n" - " None\n" + "\n" + "Parameters:\n\n" + " - perm: a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...)\n" + "\n" + "Return value: None\n" + "\n" "Can raise: IOError\n" ; @@ -975,10 +1025,10 @@ static char __Permset_delete_doc__[] = "the argument perm from the permission set. An attempt \n" "to delete a permission that is not contained in the \n" "permission set is not considered an error.\n" - "Parameters:\n" - " - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" - "Return value:\n" - " None\n" + "Parameters:\n\n" + " - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...)\n" + "Return value: None\n" + "\n" "Can raise: IOError\n" ; @@ -1002,10 +1052,10 @@ static char __Permset_test_doc__[] = "\n" "The test() function tests if the permission contained in \n" "the argument perm exits the permission set.\n" - "Parameters:\n" - " - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" - "Return value:\n" - " Bool\n" + "Parameters:\n\n" + " - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...)\n" + "Return value: Boolean\n" + "\n" "Can raise: IOError\n" ; @@ -1035,8 +1085,7 @@ static PyObject* Permset_test(PyObject* obj, PyObject* args) { static char __ACL_Type_doc__[] = "Type which represents a POSIX ACL\n" "\n" - "Parameters:\n" - " Only one keword parameter should be provided:\n" + "Parameters (only one keword parameter should be provided):\n" " - file=\"...\", meaning create ACL representing\n" " the access ACL of that file\n" " - filedef=\"...\", meaning create ACL representing\n" @@ -1050,9 +1099,10 @@ static char __ACL_Type_doc__[] = " - mode=, meaning create an ACL from a numeric mode\n" " (e.g. mode=0644) (this is valid only when the C library\n" " provides the acl_from_mode call)\n" + "\n" "If no parameters are passed, create an empty ACL; this\n" "makes sense only when your OS supports ACL modification\n" - " (i.e. it implements full POSIX.1e support)\n" + "(i.e. it implements full POSIX.1e support)\n" ; /* ACL type methods */ @@ -1063,12 +1113,15 @@ static PyMethodDef ACL_methods[] = { {"to_any_text", (PyCFunction)ACL_to_any_text, METH_VARARGS | METH_KEYWORDS, __to_any_text_doc__}, {"check", ACL_check, METH_NOARGS, __check_doc__}, + {"equiv_mode", ACL_equiv_mode, METH_NOARGS, __equiv_mode_doc__}, #endif -#ifdef HAVE_LEVEL2 +#ifdef HAVE_ACL_COPYEXT {"__getstate__", ACL_get_state, METH_NOARGS, "Dumps the ACL to an external format."}, {"__setstate__", ACL_set_state, METH_VARARGS, "Loads the ACL from an external format."}, +#endif +#ifdef HAVE_LEVEL2 {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__}, {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__}, {"append", ACL_append, METH_VARARGS, __ACL_append_doc__}, @@ -1182,10 +1235,13 @@ static char __Entry_Type_doc__[] = "\n" "The type exists only if the OS has full support for POSIX.1e\n" "Can be created either by:\n" - " e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n" + "\n" + " >>> e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n" + " >>> e = myACL.append() # another way for doing the same thing\n" + "\n" "or by:\n" - " for entry in myACL:\n" - " print entry\n" + " >>> for entry in myACL:\n" + " ... print entry\n" "\n" "Note that the Entry keeps a reference to its ACL, so even if \n" "you delete the ACL, it won't be cleaned up and will continue to \n" @@ -1285,10 +1341,11 @@ static char __Permset_Type_doc__[] = "Type which represents the permission set in an ACL entry\n" "\n" "The type exists only if the OS has full support for POSIX.1e\n" - "Can be created either by:\n" - " perms = myEntry.permset\n" - "or by:\n" - " perms = posix1e.Permset(myEntry)\n" + "Can be retrieved either by:\n\n" + ">>> perms = myEntry.permset\n" + "\n" + "or by:\n\n" + ">>> perms = posix1e.Permset(myEntry)\n" "\n" "Note that the Permset keeps a reference to its Entry, so even if \n" "you delete the entry, it won't be cleaned up and will continue to \n" @@ -1370,10 +1427,51 @@ static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) { return Py_None; } +#ifdef HAVE_LINUX +static char __has_extended_doc__[] = + "Check if a file or filehandle has an extended ACL.\n" + "\n" + "Parameter:\n" + " - either a filename or a file-like object or an integer; this\n" + " represents the filesystem object on which to act\n" + ; + +/* Check for extended ACL a file or fd */ +static PyObject* aclmodule_has_extended(PyObject* obj, PyObject* args) { + PyObject *myarg; + int nret; + int fd; + + if (!PyArg_ParseTuple(args, "O", &myarg)) + return NULL; + + if(PyString_Check(myarg)) { + const char *filename = PyString_AS_STRING(myarg); + nret = acl_extended_file(filename); + } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) { + nret = acl_extended_fd(fd); + } else { + PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int," + " or file-like object"); + return 0; + } + if(nret == -1) { + return PyErr_SetFromErrno(PyExc_IOError); + } + + /* Return the result */ + return PyBool_FromLong(nret); +} +#endif + /* The module methods */ static PyMethodDef aclmodule_methods[] = { {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__}, +#ifdef HAVE_LINUX + {"has_extended", aclmodule_has_extended, METH_VARARGS, + __has_extended_doc__}, +#endif {NULL, NULL, 0, NULL} }; @@ -1391,29 +1489,38 @@ static char __posix1e_doc__[] = " the ACL once it is created\n" "\n" "Also, in level 2, more types are available, corresponding\n" - "to acl_entry_t (Entry type), acl_permset_t (Permset type).\n" + "to acl_entry_t (the Entry type), acl_permset_t (the Permset type).\n" + "\n" + "The existence of level 2 support and other extensions can be\n" + "checked by the constants:\n" + " - HAS_ACL_ENTRY for level 2 and the Entry/Permset classes\n" + " - HAS_ACL_FROM_MODE for ACL(mode=...) usage\n" + " - HAS_ACL_CHECK for the ACL().check function\n" + " - HAS_EXTENDED_CHECK for the module-level has_extended function\n" + " - HAS_EQUIV_MODE for the ACL().equiv_mode method\n" "\n" "Example:\n" + "\n" ">>> import posix1e\n" ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" ">>> print acl1\n" "user::rw-\n" "group::rw-\n" "other::r--\n" - "\n" + ">>>\n" ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" ">>> print b\n" "user::r-x\n" "group::---\n" "other::---\n" - "\n" + ">>>\n" ">>> b.applyto(\"file.txt\")\n" ">>> print posix1e.ACL(file=\"file.txt\")\n" "user::r-x\n" "group::---\n" "other::---\n" - "\n" ">>>\n" + "\n" ; void initposix1e(void) { @@ -1474,6 +1581,10 @@ void initposix1e(void) { PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK); PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER); + /* Document extended functionality via easy-to-use constants */ + PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 1); +#else + PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 0); #endif #ifdef HAVE_LINUX @@ -1489,6 +1600,16 @@ void initposix1e(void) { PyModule_AddIntConstant(m, "ACL_DUPLICATE_ERROR", ACL_DUPLICATE_ERROR); PyModule_AddIntConstant(m, "ACL_MISS_ERROR", ACL_MISS_ERROR); PyModule_AddIntConstant(m, "ACL_ENTRY_ERROR", ACL_ENTRY_ERROR); -#endif + /* declare the Linux extensions */ + PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 1); + PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 1); + PyModule_AddIntConstant(m, "HAS_EXTENDED_CHECK", 1); + PyModule_AddIntConstant(m, "HAS_EQUIV_MODE", 1); +#else + PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 0); + PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 0); + PyModule_AddIntConstant(m, "HAS_EXTENDED_CHECK", 0); + PyModule_AddIntConstant(m, "HAS_EQUIV_MODE", 0); +#endif } diff --git a/os_linux.c b/os_linux.c deleted file mode 100644 index 1fb7203..0000000 --- a/os_linux.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int get_perm(acl_permset_t permset, acl_perm_t perm) -{ - return acl_get_perm(permset, perm); -} diff --git a/posix1e.html b/posix1e.html deleted file mode 100644 index 3698a0f..0000000 --- a/posix1e.html +++ /dev/null @@ -1,412 +0,0 @@ - - -Python: module posix1e - - - - -
 
- 
posix1e
index
/home/iusty/work/pylibacl/build/lib.linux-x86_64-2.4/posix1e.so
-

POSIX.1e ACLs manipulation

-This module provides support for manipulating POSIX.1e ACLS

-Depending on the operating system support for POSIX.1e, 
-the ACL type will have more or less capabilities:
-  - level 1, only basic support, you can create
-    ACLs from files and text descriptions;
-    once created, the type is immutable
-  - level 2, complete support, you can alter
-    the ACL once it is created

-Also, in level 2, more types are available, corresponding
-to acl_entry_t (Entry type), acl_permset_t (Permset type).

-Example:
->>> import posix1e
->>> acl1 = posix1e.ACL(file="file.txt") 
->>> print acl1
-user::rw-
-group::rw-
-other::r--

->>> b = posix1e.ACL(text="u::rx,g::-,o::-")
->>> print b
-user::r-x
-group::---
-other::---

->>> b.applyto("file.txt")
->>> print posix1e.ACL(file="file.txt")
-user::r-x
-group::---
-other::---

->>>

-

- - - - - -
 
-Classes
       
-
__builtin__.object -
-
-
ACL -
Entry -
Permset -
-
-
-

- - - - - - - -
 
-class ACL(__builtin__.object)
   Type which represents a POSIX ACL

-Parameters:
-  Only one keword parameter should be provided:
-  - file="...", meaning create ACL representing
-    the access ACL of that file
-  - filedef="...", meaning create ACL representing
-    the default ACL of that directory
-  - fd=<int>, meaning create ACL representing
-    the access ACL of that file descriptor
-  - text="...", meaning create ACL from a 
-    textual description
-  - acl=<ACL instance>, meaning create a copy
-    of an existing ACL instance
-  - mode=<int>, meaning create an ACL from a numeric mode
-    (e.g. mode=0644) (this is valid only when the C library
-    provides the acl_from_mode call)
-If no parameters are passed, create an empty ACL; this
-makes sense only when your OS supports ACL modification
- (i.e. it implements full POSIX.1e support)
 
 Methods defined here:
-
__cmp__(...)
x.__cmp__(y) <==> cmp(x,y)
- -
__eq__(...)
x.__eq__(y) <==> x==y
- -
__ge__(...)
x.__ge__(y) <==> x>=y
- -
__getstate__(...)
Dumps the ACL to an external format.
- -
__gt__(...)
x.__gt__(y) <==> x>y
- -
__init__(...)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
- -
__iter__(...)
x.__iter__() <==> iter(x)
- -
__le__(...)
x.__le__(y) <==> x<=y
- -
__lt__(...)
x.__lt__(y) <==> x<y
- -
__ne__(...)
x.__ne__(y) <==> x!=y
- -
__setstate__(...)
Loads the ACL from an external format.
- -
__str__(...)
x.__str__() <==> str(x)
- -
append(...)
Append a new Entry to the ACL and return it.

-This is a convenience function to create a new Entry 
-and append it to the ACL.
-If a parameter of type Entry instance is given, the 
-entry will be a copy of that one (as if copied with 
-Entry.copy()), otherwise, the new entry will be empty.
- -
applyto(...)
Apply the ACL to a file or filehandle.

-Parameters:
-  - either a filename or a file-like object or an integer; this
-    represents the filesystem object on which to act
-  - optional flag representing the type of ACL to set, either
-    ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT
- -
calc_mask(...)
Compute the file group class mask.

-The calc_mask() method calculates and sets the permissions 
-associated with the ACL_MASK Entry of the ACL.
-The value of the new permissions is the union of the permissions 
-granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or 
-ACL_USER.  If the ACL already contains an ACL_MASK entry, its 
-permissions are overwritten; if it does not contain an ACL_MASK 
-Entry, one is added.

-The order of existing entries in the ACL is undefined after this 
-function.
- -
check(...)
Check the ACL validity.

-This is a non-portable, Linux specific extension that allow more
-information to be retrieved in case an ACL is not valid than the
-validate() method.

-This method will return either False (the ACL is valid), or a tuple
-with two elements. The first element is one of the following
-constants:
-  - ACL_MULTI_ERROR: The ACL contains multiple entries that have a
-                     tag type that may occur at most once
-  - ACL_DUPLICATE_ERROR: The ACL contains multiple ACL_USER or 
-                         ACL_GROUP entries  with the same ID
-  - ACL_MISS_ERROR: A required entry is missing
-  - ACL_ENTRY_ERROR: The ACL contains an invalid entry tag type

-The second element of the tuple is the index of the entry that is
-invalid (in the same order as by iterating over the ACL entry)
- -
delete_entry(...)
Deletes an entry from the ACL.

-Note: Only with level 2
-Parameters:
- - the Entry object which should be deleted; note that after
-   this function is called, that object is unusable any longer
-   and should be deleted
- -
next(...)
x.next() -> the next value, or raise StopIteration
- -
to_any_text(...)
Convert the ACL to a custom text format.

-This method encapsulates the acl_to_any_text function. It allows a 
-customized text format to be generated for the ACL. See
-acl_to_any_text(3) for more details.

-Parameters:
-  - prefix: if given, this string will be prepended to all lines
-  - separator: a single character (defaults to '\n'); this will be
-               user to separate the entries in the ACL
-  - options: a bitwise combination of:
-      TEXT_ABBREVIATE: use 'u' instead of 'user', 'g' instead of 
-                       'group', etc.
-      TEXT_NUMERIC_IDS: User and group IDs are included as decimal
-                        numbers instead of names
-      TEXT_SOME_EFFECTIVE: Include comments denoting the effective
-                           permissions when some are masked
-      TEXT_ALL_EFFECTIVE: Include comments after all ACL entries
-                          affected by an ACL_MASK entry
-      TEXT_SMART_INDENT: Used in combination with the _EFFECTIVE
-                         options, this will ensure that comments 
-                         are alligned to the fourth tab position
-                         (assuming one tab equal eight spaces
- -
valid(...)
Test the ACL for validity.

-This method tests the ACL to see if it is a valid ACL
-in terms of the filesystem. More precisely, it checks that:

-The ACL contains exactly one entry with each of the
-ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries
-with ACL_USER and ACL_GROUP tag types may appear zero or more
-times in an ACL. An ACL that contains entries of ACL_USER or
-ACL_GROUP tag types must contain exactly one entry of the 
-ACL_MASK tag type. If an ACL contains no entries of
-ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.

-All user ID qualifiers must be unique among all entries of
-the ACL_USER tag type, and all group IDs must be unique among all
-entries of ACL_GROUP tag type.

-The method will return 1 for a valid ACL and 0 for an invalid one.
-This has been chosen because the specification for acl_valid in
-the POSIX.1e standard documents only one possible value for errno
-in case of an invalid ACL, so we can't differentiate between
-classes of errors. Other suggestions are welcome.
- -
-Data and other attributes defined here:
-
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -

- - - - - - - -
 
-class Entry(__builtin__.object)
   Type which represents an entry in an ACL.

-The type exists only if the OS has full support for POSIX.1e
-Can be created either by:
-  e = posix1e.Entry(myACL) # this creates a new entry in the ACL
-or by:
-  for entry in myACL:
-      print entry

-Note that the Entry keeps a reference to its ACL, so even if 
-you delete the ACL, it won't be cleaned up and will continue to 
-exist until its Entry(ies) will be deleted.
 
 Methods defined here:
-
__init__(...)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
- -
__str__(...)
x.__str__() <==> str(x)
- -
copy(...)
Copy an ACL entry.

-This method sets all the parameters to those of another
-entry, even one of another's ACL
-Parameters:
- - src, instance of type Entry
- -
-Data and other attributes defined here:
-
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -
parent = <attribute 'parent' of 'posix1e.Entry' objects>
The parent ACL of this entry
- -
permset = <attribute 'permset' of 'posix1e.Entry' objects>
The permission set of this ACL entry
- -
qualifier = <attribute 'qualifier' of 'posix1e.Entry' objects>
The qualifier of the current entry

-If the tag type is ACL_USER, this should be a user id.
-If the tag type if ACL_GROUP, this should be a group id.
-Else, it doesn't matter.
- -
tag_type = <attribute 'tag_type' of 'posix1e.Entry' objects>
The tag type of the current entry

-This is one of:
- - ACL_UNDEFINED_TAG
- - ACL_USER_OBJ
- - ACL_USER
- - ACL_GROUP_OBJ
- - ACL_GROUP
- - ACL_MASK
- - ACL_OTHER
- -

- - - - - - - -
 
-class Permset(__builtin__.object)
   Type which represents the permission set in an ACL entry

-The type exists only if the OS has full support for POSIX.1e
-Can be created either by:
-  perms = myEntry.permset
-or by:
-  perms = posix1e.Permset(myEntry)

-Note that the Permset keeps a reference to its Entry, so even if 
-you delete the entry, it won't be cleaned up and will continue to 
-exist until its Permset will be deleted.
 
 Methods defined here:
-
__init__(...)
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
- -
__str__(...)
x.__str__() <==> str(x)
- -
add(...)
Add a permission to the permission set.

-The add() function adds the permission contained in 
-the argument perm to the permission set.  An attempt 
-to add a permission that is already contained in the 
-permission set is not considered an error.
-Parameters:
-  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...
-Return value:
-  None
-Can raise: IOError
- -
clear(...)
Clear all permissions from the permission set.
- -
delete(...)
Delete a permission from the permission set.

-The delete() function deletes the permission contained in 
-the argument perm from the permission set.  An attempt 
-to delete a permission that is not contained in the 
-permission set is not considered an error.
-Parameters:
-  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...
-Return value:
-  None
-Can raise: IOError
- -
test(...)
Test if a permission exists in the permission set.

-The test() function tests if the permission contained in 
-the argument perm exits the permission set.
-Parameters:
-  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...
-Return value:
-  Bool
-Can raise: IOError
- -
-Data and other attributes defined here:
-
__new__ = <built-in method __new__ of type object>
T.__new__(S, ...) -> a new object with type S, a subtype of T
- -
execute = <attribute 'execute' of 'posix1e.Permset' objects>
Execute permsission

-This is a convenience method of access; the 
-same effect can be achieved using the functions
-add(), test(), delete(), and those can take any 
-permission defined by your platform.
- -
read = <attribute 'read' of 'posix1e.Permset' objects>
Read permsission

-This is a convenience method of access; the 
-same effect can be achieved using the functions
-add(), test(), delete(), and those can take any 
-permission defined by your platform.
- -
write = <attribute 'write' of 'posix1e.Permset' objects>
Write permsission

-This is a convenience method of access; the 
-same effect can be achieved using the functions
-add(), test(), delete(), and those can take any 
-permission defined by your platform.
- -

- - - - - -
 
-Functions
       
delete_default(...)
Delete the default ACL from a directory.

-This function deletes the default ACL associated with 
-a directory (the ACL which will be ANDed with the mode
-parameter to the open, creat functions).
-Parameters:
-  - a string representing the directory whose default ACL
-    should be deleted
-

- - - - - -
 
-Data
       ACL_DUPLICATE_ERROR = 8192
-ACL_ENTRY_ERROR = 16384
-ACL_EXECUTE = 1
-ACL_GROUP = 8
-ACL_GROUP_OBJ = 4
-ACL_MASK = 16
-ACL_MISS_ERROR = 12288
-ACL_MULTI_ERROR = 4096
-ACL_OTHER = 32
-ACL_READ = 4
-ACL_TYPE_ACCESS = 32768
-ACL_TYPE_DEFAULT = 16384
-ACL_UNDEFINED_TAG = 0
-ACL_USER = 2
-ACL_USER_OBJ = 1
-ACL_WRITE = 2
-TEXT_ABBREVIATE = 16
-TEXT_ALL_EFFECTIVE = 2
-TEXT_NUMERIC_IDS = 8
-TEXT_SMART_INDENT = 4
-TEXT_SOME_EFFECTIVE = 1
- \ No newline at end of file diff --git a/posix1e.txt b/posix1e.txt deleted file mode 100644 index ef00239..0000000 --- a/posix1e.txt +++ /dev/null @@ -1,416 +0,0 @@ -Help on module posix1e: - -NAME - posix1e - POSIX.1e ACLs manipulation - -FILE - /home/iusty/work/pylibacl/build/lib.linux-x86_64-2.4/posix1e.so - -DESCRIPTION - This module provides support for manipulating POSIX.1e ACLS - - Depending on the operating system support for POSIX.1e, - the ACL type will have more or less capabilities: - - level 1, only basic support, you can create - ACLs from files and text descriptions; - once created, the type is immutable - - level 2, complete support, you can alter - the ACL once it is created - - Also, in level 2, more types are available, corresponding - to acl_entry_t (Entry type), acl_permset_t (Permset type). - - Example: - >>> import posix1e - >>> acl1 = posix1e.ACL(file="file.txt") - >>> print acl1 - user::rw- - group::rw- - other::r-- - - >>> b = posix1e.ACL(text="u::rx,g::-,o::-") - >>> print b - user::r-x - group::--- - other::--- - - >>> b.applyto("file.txt") - >>> print posix1e.ACL(file="file.txt") - user::r-x - group::--- - other::--- - - >>> - -CLASSES - __builtin__.object - ACL - Entry - Permset - - class ACL(__builtin__.object) - | Type which represents a POSIX ACL - | - | Parameters: - | Only one keword parameter should be provided: - | - file="...", meaning create ACL representing - | the access ACL of that file - | - filedef="...", meaning create ACL representing - | the default ACL of that directory - | - fd=, meaning create ACL representing - | the access ACL of that file descriptor - | - text="...", meaning create ACL from a - | textual description - | - acl=, meaning create a copy - | of an existing ACL instance - | - mode=, meaning create an ACL from a numeric mode - | (e.g. mode=0644) (this is valid only when the C library - | provides the acl_from_mode call) - | If no parameters are passed, create an empty ACL; this - | makes sense only when your OS supports ACL modification - | (i.e. it implements full POSIX.1e support) - | - | Methods defined here: - | - | __cmp__(...) - | x.__cmp__(y) <==> cmp(x,y) - | - | __eq__(...) - | x.__eq__(y) <==> x==y - | - | __ge__(...) - | x.__ge__(y) <==> x>=y - | - | __getstate__(...) - | Dumps the ACL to an external format. - | - | __gt__(...) - | x.__gt__(y) <==> x>y - | - | __init__(...) - | x.__init__(...) initializes x; see x.__class__.__doc__ for signature - | - | __iter__(...) - | x.__iter__() <==> iter(x) - | - | __le__(...) - | x.__le__(y) <==> x<=y - | - | __lt__(...) - | x.__lt__(y) <==> x x!=y - | - | __setstate__(...) - | Loads the ACL from an external format. - | - | __str__(...) - | x.__str__() <==> str(x) - | - | append(...) - | Append a new Entry to the ACL and return it. - | - | This is a convenience function to create a new Entry - | and append it to the ACL. - | If a parameter of type Entry instance is given, the - | entry will be a copy of that one (as if copied with - | Entry.copy()), otherwise, the new entry will be empty. - | - | applyto(...) - | Apply the ACL to a file or filehandle. - | - | Parameters: - | - either a filename or a file-like object or an integer; this - | represents the filesystem object on which to act - | - optional flag representing the type of ACL to set, either - | ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT - | - | calc_mask(...) - | Compute the file group class mask. - | - | The calc_mask() method calculates and sets the permissions - | associated with the ACL_MASK Entry of the ACL. - | The value of the new permissions is the union of the permissions - | granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or - | ACL_USER. If the ACL already contains an ACL_MASK entry, its - | permissions are overwritten; if it does not contain an ACL_MASK - | Entry, one is added. - | - | The order of existing entries in the ACL is undefined after this - | function. - | - | check(...) - | Check the ACL validity. - | - | This is a non-portable, Linux specific extension that allow more - | information to be retrieved in case an ACL is not valid than the - | validate() method. - | - | This method will return either False (the ACL is valid), or a tuple - | with two elements. The first element is one of the following - | constants: - | - ACL_MULTI_ERROR: The ACL contains multiple entries that have a - | tag type that may occur at most once - | - ACL_DUPLICATE_ERROR: The ACL contains multiple ACL_USER or - | ACL_GROUP entries with the same ID - | - ACL_MISS_ERROR: A required entry is missing - | - ACL_ENTRY_ERROR: The ACL contains an invalid entry tag type - | - | The second element of the tuple is the index of the entry that is - | invalid (in the same order as by iterating over the ACL entry) - | - | delete_entry(...) - | Deletes an entry from the ACL. - | - | Note: Only with level 2 - | Parameters: - | - the Entry object which should be deleted; note that after - | this function is called, that object is unusable any longer - | and should be deleted - | - | next(...) - | x.next() -> the next value, or raise StopIteration - | - | to_any_text(...) - | Convert the ACL to a custom text format. - | - | This method encapsulates the acl_to_any_text function. It allows a - | customized text format to be generated for the ACL. See - | acl_to_any_text(3) for more details. - | - | Parameters: - | - prefix: if given, this string will be prepended to all lines - | - separator: a single character (defaults to '\n'); this will be - | user to separate the entries in the ACL - | - options: a bitwise combination of: - | TEXT_ABBREVIATE: use 'u' instead of 'user', 'g' instead of - | 'group', etc. - | TEXT_NUMERIC_IDS: User and group IDs are included as decimal - | numbers instead of names - | TEXT_SOME_EFFECTIVE: Include comments denoting the effective - | permissions when some are masked - | TEXT_ALL_EFFECTIVE: Include comments after all ACL entries - | affected by an ACL_MASK entry - | TEXT_SMART_INDENT: Used in combination with the _EFFECTIVE - | options, this will ensure that comments - | are alligned to the fourth tab position - | (assuming one tab equal eight spaces - | - | valid(...) - | Test the ACL for validity. - | - | This method tests the ACL to see if it is a valid ACL - | in terms of the filesystem. More precisely, it checks that: - | - | The ACL contains exactly one entry with each of the - | ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries - | with ACL_USER and ACL_GROUP tag types may appear zero or more - | times in an ACL. An ACL that contains entries of ACL_USER or - | ACL_GROUP tag types must contain exactly one entry of the - | ACL_MASK tag type. If an ACL contains no entries of - | ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional. - | - | All user ID qualifiers must be unique among all entries of - | the ACL_USER tag type, and all group IDs must be unique among all - | entries of ACL_GROUP tag type. - | - | The method will return 1 for a valid ACL and 0 for an invalid one. - | This has been chosen because the specification for acl_valid in - | the POSIX.1e standard documents only one possible value for errno - | in case of an invalid ACL, so we can't differentiate between - | classes of errors. Other suggestions are welcome. - | - | ---------------------------------------------------------------------- - | Data and other attributes defined here: - | - | __new__ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - - class Entry(__builtin__.object) - | Type which represents an entry in an ACL. - | - | The type exists only if the OS has full support for POSIX.1e - | Can be created either by: - | e = posix1e.Entry(myACL) # this creates a new entry in the ACL - | or by: - | for entry in myACL: - | print entry - | - | Note that the Entry keeps a reference to its ACL, so even if - | you delete the ACL, it won't be cleaned up and will continue to - | exist until its Entry(ies) will be deleted. - | - | Methods defined here: - | - | __init__(...) - | x.__init__(...) initializes x; see x.__class__.__doc__ for signature - | - | __str__(...) - | x.__str__() <==> str(x) - | - | copy(...) - | Copy an ACL entry. - | - | This method sets all the parameters to those of another - | entry, even one of another's ACL - | Parameters: - | - src, instance of type Entry - | - | ---------------------------------------------------------------------- - | Data and other attributes defined here: - | - | __new__ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - | - | parent = - | The parent ACL of this entry - | - | permset = - | The permission set of this ACL entry - | - | qualifier = - | The qualifier of the current entry - | - | If the tag type is ACL_USER, this should be a user id. - | If the tag type if ACL_GROUP, this should be a group id. - | Else, it doesn't matter. - | - | tag_type = - | The tag type of the current entry - | - | This is one of: - | - ACL_UNDEFINED_TAG - | - ACL_USER_OBJ - | - ACL_USER - | - ACL_GROUP_OBJ - | - ACL_GROUP - | - ACL_MASK - | - ACL_OTHER - - class Permset(__builtin__.object) - | Type which represents the permission set in an ACL entry - | - | The type exists only if the OS has full support for POSIX.1e - | Can be created either by: - | perms = myEntry.permset - | or by: - | perms = posix1e.Permset(myEntry) - | - | Note that the Permset keeps a reference to its Entry, so even if - | you delete the entry, it won't be cleaned up and will continue to - | exist until its Permset will be deleted. - | - | Methods defined here: - | - | __init__(...) - | x.__init__(...) initializes x; see x.__class__.__doc__ for signature - | - | __str__(...) - | x.__str__() <==> str(x) - | - | add(...) - | Add a permission to the permission set. - | - | The add() function adds the permission contained in - | the argument perm to the permission set. An attempt - | to add a permission that is already contained in the - | permission set is not considered an error. - | Parameters: - | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... - | Return value: - | None - | Can raise: IOError - | - | clear(...) - | Clear all permissions from the permission set. - | - | delete(...) - | Delete a permission from the permission set. - | - | The delete() function deletes the permission contained in - | the argument perm from the permission set. An attempt - | to delete a permission that is not contained in the - | permission set is not considered an error. - | Parameters: - | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... - | Return value: - | None - | Can raise: IOError - | - | test(...) - | Test if a permission exists in the permission set. - | - | The test() function tests if the permission contained in - | the argument perm exits the permission set. - | Parameters: - | - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ... - | Return value: - | Bool - | Can raise: IOError - | - | ---------------------------------------------------------------------- - | Data and other attributes defined here: - | - | __new__ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - | - | execute = - | Execute permsission - | - | This is a convenience method of access; the - | same effect can be achieved using the functions - | add(), test(), delete(), and those can take any - | permission defined by your platform. - | - | read = - | Read permsission - | - | This is a convenience method of access; the - | same effect can be achieved using the functions - | add(), test(), delete(), and those can take any - | permission defined by your platform. - | - | write = - | Write permsission - | - | This is a convenience method of access; the - | same effect can be achieved using the functions - | add(), test(), delete(), and those can take any - | permission defined by your platform. - -FUNCTIONS - delete_default(...) - Delete the default ACL from a directory. - - This function deletes the default ACL associated with - a directory (the ACL which will be ANDed with the mode - parameter to the open, creat functions). - Parameters: - - a string representing the directory whose default ACL - should be deleted - -DATA - ACL_DUPLICATE_ERROR = 8192 - ACL_ENTRY_ERROR = 16384 - ACL_EXECUTE = 1 - ACL_GROUP = 8 - ACL_GROUP_OBJ = 4 - ACL_MASK = 16 - ACL_MISS_ERROR = 12288 - ACL_MULTI_ERROR = 4096 - ACL_OTHER = 32 - ACL_READ = 4 - ACL_TYPE_ACCESS = 32768 - ACL_TYPE_DEFAULT = 16384 - ACL_UNDEFINED_TAG = 0 - ACL_USER = 2 - ACL_USER_OBJ = 1 - ACL_WRITE = 2 - TEXT_ABBREVIATE = 16 - TEXT_ALL_EFFECTIVE = 2 - TEXT_NUMERIC_IDS = 8 - TEXT_SMART_INDENT = 4 - TEXT_SOME_EFFECTIVE = 1 - - diff --git a/pylibacl.egg-info/PKG-INFO b/pylibacl.egg-info/PKG-INFO new file mode 100644 index 0000000..0bf4e63 --- /dev/null +++ b/pylibacl.egg-info/PKG-INFO @@ -0,0 +1,12 @@ +Metadata-Version: 1.0 +Name: pylibacl +Version: 0.4.0 +Summary: POSIX.1e ACLs for python +Home-page: http://pylibacl.sourceforge.net +Author: Iustin Pop +Author-email: iusty@k1024.org +License: LGPL +Description: This is a C extension module for Python which + implements POSIX ACLs manipulation. It is a wrapper on top + of the systems's acl C library - see acl(5). +Platform: UNKNOWN diff --git a/pylibacl.egg-info/SOURCES.txt b/pylibacl.egg-info/SOURCES.txt new file mode 100644 index 0000000..f2bca42 --- /dev/null +++ b/pylibacl.egg-info/SOURCES.txt @@ -0,0 +1,15 @@ +COPYING +IMPLEMENTATION +MANIFEST.in +Makefile +NEWS +PLATFORMS +README +acl.c +setup.cfg +setup.py +pylibacl.egg-info/PKG-INFO +pylibacl.egg-info/SOURCES.txt +pylibacl.egg-info/dependency_links.txt +pylibacl.egg-info/top_level.txt +test/test_acls.py \ No newline at end of file diff --git a/pylibacl.egg-info/dependency_links.txt b/pylibacl.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pylibacl.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pylibacl.egg-info/top_level.txt b/pylibacl.egg-info/top_level.txt new file mode 100644 index 0000000..78cf476 --- /dev/null +++ b/pylibacl.egg-info/top_level.txt @@ -0,0 +1 @@ +posix1e diff --git a/setup.cfg b/setup.cfg index f8c1ed7..cacd252 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,4 +1,9 @@ [bdist_rpm] release = 1 requires = libacl -;build_requires = libacl libacl-devel + +[egg_info] +tag_build = +tag_date = 0 +tag_svn_revision = 0 + diff --git a/setup.py b/setup.py index b2e0583..e3c895b 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -import distutils, os -from distutils.core import setup, Extension +import os +from setuptools import setup, Extension (u_sysname, u_nodename, u_release, u_version, u_machine) = os.uname() @@ -14,9 +14,12 @@ if u_sysname == "Linux": elif u_sysname == "GNU/kFreeBSD": macros.append(("HAVE_LINUX", None)) macros.append(("HAVE_LEVEL2", None)) + macros.append(("HAVE_ACL_COPY_EXT", None)) libs.append("acl") elif u_sysname == "FreeBSD": macros.append(("HAVE_FREEBSD", None)) + if u_release.startswith("7."): + macros.append(("HAVE_LEVEL2", None)) elif u_sysname == "Darwin": libs.append("pthread") else: @@ -27,7 +30,7 @@ long_desc = """This is a C extension module for Python which implements POSIX ACLs manipulation. It is a wrapper on top of the systems's acl C library - see acl(5).""" -version = "0.3.0" +version = "0.4.0" setup(name="pylibacl", version=version, @@ -36,9 +39,10 @@ setup(name="pylibacl", author="Iustin Pop", author_email="iusty@k1024.org", url="http://pylibacl.sourceforge.net", - license="GPL", + license="LGPL", ext_modules=[Extension("posix1e", ["acl.c"], libraries=libs, define_macros=macros, )], + test_suite="test/test_acls", ) diff --git a/test/test_acls.py b/test/test_acls.py new file mode 100644 index 0000000..68cd432 --- /dev/null +++ b/test/test_acls.py @@ -0,0 +1,289 @@ +# +# + +"""Unittests for the posix1e module""" + +# Copyright (C) 2002-2008 Iustin Pop +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + + +import unittest +import os +import tempfile + +import posix1e +from posix1e import * + +TEST_DIR = os.environ.get("TESTDIR", ".") + +BASIC_ACL_TEXT = "u::rw,g::r,o::-" + +def _skip_test(fn): + """Wrapper to skip a test""" + new_fn = lambda x: None + new_fn.__doc__ = "SKIPPED %s" % fn.__doc__ + return new_fn + + +def has_ext(extension): + """Decorator to skip tests based on platform support""" + if not extension: + return _skip_test + else: + return lambda x: x + + +class aclTest: + """Support functions ACLs""" + + def setUp(self): + """set up function""" + self.rmfiles = [] + self.rmdirs = [] + + def tearDown(self): + """tear down function""" + for fname in self.rmfiles: + os.unlink(fname) + for dname in self.rmdirs: + os.rmdir(dname) + + def _getfile(self): + """create a temp file""" + fh, fname = tempfile.mkstemp(".test", "xattr-", TEST_DIR) + self.rmfiles.append(fname) + return fh, fname + + def _getdir(self): + """create a temp dir""" + dname = tempfile.mkdtemp(".test", "xattr-", TEST_DIR) + self.rmdirs.append(dname) + return dname + + def _getsymlink(self): + """create a symlink""" + fh, fname = self._getfile() + os.close(fh) + os.unlink(fname) + os.symlink(fname + ".non-existent", fname) + return fname + + +class LoadTests(aclTest, unittest.TestCase): + """Load/create tests""" + def testFromFile(self): + """Test loading ACLs from a file""" + _, fname = self._getfile() + acl1 = posix1e.ACL(file=fname) + self.failUnless(acl1.valid(), "ACL read from file should be valid") + + def testFromDir(self): + """Test loading ACLs from a directory""" + dname = self._getdir() + acl1 = posix1e.ACL(file=dname) + acl2 = posix1e.ACL(filedef=dname) + self.failUnless(acl1.valid(), + "ACL read from directory should be valid") + # default ACLs might or might not be valid; missing ones are + # not valid, so we don't test acl2 for validity + + def testFromFd(self): + """Test loading ACLs from a file descriptor""" + fd, _ = self._getfile() + acl1 = posix1e.ACL(fd=fd) + self.failUnless(acl1.valid(), "ACL read from fd should be valid") + + def testFromEmpty(self): + """Test creating an empty ACL""" + acl1 = posix1e.ACL() + self.failIf(acl1.valid(), "Empty ACL should not be valid") + + def testFromText(self): + """Test creating an ACL from text""" + acl1 = posix1e.ACL(text=BASIC_ACL_TEXT) + self.failUnless(acl1.valid(), + "ACL based on standard description should be valid") + +class AclExtensions(aclTest, unittest.TestCase): + """ACL extensions checks""" + + @has_ext(HAS_ACL_FROM_MODE) + def testFromMode(self): + """Test loading ACLs from an octal mode""" + acl1 = posix1e.ACL(mode=0644) + self.failUnless(acl1.valid(), + "ACL created via octal mode shoule be valid") + + @has_ext(HAS_ACL_CHECK) + def testAclCheck(self): + """Test the acl_check method""" + acl1 = posix1e.ACL(text=BASIC_ACL_TEXT) + self.failIf(acl1.check(), "ACL is not valid") + acl2 = posix1e.ACL() + self.failUnless(acl2.check(), "Empty ACL should not be valid") + + @has_ext(HAS_EXTENDED_CHECK) + def testExtended(self): + """Test the acl_extended function""" + fd, fname = self._getfile() + basic_acl = posix1e.ACL(text=BASIC_ACL_TEXT) + basic_acl.applyto(fd) + for item in fd, fname: + self.failIf(has_extended(item), + "A simple ACL should not be reported as extended") + enhanced_acl = posix1e.ACL(text="u::rw,g::-,o::-,u:root:rw,mask::r") + self.failUnless(enhanced_acl.valid(), + "Failure to build an extended ACL") + enhanced_acl.applyto(fd) + for item in fd, fname: + self.failUnless(has_extended(item), + "An extended ACL should be reported as such") + + @has_ext(HAS_EQUIV_MODE) + def testEquivMode(self): + """Test the equiv_mode function""" + if HAS_ACL_FROM_MODE: + for mode in 0644, 0755: + acl = posix1e.ACL(mode=mode) + self.failUnlessEqual(acl.equiv_mode(), mode) + acl = posix1e.ACL(text="u::rw,g::r,o::r") + self.failUnlessEqual(acl.equiv_mode(), 0644) + acl = posix1e.ACL(text="u::rx,g::-,o::-") + self.failUnlessEqual(acl.equiv_mode(), 0500) + + +class WriteTests(aclTest, unittest.TestCase): + """Write tests""" + + def testDeleteDefault(self): + """Test removing the default ACL""" + dname = self._getdir() + posix1e.delete_default(dname) + + def testReapply(self): + """Test re-applying an ACL""" + fd, fname = self._getfile() + acl1 = posix1e.ACL(fd=fd) + acl1.applyto(fd) + acl1.applyto(fname) + dname = self._getdir() + acl2 = posix1e.ACL(file=fname) + acl2.applyto(dname) + + +class ModificationTests(aclTest, unittest.TestCase): + """ACL modification tests""" + + @has_ext(HAS_ACL_ENTRY) + def testAppend(self): + """Test append a new Entry to the ACL""" + acl = posix1e.ACL() + e = acl.append() + e.tag_type = posix1e.ACL_OTHER + acl.calc_mask() + + @has_ext(HAS_ACL_ENTRY) + def testDelete(self): + """Test delete Entry from the ACL""" + acl = posix1e.ACL() + e = acl.append() + e.tag_type = posix1e.ACL_OTHER + acl.calc_mask() + acl.delete_entry(e) + acl.calc_mask() + + @has_ext(HAS_ACL_ENTRY) + def testDoubleEntries(self): + """Test double entries""" + acl = posix1e.ACL(text=BASIC_ACL_TEXT) + self.failUnless(acl.valid(), "ACL is not valid") + for tag_type in (posix1e.ACL_USER_OBJ, posix1e.ACL_GROUP_OBJ, + posix1e.ACL_OTHER): + e = acl.append() + e.tag_type = tag_type + e.permset.clear() + self.failIf(acl.valid(), + "ACL containing duplicate entries should not be valid") + acl.delete_entry(e) + + @has_ext(HAS_ACL_ENTRY) + def testMultipleGoodEntries(self): + """Test multiple valid entries""" + acl = posix1e.ACL(text=BASIC_ACL_TEXT) + self.failUnless(acl.valid(), "ACL is not valid") + for tag_type in (posix1e.ACL_USER, + posix1e.ACL_GROUP): + for obj_id in range(5): + e = acl.append() + e.tag_type = tag_type + e.qualifier = obj_id + e.permset.clear() + acl.calc_mask() + self.failUnless(acl.valid(), + "ACL should be able to hold multiple" + " user/group entries") + + @has_ext(HAS_ACL_ENTRY) + def testMultipleBadEntries(self): + """Test multiple invalid entries""" + acl = posix1e.ACL(text=BASIC_ACL_TEXT) + self.failUnless(acl.valid(), "ACL built from standard description" + " should be valid") + for tag_type in (posix1e.ACL_USER, + posix1e.ACL_GROUP): + e1 = acl.append() + e1.tag_type = tag_type + e1.qualifier = 0 + e1.permset.clear() + acl.calc_mask() + self.failUnless(acl.valid(), "ACL should be able to add a" + " user/group entry") + e2 = acl.append() + e2.tag_type = tag_type + e2.qualifier = 0 + e2.permset.clear() + acl.calc_mask() + self.failIf(acl.valid(), "ACL should not validate when" + " containing two duplicate entries") + acl.delete_entry(e1) + acl.delete_entry(e2) + + @has_ext(HAS_ACL_ENTRY) + def testPermset(self): + """Test permissions""" + acl = posix1e.ACL() + e = acl.append() + ps = e.permset + ps.clear() + pmap = { + posix1e.ACL_READ: "read", + posix1e.ACL_WRITE: "write", + posix1e.ACL_EXECUTE: "execute", + } + for perm in pmap: + self.failIf(ps.test(perm), "Empty permission set should not" + " have permission '%s'" % pmap[perm]) + ps.add(perm) + self.failUnless(ps.test(perm), "Permission '%s' should exist" + " after addition" % pmap[perm]) + ps.delete(perm) + self.failIf(ps.test(perm), "Permission '%s' should not exist" + " after deletion" % pmap[perm]) + + +if __name__ == "__main__": + unittest.main() -- 2.39.2