@@ -0,0 +1,213 @@
+Checklist
+
+(and a short version for the impatient):
+
+Commits:
+
+* make commits of logical units
+* check for unnecessary whitespace with "git diff --check" before committing
+* do not check in commented out code or unneeded files
+* the first line of the commit message should be a short description and
+ should skip the full stop
+* the body should provide a meaningful commit message, which:
+ * uses the imperative, present tense: "change", not "changed" or "changes".
+ * includes motivation for the change, and contrasts its implementation with
+ previous behaviour
+* if you want your work included in the main repository, add a "Signed-off-by:
+ Your Name <you@example.com>" line to the commit message (or just use the
+ option "-s" when committing) to confirm that you agree to the Developer's
+ Certificate of Origin
+* make sure that you have tests for the bug you are fixing
+* make sure that the test suite passes after your commit. This distribution
+ is built with Dist::Zilla ensure that running `dzil test` passes. You are
+ responsible for ensuring that generated, hand written and author tests pass.
+
+Patch:
+
+* if you change, add, or remove any features or make some other user
+ interface change, the associated documentation should be updated as well.
+* if your name is not writable in ASCII, make sure that you send the
+ patch in the correct encoding.
+
+Long version:
+
+I started reading over the SubmittingPatches document for git,
+primarily because I wanted to have a document similar to it for
+my projects to make sure people understand what they are doing
+when they write "Signed-off-by" line.
+
+But the patch submission requirements are a lot more relaxed
+here on the technical/contents front, because my projects are
+thousand times smaller ;-). So here is only the relevant bits.
+
+
+(0) Decide what to base your work on.
+
+In general, always base your work on the oldest branch that your
+change is relevant to.
+
+* A bugfix should be based on 'maint' in general. If the bug is not
+present in 'maint', base it on 'master'. For a bug that's not yet
+in 'master', find the topic that introduces the regression, and
+base your work on the tip of the topic. If a 'maint' branch is not present
+base it on master.
+
+* A new feature should be based on 'master' in general. If the new
+feature depends on a topic that is in 'pu', but not in 'master', base your
+work on the tip of that topic.
+
+* Corrections and enhancements to a topic not yet in 'master' should be
+based on the tip of that topic. If the topic has not been merged to 'next',
+it's alright to add a note to squash minor corrections into the series.
+
+* In the exceptional case that a new feature depends on several topics
+not in 'master', start working on 'next' or 'pu' privately and send out
+patches for discussion. Before the final merge, you may have to wait until
+some of the dependent topics graduate to 'master', and rebase your work.
+
+To find the tip of a topic branch, run "git log --first-parent
+master..pu" and look for the merge commit. The second parent of this
+commit is the tip of the topic branch.
+
+
+(1) Make separate commits for logically separate changes.
+
+Unless your patch is really trivial, you should not be sending
+out a patch that was generated between your working tree and
+your commit head. Instead, always make a commit with complete
+commit message and generate a series of patches from your
+repository. It is a good discipline.
+
+Describe the technical detail of the change(s).
+
+If your description starts to get too long, that's a sign that you
+probably need to split up your commit to finer grained pieces.
+That being said, patches which plainly describe the things that
+help reviewers check the patch, and future maintainers understand
+the code, are the most beautiful patches. Descriptions that summarise
+the point in the subject well, and describe the motivation for the
+change, the approach taken by the change, and if relevant how this
+differs substantially from the prior version, can be found on Usenet
+archives back into the late 80's. Consider it like good Netiquette,
+but for code.
+
+Oh, another thing. I am picky about whitespaces. Make sure your
+changes do not trigger errors with the sample pre-commit hook shipped
+in templates/hooks--pre-commit. To help ensure this does not happen,
+run git diff --check on your changes before you commit.
+
+
+(2) Generate your patch using git tools out of your commits.
+
+git based diff tools (git, Cogito, and StGIT included) generate
+unidiff which is the preferred format.
+
+You do not have to be afraid to use -M option to "git diff" or
+"git format-patch", if your patch involves file renames. The
+receiving end can handle them just fine.
+
+Please make sure your patch does not include any extra files
+which do not belong in a patch submission. Make sure to review
+your patch after generating it, to ensure accuracy. Before
+sending out, please make sure it cleanly applies to the "master"
+branch head. If you are preparing a work based on "next" branch,
+that is fine, but please mark it as such.
+
+(4) Sign your work
+
+To improve tracking of who did what, we've borrowed the
+"sign-off" procedure from the Linux kernel project on patches
+that are being emailed around. Although this project is a lot
+smaller it is a good discipline to follow it.
+
+The sign-off is a simple line at the end of the explanation for
+the patch, which certifies that you wrote it or otherwise have
+the right to pass it on as a open-source patch. The rules are
+pretty simple: if you can certify the below:
+
+ Developer's Certificate of Origin 1.1
+
+ By making a contribution to this project, I certify that:
+
+ (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+ (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+ (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+ (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+then you just add a line saying
+
+ Signed-off-by: Random J Developer <random@developer.example.org>
+
+This line can be automatically added by git if you run the git-commit
+command with the -s option.
+
+Notice that you can place your own Signed-off-by: line when
+forwarding somebody else's patch with the above rules for
+D-C-O. Indeed you are encouraged to do so.
+
+Also notice that a real name is used in the Signed-off-by: line. Please
+don't hide your real name.
+
+Some people also put extra tags at the end.
+
+"Acked-by:" says that the patch was reviewed by the person who
+is more familiar with the issues and the area the patch attempts
+to modify. "Tested-by:" says the patch was tested by the person
+and found to have the desired effect.
+
+
+An ideal patch flow
+
+Here is an ideal patch flow for this project the current maintainer
+suggests to the contributors:
+
+0. You come up with an itch. You code it up.
+1. Send it to the bug tracker and cc people who may need to know about
+ the change.
+
+ The people who may need to know are the ones whose
+ code you are butchering. These people happen to be the ones who are most
+ likely to be knowledgeable enough to help you, but they have no obligation to
+ help you (i.e. you ask for help, don't demand). "git log -p --
+ $area_you_are_modifying" would help you find out who they are.
+
+2. You get comments and suggestions for improvements. You may even
+ get them in a "on top of your change" patch form.
+
+3. Polish, refine, and re-send to the the people who spend their
+ time to improve your patch. Go back to step (2).
+
+4. A topic branch is created with the patch and is merged to 'next',
+ and cooked further and eventually graduates to 'master'.
+
+In any time between the (2)-(3) cycle, the maintainer may pick it up
+from the list and queue it to 'pu', in order to make it easier for
+people play with it without having to pick up and apply the patch to
+their trees themselves.
+
+
+Know the status of your patch after submission
+
+* You can use Git itself to find out when your patch is merged in
+master. 'git pull --rebase' will automatically skip already-applied
+patches, and will let you know. This works only if you rebase on top
+of the branch in which your patch has been merged (i.e. it will not
+tell you if your patch is merged in pu if you rebase on top of
+master).
@@ -1,11 +1,55 @@
-Revision history for Perl extension File::chmod.
+Revision history for Perl extension File-chmod.
-0.32 Sat Jul 28 18:40:00 2007
+0.40 2013-11-15
+ - fix prototype mismatch with chmod() when autodie is used. GH #3 (arrestee)
+ [DEPRECATIONS]
+ - undeprecating the default of $UMASK is true
+ tested against my local chmod and it does obey umask. This will no
+ longer be removed.
+
+0.39 2013-09-14
+ - fix tests failing to run as user with override privileges
+ RT #88543 ( zefram )
+ - add more tests
+
+0.38 2013-09-09
+ - fix sticky bit tests for BSD ( Slaven Rezić )
+ - disable windows tests
+
+0.37 2013-09-08
+ - verify and fix RT #78107 chmod('o+t') should set sticky-bit like unix
+ chmod o+t
+
+0.36 2013-09-08
+ - improve Pod using Pod::Weaver, this will allow better linking on web
+ interfaces
+
+0.35 2013-09-08
+ - add read/write tests
+ - remove REVISIONS from pod
+ - add Test::PodSpelling, and fix spelling errors
+
+0.34 2013-09-08
+ - fix basic.t to not fail on windows
+
+0.33 2013-09-07
+ [DEPRECATIONS]
+ - $UMASK is true, this behavior is surprising if you're used to UNIX chmod
+ [NEWS]
+ - new maintainer Caleb Cushing
+ - migrate to Dist::Zilla
+ - add tests (note test failures are likely to be a result of new tests,
+ the code hasn't really changed)
+
+0.32 2007-07-28
- added copyright and license
-0.31 DAMMIT!
+0.31 1999-07-21
+ - fixed getsymchmod() bug
+ - was using map() incorrectly in getmod().
+ - condensed lschmod()
-0.30 Wed Jul 21 15:00:00 1999
+0.30 1999-07-21
- added umask() honoring for symchmod()
- function name changes
- fixed debugging bugs
@@ -15,20 +59,20 @@ Revision history for Perl extension File::chmod.
- compacted code
- see the new REVISIONS section in the docs for explanations
-0.22 Sat Apr 24 11:08:27 1999
+0.22 1999-04-24
- refixed the untarring error (now it works nicely)
-0.20 Sat Apr 3 16:24:14 1999
+0.20 1999-04-03
- fixed the untarring error (didn't appear in a directory)
-0.12 Sat Feb 13 09:24:56 1999
+0.12 1999-02-13
- fixed determine_mode() method for determining mode
-0.11 Fri Feb 12 20:21:37 1999
+0.11 1999-02-12
- fixed determine_mode() bug
-0.10 Fri Feb 12 19:15:04 1999
+0.10 1999-02-12
- changed @EXPORT and @EXPORT_OK functions
-0.01 Sat Feb 6 17:36:42 1999
+0.01 1999-02-06
- original version; created by h2xs 1.18
@@ -0,0 +1,379 @@
+This software is copyright (c) 2013 by Caleb Cushing and Jeff Pinyan.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+Terms of the Perl programming language system itself
+
+a) the GNU General Public License as published by the Free
+ Software Foundation; either version 1, or (at your option) any
+ later version, or
+b) the "Artistic License"
+
+--- The GNU General Public License, Version 1, February 1989 ---
+
+This software is Copyright (c) 2013 by Caleb Cushing and Jeff Pinyan.
+
+This is free software, licensed under:
+
+ The GNU General Public License, Version 1, February 1989
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 1, February 1989
+
+ Copyright (C) 1989 Free Software Foundation, Inc.
+ 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The license agreements of most software companies try to keep users
+at the mercy of those companies. By contrast, our 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. The
+General Public License applies to the Free Software Foundation's
+software and to any other program whose authors commit to using it.
+You can use it for your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Specifically, the General Public License is designed to make
+sure that you have the freedom to give away or sell copies of free
+software, 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 a 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 tell them 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.
+
+ 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 Agreement 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 work containing the
+Program or a portion of it, either verbatim or with modifications. Each
+licensee is addressed as "you".
+
+ 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
+General Public License and to the absence of any warranty; and give any
+other recipients of the Program a copy of this General Public License
+along with the Program. You may charge a fee for the physical act of
+transferring a copy.
+
+ 2. You may modify your copy or copies of the Program or any portion of
+it, and copy and distribute such modifications under the terms of Paragraph
+1 above, provided that you also do the following:
+
+ a) cause the modified files to carry prominent notices stating that
+ you changed the files and the date of any change; and
+
+ b) cause the whole of any work that you distribute or publish, that
+ in whole or in part contains the Program or any part thereof, either
+ with or without modifications, to be licensed at no charge to all
+ third parties under the terms of this General Public License (except
+ that you may choose to grant warranty protection to some or all
+ third parties, at your option).
+
+ c) If the modified program normally reads commands interactively when
+ run, you must cause it, when started running for such interactive use
+ in the simplest and most usual 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 General
+ Public License.
+
+ d) 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.
+
+Mere aggregation of another independent work with the Program (or its
+derivative) on a volume of a storage or distribution medium does not bring
+the other work under the scope of these terms.
+
+ 3. You may copy and distribute the Program (or a portion or derivative of
+it, under Paragraph 2) in object code or executable form under the terms of
+Paragraphs 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
+ Paragraphs 1 and 2 above; or,
+
+ b) accompany it with a written offer, valid for at least three
+ years, to give any third party free (except for a nominal charge
+ for the cost of distribution) a complete machine-readable copy of the
+ corresponding source code, to be distributed under the terms of
+ Paragraphs 1 and 2 above; or,
+
+ c) accompany it with the information you received as to where the
+ corresponding source code may be obtained. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form alone.)
+
+Source code for a work means the preferred form of the work for making
+modifications to it. For an executable file, complete source code means
+all the source code for all modules it contains; but, as a special
+exception, it need not include source code for modules which are standard
+libraries that accompany the operating system on which the executable
+file runs, or for standard header files or definitions files that
+accompany that operating system.
+
+ 4. You may not copy, modify, sublicense, distribute or transfer the
+Program except as expressly provided under this General Public License.
+Any attempt otherwise to copy, modify, sublicense, distribute or transfer
+the Program is void, and will automatically terminate your rights to use
+the Program under this License. However, parties who have received
+copies, or rights to use copies, from you under this General Public
+License will not have their licenses terminated so long as such parties
+remain in full compliance.
+
+ 5. By copying, distributing or modifying 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.
+
+ 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.
+
+ 7. 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 the 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
+the license, you may choose any version ever published by the Free Software
+Foundation.
+
+ 8. 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
+
+ 9. 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.
+
+ 10. 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
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to humanity, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+ To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 1, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19xx name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the
+commands you use may be called something other than `show w' and `show
+c'; they could even be mouse-clicks or menu items--whatever suits your
+program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ program `Gnomovision' (a program to direct compilers to make passes
+ at assemblers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
+--- The Artistic License 1.0 ---
+
+This software is Copyright (c) 2013 by Caleb Cushing and Jeff Pinyan.
+
+This is free software, licensed under:
+
+ The Artistic License 1.0
+
+The Artistic License
+
+Preamble
+
+The intent of this document is to state the conditions under which a Package
+may be copied, such that the Copyright Holder maintains some semblance of
+artistic control over the development of the package, while giving the users of
+the package the right to use and distribute the Package in a more-or-less
+customary fashion, plus the right to make reasonable modifications.
+
+Definitions:
+
+ - "Package" refers to the collection of files distributed by the Copyright
+ Holder, and derivatives of that collection of files created through
+ textual modification.
+ - "Standard Version" refers to such a Package if it has not been modified,
+ or has been modified in accordance with the wishes of the Copyright
+ Holder.
+ - "Copyright Holder" is whoever is named in the copyright or copyrights for
+ the package.
+ - "You" is you, if you're thinking about copying or distributing this Package.
+ - "Reasonable copying fee" is whatever you can justify on the basis of media
+ cost, duplication charges, time of people involved, and so on. (You will
+ not be required to justify it to the Copyright Holder, but only to the
+ computing community at large as a market that must bear the fee.)
+ - "Freely Available" means that no fee is charged for the item itself, though
+ there may be fees involved in handling the item. It also means that
+ recipients of the item may redistribute it under the same conditions they
+ received it.
+
+1. You may make and give away verbatim copies of the source form of the
+Standard Version of this Package without restriction, provided that you
+duplicate all of the original copyright notices and associated disclaimers.
+
+2. You may apply bug fixes, portability fixes and other modifications derived
+from the Public Domain or from the Copyright Holder. A Package modified in such
+a way shall still be considered the Standard Version.
+
+3. You may otherwise modify your copy of this Package in any way, provided that
+you insert a prominent notice in each changed file stating how and when you
+changed that file, and provided that you do at least ONE of the following:
+
+ a) place your modifications in the Public Domain or otherwise make them
+ Freely Available, such as by posting said modifications to Usenet or an
+ equivalent medium, or placing the modifications on a major archive site
+ such as ftp.uu.net, or by allowing the Copyright Holder to include your
+ modifications in the Standard Version of the Package.
+
+ b) use the modified Package only within your corporation or organization.
+
+ c) rename any non-standard executables so the names do not conflict with
+ standard executables, which must also be provided, and provide a separate
+ manual page for each non-standard executable that clearly documents how it
+ differs from the Standard Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+4. You may distribute the programs of this Package in object code or executable
+form, provided that you do at least ONE of the following:
+
+ a) distribute a Standard Version of the executables and library files,
+ together with instructions (in the manual page or equivalent) on where to
+ get the Standard Version.
+
+ b) accompany the distribution with the machine-readable source of the Package
+ with your modifications.
+
+ c) accompany any non-standard executables with their corresponding Standard
+ Version executables, giving the non-standard executables non-standard
+ names, and clearly documenting the differences in manual pages (or
+ equivalent), together with instructions on where to get the Standard
+ Version.
+
+ d) make other distribution arrangements with the Copyright Holder.
+
+5. You may charge a reasonable copying fee for any distribution of this
+Package. You may charge any fee you choose for support of this Package. You
+may not charge a fee for this Package itself. However, you may distribute this
+Package in aggregate with other (possibly commercial) programs as part of a
+larger (possibly commercial) software distribution provided that you do not
+advertise this Package as a product of your own.
+
+6. The scripts and library files supplied as input to or produced as output
+from the programs of this Package do not automatically fall under the copyright
+of this Package, but belong to whomever generated them, and may be sold
+commercially, and may be aggregated with this Package.
+
+7. C or perl subroutines supplied by you and linked into this Package shall not
+be considered part of this Package.
+
+8. The name of the Copyright Holder may not be used to endorse or promote
+products derived from this software without specific prior written permission.
+
+9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+The End
+
@@ -1,6 +1,33 @@
+CONTRIBUTING
Changes
+LICENSE
MANIFEST
+META.json
+META.yml
Makefile.PL
-chmod.pm
-test.pl
-META.yml Module meta-data (added by MakeMaker)
+README
+lib/File/chmod.pm
+perlcritic.rc
+t/00-compile.t
+t/000-report-versions-tiny.t
+t/author-critic.t
+t/author-pod-spell.t
+t/author-test-eol.t
+t/executable.t
+t/load_chmod.t
+t/read.t
+t/release-cpan-changes.t
+t/release-dist-manifest.t
+t/release-distmeta.t
+t/release-kwalitee.t
+t/release-meta-json.t
+t/release-minimum-version.t
+t/release-mojibake.t
+t/release-pod-coverage.t
+t/release-pod-syntax.t
+t/release-portability.t
+t/release-synopsis.t
+t/release-test-version.t
+t/release-unused-vars.t
+t/sticky-bit.t
+t/write.t
@@ -0,0 +1,88 @@
+{
+ "abstract" : "Implements symbolic and ls chmod modes",
+ "author" : [
+ "Jeff Pinyan <japhy.734+CPAN@gmail.com>",
+ "Caleb Cushing <xenoterracide@gmail.com>"
+ ],
+ "dynamic_config" : 0,
+ "generated_by" : "Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830",
+ "license" : [
+ "perl_5"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "File-chmod",
+ "no_index" : {
+ "file" : [
+ "perlcritic.rc"
+ ]
+ },
+ "prereqs" : {
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "6.30"
+ }
+ },
+ "develop" : {
+ "requires" : {
+ "Pod::Coverage::TrustPod" : "0",
+ "Test::CPAN::Changes" : "0.19",
+ "Test::CPAN::Meta" : "0",
+ "Test::Kwalitee" : "1.12",
+ "Test::Pod" : "1.41",
+ "Test::Pod::Coverage" : "1.08",
+ "version" : "0.9901"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Carp" : "0",
+ "Exporter" : "0",
+ "base" : "0",
+ "strict" : "0",
+ "vars" : "0",
+ "warnings" : "0"
+ }
+ },
+ "test" : {
+ "requires" : {
+ "English" : "0",
+ "File::Spec" : "0",
+ "File::Temp" : "0",
+ "IO::Handle" : "0",
+ "IPC::Open3" : "0",
+ "Test::More" : "0.88",
+ "autodie" : "0",
+ "utf8" : "0"
+ }
+ }
+ },
+ "provides" : {
+ "File::chmod" : {
+ "file" : "lib/File/chmod.pm",
+ "version" : "0.40"
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "bugtracker" : {
+ "web" : "https://github.com/xenoterracide/file-chmod/issues"
+ },
+ "homepage" : "https://metacpan.org/dist/File-chmod",
+ "repository" : {
+ "type" : "git",
+ "url" : "git://github.com/xenoterracide/file-chmod.git",
+ "web" : "https://github.com/xenoterracide/file-chmod"
+ }
+ },
+ "version" : "0.40",
+ "x_contributors" : [
+ "David Steinbrunner <dsteinbrunner@pobox.com>",
+ "Slaven Rezic <slaven@rezic.de>",
+ "Steve Throckmorton <arrestee@gmail.com>",
+ "Tim <oylenshpeegul@gmail.com>"
+ ]
+}
+
@@ -1,10 +1,47 @@
-# http://module-build.sourceforge.net/META-spec.html
-#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
-name: File-chmod
-version: 0.32
-version_from: chmod.pm
-installdirs: site
+---
+abstract: 'Implements symbolic and ls chmod modes'
+author:
+ - 'Jeff Pinyan <japhy.734+CPAN@gmail.com>'
+ - 'Caleb Cushing <xenoterracide@gmail.com>'
+build_requires:
+ English: 0
+ File::Spec: 0
+ File::Temp: 0
+ IO::Handle: 0
+ IPC::Open3: 0
+ Test::More: 0.88
+ autodie: 0
+ utf8: 0
+configure_requires:
+ ExtUtils::MakeMaker: 6.30
+dynamic_config: 0
+generated_by: 'Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830'
+license: perl
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: 1.4
+name: File-chmod
+no_index:
+ file:
+ - perlcritic.rc
+provides:
+ File::chmod:
+ file: lib/File/chmod.pm
+ version: 0.40
requires:
-
-distribution_type: module
-generated_by: ExtUtils::MakeMaker version 6.30
+ Carp: 0
+ Exporter: 0
+ base: 0
+ strict: 0
+ vars: 0
+ warnings: 0
+resources:
+ bugtracker: https://github.com/xenoterracide/file-chmod/issues
+ homepage: https://metacpan.org/dist/File-chmod
+ repository: git://github.com/xenoterracide/file-chmod.git
+version: 0.40
+x_contributors:
+ - 'David Steinbrunner <dsteinbrunner@pobox.com>'
+ - 'Slaven Rezic <slaven@rezic.de>'
+ - 'Steve Throckmorton <arrestee@gmail.com>'
+ - 'Tim <oylenshpeegul@gmail.com>'
@@ -1,7 +1,77 @@
-use ExtUtils::MakeMaker;
-# See lib/ExtUtils/MakeMaker.pm for details of how to influence
-# the contents of the Makefile that is written.
-WriteMakefile(
- 'NAME' => 'File::chmod',
- 'VERSION_FROM' => 'chmod.pm', # finds $VERSION
+
+use strict;
+use warnings;
+
+
+
+use ExtUtils::MakeMaker 6.30;
+
+
+
+my %WriteMakefileArgs = (
+ "ABSTRACT" => "Implements symbolic and ls chmod modes",
+ "AUTHOR" => "Jeff Pinyan <japhy.734+CPAN\@gmail.com>, Caleb Cushing <xenoterracide\@gmail.com>",
+ "BUILD_REQUIRES" => {},
+ "CONFIGURE_REQUIRES" => {
+ "ExtUtils::MakeMaker" => "6.30"
+ },
+ "DISTNAME" => "File-chmod",
+ "EXE_FILES" => [],
+ "LICENSE" => "perl",
+ "NAME" => "File::chmod",
+ "PREREQ_PM" => {
+ "Carp" => 0,
+ "Exporter" => 0,
+ "base" => 0,
+ "strict" => 0,
+ "vars" => 0,
+ "warnings" => 0
+ },
+ "TEST_REQUIRES" => {
+ "English" => 0,
+ "File::Spec" => 0,
+ "File::Temp" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "Test::More" => "0.88",
+ "autodie" => 0,
+ "utf8" => 0
+ },
+ "VERSION" => "0.40",
+ "test" => {
+ "TESTS" => "t/*.t"
+ }
);
+
+
+my %FallbackPrereqs = (
+ "Carp" => 0,
+ "English" => 0,
+ "Exporter" => 0,
+ "File::Spec" => 0,
+ "File::Temp" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "Test::More" => "0.88",
+ "autodie" => 0,
+ "base" => 0,
+ "strict" => 0,
+ "utf8" => 0,
+ "vars" => 0,
+ "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+ delete $WriteMakefileArgs{TEST_REQUIRES};
+ delete $WriteMakefileArgs{BUILD_REQUIRES};
+ $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
+}
+
+delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
+ unless eval { ExtUtils::MakeMaker->VERSION(6.52) };
+
+WriteMakefile(%WriteMakefileArgs);
+
+
+
@@ -0,0 +1,174 @@
+NAME
+ File::chmod - Implements symbolic and ls chmod modes
+
+VERSION
+ version 0.40
+
+SYNOPSIS
+ use File::chmod;
+ $File::chmod::UMASK = 0; # you may want this, it ignores the systems umask setting
+
+ # chmod takes all three types
+ # these all do the same thing
+ chmod(0666,@files);
+ chmod("=rw",@files);
+ chmod("-rw-rw-rw-",@files);
+
+ # or
+
+ use File::chmod qw( symchmod lschmod );
+
+ chmod(0666,@files); # this is the normal chmod
+ symchmod("=rw",@files); # takes symbolic modes only
+ lschmod("-rw-rw-rw-",@files); # takes "ls" modes only
+
+ # more functions, read on to understand
+
+DESCRIPTION
+ File::chmod is a utility that allows you to bypass system calls or bit
+ processing of a file's permissions. It overloads the chmod() function
+ with its own that gets an octal mode, a symbolic mode (see below), or an
+ "ls" mode (see below). If you wish not to overload chmod(), you can
+ export symchmod() and lschmod(), which take, respectively, a symbolic
+ mode and an "ls" mode.
+
+ An added feature to version 0.30 is the $UMASK variable, explained in
+ detail below; if "symchmod()" is called and this variable is true, then
+ the function uses the (also new) $MASK variable (which defaults to
+ "umask()") as a mask against the new mode. This mode is on by default,
+ and changes the behavior from what you would expect if you are used to
+ UNIX "chmod".
+
+ Symbolic modes are thoroughly described in your chmod(1) man page, but
+ here are a few examples.
+
+ chmod("+x","file1","file2"); # overloaded chmod(), that is...
+ # turns on the execute bit for all users on those two files
+
+ chmod("o=,g-w","file1","file2");
+ # removes 'other' permissions, and the write bit for 'group'
+
+ chmod("=u","file1","file2");
+ # sets all bits to those in 'user'
+
+ "ls" modes are the type produced on the left-hand side of an "ls -l" on
+ a directory. Examples are:
+
+ chmod("-rwxr-xr-x","file1","file2");
+ # the 0755 setting; user has read-write-execute, group and others
+ # have read-execute priveleges
+
+ chmod("-rwsrws---","file1","file2");
+ # sets read-write-execute for user and group, none for others
+ # also sets set-uid and set-gid bits
+
+ The regular chmod() and lschmod() are absolute; that is, they are not
+ appending to or subtracting from the current file mode. They set it,
+ regardless of what it had been before. symchmod() is useful for allowing
+ the modifying of a file's permissions without having to run a system
+ call or determining the file's permissions, and then combining that with
+ whatever bits are appropriate. It also operates separately on each file.
+
+FUNCTIONS - EXPORT
+ chmod(MODE,FILES)
+ Takes an octal, symbolic, or "ls" mode, and then chmods each file
+ appropriately.
+
+ getchmod(MODE,FILES)
+ Returns a list of modified permissions, without chmodding files. Accepts
+ any of the three kinds of modes.
+
+ @newmodes = getchmod("+x","file1","file2");
+ # @newmodes holds the octal permissions of the files'
+ # modes, if they were to be sent through chmod("+x"...)
+
+FUNCTIONS - EXPORT_OK
+ symchmod(MODE,FILES)
+ Takes a symbolic permissions mode, and chmods each file.
+
+ lschmod(MODE,FILES)
+ Takes an "ls" permissions mode, and chmods each file.
+
+ getsymchmod(MODE,FILES)
+ Returns a list of modified permissions, without chmodding files. Accepts
+ only symbolic permission modes.
+
+ getlschmod(MODE,FILES)
+ Returns a list of modified permissions, without chmodding files. Accepts
+ only "ls" permission modes.
+
+ getmod(FILES)
+ Returns a list of the current mode of each file.
+
+VARIABLES
+ $File::chmod::DEBUG
+ If set to a true value, it will report warnings, similar to those
+ produced by chmod() on your system. Otherwise, the functions will not
+ report errors. Example: a file can not have file-locking and the set-gid
+ bits on at the same time. If $File::chmod::DEBUG is true, the function
+ will report an error. If not, you are not warned of the conflict. It is
+ set to 1 as default.
+
+ $File::chmod::MASK
+ Contains the umask to apply to new file modes when using getsymchmod().
+ This defaults to the return value of umask() at compile time. Is only
+ applied if $UMASK is true.
+
+ $File::chmod::UMASK
+ This is a boolean which tells getsymchmod() whether or not to apply the
+ umask found in $MASK. It defaults to true.
+
+PORTING
+ This is only good on Unix-like boxes. I would like people to help me
+ work on File::chmod for any OS that deserves it. If you would like to
+ help, please email me (address below) with the OS and any information
+ you might have on how chmod() should work on it; if you don't have any
+ specific information, but would still like to help, hey, that's good
+ too. I have the following information (from "perlport"):
+
+ Win32
+ Only good for changing "owner" read-write access, "group", and
+ "other" bits are meaningless. *NOTE: Win32::File and
+ Win32::FileSecurity already do this. I do not currently see a need
+ to port File::chmod.*
+
+ MacOS
+ Only limited meaning. Disabling/enabling write permission is mapped
+ to locking/unlocking the file.
+
+ RISC OS
+ Only good for changing "owner" and "other" read-write access.
+
+SEE ALSO
+ Stat::lsMode (by Mark-James Dominus, CPAN ID: MJD)
+ chmod(1) manpage
+ perldoc -f chmod
+ perldoc -f stat
+
+BUGS
+ Please report any bugs or feature requests on the bugtracker website
+ https://github.com/xenoterracide/file-chmod/issues
+
+ When submitting a bug or request, please include a test-file or a patch
+ to an existing test-file that illustrates the bug or desired feature.
+
+CONTRIBUTORS
+ * David Steinbrunner <dsteinbrunner@pobox.com>
+
+ * Slaven Rezic <slaven@rezic.de>
+
+ * Steve Throckmorton <arrestee@gmail.com>
+
+ * Tim <oylenshpeegul@gmail.com>
+
+AUTHORS
+ * Jeff Pinyan <japhy.734+CPAN@gmail.com>
+
+ * Caleb Cushing <xenoterracide@gmail.com>
+
+COPYRIGHT AND LICENSE
+ This software is copyright (c) 2013 by Caleb Cushing and Jeff Pinyan.
+
+ This is free software; you can redistribute it and/or modify it under
+ the same terms as the Perl 5 programming language system itself.
+
@@ -1,647 +0,0 @@
-package File::chmod;
-
-use Carp;
-use strict;
-use vars qw(
- $VERSION @ISA @EXPORT @EXPORT_OK $DEBUG
- $UMASK $MASK $VAL $W $MODE
-);
-
-require Exporter;
-
-@ISA = qw( Exporter );
-@EXPORT = qw( chmod getchmod );
-@EXPORT_OK = qw( symchmod lschmod getsymchmod getlschmod getmod );
-
-$VERSION = '0.32';
-$DEBUG = 1;
-$UMASK = 1;
-$MASK = umask;
-
-my ($SYM,$LS) = (1,2);
-my %ERROR = (
- EDETMOD => "use of determine_mode is deprecated",
- ENEXLOC => "cannot set group execute on locked file",
- ENLOCEX => "cannot set file locking on group executable file",
- ENSGLOC => "cannot set-gid on locked file",
- ENLOCSG => "cannot set file locking on set-gid file",
- ENEXUID => "execute bit must be on for set-uid",
- ENEXGID => "execute bit must be on for set-gid",
- ENULSID => "set-id has no effect for 'others'",
- ENULSBG => "sticky bit has no effect for 'group'",
- ENULSBO => "sticky bit has no effect for 'others'",
-);
-
-
-sub getmod {
- my @return = map { (stat)[2] & 07777 } @_;
- return wantarray ? @return : $return[0];
-}
-
-
-sub chmod {
- my $mode = shift;
- my $how = mode($mode);
-
- return symchmod($mode,@_) if $how == $SYM;
- return lschmod($mode,@_) if $how == $LS;
- return CORE::chmod($mode,@_);
-}
-
-
-sub getchmod {
- my $mode = shift;
- my $how = mode($mode);
-
- return getsymchmod($mode,@_) if $how == $SYM;
- return getlschmod($mode,@_) if $how == $LS;
- return wantarray ? (($mode) x @_) : $mode;
-}
-
-
-sub symchmod {
- my $mode = shift;
- my @return = getsymchmod($mode,@_);
- my $ret = 0;
- for (@_){ $ret++ if CORE::chmod(shift(@return),$_) }
- return $ret;
-}
-
-
-sub getsymchmod {
- my $mode = shift;
- my @return;
-
- croak "symchmod received non-symbolic mode: $mode" if mode($mode) != $SYM;
-
- for (@_){
- local $VAL = getmod($_);
-
- for my $this (split /,/, $mode){
- local $W = 0;
- my $or;
-
- for (split //, $this){
- if (not defined $or and /[augo]/){
- /a/ and $W |= 7, next;
- /u/ and $W |= 1, next;
- /g/ and $W |= 2, next;
- /o/ and $W |= 4, next;
- }
-
- if (/[-+=]/){
- $W ||= 7;
- $or = (/[=+]/ ? 1 : 0);
- clear() if /=/;
- next;
- }
-
- croak "Bad mode $this" if not defined $or;
- croak "Unknown mode: $mode" if !/[ugorwxslt]/;
-
- /u/ and $or ? u_or() : u_not();
- /g/ and $or ? g_or() : g_not();
- /o/ and $or ? o_or() : o_not();
- /r/ and $or ? r_or() : r_not();
- /w/ and $or ? w_or() : w_not();
- /x/ and $or ? x_or() : x_not();
- /s/ and $or ? s_or() : s_not();
- /l/ and $or ? l_or() : l_not();
- /t/ and $or ? t_or() : t_not();
- }
- }
- $VAL &= ~$MASK if $UMASK;
- push @return, $VAL;
- }
- return wantarray ? @return : $return[0];
-}
-
-
-sub lschmod {
- my $mode = shift;
- return CORE::chmod(getlschmod($mode,@_),@_);
-}
-
-
-sub getlschmod {
- my $mode = shift;
- my $VAL = 0;
-
- croak "lschmod received non-ls mode: $mode" if mode($mode) != $LS;
-
- my ($u,$g,$o) = ($mode =~ /^.(...)(...)(...)$/);
-
- for ($u){
- $VAL |= 0400 if /r/;
- $VAL |= 0200 if /w/;
- $VAL |= 0100 if /[xs]/;
- $VAL |= 04000 if /[sS]/;
- }
-
- for ($g){
- $VAL |= 0040 if /r/;
- $VAL |= 0020 if /w/;
- $VAL |= 0010 if /[xs]/;
- $VAL |= 02000 if /[sS]/;
- }
-
- for ($o){
- $VAL |= 0004 if /r/;
- $VAL |= 0002 if /w/;
- $VAL |= 0001 if /[xt]/;
- $VAL |= 01000 if /[Tt]/;
- }
-
- return wantarray ? (($VAL) x @_) : $VAL;
-}
-
-
-sub mode {
- my $mode = shift;
- return 0 if $mode !~ /\D/;
- return $SYM if $mode =~ /[augo=+,]/;
- return $LS if $mode =~ /^.([r-][w-][xSs-]){2}[r-][w-][xTt-]$/;
- return $SYM;
-}
-
-
-sub determine_mode {
- warn $ERROR{EDECMOD};
- mode(@_);
-}
-
-
-sub clear {
- $W & 1 and $VAL &= 02077;
- $W & 2 and $VAL &= 05707;
- $W & 4 and $VAL &= 07770;
-}
-
-
-sub u_or {
- my $val = $VAL;
- $W & 2 and ($VAL |= (($val & 0700)>>3 | ($val & 04000)>>1));
- $W & 4 and ($VAL |= (($val & 0700)>>6));
-}
-
-
-sub u_not {
- my $val = $VAL;
- $W & 1 and $VAL &= ~(($val & 0700) | ($val & 05000));
- $W & 2 and $VAL &= ~(($val & 0700)>>3 | ($val & 04000)>>1);
- $W & 4 and $VAL &= ~(($val & 0700)>>6);
-}
-
-
-sub g_or {
- my $val = $VAL;
- $W & 1 and $VAL |= (($val & 070)<<3 | ($val & 02000)<<1);
- $W & 4 and $VAL |= ($val & 070)>>3;
-}
-
-
-sub g_not {
- my $val = $VAL;
- $W & 1 and $VAL &= ~(($val & 070)<<3 | ($val & 02000)<<1);
- $W & 2 and $VAL &= ~(($val & 070) | ($val & 02000));
- $W & 4 and $VAL &= ~(($val & 070)>>3);
-}
-
-
-sub o_or {
- my $val = $VAL;
- $W & 1 and $VAL |= (($val & 07)<<6);
- $W & 2 and $VAL |= (($val & 07)<<3);
-}
-
-
-sub o_not {
- my $val = $VAL;
- $W & 1 and $VAL &= ~(($val & 07)<<6);
- $W & 2 and $VAL &= ~(($val & 07)<<3);
- $W & 4 and $VAL &= ~($val & 07);
-}
-
-
-sub r_or {
- $W & 1 and $VAL |= 0400;
- $W & 2 and $VAL |= 0040;
- $W & 4 and $VAL |= 0004;
-}
-
-
-sub r_not {
- $W & 1 and $VAL &= ~0400;
- $W & 2 and $VAL &= ~0040;
- $W & 4 and $VAL &= ~0004;
-}
-
-
-sub w_or {
- $W & 1 and $VAL |= 0200;
- $W & 2 and $VAL |= 0020;
- $W & 4 and $VAL |= 0002;
-}
-
-
-sub w_not {
- $W & 1 and $VAL &= ~0200;
- $W & 2 and $VAL &= ~0020;
- $W & 4 and $VAL &= ~0002;
-}
-
-
-sub x_or {
- if ($VAL & 02000){ $DEBUG and warn($ERROR{ENEXLOC}), return }
- $W & 1 and $VAL |= 0100;
- $W & 2 and $VAL |= 0010;
- $W & 4 and $VAL |= 0001;
-}
-
-
-sub x_not {
- $W & 1 and $VAL &= ~0100;
- $W & 2 and $VAL &= ~0010;
- $W & 4 and $VAL &= ~0001;
-}
-
-
-sub s_or {
- if ($VAL & 02000){ $DEBUG and warn($ERROR{ENSGLOC}), return }
- if (not $VAL & 00100){ $DEBUG and warn($ERROR{ENEXUID}), return }
- if (not $VAL & 00010){ $DEBUG and warn($ERROR{ENEXGID}), return }
- $W & 1 and $VAL |= 04000;
- $W & 2 and $VAL |= 02000;
- $W & 4 and $DEBUG and warn $ERROR{ENULSID};
-}
-
-
-sub s_not {
- $W & 1 and $VAL &= ~04000;
- $W & 2 and $VAL &= ~02000;
- $W & 4 and $DEBUG and warn $ERROR{ENULSID};
-}
-
-
-sub l_or {
- if ($VAL & 02010){ $DEBUG and warn($ERROR{ENLOCSG}), return }
- if ($VAL & 00010){ $DEBUG and warn($ERROR{ENLOCEX}), return }
- $VAL |= 02000;
-}
-
-
-sub l_not {
- $VAL &= ~02000 if not $VAL & 00010;
-}
-
-
-sub t_or {
- $W & 1 and $VAL |= 01000;
- $W & 2 and $DEBUG and warn $ERROR{ENULSBG};
- $W & 4 and $DEBUG and warn $ERROR{ENULSBO};
-}
-
-
-sub t_not {
- $W & 1 and $VAL &= ~01000;
- $W & 2 and $DEBUG and warn $ERROR{ENULSBG};
- $W & 4 and $DEBUG and warn $ERROR{ENULSBO};
-}
-
-
-1;
-
-__END__
-
-=head1 NAME
-
-File::chmod - Implements symbolic and ls chmod modes
-
-=head1 VERSION
-
-This is File::chmod v0.32.
-
-=head1 SYNOPSIS
-
- use File::chmod;
-
- # chmod takes all three types
- # these all do the same thing
- chmod(0666,@files);
- chmod("=rw",@files);
- chmod("-rw-rw-rw-",@files);
-
- # or
-
- use File::chmod qw( symchmod lschmod );
-
- chmod(0666,@files); # this is the normal chmod
- symchmod("=rw",@files); # takes symbolic modes only
- lschmod("-rw-rw-rw-",@files); # takes "ls" modes only
-
- # more functions, read on to understand
-
-=head1 DESCRIPTION
-
-File::chmod is a utility that allows you to bypass system calls or bit
-processing of a file's permissions. It overloads the chmod() function
-with its own that gets an octal mode, a symbolic mode (see below), or
-an "ls" mode (see below). If you wish not to overload chmod(), you can
-export symchmod() and lschmod(), which take, respectively, a symbolic
-mode and an "ls" mode.
-
-Symbolic modes are thoroughly described in your chmod(1) man page, but
-here are a few examples.
-
- # NEW: if $UMASK is true, symchmod() applies a bit-mask found in $MASK
-
- chmod("+x","file1","file2"); # overloaded chmod(), that is...
- # turns on the execute bit for all users on those two files
-
- chmod("o=,g-w","file1","file2");
- # removes 'other' permissions, and the write bit for 'group'
-
- chmod("=u","file1","file2");
- # sets all bits to those in 'user'
-
-"ls" modes are the type produced on the left-hand side of an C<ls -l> on a
-directory. Examples are:
-
- chmod("-rwxr-xr-x","file1","file2");
- # the 0755 setting; user has read-write-execute, group and others
- # have read-execute priveleges
-
- chmod("-rwsrws---","file1","file2");
- # sets read-write-execute for user and group, none for others
- # also sets set-uid and set-gid bits
-
-The regular chmod() and lschmod() are absolute; that is, they are not
-appending to or subtracting from the current file mode. They set it,
-regardless of what it had been before. symchmod() is useful for allowing
-the modifying of a file's permissions without having to run a system call
-or determining the file's permissions, and then combining that with whatever
-bits are appropriate. It also operates separately on each file.
-
-An added feature to version 0.30 is the $UMASK variable, explained below; if
-symchmod() is called and this variable is true, then the function uses the
-(also new) $MASK variable (which defaults to umask()) as a mask against the
-new mode. This is documented below more clearly.
-
-=head2 Functions
-
-Exported by default:
-
-=over 4
-
-=item chmod(MODE,FILES)
-
-Takes an octal, symbolic, or "ls" mode, and then chmods each file
-appropriately.
-
-=item getchmod(MODE,FILES)
-
-Returns a list of modified permissions, without chmodding files.
-Accepts any of the three kinds of modes.
-
- @newmodes = getchmod("+x","file1","file2");
- # @newmodes holds the octal permissons of the files'
- # modes, if they were to be sent through chmod("+x"...)
-
-=back
-
-Exported by request:
-
-=over 4
-
-=item symchmod(MODE,FILES)
-
-Takes a symbolic permissions mode, and chmods each file.
-
-=item lschmod(MODE,FILES)
-
-Takes an "ls" permissions mode, and chmods each file.
-
-=item getsymchmod(MODE,FILES)
-
-Returns a list of modified permissions, without chmodding files.
-Accepts only symbolic permisson modes.
-
-=item getlschmod(MODE,FILES)
-
-Returns a list of modified permissions, without chmodding files.
-Accepts only "ls" permisson modes.
-
-=item getmod(FILES)
-
-Returns a list of the current mode of each file.
-
-=back
-
-=head2 Variables
-
-=over 4
-
-=item $File::chmod::DEBUG
-
-If set to a true value, it will report warnings, similar to those produced
-by chmod() on your system. Otherwise, the functions will not report errors.
-Example: a file can not have file-locking and the set-gid bits on at the
-same time. If $File::chmod::DEBUG is true, the function will report an
-error. If not, you are not warned of the conflict. It is set to 1 as
-default.
-
-=item $File::chmod::MASK
-
-Contains the umask to apply to new file modes when using getsymchmod(). This
-defaults to the return value of umask() at compile time. Is only applied if
-$UMASK is true.
-
-=item $File::chmod::UMASK
-
-This is a boolean which tells getsymchmod() whether or not to apply the umask
-found in $MASK. It defaults to true.
-
-=back
-
-=head1 REVISIONS
-
-I<Note: this section was started with version 0.30.>
-
-This is an in-depth look at the changes being made from version to version.
-
-=head2 0.31 to 0.32
-
-=over 4
-
-=item B<license added>
-
-I added a license to this module so that it can be used places without asking
-my permission. Sorry, Adam.
-
-=back
-
-=head2 0.30 to 0.31
-
-=over 4
-
-=item B<fixed getsymchmod() bug>
-
-Whoa. getsymchmod() was doing some crazy ish. That's about all I can say.
-I did a great deal of debugging, and fixed it up. It ALL had to do with two
-things:
-
- $or = (/+=/ ? 1 : 0); # should have been /[+=]/
-
- /u/ && $ok ? u_or() : u_not(); # should have been /u/ and $ok
-
-=item B<fixed getmod() bug>
-
-I was using map() incorrectly in getmod(). Fixed that.
-
-=item B<condensed lschmod()>
-
-I shorted it up, getting rid a variable.
-
-=back
-
-=head2 0.21 to 0.30
-
-=over 4
-
-=item B<added umask() honoring for symchmod()>
-
-The symchmod() function now honors the $UMASK and $MASK variables. $UMASK is
-a boolean which indicates whether or not to honor the $MASK variable. $MASK
-holds a umask, and it defaults to umask(). $UMASK defaults to true. These
-variables are NOT exported. They must explictly set (i.e. $File::chmod::UMASK
-= 0).
-
-=item B<function name changes>
-
-Renamed internal function determine_mode() to mode(). However, if you happen
-to be using determine_mode() somewhere, mode() will be called, but you'll also
-get a warning about deprecation.
-
-Renamed internal functions {or,not}_{l,s,t} to {l,s,t}_{or,not}. This is to
-keep in standard with the OTHER 6 pairs of bitwise functions, such as r_or()
-and g_not(). I don't know WHY the others had 'not' or 'or' in the front.
-
-=item B<fixed debugging bugs>
-
-Certain calls to warn() were not guarded by the $DEBUG variable, and now they
-are. Also, for some reason, I left a debugging check (that didn't check to
-see if $DEBUG was true) in getsymchmod(), line 118. It printed "ENTERING /g/".
-It's gone now.
-
-=item B<fixed set-uid and set-gid bug>
-
-Heh, it seems that in the previous version of File::chmod, the following code
-went along broken:
-
- # or_s sub, File/chmod.pm, v0.21, line 330
- ($VAL & 00100) && do {
- $DEBUG && warn("execute bit must be on for set-uid"); 1;
- } && next;
-
-Aside from me using '&&' more than enough (changed in the new code), this is
-broken. This is now fixed.
-
-=item B<fixed file lock/set-gid bug>
-
-The not_l() function (now renamed to l_not()) used to take the file mode and
-bit-wise NOT it with ~02000. However, it did not check if the file was locked
-vs. set-gid. Now, the function is C<$VAL &= ~02000 if not $VAL & 00010;>.
-
-=item B<removed useless data structures>
-
-I do not know why I had the $S variable, or %r, %w, and %x hashes. In fact,
-$S was declared in C<use vars qw( ... );>, but never given a value, and the
-%r, %w, and %x hashes had a 'full' key which never got used. And the hashes
-themselves weren't really needed anyway. Here is a list of the variables no
-longer in use, and what they have been replaced with (if any):
-
- $S nothing
- $U, $G, $O $W
- %r, %w, %x octal numbers
- @files @_ (I had @files = @_; in nearly EVERY sub)
- $c $_
-
-=item B<compacted code>
-
-The first version of File::chmod that was published was 0.13, and it was
-written in approximately 10 days, being given the off-and-on treatment I end
-up having to give several projects, due to more pressing matters. Well, since
-then, most of the code has stayed the same, although bugs were worked out.
-Well, I got rid of a lot of slow, clunky, and redundant sections of code in
-this version. Sections include the processing of each character of the mode
-in getsymchmod(), the getmod() subroutine, um, nearly ALL of the getsymchmod()
-function, now that I look at it.
-
-Here's part of the getsymchmod() rewrite:
-
- for ($c){
- if (/u/){
- u_or() if $MODE eq "+" or $MODE eq "=";
- u_not() if $MODE eq "-";
- }
- ...
- }
-
- # changed to
-
- /u/ && $or ? u_or() : u_and();
- # note: operating on $_, $c isn't used anymore
- # note: $or holds 1 if the $MODE was + or =, 0 if $MODE was -
- # note: previous was redundant. didn't need $MODE eq "-" check
- # because u_or() and u_not() both go to the next character
-
-=back
-
-=head1 PORTING
-
-This is only good on Unix-like boxes. I would like people to help me work on
-File::chmod for any OS that deserves it. If you would like to help, please
-email me (address below) with the OS and any information you might have on how
-chmod() should work on it; if you don't have any specific information, but
-would still like to help, hey, that's good too. I have the following
-information (from L</perlport>):
-
-=over 4
-
-=item Win32
-
-Only good for changing "owner" read-write access, "group", and "other" bits
-are meaningless. I<NOTE: Win32::File and Win32::FileSecurity already do
-this. I do not currently see a need to port File::chmod.>
-
-=item MacOS
-
-Only limited meaning. Disabling/enabling write permission is mapped to
-locking/unlocking the file.
-
-=item RISC OS
-
-Only good for changing "owner" and "other" read-write access.
-
-=back
-
-=head1 AUTHOR
-
-Jeff C<japhy> Pinyan, F<japhy.734+CPAN@gmail.com>, CPAN ID: PINYAN
-
-=head1 SEE ALSO
-
- Stat::lsMode (by Mark-James Dominus, CPAN ID: MJD)
- chmod(1) manpage
- perldoc -f chmod
- perldoc -f stat
-
-=head1 COPYRIGHT AND LICENCE
-
-Copyright (C) 2007 by Jeff Pinyan
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.8.8 or,
-at your option, any later version of Perl 5 you may have available.
-
-=cut
@@ -0,0 +1,565 @@
+package File::chmod;
+use strict;
+use warnings;
+use Carp;
+use vars qw( $VAL $W $MODE );
+
+use base 'Exporter';
+
+our $VERSION = '0.40'; # VERSION
+
+our @EXPORT = (qw( chmod getchmod )); ## no critic ( ProhibitAutomaticExportation )
+our @EXPORT_OK = (qw( symchmod lschmod getsymchmod getlschmod getmod ));
+
+our $DEBUG = 1;
+our $UMASK = 2;
+our $MASK = umask;
+
+
+my ($SYM,$LS) = (1,2);
+my %ERROR = (
+ EDETMOD => "use of determine_mode is deprecated",
+ ENEXLOC => "cannot set group execute on locked file",
+ ENLOCEX => "cannot set file locking on group executable file",
+ ENSGLOC => "cannot set-gid on locked file",
+ ENLOCSG => "cannot set file locking on set-gid file",
+ ENEXUID => "execute bit must be on for set-uid",
+ ENEXGID => "execute bit must be on for set-gid",
+ ENULSID => "set-id has no effect for 'others'",
+ ENULSBG => "sticky bit has no effect for 'group'",
+ ENULSBU => "sticky bit has no effect for 'user'",
+);
+
+sub getmod {
+ my @return = map { (stat)[2] & 07777 } @_;
+ return wantarray ? @return : $return[0];
+}
+
+
+sub chmod (@) { ## no critic ( Subroutines::ProhibitBuiltinHomonyms Subroutines::ProhibitSubroutinePrototypes )
+ my $mode = shift;
+ my $how = mode($mode);
+
+ return symchmod($mode,@_) if $how == $SYM;
+ return lschmod($mode,@_) if $how == $LS;
+ return CORE::chmod($mode,@_);
+}
+
+
+sub getchmod {
+ my $mode = shift;
+ my $how = mode($mode);
+
+ return getsymchmod($mode,@_) if $how == $SYM;
+ return getlschmod($mode,@_) if $how == $LS;
+ return wantarray ? (($mode) x @_) : $mode;
+}
+
+
+sub symchmod {
+ my $mode = shift;
+
+ my @return = getsymchmod($mode,@_);
+ my $ret = 0;
+ for (@_){ $ret++ if CORE::chmod(shift(@return),$_) }
+ return $ret;
+}
+
+
+sub getsymchmod {
+ my $mode = shift;
+ my @return;
+
+ croak "symchmod received non-symbolic mode: $mode" if mode($mode) != $SYM;
+
+ for (@_){
+ local $VAL = getmod($_);
+
+ for my $this (split /,/, $mode){
+ local $W = 0;
+ my $or;
+
+ for (split //, $this){
+ if (not defined $or and /[augo]/){
+ /a/ and $W |= 7, next;
+ /u/ and $W |= 1, next;
+ /g/ and $W |= 2, next;
+ /o/ and $W |= 4, next;
+ }
+
+ if (/[-+=]/){
+ $W ||= 7;
+ $or = (/[=+]/ ? 1 : 0);
+ clear() if /=/;
+ next;
+ }
+
+ croak "Bad mode $this" if not defined $or;
+ croak "Unknown mode: $mode" if !/[ugorwxslt]/;
+
+ /u/ and $or ? u_or() : u_not();
+ /g/ and $or ? g_or() : g_not();
+ /o/ and $or ? o_or() : o_not();
+ /r/ and $or ? r_or() : r_not();
+ /w/ and $or ? w_or() : w_not();
+ /x/ and $or ? x_or() : x_not();
+ /s/ and $or ? s_or() : s_not();
+ /l/ and $or ? l_or() : l_not();
+ /t/ and $or ? t_or() : t_not();
+ }
+ }
+ $VAL &= ~$MASK if $UMASK;
+ push @return, $VAL;
+ }
+ return wantarray ? @return : $return[0];
+}
+
+
+sub lschmod {
+ my $mode = shift;
+
+ return CORE::chmod(getlschmod($mode,@_),@_);
+}
+
+
+sub getlschmod {
+ my $mode = shift;
+ my $VAL = 0;
+
+ croak "lschmod received non-ls mode: $mode" if mode($mode) != $LS;
+
+ my ($u,$g,$o) = ($mode =~ /^.(...)(...)(...)$/);
+
+ for ($u){
+ $VAL |= 0400 if /r/;
+ $VAL |= 0200 if /w/;
+ $VAL |= 0100 if /[xs]/;
+ $VAL |= 04000 if /[sS]/;
+ }
+
+ for ($g){
+ $VAL |= 0040 if /r/;
+ $VAL |= 0020 if /w/;
+ $VAL |= 0010 if /[xs]/;
+ $VAL |= 02000 if /[sS]/;
+ }
+
+ for ($o){
+ $VAL |= 0004 if /r/;
+ $VAL |= 0002 if /w/;
+ $VAL |= 0001 if /[xt]/;
+ $VAL |= 01000 if /[Tt]/;
+ }
+
+ return wantarray ? (($VAL) x @_) : $VAL;
+}
+
+
+sub mode {
+ my $mode = shift;
+ return 0 if $mode !~ /\D/;
+ return $SYM if $mode =~ /[augo=+,]/;
+ return $LS if $mode =~ /^.([r-][w-][xSs-]){2}[r-][w-][xTt-]$/;
+ return $SYM;
+}
+
+
+sub determine_mode {
+ carp $ERROR{EDECMOD};
+ mode(@_);
+}
+
+
+sub clear {
+ $W & 1 and $VAL &= 02077;
+ $W & 2 and $VAL &= 05707;
+ $W & 4 and $VAL &= 07770;
+}
+
+
+sub u_or {
+ my $val = $VAL;
+ $W & 2 and ($VAL |= (($val & 0700)>>3 | ($val & 04000)>>1));
+ $W & 4 and ($VAL |= (($val & 0700)>>6));
+}
+
+
+sub u_not {
+ my $val = $VAL;
+ $W & 1 and $VAL &= ~(($val & 0700) | ($val & 05000));
+ $W & 2 and $VAL &= ~(($val & 0700)>>3 | ($val & 04000)>>1);
+ $W & 4 and $VAL &= ~(($val & 0700)>>6);
+}
+
+
+sub g_or {
+ my $val = $VAL;
+ $W & 1 and $VAL |= (($val & 070)<<3 | ($val & 02000)<<1);
+ $W & 4 and $VAL |= ($val & 070)>>3;
+}
+
+
+sub g_not {
+ my $val = $VAL;
+ $W & 1 and $VAL &= ~(($val & 070)<<3 | ($val & 02000)<<1);
+ $W & 2 and $VAL &= ~(($val & 070) | ($val & 02000));
+ $W & 4 and $VAL &= ~(($val & 070)>>3);
+}
+
+
+sub o_or {
+ my $val = $VAL;
+ $W & 1 and $VAL |= (($val & 07)<<6);
+ $W & 2 and $VAL |= (($val & 07)<<3);
+}
+
+
+sub o_not {
+ my $val = $VAL;
+ $W & 1 and $VAL &= ~(($val & 07)<<6);
+ $W & 2 and $VAL &= ~(($val & 07)<<3);
+ $W & 4 and $VAL &= ~($val & 07);
+}
+
+
+sub r_or {
+ $W & 1 and $VAL |= 0400;
+ $W & 2 and $VAL |= 0040;
+ $W & 4 and $VAL |= 0004;
+}
+
+
+sub r_not {
+ $W & 1 and $VAL &= ~0400;
+ $W & 2 and $VAL &= ~0040;
+ $W & 4 and $VAL &= ~0004;
+}
+
+
+sub w_or {
+ $W & 1 and $VAL |= 0200;
+ $W & 2 and $VAL |= 0020;
+ $W & 4 and $VAL |= 0002;
+}
+
+
+sub w_not {
+ $W & 1 and $VAL &= ~0200;
+ $W & 2 and $VAL &= ~0020;
+ $W & 4 and $VAL &= ~0002;
+}
+
+
+sub x_or {
+ if ($VAL & 02000){ $DEBUG and carp($ERROR{ENEXLOC}), return }
+ $W & 1 and $VAL |= 0100;
+ $W & 2 and $VAL |= 0010;
+ $W & 4 and $VAL |= 0001;
+}
+
+
+sub x_not {
+ $W & 1 and $VAL &= ~0100;
+ $W & 2 and $VAL &= ~0010;
+ $W & 4 and $VAL &= ~0001;
+}
+
+
+sub s_or {
+ if ($VAL & 02000){ $DEBUG and carp($ERROR{ENSGLOC}), return }
+ if (not $VAL & 00100){ $DEBUG and carp($ERROR{ENEXUID}), return }
+ if (not $VAL & 00010){ $DEBUG and carp($ERROR{ENEXGID}), return }
+ $W & 1 and $VAL |= 04000;
+ $W & 2 and $VAL |= 02000;
+ $W & 4 and $DEBUG and carp $ERROR{ENULSID};
+}
+
+
+sub s_not {
+ $W & 1 and $VAL &= ~04000;
+ $W & 2 and $VAL &= ~02000;
+ $W & 4 and $DEBUG and carp $ERROR{ENULSID};
+}
+
+
+sub l_or {
+ if ($VAL & 02010){ $DEBUG and carp ($ERROR{ENLOCSG}), return }
+ if ($VAL & 00010){ $DEBUG and carp ($ERROR{ENLOCEX}), return }
+ $VAL |= 02000;
+}
+
+
+sub l_not {
+ $VAL &= ~02000 if not $VAL & 00010;
+}
+
+
+sub t_or {
+ $W & 1 and $DEBUG and carp $ERROR{ENULSBU};
+ $W & 2 and $DEBUG and carp $ERROR{ENULSBG};
+ $W & 4 and $VAL |= 01000;
+}
+
+
+sub t_not {
+ $W & 1 and $DEBUG and carp $ERROR{ENULSBU};
+ $W & 2 and $DEBUG and carp $ERROR{ENULSBG};
+ $W & 4 and $VAL &= ~01000;
+}
+
+
+1;
+# ABSTRACT: Implements symbolic and ls chmod modes
+
+__END__
+
+=pod
+
+=head1 NAME
+
+File::chmod - Implements symbolic and ls chmod modes
+
+=head1 VERSION
+
+version 0.40
+
+=head1 SYNOPSIS
+
+ use File::chmod;
+ $File::chmod::UMASK = 0; # you may want this, it ignores the systems umask setting
+
+ # chmod takes all three types
+ # these all do the same thing
+ chmod(0666,@files);
+ chmod("=rw",@files);
+ chmod("-rw-rw-rw-",@files);
+
+ # or
+
+ use File::chmod qw( symchmod lschmod );
+
+ chmod(0666,@files); # this is the normal chmod
+ symchmod("=rw",@files); # takes symbolic modes only
+ lschmod("-rw-rw-rw-",@files); # takes "ls" modes only
+
+ # more functions, read on to understand
+
+=head1 DESCRIPTION
+
+File::chmod is a utility that allows you to bypass system calls or bit
+processing of a file's permissions. It overloads the chmod() function
+with its own that gets an octal mode, a symbolic mode (see below), or
+an "ls" mode (see below). If you wish not to overload chmod(), you can
+export symchmod() and lschmod(), which take, respectively, a symbolic
+mode and an "ls" mode.
+
+An added feature to version 0.30 is the C<$UMASK> variable, explained in
+detail below; if C<symchmod()> is called and this variable is true, then the
+function uses the (also new) C<$MASK> variable (which defaults to C<umask()>)
+as a mask against the new mode. This mode is on by default, and changes the
+behavior from what you would expect if you are used to UNIX C<chmod>.
+
+Symbolic modes are thoroughly described in your chmod(1) man page, but
+here are a few examples.
+
+ chmod("+x","file1","file2"); # overloaded chmod(), that is...
+ # turns on the execute bit for all users on those two files
+
+ chmod("o=,g-w","file1","file2");
+ # removes 'other' permissions, and the write bit for 'group'
+
+ chmod("=u","file1","file2");
+ # sets all bits to those in 'user'
+
+"ls" modes are the type produced on the left-hand side of an C<ls -l> on a
+directory. Examples are:
+
+ chmod("-rwxr-xr-x","file1","file2");
+ # the 0755 setting; user has read-write-execute, group and others
+ # have read-execute priveleges
+
+ chmod("-rwsrws---","file1","file2");
+ # sets read-write-execute for user and group, none for others
+ # also sets set-uid and set-gid bits
+
+The regular chmod() and lschmod() are absolute; that is, they are not
+appending to or subtracting from the current file mode. They set it,
+regardless of what it had been before. symchmod() is useful for allowing
+the modifying of a file's permissions without having to run a system call
+or determining the file's permissions, and then combining that with whatever
+bits are appropriate. It also operates separately on each file.
+
+=head1 FUNCTIONS - EXPORT
+
+=head2 chmod(MODE,FILES)
+
+Takes an octal, symbolic, or "ls" mode, and then chmods each file
+appropriately.
+
+=head2 getchmod(MODE,FILES)
+
+Returns a list of modified permissions, without chmodding files.
+Accepts any of the three kinds of modes.
+
+ @newmodes = getchmod("+x","file1","file2");
+ # @newmodes holds the octal permissions of the files'
+ # modes, if they were to be sent through chmod("+x"...)
+
+=head1 FUNCTIONS - EXPORT_OK
+
+=head2 symchmod(MODE,FILES)
+
+Takes a symbolic permissions mode, and chmods each file.
+
+=head2 lschmod(MODE,FILES)
+
+Takes an "ls" permissions mode, and chmods each file.
+
+=head2 getsymchmod(MODE,FILES)
+
+Returns a list of modified permissions, without chmodding files.
+Accepts only symbolic permission modes.
+
+=head2 getlschmod(MODE,FILES)
+
+Returns a list of modified permissions, without chmodding files.
+Accepts only "ls" permission modes.
+
+=head2 getmod(FILES)
+
+Returns a list of the current mode of each file.
+
+=head1 VARIABLES
+
+=head2 $File::chmod::DEBUG
+
+If set to a true value, it will report warnings, similar to those produced
+by chmod() on your system. Otherwise, the functions will not report errors.
+Example: a file can not have file-locking and the set-gid bits on at the
+same time. If $File::chmod::DEBUG is true, the function will report an
+error. If not, you are not warned of the conflict. It is set to 1 as
+default.
+
+=head2 $File::chmod::MASK
+
+Contains the umask to apply to new file modes when using getsymchmod(). This
+defaults to the return value of umask() at compile time. Is only applied if
+$UMASK is true.
+
+=head2 $File::chmod::UMASK
+
+This is a boolean which tells getsymchmod() whether or not to apply the umask
+found in $MASK. It defaults to true.
+
+=for test_synopsis my ( @files );
+
+=head1 PORTING
+
+This is only good on Unix-like boxes. I would like people to help me work on
+L<File::chmod> for any OS that deserves it. If you would like to help, please
+email me (address below) with the OS and any information you might have on how
+chmod() should work on it; if you don't have any specific information, but
+would still like to help, hey, that's good too. I have the following
+information (from L</perlport>):
+
+=over 4
+
+=item Win32
+
+Only good for changing "owner" read-write access, "group", and "other" bits
+are meaningless. I<NOTE: Win32::File and Win32::FileSecurity already do
+this. I do not currently see a need to port File::chmod.>
+
+=item MacOS
+
+Only limited meaning. Disabling/enabling write permission is mapped to
+locking/unlocking the file.
+
+=item RISC OS
+
+Only good for changing "owner" and "other" read-write access.
+
+=back
+
+=head1 SEE ALSO
+
+ Stat::lsMode (by Mark-James Dominus, CPAN ID: MJD)
+ chmod(1) manpage
+ perldoc -f chmod
+ perldoc -f stat
+
+=for Pod::Coverage clear
+determine_mode
+g_not
+g_or
+l_not
+l_or
+mode
+o_not
+o_or
+r_not
+r_or
+s_not
+s_or
+t_not
+t_or
+u_not
+u_or
+w_not
+w_or
+x_not
+x_or
+
+=head1 BUGS
+
+Please report any bugs or feature requests on the bugtracker website
+https://github.com/xenoterracide/file-chmod/issues
+
+When submitting a bug or request, please include a test-file or a
+patch to an existing test-file that illustrates the bug or desired
+feature.
+
+=head1 CONTRIBUTORS
+
+=over 4
+
+=item *
+
+David Steinbrunner <dsteinbrunner@pobox.com>
+
+=item *
+
+Slaven Rezic <slaven@rezic.de>
+
+=item *
+
+Steve Throckmorton <arrestee@gmail.com>
+
+=item *
+
+Tim <oylenshpeegul@gmail.com>
+
+=back
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Jeff Pinyan <japhy.734+CPAN@gmail.com>
+
+=item *
+
+Caleb Cushing <xenoterracide@gmail.com>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2013 by Caleb Cushing and Jeff Pinyan.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
@@ -0,0 +1,6 @@
+theme = core
+severity = 3
+verbose = 9
+exclude = ProhibitLeadingZeros RequireFinalReturn RequireArgUnpacking ProhibitCommaSeparatedStatements RequireExtendedFormatting
+[Subroutines::ProhibitExcessComplexity]
+max_mccabe = 37
@@ -0,0 +1,48 @@
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.037
+
+use Test::More tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
+
+
+
+my @module_files = (
+ 'File/chmod.pm'
+);
+
+
+
+# no fake home requested
+
+my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib';
+
+use File::Spec;
+use IPC::Open3;
+use IO::Handle;
+
+my @warnings;
+for my $lib (@module_files)
+{
+ # see L<perlfaq8/How can I capture STDERR from an external command?>
+ open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
+ my $stderr = IO::Handle->new;
+
+ my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
+ binmode $stderr, ':crlf' if $^O eq 'MSWin32';
+ my @_warnings = <$stderr>;
+ waitpid($pid, 0);
+ is($?, 0, "$lib loaded ok");
+
+ if (@_warnings)
+ {
+ warn @_warnings;
+ push @warnings, @_warnings;
+ }
+}
+
+
+
+is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING};
+
+
@@ -0,0 +1,84 @@
+use strict;
+use warnings;
+use Test::More 0.88;
+# This is a relatively nice way to avoid Test::NoWarnings breaking our
+# expectations by adding extra tests, without using no_plan. It also helps
+# avoid any other test module that feels introducing random tests, or even
+# test plans, is a nice idea.
+our $success = 0;
+END { $success && done_testing; }
+
+# List our own version used to generate this
+my $v = "\nGenerated by Dist::Zilla::Plugin::ReportVersions::Tiny v1.10\n";
+
+eval { # no excuses!
+ # report our Perl details
+ my $want = "any version";
+ $v .= "perl: $] (wanted $want) on $^O from $^X\n\n";
+};
+defined($@) and diag("$@");
+
+# Now, our module version dependencies:
+sub pmver {
+ my ($module, $wanted) = @_;
+ $wanted = " (want $wanted)";
+ my $pmver;
+ eval "require $module;";
+ if ($@) {
+ if ($@ =~ m/Can't locate .* in \@INC/) {
+ $pmver = 'module not found.';
+ } else {
+ diag("${module}: $@");
+ $pmver = 'died during require.';
+ }
+ } else {
+ my $version;
+ eval { $version = $module->VERSION; };
+ if ($@) {
+ diag("${module}: $@");
+ $pmver = 'died during VERSION check.';
+ } elsif (defined $version) {
+ $pmver = "$version";
+ } else {
+ $pmver = '<undef>';
+ }
+ }
+
+ # So, we should be good, right?
+ return sprintf('%-45s => %-10s%-15s%s', $module, $pmver, $wanted, "\n");
+}
+
+eval { $v .= pmver('Carp','any version') };
+eval { $v .= pmver('English','any version') };
+eval { $v .= pmver('Exporter','any version') };
+eval { $v .= pmver('ExtUtils::MakeMaker','6.30') };
+eval { $v .= pmver('File::Spec','any version') };
+eval { $v .= pmver('File::Temp','any version') };
+eval { $v .= pmver('IO::Handle','any version') };
+eval { $v .= pmver('IPC::Open3','any version') };
+eval { $v .= pmver('Test::More','0.88') };
+eval { $v .= pmver('autodie','any version') };
+eval { $v .= pmver('base','any version') };
+eval { $v .= pmver('strict','any version') };
+eval { $v .= pmver('utf8','any version') };
+eval { $v .= pmver('vars','any version') };
+eval { $v .= pmver('warnings','any version') };
+
+
+# All done.
+$v .= <<'EOT';
+
+Thanks for using my code. I hope it works for you.
+If not, please try and include this output in the bug report.
+That will help me reproduce the issue and solve your problem.
+
+EOT
+
+diag($v);
+ok(1, "we really didn't test anything, just reporting data");
+$success = 1;
+
+# Work around another nasty module on CPAN. :/
+no warnings 'once';
+$Template::Test::NO_FLUSH = 1;
+exit 0;
@@ -0,0 +1,20 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{AUTHOR_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for testing by the author');
+ }
+}
+
+
+use strict;
+use warnings;
+
+use Test::More;
+use English qw(-no_match_vars);
+
+eval "use Test::Perl::Critic";
+plan skip_all => 'Test::Perl::Critic required to criticise code' if $@;
+Test::Perl::Critic->import( -profile => "perlcritic.rc" ) if -e "perlcritic.rc";
+all_critic_ok();
@@ -0,0 +1,43 @@
+
+BEGIN {
+ unless ($ENV{AUTHOR_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for testing by the author');
+ }
+}
+
+use strict;
+use warnings;
+use Test::More;
+
+# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006001
+use Test::Spelling 0.12;
+use Pod::Wordlist;
+
+
+add_stopwords(<DATA>);
+all_pod_files_spelling_ok( qw( bin lib ) );
+__DATA__
+chmods
+chmodding
+Jeff
+Pinyan
+japhy
+Caleb
+Cushing
+xenoterracide
+and
+David
+Steinbrunner
+dsteinbrunner
+Slaven
+Rezic
+slaven
+Steve
+Throckmorton
+arrestee
+Tim
+oylenshpeegul
+lib
+File
+chmod
@@ -0,0 +1,16 @@
+
+BEGIN {
+ unless ($ENV{AUTHOR_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for testing by the author');
+ }
+}
+
+use strict;
+use warnings;
+use Test::More;
+
+# generated by Dist::Zilla::Plugin::Test::EOL 0.08
+use Test::EOL;
+
+all_perl_files_ok({ trailing_whitespace => 1 });
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+use Test::More;
+use English '-no_match_vars';
+use File::Temp ();
+use File::chmod qw( chmod getmod );
+$File::chmod::UMASK = 0;
+
+plan skip_all => "Windows perms work differently" if $OSNAME eq 'MSWin32';
+
+my $tmp = File::Temp->new;
+my $fn = $tmp->filename;
+
+note sprintf "original state of %s: %o\n", $fn, getmod( $fn );
+
+ok chmod("+x", $fn ), "chmod +x $fn";
+ok -x $fn, "$fn executable";
+
+ok chmod("-x", $fn ), "chmod -x $fn";
+ok ! -x $fn, "$fn not executable";
+
+done_testing;
@@ -0,0 +1,29 @@
+# load_chmod.t
+#
+# Since perl v5.14 (or thereabouts), a warning is issued when the autodie
+# pragma is used and &File::chmod::chmod doesn't match the prototype of (@)
+# that CORE::chmod has. Adding a prototype to &File::chmod::chmod silences
+# the warning. This test ensures that the prototype doesn't get lost
+# somewhere in the future.
+
+use strict;
+use warnings;
+use autodie;
+use utf8;
+use Test::More;
+
+my $test_passed;
+BEGIN {
+ $test_passed = 1;
+ $SIG{__WARN__} = sub {
+ my $msg = shift;
+ if ( $msg =~ m/Prototype\s+mismatch:\s+sub\s+main::chmod/i ) {
+ $test_passed = 0;
+ }
+ };
+}
+
+use File::chmod;
+ok( $test_passed, "Load File::chmod without 'Missing prototype' warning" );
+
+done_testing;
@@ -0,0 +1,41 @@
+use strict;
+use warnings;
+use Test::More;
+use English '-no_match_vars';
+use File::Temp ();
+use File::chmod qw( chmod getmod );
+$File::chmod::UMASK = 0;
+
+plan skip_all => "Windows perms work differently" if $OSNAME eq 'MSWin32';
+
+my $tmp = File::Temp->new;
+my $fn = $tmp->filename;
+
+chmod( 0000, $fn );
+note sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+ok chmod("+r", $fn ), "chmod +r $fn";
+is sprintf( '%o', getmod( $fn ) ), 444, "$fn is 444";
+
+ok chmod("-r", $fn ), "chmod -r $fn";
+is sprintf( '%o', getmod( $fn ) ), 000, "$fn is 000";
+
+ok chmod("u+r", $fn ), "chmod u+r $fn";
+is sprintf( '%o', getmod( $fn ) ), 400, "$fn is 400";
+
+ok chmod("u-r", $fn ), "chmod u-r $fn";
+is sprintf( '%o', getmod( $fn ) ), 000, "$fn is 000";
+
+ok chmod("ug+r", $fn ), "chmod ug+r $fn";
+is sprintf( '%o', getmod( $fn ) ), 440, "$fn is 440";
+
+ok chmod("ug-r", $fn ), "chmod ug+r $fn";
+is sprintf( '%o', getmod( $fn ) ), 000, "$fn is 000";
+
+ok chmod("ugo+r", $fn ), "chmod ugo+r $fn";
+is sprintf( '%o', getmod( $fn ) ), 444, "$fn is 444";
+
+ok chmod("ugo-r", $fn ), "chmod ugo+r $fn";
+is sprintf( '%o', getmod( $fn ) ), 000, "$fn is 000";
+
+done_testing;
@@ -0,0 +1,19 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use strict;
+use warnings;
+
+use Test::More 0.96 tests => 2;
+use_ok('Test::CPAN::Changes');
+subtest 'changes_ok' => sub {
+ changes_file_ok('Changes');
+};
+done_testing();
@@ -0,0 +1,16 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::DistManifest";
+plan skip_all => "Test::DistManifest required for testing the manifest"
+ if $@;
+manifest_ok();
@@ -0,0 +1,15 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::CPAN::Meta";
+plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@;
+meta_yaml_ok();
@@ -0,0 +1,12 @@
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+# this test was generated with Dist::Zilla::Plugin::Test::Kwalitee 2.07
+use strict;
+use warnings;
+use Test::Kwalitee;
@@ -0,0 +1,14 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+eval 'use Test::CPAN::Meta::JSON';
+plan skip_all => 'Test::CPAN::Meta::JSON required for testing META.json' if $@;
+meta_json_ok();
@@ -0,0 +1,16 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::MinimumVersion";
+plan skip_all => "Test::MinimumVersion required for testing minimum versions"
+ if $@;
+all_minimum_version_from_metayml_ok();
@@ -0,0 +1,20 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use strict;
+use warnings qw(all);
+
+use Test::More;
+
+## no critic (ProhibitStringyEval, RequireCheckingReturnValueOfEval)
+eval q(use Test::Mojibake);
+plan skip_all => q(Test::Mojibake required for source encoding testing) if $@;
+
+all_files_encoding_ok();
@@ -0,0 +1,21 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::Pod::Coverage 1.08";
+plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
+ if $@;
+
+eval "use Pod::Coverage::TrustPod";
+plan skip_all => "Pod::Coverage::TrustPod required for testing POD coverage"
+ if $@;
+
+all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
@@ -0,0 +1,15 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+use Test::More;
+
+eval "use Test::Pod 1.41";
+plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;
+
+all_pod_files_ok();
@@ -0,0 +1,19 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use strict;
+use warnings;
+
+use Test::More;
+
+eval 'use Test::Portability::Files';
+plan skip_all => 'Test::Portability::Files required for testing portability'
+ if $@;
+run_tests();
@@ -0,0 +1,16 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::Synopsis";
+plan skip_all => "Test::Synopsis required for testing synopses"
+ if $@;
+all_synopsis_ok();
@@ -0,0 +1,30 @@
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+use strict;
+use warnings;
+use Test::More;
+
+# generated by Dist::Zilla::Plugin::Test::Version 0.002004
+BEGIN { eval "use Test::Version; 1;" or die $@; }
+
+my @imports = ( 'version_all_ok' );
+
+my $params = {
+ is_strict => 0,
+ has_version => 1,
+};
+
+push @imports, $params
+ if version->parse( $Test::Version::VERSION ) >= version->parse('1.002');
+
+
+Test::Version->import(@imports);
+
+version_all_ok;
+done_testing;
@@ -0,0 +1,16 @@
+#!perl
+
+BEGIN {
+ unless ($ENV{RELEASE_TESTING}) {
+ require Test::More;
+ Test::More::plan(skip_all => 'these tests are for release candidate testing');
+ }
+}
+
+
+use Test::More;
+
+eval "use Test::Vars";
+plan skip_all => "Test::Vars required for testing unused vars"
+ if $@;
+all_vars_ok();
@@ -0,0 +1,39 @@
+use strict;
+use warnings;
+use Test::More;
+use English '-no_match_vars';
+use File::Temp ();
+use File::chmod qw( chmod getmod );
+$File::chmod::UMASK = 0;
+
+plan skip_all => "Windows perms work differently" if $OSNAME eq 'MSWin32';
+plan skip_all => "old File::Temp without newdir" if !File::Temp->can('newdir');
+
+my $tmp = File::Temp->newdir;
+my $fn = $tmp->dirname;
+note sprintf "original state of %s: %o\n", $fn, getmod( $fn );
+
+
+ok chmod("+t", $fn ), "chmod +t $fn";
+ok -k $fn, "$fn sticky"
+ or diag sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+ok chmod("-t", $fn ), "chmod -t $fn";
+ok ! -k $fn, "$fn not sticky"
+ or diag sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+
+ok chmod("o+t", $fn ), "chmod o+t $fn";
+ok -k $fn, "$fn sticky"
+ or diag sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+ok chmod("o-t", $fn ), "chmod o-t $fn";
+ok ! -k $fn, "$fn not sticky"
+ or diag sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+
+ok chmod("u+t", $fn ), "chmod u+t $fn";
+ok ! -k $fn, "$fn sticky"
+ or diag sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+done_testing;
@@ -0,0 +1,23 @@
+use strict;
+use warnings;
+use Test::More;
+use English '-no_match_vars';
+use File::Temp ();
+use File::chmod qw( chmod getmod );
+$File::chmod::UMASK = 0;
+
+plan skip_all => "Windows perms work differently" if $OSNAME eq 'MSWin32';
+
+my $tmp = File::Temp->new;
+my $fn = $tmp->filename;
+
+chmod( 0000, $fn );
+note sprintf "state of %s: %o\n", $fn, getmod( $fn );
+
+ok chmod("+w", $fn ), "chmod +w $fn";
+is sprintf( '%o', getmod( $fn ) ), 222, "$fn is 222";
+
+ok chmod("-w", $fn ), "chmod -w $fn";
+is sprintf( '%o', getmod( $fn ) ), 000, "$fn is 000";
+
+done_testing;
@@ -1,29 +0,0 @@
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl test.pl'
-
-######################### We start with some black magic to print on failure.
-
-# Change 1..1 below to 1..last_test_to_print .
-# (It may become useful if the test is moved to ./t subdirectory.)
-
-BEGIN { $| = 1; print "1..1\n"; }
-END {print "not ok 1\n" unless $loaded;}
-use File::chmod qw( chmod getmod );
-$loaded = 1;
-print "ok 1\n";
-
-######################### End of black magic.
-
-# Insert your test code below (better if it prints "ok 13"
-# (correspondingly "not ok 13") depending on the success of chunk 13
-# of the test code):
-
-printf "original state of chmod.pm: %05o\n", getmod("chmod.pm");
-
-print "calling: chmod('+x', 'chmod.pm')... ";
-chmod("+x","chmod.pm") or warn "couldn't chmod +x chmod.pm: $!";
-printf "chmod.pm: %05o\n", getmod("chmod.pm");
-
-print "calling: chmod('-x', 'chmod.pm')... ";
-chmod("-x","chmod.pm") or warn "couldn't chmod -x chmod.pm: $!";
-printf "chmod.pm: %05o\n", getmod("chmod.pm");