Added Cyg-Win
This commit is contained in:
parent
82cbc206eb
commit
413c315806
10586 changed files with 3806249 additions and 0 deletions
402
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Basename.pm
Normal file
402
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Basename.pm
Normal file
|
|
@ -0,0 +1,402 @@
|
|||
=head1 NAME
|
||||
|
||||
File::Basename - Parse file paths into directory, filename and suffix.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::Basename;
|
||||
|
||||
my ($name, $path, $suffix) = fileparse($fullname, @suffixlist);
|
||||
my $name = fileparse($fullname, @suffixlist);
|
||||
|
||||
my $basename = basename($fullname, @suffixlist);
|
||||
my $dirname = dirname($fullname);
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
These routines allow you to parse file paths into their directory, filename
|
||||
and suffix.
|
||||
|
||||
B<NOTE>: C<dirname()> and C<basename()> emulate the behaviours, and
|
||||
quirks, of the shell and C functions of the same name. See each
|
||||
function's documentation for details. If your concern is just parsing
|
||||
paths it is safer to use L<File::Spec>'s C<splitpath()> and
|
||||
C<splitdir()> methods.
|
||||
|
||||
It is guaranteed that
|
||||
|
||||
# Where $path_separator is / for Unix, \ for Windows, etc...
|
||||
dirname($path) . $path_separator . basename($path);
|
||||
|
||||
is equivalent to the original path for all systems but VMS.
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
package File::Basename;
|
||||
|
||||
# File::Basename is used during the Perl build, when the re extension may
|
||||
# not be available, but we only actually need it if running under tainting.
|
||||
BEGIN {
|
||||
if (${^TAINT}) {
|
||||
require re;
|
||||
re->import('taint');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
use strict;
|
||||
use 5.006;
|
||||
use warnings;
|
||||
our(@ISA, @EXPORT, $VERSION, $Fileparse_fstype, $Fileparse_igncase);
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw(fileparse fileparse_set_fstype basename dirname);
|
||||
$VERSION = "2.86";
|
||||
|
||||
fileparse_set_fstype($^O);
|
||||
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<fileparse>
|
||||
X<fileparse>
|
||||
|
||||
my($filename, $dirs, $suffix) = fileparse($path);
|
||||
my($filename, $dirs, $suffix) = fileparse($path, @suffixes);
|
||||
my $filename = fileparse($path, @suffixes);
|
||||
|
||||
The C<fileparse()> routine divides a file path into its $dirs, $filename
|
||||
and (optionally) the filename $suffix.
|
||||
|
||||
$dirs contains everything up to and including the last
|
||||
directory separator in the $path including the volume (if applicable).
|
||||
The remainder of the $path is the $filename.
|
||||
|
||||
# On Unix returns ("baz", "/foo/bar/", "")
|
||||
fileparse("/foo/bar/baz");
|
||||
|
||||
# On Windows returns ("baz", 'C:\foo\bar\', "")
|
||||
fileparse('C:\foo\bar\baz');
|
||||
|
||||
# On Unix returns ("", "/foo/bar/baz/", "")
|
||||
fileparse("/foo/bar/baz/");
|
||||
|
||||
If @suffixes are given each element is a pattern (either a string or a
|
||||
C<qr//>) matched against the end of the $filename. The matching
|
||||
portion is removed and becomes the $suffix.
|
||||
|
||||
# On Unix returns ("baz", "/foo/bar/", ".txt")
|
||||
fileparse("/foo/bar/baz.txt", qr/\.[^.]*/);
|
||||
|
||||
If type is non-Unix (see L</fileparse_set_fstype>) then the pattern
|
||||
matching for suffix removal is performed case-insensitively, since
|
||||
those systems are not case-sensitive when opening existing files.
|
||||
|
||||
You are guaranteed that C<$dirs . $filename . $suffix> will
|
||||
denote the same location as the original $path.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub fileparse {
|
||||
my($fullname,@suffices) = @_;
|
||||
|
||||
unless (defined $fullname) {
|
||||
require Carp;
|
||||
Carp::croak("fileparse(): need a valid pathname");
|
||||
}
|
||||
|
||||
my $orig_type = '';
|
||||
my($type,$igncase) = ($Fileparse_fstype, $Fileparse_igncase);
|
||||
|
||||
my($taint) = substr($fullname,0,0); # Is $fullname tainted?
|
||||
|
||||
if ($type eq "VMS" and $fullname =~ m{/} ) {
|
||||
# We're doing Unix emulation
|
||||
$orig_type = $type;
|
||||
$type = 'Unix';
|
||||
}
|
||||
|
||||
my($dirpath, $basename);
|
||||
|
||||
if (grep { $type eq $_ } qw(MSDOS DOS MSWin32 Epoc)) {
|
||||
($dirpath,$basename) = ($fullname =~ /^((?:.*[:\\\/])?)(.*)/s);
|
||||
$dirpath .= '.\\' unless $dirpath =~ /[\\\/]\z/;
|
||||
}
|
||||
elsif ($type eq "OS2") {
|
||||
($dirpath,$basename) = ($fullname =~ m#^((?:.*[:\\/])?)(.*)#s);
|
||||
$dirpath = './' unless $dirpath; # Can't be 0
|
||||
$dirpath .= '/' unless $dirpath =~ m#[\\/]\z#;
|
||||
}
|
||||
elsif ($type eq "MacOS") {
|
||||
($dirpath,$basename) = ($fullname =~ /^(.*:)?(.*)/s);
|
||||
$dirpath = ':' unless $dirpath;
|
||||
}
|
||||
elsif ($type eq "AmigaOS") {
|
||||
($dirpath,$basename) = ($fullname =~ /(.*[:\/])?(.*)/s);
|
||||
$dirpath = './' unless $dirpath;
|
||||
}
|
||||
elsif ($type eq 'VMS' ) {
|
||||
($dirpath,$basename) = ($fullname =~ /^(.*[:>\]])?(.*)/s);
|
||||
$dirpath ||= ''; # should always be defined
|
||||
}
|
||||
else { # Default to Unix semantics.
|
||||
($dirpath,$basename) = ($fullname =~ m{^(.*/)?(.*)}s);
|
||||
if ($orig_type eq 'VMS' and $fullname =~ m{^(/[^/]+/000000(/|$))(.*)}) {
|
||||
# dev:[000000] is top of VMS tree, similar to Unix '/'
|
||||
# so strip it off and treat the rest as "normal"
|
||||
my $devspec = $1;
|
||||
my $remainder = $3;
|
||||
($dirpath,$basename) = ($remainder =~ m{^(.*/)?(.*)}s);
|
||||
$dirpath ||= ''; # should always be defined
|
||||
$dirpath = $devspec.$dirpath;
|
||||
}
|
||||
$dirpath = './' unless $dirpath;
|
||||
}
|
||||
|
||||
|
||||
my $tail = '';
|
||||
my $suffix = '';
|
||||
if (@suffices) {
|
||||
foreach $suffix (@suffices) {
|
||||
my $pat = ($igncase ? '(?i)' : '') . "($suffix)\$";
|
||||
if ($basename =~ s/$pat//s) {
|
||||
$taint .= substr($suffix,0,0);
|
||||
$tail = $1 . $tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure taint is propagated from the path to its pieces.
|
||||
$tail .= $taint;
|
||||
wantarray ? ($basename .= $taint, $dirpath .= $taint, $tail)
|
||||
: ($basename .= $taint);
|
||||
}
|
||||
|
||||
|
||||
|
||||
=item C<basename>
|
||||
X<basename> X<filename>
|
||||
|
||||
my $filename = basename($path);
|
||||
my $filename = basename($path, @suffixes);
|
||||
|
||||
This function is provided for compatibility with the Unix shell command
|
||||
C<basename(1)>. It does B<NOT> always return the file name portion of a
|
||||
path as you might expect. To be safe, if you want the file name portion of
|
||||
a path use C<fileparse()>.
|
||||
|
||||
C<basename()> returns the last level of a filepath even if the last
|
||||
level is clearly directory. In effect, it is acting like C<pop()> for
|
||||
paths. This differs from C<fileparse()>'s behaviour.
|
||||
|
||||
# Both return "bar"
|
||||
basename("/foo/bar");
|
||||
basename("/foo/bar/");
|
||||
|
||||
@suffixes work as in C<fileparse()> except all regex metacharacters are
|
||||
quoted.
|
||||
|
||||
# These two function calls are equivalent.
|
||||
my $filename = basename("/foo/bar/baz.txt", ".txt");
|
||||
my $filename = fileparse("/foo/bar/baz.txt", qr/\Q.txt\E/);
|
||||
|
||||
Also note that in order to be compatible with the shell command,
|
||||
C<basename()> does not strip off a suffix if it is identical to the
|
||||
remaining characters in the filename.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub basename {
|
||||
my($path) = shift;
|
||||
|
||||
# From BSD basename(1)
|
||||
# The basename utility deletes any prefix ending with the last slash '/'
|
||||
# character present in string (after first stripping trailing slashes)
|
||||
_strip_trailing_sep($path);
|
||||
|
||||
my($basename, $dirname, $suffix) = fileparse( $path, map("\Q$_\E",@_) );
|
||||
|
||||
# From BSD basename(1)
|
||||
# The suffix is not stripped if it is identical to the remaining
|
||||
# characters in string.
|
||||
if( length $suffix and !length $basename ) {
|
||||
$basename = $suffix;
|
||||
}
|
||||
|
||||
# Ensure that basename '/' == '/'
|
||||
if( !length $basename ) {
|
||||
$basename = $dirname;
|
||||
}
|
||||
|
||||
return $basename;
|
||||
}
|
||||
|
||||
|
||||
|
||||
=item C<dirname>
|
||||
X<dirname>
|
||||
|
||||
This function is provided for compatibility with the Unix shell
|
||||
command C<dirname(1)> and has inherited some of its quirks. In spite of
|
||||
its name it does B<NOT> always return the directory name as you might
|
||||
expect. To be safe, if you want the directory name of a path use
|
||||
C<fileparse()>.
|
||||
|
||||
Only on VMS (where there is no ambiguity between the file and directory
|
||||
portions of a path) and AmigaOS (possibly due to an implementation quirk in
|
||||
this module) does C<dirname()> work like C<fileparse($path)>, returning just the
|
||||
$dirs.
|
||||
|
||||
# On VMS and AmigaOS
|
||||
my $dirs = dirname($path);
|
||||
|
||||
When using Unix or MSDOS syntax this emulates the C<dirname(1)> shell function
|
||||
which is subtly different from how C<fileparse()> works. It returns all but
|
||||
the last level of a file path even if the last level is clearly a directory.
|
||||
In effect, it is not returning the directory portion but simply the path one
|
||||
level up acting like C<chop()> for file paths.
|
||||
|
||||
Also unlike C<fileparse()>, C<dirname()> does not include a trailing slash on
|
||||
its returned path.
|
||||
|
||||
# returns /foo/bar. fileparse() would return /foo/bar/
|
||||
dirname("/foo/bar/baz");
|
||||
|
||||
# also returns /foo/bar despite the fact that baz is clearly a
|
||||
# directory. fileparse() would return /foo/bar/baz/
|
||||
dirname("/foo/bar/baz/");
|
||||
|
||||
# returns '.'. fileparse() would return 'foo/'
|
||||
dirname("foo/");
|
||||
|
||||
Under VMS, if there is no directory information in the $path, then the
|
||||
current default device and directory is used.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
sub dirname {
|
||||
my $path = shift;
|
||||
|
||||
my($type) = $Fileparse_fstype;
|
||||
|
||||
if( $type eq 'VMS' and $path =~ m{/} ) {
|
||||
# Parse as Unix
|
||||
local($File::Basename::Fileparse_fstype) = '';
|
||||
return dirname($path);
|
||||
}
|
||||
|
||||
my($basename, $dirname) = fileparse($path);
|
||||
|
||||
if ($type eq 'VMS') {
|
||||
$dirname ||= $ENV{DEFAULT};
|
||||
}
|
||||
elsif ($type eq 'MacOS') {
|
||||
if( !length($basename) && $dirname !~ /^[^:]+:\z/) {
|
||||
_strip_trailing_sep($dirname);
|
||||
($basename,$dirname) = fileparse $dirname;
|
||||
}
|
||||
$dirname .= ":" unless $dirname =~ /:\z/;
|
||||
}
|
||||
elsif (grep { $type eq $_ } qw(MSDOS DOS MSWin32 OS2)) {
|
||||
_strip_trailing_sep($dirname);
|
||||
unless( length($basename) ) {
|
||||
($basename,$dirname) = fileparse $dirname;
|
||||
_strip_trailing_sep($dirname);
|
||||
}
|
||||
}
|
||||
elsif ($type eq 'AmigaOS') {
|
||||
if ( $dirname =~ /:\z/) { return $dirname }
|
||||
chop $dirname;
|
||||
$dirname =~ s{[^:/]+\z}{} unless length($basename);
|
||||
}
|
||||
else {
|
||||
_strip_trailing_sep($dirname);
|
||||
unless( length($basename) ) {
|
||||
($basename,$dirname) = fileparse $dirname;
|
||||
_strip_trailing_sep($dirname);
|
||||
}
|
||||
}
|
||||
|
||||
$dirname;
|
||||
}
|
||||
|
||||
|
||||
# Strip the trailing path separator.
|
||||
sub _strip_trailing_sep {
|
||||
my $type = $Fileparse_fstype;
|
||||
|
||||
if ($type eq 'MacOS') {
|
||||
$_[0] =~ s/([^:]):\z/$1/s;
|
||||
}
|
||||
elsif (grep { $type eq $_ } qw(MSDOS DOS MSWin32 OS2)) {
|
||||
$_[0] =~ s/([^:])[\\\/]*\z/$1/;
|
||||
}
|
||||
else {
|
||||
$_[0] =~ s{(.)/*\z}{$1}s;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
=item C<fileparse_set_fstype>
|
||||
X<filesystem>
|
||||
|
||||
my $type = fileparse_set_fstype();
|
||||
my $previous_type = fileparse_set_fstype($type);
|
||||
|
||||
Normally File::Basename will assume a file path type native to your current
|
||||
operating system (ie. /foo/bar style on Unix, \foo\bar on Windows, etc...).
|
||||
With this function you can override that assumption.
|
||||
|
||||
Valid $types are "MacOS", "VMS", "AmigaOS", "OS2", "RISCOS",
|
||||
"MSWin32", "DOS" (also "MSDOS" for backwards bug compatibility),
|
||||
"Epoc" and "Unix" (all case-insensitive). If an unrecognized $type is
|
||||
given "Unix" will be assumed.
|
||||
|
||||
If you've selected VMS syntax, and the file specification you pass to
|
||||
one of these routines contains a "/", they assume you are using Unix
|
||||
emulation and apply the Unix syntax rules instead, for that function
|
||||
call only.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
BEGIN {
|
||||
|
||||
my @Ignore_Case = qw(MacOS VMS AmigaOS OS2 RISCOS MSWin32 MSDOS DOS Epoc);
|
||||
my @Types = (@Ignore_Case, qw(Unix));
|
||||
|
||||
sub fileparse_set_fstype {
|
||||
my $old = $Fileparse_fstype;
|
||||
|
||||
if (@_) {
|
||||
my $new_type = shift;
|
||||
|
||||
$Fileparse_fstype = 'Unix'; # default
|
||||
foreach my $type (@Types) {
|
||||
$Fileparse_fstype = $type if $new_type =~ /^$type/i;
|
||||
}
|
||||
|
||||
$Fileparse_igncase =
|
||||
(grep $Fileparse_fstype eq $_, @Ignore_Case) ? 1 : 0;
|
||||
}
|
||||
|
||||
return $old;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<dirname(1)>, L<basename(1)>, L<File::Spec>
|
||||
174
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Compare.pm
Normal file
174
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Compare.pm
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
package File::Compare 1.1008;
|
||||
|
||||
use v5.12;
|
||||
use warnings;
|
||||
|
||||
use Exporter 'import';
|
||||
|
||||
our @EXPORT = qw(compare);
|
||||
our @EXPORT_OK = qw(cmp compare_text);
|
||||
|
||||
our $Too_Big = 1024 * 1024 * 2;
|
||||
|
||||
sub croak {
|
||||
require Carp;
|
||||
goto &Carp::croak;
|
||||
}
|
||||
|
||||
sub compare {
|
||||
croak("Usage: compare( file1, file2 [, buffersize]) ")
|
||||
unless(@_ == 2 || @_ == 3);
|
||||
|
||||
my ($from, $to, $size) = @_;
|
||||
my $text_mode = defined($size) && (ref($size) eq 'CODE' || $size < 0);
|
||||
|
||||
my ($fromsize, $closefrom, $closeto);
|
||||
local (*FROM, *TO);
|
||||
|
||||
croak("from undefined") unless (defined $from);
|
||||
croak("to undefined") unless (defined $to);
|
||||
|
||||
if (ref($from) &&
|
||||
(UNIVERSAL::isa($from, 'GLOB') || UNIVERSAL::isa($from, 'IO::Handle'))) {
|
||||
*FROM = *$from;
|
||||
} elsif (ref(\$from) eq 'GLOB') {
|
||||
*FROM = $from;
|
||||
} else {
|
||||
open(FROM, '<', $from) or goto fail_open1;
|
||||
unless ($text_mode) {
|
||||
binmode FROM;
|
||||
$fromsize = -s FROM;
|
||||
}
|
||||
$closefrom = 1;
|
||||
}
|
||||
|
||||
if (ref($to) &&
|
||||
(UNIVERSAL::isa($to, 'GLOB') || UNIVERSAL::isa($to, 'IO::Handle'))) {
|
||||
*TO = *$to;
|
||||
} elsif (ref(\$to) eq 'GLOB') {
|
||||
*TO = $to;
|
||||
} else {
|
||||
open(TO, '<', $to) or goto fail_open2;
|
||||
binmode TO unless $text_mode;
|
||||
$closeto = 1;
|
||||
}
|
||||
|
||||
if (!$text_mode && $closefrom && $closeto) {
|
||||
# If both are opened files we know they differ if their size differ
|
||||
goto fail_inner if $fromsize != -s TO;
|
||||
}
|
||||
|
||||
if ($text_mode) {
|
||||
local $/ = "\n";
|
||||
my ($fline, $tline);
|
||||
while (defined($fline = <FROM>)) {
|
||||
goto fail_inner unless defined($tline = <TO>);
|
||||
if (ref $size) {
|
||||
# $size contains ref to comparison function
|
||||
goto fail_inner if &$size($fline, $tline);
|
||||
} else {
|
||||
goto fail_inner if $fline ne $tline;
|
||||
}
|
||||
}
|
||||
goto fail_inner if defined($tline = <TO>);
|
||||
}
|
||||
else {
|
||||
unless (defined($size) && $size > 0) {
|
||||
$size = $fromsize || -s TO || 0;
|
||||
$size = 1024 if $size < 512;
|
||||
$size = $Too_Big if $size > $Too_Big;
|
||||
}
|
||||
|
||||
my ($fr, $tr, $fbuf, $tbuf);
|
||||
$fbuf = $tbuf = '';
|
||||
while(defined($fr = read(FROM, $fbuf, $size)) && $fr > 0) {
|
||||
unless (defined($tr = read(TO, $tbuf, $fr)) && $tbuf eq $fbuf) {
|
||||
goto fail_inner;
|
||||
}
|
||||
}
|
||||
goto fail_inner if defined($tr = read(TO, $tbuf, $size)) && $tr > 0;
|
||||
}
|
||||
|
||||
close(TO) || goto fail_open2 if $closeto;
|
||||
close(FROM) || goto fail_open1 if $closefrom;
|
||||
|
||||
return 0;
|
||||
|
||||
# All of these contortions try to preserve error messages...
|
||||
fail_inner:
|
||||
close(TO) || goto fail_open2 if $closeto;
|
||||
close(FROM) || goto fail_open1 if $closefrom;
|
||||
|
||||
return 1;
|
||||
|
||||
fail_open2:
|
||||
if ($closefrom) {
|
||||
my $status = $!;
|
||||
$! = 0;
|
||||
close FROM;
|
||||
$! = $status unless $!;
|
||||
}
|
||||
fail_open1:
|
||||
return -1;
|
||||
}
|
||||
|
||||
sub cmp;
|
||||
*cmp = \&compare;
|
||||
|
||||
sub compare_text {
|
||||
my ($from, $to, $cmp) = @_;
|
||||
croak("Usage: compare_text( file1, file2 [, cmp-function])")
|
||||
unless @_ == 2 || @_ == 3;
|
||||
croak("Third arg to compare_text() function must be a code reference")
|
||||
if @_ == 3 && ref($cmp) ne 'CODE';
|
||||
|
||||
# Using a negative buffer size puts compare into text_mode too
|
||||
compare($from, $to, $cmp // -1);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
File::Compare - Compare files or filehandles
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::Compare;
|
||||
|
||||
if (compare("file1", "file2") == 0) {
|
||||
print "They're equal\n";
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The C<File::Compare::compare> function compares the contents of two
|
||||
sources, each of which can be a file or a file handle. It is exported
|
||||
from C<File::Compare> by default.
|
||||
|
||||
C<File::Compare::cmp> is a synonym for C<File::Compare::compare>. It is
|
||||
exported from C<File::Compare> only by request.
|
||||
|
||||
C<File::Compare::compare_text> does a line by line comparison of the two
|
||||
files. It stops as soon as a difference is detected. C<compare_text()>
|
||||
accepts an optional third argument: This must be a CODE reference to
|
||||
a line comparison function, which returns C<0> when both lines are considered
|
||||
equal. For example:
|
||||
|
||||
compare_text($file1, $file2)
|
||||
|
||||
is basically equivalent to
|
||||
|
||||
compare_text($file1, $file2, sub {$_[0] ne $_[1]} )
|
||||
|
||||
=head1 RETURN
|
||||
|
||||
C<File::Compare::compare> and its sibling functions return C<0> if the files
|
||||
are equal, C<1> if the files are unequal, or C<-1> if an error was encountered.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
C<File::Compare> was written by Nick Ing-Simmons.
|
||||
Its original documentation was written by Chip Salzenberg.
|
||||
513
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Copy.pm
Normal file
513
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Copy.pm
Normal file
|
|
@ -0,0 +1,513 @@
|
|||
# File/Copy.pm. Written in 1994 by Aaron Sherman <ajs@ajs.com>. This
|
||||
# source code has been placed in the public domain by the author.
|
||||
# Please be kind and preserve the documentation.
|
||||
#
|
||||
# Additions copyright 1996 by Charles Bailey. Permission is granted
|
||||
# to distribute the revised code under the same terms as Perl itself.
|
||||
|
||||
package File::Copy;
|
||||
|
||||
use 5.035007;
|
||||
use strict;
|
||||
use warnings; no warnings 'newline';
|
||||
no warnings 'experimental::builtin';
|
||||
use builtin 'blessed';
|
||||
use overload;
|
||||
use File::Spec;
|
||||
use Config;
|
||||
# We want HiRes stat and utime if available
|
||||
BEGIN { eval q{ use Time::HiRes qw( stat utime ) } };
|
||||
our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
|
||||
sub copy;
|
||||
sub syscopy;
|
||||
sub cp;
|
||||
sub mv;
|
||||
|
||||
$VERSION = '2.41';
|
||||
|
||||
require Exporter;
|
||||
@ISA = qw(Exporter);
|
||||
@EXPORT = qw(copy move);
|
||||
@EXPORT_OK = qw(cp mv);
|
||||
|
||||
$Too_Big = 1024 * 1024 * 2;
|
||||
|
||||
sub croak {
|
||||
require Carp;
|
||||
goto &Carp::croak;
|
||||
}
|
||||
|
||||
sub carp {
|
||||
require Carp;
|
||||
goto &Carp::carp;
|
||||
}
|
||||
|
||||
sub _catname {
|
||||
my($from, $to) = @_;
|
||||
if (not defined &basename) {
|
||||
require File::Basename;
|
||||
File::Basename->import( 'basename' );
|
||||
}
|
||||
|
||||
return File::Spec->catfile($to, basename($from));
|
||||
}
|
||||
|
||||
# _eq($from, $to) tells whether $from and $to are identical
|
||||
sub _eq {
|
||||
my ($from, $to) = map {
|
||||
blessed($_) && overload::Method($_, q{""})
|
||||
? "$_"
|
||||
: $_
|
||||
} (@_);
|
||||
return '' if ( (ref $from) xor (ref $to) );
|
||||
return $from == $to if ref $from;
|
||||
return $from eq $to;
|
||||
}
|
||||
|
||||
sub copy {
|
||||
croak("Usage: copy(FROM, TO [, BUFFERSIZE]) ")
|
||||
unless(@_ == 2 || @_ == 3);
|
||||
|
||||
my $from = shift;
|
||||
my $to = shift;
|
||||
|
||||
my $size;
|
||||
if (@_) {
|
||||
$size = shift(@_) + 0;
|
||||
croak("Bad buffer size for copy: $size\n") unless ($size > 0);
|
||||
}
|
||||
|
||||
my $from_a_handle = (ref($from)
|
||||
? (ref($from) eq 'GLOB'
|
||||
|| UNIVERSAL::isa($from, 'GLOB')
|
||||
|| UNIVERSAL::isa($from, 'IO::Handle'))
|
||||
: (ref(\$from) eq 'GLOB'));
|
||||
my $to_a_handle = (ref($to)
|
||||
? (ref($to) eq 'GLOB'
|
||||
|| UNIVERSAL::isa($to, 'GLOB')
|
||||
|| UNIVERSAL::isa($to, 'IO::Handle'))
|
||||
: (ref(\$to) eq 'GLOB'));
|
||||
|
||||
if (_eq($from, $to)) { # works for references, too
|
||||
carp("'$from' and '$to' are identical (not copied)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$from_a_handle && !$to_a_handle && -d $to && ! -d $from) {
|
||||
$to = _catname($from, $to);
|
||||
}
|
||||
|
||||
if ((($Config{d_symlink} && $Config{d_readlink}) || $Config{d_link}) &&
|
||||
!($^O eq 'os2')) {
|
||||
my @fs = stat($from);
|
||||
if (@fs) {
|
||||
my @ts = stat($to);
|
||||
if (@ts && $fs[0] == $ts[0] && $fs[1] eq $ts[1] && !-p $from) {
|
||||
carp("'$from' and '$to' are identical (not copied)");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif (_eq($from, $to)) {
|
||||
carp("'$from' and '$to' are identical (not copied)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (defined &syscopy && !$Syscopy_is_copy
|
||||
&& !$to_a_handle
|
||||
&& !($from_a_handle && $^O eq 'os2' ) # OS/2 cannot handle handles
|
||||
&& !($from_a_handle && $^O eq 'MSWin32')
|
||||
)
|
||||
{
|
||||
if ($^O eq 'VMS' && -e $from
|
||||
&& ! -d $to && ! -d $from) {
|
||||
|
||||
# VMS natively inherits path components from the source of a
|
||||
# copy, but we want the Unixy behavior of inheriting from
|
||||
# the current working directory. Also, default in a trailing
|
||||
# dot for null file types.
|
||||
|
||||
$to = VMS::Filespec::rmsexpand(VMS::Filespec::vmsify($to), '.');
|
||||
|
||||
# Get rid of the old versions to be like UNIX
|
||||
1 while unlink $to;
|
||||
}
|
||||
|
||||
return syscopy($from, $to) || 0;
|
||||
}
|
||||
|
||||
my $closefrom = 0;
|
||||
my $closeto = 0;
|
||||
my ($status, $r, $buf);
|
||||
local($\) = '';
|
||||
|
||||
my $from_h;
|
||||
if ($from_a_handle) {
|
||||
$from_h = $from;
|
||||
} else {
|
||||
open $from_h, "<", $from or goto fail_open1;
|
||||
binmode $from_h or die "($!,$^E)";
|
||||
$closefrom = 1;
|
||||
}
|
||||
|
||||
# Seems most logical to do this here, in case future changes would want to
|
||||
# make this croak for some reason.
|
||||
unless (defined $size) {
|
||||
$size = tied(*$from_h) ? 0 : -s $from_h || 0;
|
||||
$size = 1024 if ($size < 512);
|
||||
$size = $Too_Big if ($size > $Too_Big);
|
||||
}
|
||||
|
||||
my $to_h;
|
||||
if ($to_a_handle) {
|
||||
$to_h = $to;
|
||||
} else {
|
||||
$to_h = \do { local *FH }; # XXX is this line obsolete?
|
||||
open $to_h, ">", $to or goto fail_open2;
|
||||
binmode $to_h or die "($!,$^E)";
|
||||
$closeto = 1;
|
||||
}
|
||||
|
||||
$! = 0;
|
||||
for (;;) {
|
||||
my ($r, $w, $t);
|
||||
defined($r = sysread($from_h, $buf, $size))
|
||||
or goto fail_inner;
|
||||
last unless $r;
|
||||
for ($w = 0; $w < $r; $w += $t) {
|
||||
$t = syswrite($to_h, $buf, $r - $w, $w)
|
||||
or goto fail_inner;
|
||||
}
|
||||
}
|
||||
|
||||
close($to_h) || goto fail_open2 if $closeto;
|
||||
close($from_h) || goto fail_open1 if $closefrom;
|
||||
|
||||
# Use this idiom to avoid uninitialized value warning.
|
||||
return 1;
|
||||
|
||||
# All of these contortions try to preserve error messages...
|
||||
fail_inner:
|
||||
if ($closeto) {
|
||||
$status = $!;
|
||||
$! = 0;
|
||||
close $to_h;
|
||||
$! = $status unless $!;
|
||||
}
|
||||
fail_open2:
|
||||
if ($closefrom) {
|
||||
$status = $!;
|
||||
$! = 0;
|
||||
close $from_h;
|
||||
$! = $status unless $!;
|
||||
}
|
||||
fail_open1:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub cp {
|
||||
my($from,$to) = @_;
|
||||
my(@fromstat) = stat $from;
|
||||
my(@tostat) = stat $to;
|
||||
my $perm;
|
||||
|
||||
return 0 unless copy(@_) and @fromstat;
|
||||
|
||||
if (@tostat) {
|
||||
$perm = $tostat[2];
|
||||
} else {
|
||||
$perm = $fromstat[2] & ~(umask || 0);
|
||||
@tostat = stat $to;
|
||||
}
|
||||
# Might be more robust to look for S_I* in Fcntl, but we're
|
||||
# trying to avoid dependence on any XS-containing modules,
|
||||
# since File::Copy is used during the Perl build.
|
||||
$perm &= 07777;
|
||||
if ($perm & 06000) {
|
||||
croak("Unable to check setuid/setgid permissions for $to: $!")
|
||||
unless @tostat;
|
||||
|
||||
if ($perm & 04000 and # setuid
|
||||
$fromstat[4] != $tostat[4]) { # owner must match
|
||||
$perm &= ~06000;
|
||||
}
|
||||
|
||||
if ($perm & 02000 && $> != 0) { # if not root, setgid
|
||||
my $ok = $fromstat[5] == $tostat[5]; # group must match
|
||||
if ($ok) { # and we must be in group
|
||||
$ok = grep { $_ == $fromstat[5] } split /\s+/, $)
|
||||
}
|
||||
$perm &= ~06000 unless $ok;
|
||||
}
|
||||
}
|
||||
return 0 unless @tostat;
|
||||
return 1 if $perm == ($tostat[2] & 07777);
|
||||
return eval { chmod $perm, $to; } ? 1 : 0;
|
||||
}
|
||||
|
||||
sub _move {
|
||||
croak("Usage: move(FROM, TO) ") unless @_ == 3;
|
||||
|
||||
my($from,$to,$fallback) = @_;
|
||||
|
||||
my($fromsz,$tosz1,$tomt1,$tosz2,$tomt2,$sts,$ossts);
|
||||
|
||||
if (-d $to && ! -d $from) {
|
||||
$to = _catname($from, $to);
|
||||
}
|
||||
|
||||
($tosz1,$tomt1) = (stat($to))[7,9];
|
||||
$fromsz = -s $from;
|
||||
if ($^O eq 'os2' and defined $tosz1 and defined $fromsz) {
|
||||
# will not rename with overwrite
|
||||
unlink $to;
|
||||
}
|
||||
|
||||
if ($^O eq 'VMS' && -e $from
|
||||
&& ! -d $to && ! -d $from) {
|
||||
|
||||
# VMS natively inherits path components from the source of a
|
||||
# copy, but we want the Unixy behavior of inheriting from
|
||||
# the current working directory. Also, default in a trailing
|
||||
# dot for null file types.
|
||||
|
||||
$to = VMS::Filespec::rmsexpand(VMS::Filespec::vmsify($to), '.');
|
||||
|
||||
# Get rid of the old versions to be like UNIX
|
||||
1 while unlink $to;
|
||||
}
|
||||
|
||||
return 1 if rename $from, $to;
|
||||
|
||||
# Did rename return an error even though it succeeded, because $to
|
||||
# is on a remote NFS file system, and NFS lost the server's ack?
|
||||
return 1 if defined($fromsz) && !-e $from && # $from disappeared
|
||||
(($tosz2,$tomt2) = (stat($to))[7,9]) && # $to's there
|
||||
((!defined $tosz1) || # not before or
|
||||
($tosz1 != $tosz2 or $tomt1 != $tomt2)) && # was changed
|
||||
$tosz2 == $fromsz; # it's all there
|
||||
|
||||
($tosz1,$tomt1) = (stat($to))[7,9]; # just in case rename did something
|
||||
|
||||
{
|
||||
local $@;
|
||||
eval {
|
||||
local $SIG{__DIE__};
|
||||
$fallback->($from,$to) or die;
|
||||
my($atime, $mtime) = (stat($from))[8,9];
|
||||
utime($atime, $mtime, $to);
|
||||
unlink($from) or die;
|
||||
};
|
||||
return 1 unless $@;
|
||||
}
|
||||
($sts,$ossts) = ($! + 0, $^E + 0);
|
||||
|
||||
($tosz2,$tomt2) = ((stat($to))[7,9],0,0) if defined $tomt1;
|
||||
unlink($to) if !defined($tomt1) or $tomt1 != $tomt2 or $tosz1 != $tosz2;
|
||||
($!,$^E) = ($sts,$ossts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub move { _move(@_,\©); }
|
||||
sub mv { _move(@_,\&cp); }
|
||||
|
||||
# &syscopy is an XSUB under OS/2
|
||||
unless (defined &syscopy) {
|
||||
if ($^O eq 'VMS') {
|
||||
*syscopy = \&rmscopy;
|
||||
} elsif ($^O eq 'MSWin32' && defined &DynaLoader::boot_DynaLoader) {
|
||||
# Win32::CopyFile() fill only work if we can load Win32.xs
|
||||
*syscopy = sub {
|
||||
return 0 unless @_ == 2;
|
||||
return Win32::CopyFile(@_, 1);
|
||||
};
|
||||
} else {
|
||||
$Syscopy_is_copy = 1;
|
||||
*syscopy = \©
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
File::Copy - Copy files or filehandles
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::Copy;
|
||||
|
||||
copy("sourcefile", "destinationfile") or die "Copy failed: $!";
|
||||
copy("Copy.pm", \*STDOUT);
|
||||
move("/dev1/sourcefile", "/dev2/destinationfile");
|
||||
|
||||
use File::Copy "cp";
|
||||
|
||||
my $n = FileHandle->new("/a/file", "r");
|
||||
cp($n, "x");
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The File::Copy module provides two basic functions, C<copy> and
|
||||
C<move>, which are useful for getting the contents of a file from
|
||||
one place to another.
|
||||
|
||||
=over 4
|
||||
|
||||
=item copy
|
||||
X<copy> X<cp>
|
||||
|
||||
The C<copy> function takes two
|
||||
parameters: a file to copy from and a file to copy to. Either
|
||||
argument may be a string, a FileHandle reference or a FileHandle
|
||||
glob. Obviously, if the first argument is a filehandle of some
|
||||
sort, it will be read from, and if it is a file I<name> it will
|
||||
be opened for reading. Likewise, the second argument will be
|
||||
written to. If the second argument does not exist but the parent
|
||||
directory does exist, then it will be created. Trying to copy
|
||||
a file into a non-existent directory is an error.
|
||||
Trying to copy a file on top of itself is also an error.
|
||||
C<copy> will not overwrite read-only files.
|
||||
|
||||
If the destination (second argument) already exists and is a directory,
|
||||
and the source (first argument) is not a filehandle, then the source
|
||||
file will be copied into the directory specified by the destination,
|
||||
using the same base name as the source file. It's a failure to have a
|
||||
filehandle as the source when the destination is a directory.
|
||||
|
||||
B<Note that passing in
|
||||
files as handles instead of names may lead to loss of information
|
||||
on some operating systems; it is recommended that you use file
|
||||
names whenever possible.> Files are opened in binary mode where
|
||||
applicable. To get a consistent behaviour when copying from a
|
||||
filehandle to a file, use C<binmode> on the filehandle.
|
||||
|
||||
An optional third parameter can be used to specify the buffer
|
||||
size used for copying. This is the number of bytes from the
|
||||
first file, that will be held in memory at any given time, before
|
||||
being written to the second file. The default buffer size depends
|
||||
upon the file, but will generally be the whole file (up to 2MB), or
|
||||
1k for filehandles that do not reference files (eg. sockets).
|
||||
|
||||
You may use the syntax C<use File::Copy "cp"> to get at the C<cp>
|
||||
alias for this function. The syntax is I<exactly> the same. The
|
||||
behavior is nearly the same as well: as of version 2.15, C<cp> will
|
||||
preserve the source file's permission bits like the shell utility
|
||||
C<cp(1)> would do with default options, while C<copy> uses the default
|
||||
permissions for the target file (which may depend on the process'
|
||||
C<umask>, file ownership, inherited ACLs, etc.). That is, if the
|
||||
destination file already exists, C<cp> will leave its permissions
|
||||
unchanged; otherwise the permissions are taken from the source file
|
||||
and modified by the C<umask>. If an error occurs in setting
|
||||
permissions, C<cp> will return 0, regardless of whether the file was
|
||||
successfully copied.
|
||||
|
||||
=item move
|
||||
X<move> X<mv> X<rename>
|
||||
|
||||
The C<move> function also takes two parameters: the current name
|
||||
and the intended name of the file to be moved. If the destination
|
||||
already exists and is a directory, and the source is not a
|
||||
directory, then the source file will be renamed into the directory
|
||||
specified by the destination.
|
||||
|
||||
If possible, move() will simply rename the file. Otherwise, it copies
|
||||
the file to the new location and deletes the original. If an error occurs
|
||||
during this copy-and-delete process, you may be left with a (possibly partial)
|
||||
copy of the file under the destination name.
|
||||
|
||||
You may use the C<mv> alias for this function in the same way that
|
||||
you may use the C<cp> alias for C<copy>.
|
||||
|
||||
=item syscopy
|
||||
X<syscopy>
|
||||
|
||||
File::Copy also provides the C<syscopy> routine, which copies the
|
||||
file specified in the first parameter to the file specified in the
|
||||
second parameter, preserving OS-specific attributes and file
|
||||
structure. For Unix systems, this is equivalent to the simple
|
||||
C<copy> routine, which doesn't preserve OS-specific attributes. For
|
||||
VMS systems, this calls the C<rmscopy> routine (see below). For OS/2
|
||||
systems, this calls the C<syscopy> XSUB directly. For Win32 systems,
|
||||
this calls C<Win32::CopyFile>.
|
||||
|
||||
B<Special behaviour if C<syscopy> is defined (OS/2, VMS and Win32)>:
|
||||
|
||||
If both arguments to C<copy> are not file handles,
|
||||
then C<copy> will perform a "system copy" of
|
||||
the input file to a new output file, in order to preserve file
|
||||
attributes, indexed file structure, I<etc.> The buffer size
|
||||
parameter is ignored. If either argument to C<copy> is a
|
||||
handle to an opened file, then data is copied using Perl
|
||||
operators, and no effort is made to preserve file attributes
|
||||
or record structure.
|
||||
|
||||
The system copy routine may also be called directly under VMS and OS/2
|
||||
as C<File::Copy::syscopy> (or under VMS as C<File::Copy::rmscopy>, which
|
||||
is the routine that does the actual work for syscopy).
|
||||
|
||||
=item rmscopy($from,$to[,$date_flag])
|
||||
X<rmscopy>
|
||||
|
||||
The first and second arguments may be strings, typeglobs, typeglob
|
||||
references, or objects inheriting from IO::Handle;
|
||||
they are used in all cases to obtain the
|
||||
I<filespec> of the input and output files, respectively. The
|
||||
name and type of the input file are used as defaults for the
|
||||
output file, if necessary.
|
||||
|
||||
A new version of the output file is always created, which
|
||||
inherits the structure and RMS attributes of the input file,
|
||||
except for owner and protections (and possibly timestamps;
|
||||
see below). All data from the input file is copied to the
|
||||
output file; if either of the first two parameters to C<rmscopy>
|
||||
is a file handle, its position is unchanged. (Note that this
|
||||
means a file handle pointing to the output file will be
|
||||
associated with an old version of that file after C<rmscopy>
|
||||
returns, not the newly created version.)
|
||||
|
||||
The third parameter is an integer flag, which tells C<rmscopy>
|
||||
how to handle timestamps. If it is E<lt> 0, none of the input file's
|
||||
timestamps are propagated to the output file. If it is E<gt> 0, then
|
||||
it is interpreted as a bitmask: if bit 0 (the LSB) is set, then
|
||||
timestamps other than the revision date are propagated; if bit 1
|
||||
is set, the revision date is propagated. If the third parameter
|
||||
to C<rmscopy> is 0, then it behaves much like the DCL COPY command:
|
||||
if the name or type of the output file was explicitly specified,
|
||||
then no timestamps are propagated, but if they were taken implicitly
|
||||
from the input filespec, then all timestamps other than the
|
||||
revision date are propagated. If this parameter is not supplied,
|
||||
it defaults to 0.
|
||||
|
||||
C<rmscopy> is VMS specific and cannot be exported; it must be
|
||||
referenced by its full name, e.g.:
|
||||
|
||||
File::Copy::rmscopy($from, $to) or die $!;
|
||||
|
||||
Like C<copy>, C<rmscopy> returns 1 on success. If an error occurs,
|
||||
it sets C<$!>, deletes the output file, and returns 0.
|
||||
|
||||
=back
|
||||
|
||||
=head1 RETURN
|
||||
|
||||
All functions return 1 on success, 0 on failure.
|
||||
$! will be set if an error was encountered.
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Before calling copy() or move() on a filehandle, the caller should
|
||||
close or flush() the file to avoid writes being lost. Note that this
|
||||
is the case even for move(), because it may actually copy the file,
|
||||
depending on the OS-specific implementation, and the underlying
|
||||
filesystem(s).
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
File::Copy was written by Aaron Sherman I<E<lt>ajs@ajs.comE<gt>> in 1995,
|
||||
and updated by Charles Bailey I<E<lt>bailey@newman.upenn.eduE<gt>> in 1996.
|
||||
|
||||
=cut
|
||||
|
||||
1738
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Fetch.pm
Normal file
1738
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Fetch.pm
Normal file
File diff suppressed because it is too large
Load diff
1124
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Find.pm
Normal file
1124
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Find.pm
Normal file
File diff suppressed because it is too large
Load diff
679
Agent-Windows/OGP64/usr/share/perl5/5.40/File/GlobMapper.pm
Normal file
679
Agent-Windows/OGP64/usr/share/perl5/5.40/File/GlobMapper.pm
Normal file
|
|
@ -0,0 +1,679 @@
|
|||
package File::GlobMapper;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp;
|
||||
|
||||
our ($CSH_GLOB);
|
||||
|
||||
BEGIN
|
||||
{
|
||||
if ($] < 5.006)
|
||||
{
|
||||
require File::BSDGlob; File::BSDGlob->import(':glob');
|
||||
$CSH_GLOB = File::BSDGlob::GLOB_CSH();
|
||||
*globber = \&File::BSDGlob::csh_glob;
|
||||
}
|
||||
else
|
||||
{
|
||||
require File::Glob; File::Glob->import(':glob');
|
||||
$CSH_GLOB = File::Glob::GLOB_CSH();
|
||||
#*globber = \&File::Glob::bsd_glob;
|
||||
*globber = \&File::Glob::csh_glob;
|
||||
}
|
||||
}
|
||||
|
||||
our ($Error);
|
||||
|
||||
our ($VERSION, @EXPORT_OK);
|
||||
$VERSION = '1.001';
|
||||
@EXPORT_OK = qw( globmap );
|
||||
|
||||
|
||||
our ($noPreBS, $metachars, $matchMetaRE, %mapping, %wildCount);
|
||||
$noPreBS = '(?<!\\\)' ; # no preceding backslash
|
||||
$metachars = '.*?[](){}';
|
||||
$matchMetaRE = '[' . quotemeta($metachars) . ']';
|
||||
|
||||
%mapping = (
|
||||
'*' => '([^/]*)',
|
||||
'?' => '([^/])',
|
||||
'.' => '\.',
|
||||
'[' => '([',
|
||||
'(' => '(',
|
||||
')' => ')',
|
||||
);
|
||||
|
||||
%wildCount = map { $_ => 1 } qw/ * ? . { ( [ /;
|
||||
|
||||
sub globmap ($$;)
|
||||
{
|
||||
my $inputGlob = shift ;
|
||||
my $outputGlob = shift ;
|
||||
|
||||
my $obj = File::GlobMapper->new($inputGlob, $outputGlob, @_)
|
||||
or croak "globmap: $Error" ;
|
||||
return $obj->getFileMap();
|
||||
}
|
||||
|
||||
sub new
|
||||
{
|
||||
my $class = shift ;
|
||||
my $inputGlob = shift ;
|
||||
my $outputGlob = shift ;
|
||||
# TODO -- flags needs to default to whatever File::Glob does
|
||||
my $flags = shift || $CSH_GLOB ;
|
||||
#my $flags = shift ;
|
||||
|
||||
$inputGlob =~ s/^\s*\<\s*//;
|
||||
$inputGlob =~ s/\s*\>\s*$//;
|
||||
|
||||
$outputGlob =~ s/^\s*\<\s*//;
|
||||
$outputGlob =~ s/\s*\>\s*$//;
|
||||
|
||||
my %object =
|
||||
( InputGlob => $inputGlob,
|
||||
OutputGlob => $outputGlob,
|
||||
GlobFlags => $flags,
|
||||
Braces => 0,
|
||||
WildCount => 0,
|
||||
Pairs => [],
|
||||
Sigil => '#',
|
||||
);
|
||||
|
||||
my $self = bless \%object, ref($class) || $class ;
|
||||
|
||||
$self->_parseInputGlob()
|
||||
or return undef ;
|
||||
|
||||
$self->_parseOutputGlob()
|
||||
or return undef ;
|
||||
|
||||
my @inputFiles = globber($self->{InputGlob}, $flags) ;
|
||||
|
||||
if (GLOB_ERROR)
|
||||
{
|
||||
$Error = $!;
|
||||
return undef ;
|
||||
}
|
||||
|
||||
#if (whatever)
|
||||
{
|
||||
my $missing = grep { ! -e $_ } @inputFiles ;
|
||||
|
||||
if ($missing)
|
||||
{
|
||||
$Error = "$missing input files do not exist";
|
||||
return undef ;
|
||||
}
|
||||
}
|
||||
|
||||
$self->{InputFiles} = \@inputFiles ;
|
||||
|
||||
$self->_getFiles()
|
||||
or return undef ;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub _retError
|
||||
{
|
||||
my $string = shift ;
|
||||
$Error = "$string in input fileglob" ;
|
||||
return undef ;
|
||||
}
|
||||
|
||||
sub _unmatched
|
||||
{
|
||||
my $delimeter = shift ;
|
||||
|
||||
_retError("Unmatched $delimeter");
|
||||
return undef ;
|
||||
}
|
||||
|
||||
sub _parseBit
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
my $string = shift ;
|
||||
|
||||
my $out = '';
|
||||
my $depth = 0 ;
|
||||
|
||||
while ($string =~ s/(.*?)$noPreBS(,|$matchMetaRE)//)
|
||||
{
|
||||
$out .= quotemeta($1) ;
|
||||
$out .= $mapping{$2} if defined $mapping{$2};
|
||||
|
||||
++ $self->{WildCount} if $wildCount{$2} ;
|
||||
|
||||
if ($2 eq ',')
|
||||
{
|
||||
return _unmatched("(")
|
||||
if $depth ;
|
||||
|
||||
$out .= '|';
|
||||
}
|
||||
elsif ($2 eq '(')
|
||||
{
|
||||
++ $depth ;
|
||||
}
|
||||
elsif ($2 eq ')')
|
||||
{
|
||||
return _unmatched(")")
|
||||
if ! $depth ;
|
||||
|
||||
-- $depth ;
|
||||
}
|
||||
elsif ($2 eq '[')
|
||||
{
|
||||
# TODO -- quotemeta & check no '/'
|
||||
# TODO -- check for \] & other \ within the []
|
||||
$string =~ s#(.*?\])##
|
||||
or return _unmatched("[");
|
||||
$out .= "$1)" ;
|
||||
}
|
||||
elsif ($2 eq ']')
|
||||
{
|
||||
return _unmatched("]");
|
||||
}
|
||||
elsif ($2 eq '{' || $2 eq '}')
|
||||
{
|
||||
return _retError("Nested {} not allowed");
|
||||
}
|
||||
}
|
||||
|
||||
$out .= quotemeta $string;
|
||||
|
||||
return _unmatched("(")
|
||||
if $depth ;
|
||||
|
||||
return $out ;
|
||||
}
|
||||
|
||||
sub _parseInputGlob
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
my $string = $self->{InputGlob} ;
|
||||
my $inGlob = '';
|
||||
|
||||
# Multiple concatenated *'s don't make sense
|
||||
#$string =~ s#\*\*+#*# ;
|
||||
|
||||
# TODO -- Allow space to delimit patterns?
|
||||
#my @strings = split /\s+/, $string ;
|
||||
#for my $str (@strings)
|
||||
my $out = '';
|
||||
my $depth = 0 ;
|
||||
|
||||
while ($string =~ s/(.*?)$noPreBS($matchMetaRE)//)
|
||||
{
|
||||
$out .= quotemeta($1) ;
|
||||
$out .= $mapping{$2} if defined $mapping{$2};
|
||||
++ $self->{WildCount} if $wildCount{$2} ;
|
||||
|
||||
if ($2 eq '(')
|
||||
{
|
||||
++ $depth ;
|
||||
}
|
||||
elsif ($2 eq ')')
|
||||
{
|
||||
return _unmatched(")")
|
||||
if ! $depth ;
|
||||
|
||||
-- $depth ;
|
||||
}
|
||||
elsif ($2 eq '[')
|
||||
{
|
||||
# TODO -- quotemeta & check no '/' or '(' or ')'
|
||||
# TODO -- check for \] & other \ within the []
|
||||
$string =~ s#(.*?\])##
|
||||
or return _unmatched("[");
|
||||
$out .= "$1)" ;
|
||||
}
|
||||
elsif ($2 eq ']')
|
||||
{
|
||||
return _unmatched("]");
|
||||
}
|
||||
elsif ($2 eq '}')
|
||||
{
|
||||
return _unmatched("}");
|
||||
}
|
||||
elsif ($2 eq '{')
|
||||
{
|
||||
# TODO -- check no '/' within the {}
|
||||
# TODO -- check for \} & other \ within the {}
|
||||
|
||||
my $tmp ;
|
||||
unless ( $string =~ s/(.*?)$noPreBS\}//)
|
||||
{
|
||||
return _unmatched("{");
|
||||
}
|
||||
#$string =~ s#(.*?)\}##;
|
||||
|
||||
#my $alt = join '|',
|
||||
# map { quotemeta $_ }
|
||||
# split "$noPreBS,", $1 ;
|
||||
my $alt = $self->_parseBit($1);
|
||||
defined $alt or return 0 ;
|
||||
$out .= "($alt)" ;
|
||||
|
||||
++ $self->{Braces} ;
|
||||
}
|
||||
}
|
||||
|
||||
return _unmatched("(")
|
||||
if $depth ;
|
||||
|
||||
$out .= quotemeta $string ;
|
||||
|
||||
|
||||
$self->{InputGlob} =~ s/$noPreBS[\(\)]//g;
|
||||
$self->{InputPattern} = $out ;
|
||||
|
||||
#print "# INPUT '$self->{InputGlob}' => '$out'\n";
|
||||
|
||||
return 1 ;
|
||||
|
||||
}
|
||||
|
||||
sub _parseOutputGlob
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
my $string = $self->{OutputGlob} ;
|
||||
my $maxwild = $self->{WildCount};
|
||||
|
||||
if ($self->{GlobFlags} & GLOB_TILDE)
|
||||
#if (1)
|
||||
{
|
||||
$string =~ s{
|
||||
^ ~ # find a leading tilde
|
||||
( # save this in $1
|
||||
[^/] # a non-slash character
|
||||
* # repeated 0 or more times (0 means me)
|
||||
)
|
||||
}{
|
||||
$1
|
||||
? (getpwnam($1))[7]
|
||||
: ( $ENV{HOME} || $ENV{LOGDIR} )
|
||||
}ex;
|
||||
|
||||
}
|
||||
|
||||
# max #1 must be == to max no of '*' in input
|
||||
while ( $string =~ m/#(\d)/g )
|
||||
{
|
||||
croak "Max wild is #$maxwild, you tried #$1"
|
||||
if $1 > $maxwild ;
|
||||
}
|
||||
|
||||
my $noPreBS = '(?<!\\\)' ; # no preceding backslash
|
||||
#warn "noPreBS = '$noPreBS'\n";
|
||||
|
||||
#$string =~ s/${noPreBS}\$(\d)/\${$1}/g;
|
||||
$string =~ s/${noPreBS}#(\d)/\${$1}/g;
|
||||
$string =~ s#${noPreBS}\*#\${inFile}#g;
|
||||
$string = '"' . $string . '"';
|
||||
|
||||
#print "OUTPUT '$self->{OutputGlob}' => '$string'\n";
|
||||
$self->{OutputPattern} = $string ;
|
||||
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
sub _getFiles
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
my %outInMapping = ();
|
||||
my %inFiles = () ;
|
||||
|
||||
foreach my $inFile (@{ $self->{InputFiles} })
|
||||
{
|
||||
next if $inFiles{$inFile} ++ ;
|
||||
|
||||
my $outFile = $inFile ;
|
||||
|
||||
if ( $inFile =~ m/$self->{InputPattern}/ )
|
||||
{
|
||||
no warnings 'uninitialized';
|
||||
eval "\$outFile = $self->{OutputPattern};" ;
|
||||
|
||||
if (defined $outInMapping{$outFile})
|
||||
{
|
||||
$Error = "multiple input files map to one output file";
|
||||
return undef ;
|
||||
}
|
||||
$outInMapping{$outFile} = $inFile;
|
||||
push @{ $self->{Pairs} }, [$inFile, $outFile];
|
||||
}
|
||||
}
|
||||
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
sub getFileMap
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
return $self->{Pairs} ;
|
||||
}
|
||||
|
||||
sub getHash
|
||||
{
|
||||
my $self = shift ;
|
||||
|
||||
return { map { $_->[0] => $_->[1] } @{ $self->{Pairs} } } ;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
File::GlobMapper - Extend File Glob to Allow Input and Output Files
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::GlobMapper qw( globmap );
|
||||
|
||||
my $aref = globmap $input => $output
|
||||
or die $File::GlobMapper::Error ;
|
||||
|
||||
my $gm = File::GlobMapper->new( $input => $output )
|
||||
or die $File::GlobMapper::Error ;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module needs Perl5.005 or better.
|
||||
|
||||
This module takes the existing C<File::Glob> module as a starting point and
|
||||
extends it to allow new filenames to be derived from the files matched by
|
||||
C<File::Glob>.
|
||||
|
||||
This can be useful when carrying out batch operations on multiple files that
|
||||
have both an input filename and output filename and the output file can be
|
||||
derived from the input filename. Examples of operations where this can be
|
||||
useful include, file renaming, file copying and file compression.
|
||||
|
||||
|
||||
=head2 Behind The Scenes
|
||||
|
||||
To help explain what C<File::GlobMapper> does, consider what code you
|
||||
would write if you wanted to rename all files in the current directory
|
||||
that ended in C<.tar.gz> to C<.tgz>. So say these files are in the
|
||||
current directory
|
||||
|
||||
alpha.tar.gz
|
||||
beta.tar.gz
|
||||
gamma.tar.gz
|
||||
|
||||
and they need renamed to this
|
||||
|
||||
alpha.tgz
|
||||
beta.tgz
|
||||
gamma.tgz
|
||||
|
||||
Below is a possible implementation of a script to carry out the rename
|
||||
(error cases have been omitted)
|
||||
|
||||
foreach my $old ( glob "*.tar.gz" )
|
||||
{
|
||||
my $new = $old;
|
||||
$new =~ s#(.*)\.tar\.gz$#$1.tgz# ;
|
||||
|
||||
rename $old => $new
|
||||
or die "Cannot rename '$old' to '$new': $!\n;
|
||||
}
|
||||
|
||||
Notice that a file glob pattern C<*.tar.gz> was used to match the
|
||||
C<.tar.gz> files, then a fairly similar regular expression was used in
|
||||
the substitute to allow the new filename to be created.
|
||||
|
||||
Given that the file glob is just a cut-down regular expression and that it
|
||||
has already done a lot of the hard work in pattern matching the filenames,
|
||||
wouldn't it be handy to be able to use the patterns in the fileglob to
|
||||
drive the new filename?
|
||||
|
||||
Well, that's I<exactly> what C<File::GlobMapper> does.
|
||||
|
||||
Here is same snippet of code rewritten using C<globmap>
|
||||
|
||||
for my $pair (globmap '<*.tar.gz>' => '<#1.tgz>' )
|
||||
{
|
||||
my ($from, $to) = @$pair;
|
||||
rename $from => $to
|
||||
or die "Cannot rename '$old' to '$new': $!\n;
|
||||
}
|
||||
|
||||
So how does it work?
|
||||
|
||||
Behind the scenes the C<globmap> function does a combination of a
|
||||
file glob to match existing filenames followed by a substitute
|
||||
to create the new filenames.
|
||||
|
||||
Notice how both parameters to C<globmap> are strings that are delimited by <>.
|
||||
This is done to make them look more like file globs - it is just syntactic
|
||||
sugar, but it can be handy when you want the strings to be visually
|
||||
distinctive. The enclosing <> are optional, so you don't have to use them - in
|
||||
fact the first thing globmap will do is remove these delimiters if they are
|
||||
present.
|
||||
|
||||
The first parameter to C<globmap>, C<*.tar.gz>, is an I<Input File Glob>.
|
||||
Once the enclosing "< ... >" is removed, this is passed (more or
|
||||
less) unchanged to C<File::Glob> to carry out a file match.
|
||||
|
||||
Next the fileglob C<*.tar.gz> is transformed behind the scenes into a
|
||||
full Perl regular expression, with the additional step of wrapping each
|
||||
transformed wildcard metacharacter sequence in parenthesis.
|
||||
|
||||
In this case the input fileglob C<*.tar.gz> will be transformed into
|
||||
this Perl regular expression
|
||||
|
||||
([^/]*)\.tar\.gz
|
||||
|
||||
Wrapping with parenthesis allows the wildcard parts of the Input File
|
||||
Glob to be referenced by the second parameter to C<globmap>, C<#1.tgz>,
|
||||
the I<Output File Glob>. This parameter operates just like the replacement
|
||||
part of a substitute command. The difference is that the C<#1> syntax
|
||||
is used to reference sub-patterns matched in the input fileglob, rather
|
||||
than the C<$1> syntax that is used with perl regular expressions. In
|
||||
this case C<#1> is used to refer to the text matched by the C<*> in the
|
||||
Input File Glob. This makes it easier to use this module where the
|
||||
parameters to C<globmap> are typed at the command line.
|
||||
|
||||
The final step involves passing each filename matched by the C<*.tar.gz>
|
||||
file glob through the derived Perl regular expression in turn and
|
||||
expanding the output fileglob using it.
|
||||
|
||||
The end result of all this is a list of pairs of filenames. By default
|
||||
that is what is returned by C<globmap>. In this example the data structure
|
||||
returned will look like this
|
||||
|
||||
( ['alpha.tar.gz' => 'alpha.tgz'],
|
||||
['beta.tar.gz' => 'beta.tgz' ],
|
||||
['gamma.tar.gz' => 'gamma.tgz']
|
||||
)
|
||||
|
||||
|
||||
Each pair is an array reference with two elements - namely the I<from>
|
||||
filename, that C<File::Glob> has matched, and a I<to> filename that is
|
||||
derived from the I<from> filename.
|
||||
|
||||
|
||||
|
||||
=head2 Limitations
|
||||
|
||||
C<File::GlobMapper> has been kept simple deliberately, so it isn't intended to
|
||||
solve all filename mapping operations. Under the hood C<File::Glob> (or for
|
||||
older versions of Perl, C<File::BSDGlob>) is used to match the files, so you
|
||||
will never have the flexibility of full Perl regular expression.
|
||||
|
||||
=head2 Input File Glob
|
||||
|
||||
The syntax for an Input FileGlob is identical to C<File::Glob>, except
|
||||
for the following
|
||||
|
||||
=over 5
|
||||
|
||||
=item 1.
|
||||
|
||||
No nested {}
|
||||
|
||||
=item 2.
|
||||
|
||||
Whitespace does not delimit fileglobs.
|
||||
|
||||
=item 3.
|
||||
|
||||
The use of parenthesis can be used to capture parts of the input filename.
|
||||
|
||||
=item 4.
|
||||
|
||||
If an Input glob matches the same file more than once, only the first
|
||||
will be used.
|
||||
|
||||
=back
|
||||
|
||||
The syntax
|
||||
|
||||
=over 5
|
||||
|
||||
=item B<~>
|
||||
|
||||
=item B<~user>
|
||||
|
||||
|
||||
=item B<.>
|
||||
|
||||
Matches a literal '.'.
|
||||
Equivalent to the Perl regular expression
|
||||
|
||||
\.
|
||||
|
||||
=item B<*>
|
||||
|
||||
Matches zero or more characters, except '/'. Equivalent to the Perl
|
||||
regular expression
|
||||
|
||||
[^/]*
|
||||
|
||||
=item B<?>
|
||||
|
||||
Matches zero or one character, except '/'. Equivalent to the Perl
|
||||
regular expression
|
||||
|
||||
[^/]?
|
||||
|
||||
=item B<\>
|
||||
|
||||
Backslash is used, as usual, to escape the next character.
|
||||
|
||||
=item B<[]>
|
||||
|
||||
Character class.
|
||||
|
||||
=item B<{,}>
|
||||
|
||||
Alternation
|
||||
|
||||
=item B<()>
|
||||
|
||||
Capturing parenthesis that work just like perl
|
||||
|
||||
=back
|
||||
|
||||
Any other character it taken literally.
|
||||
|
||||
=head2 Output File Glob
|
||||
|
||||
The Output File Glob is a normal string, with 2 glob-like features.
|
||||
|
||||
The first is the '*' metacharacter. This will be replaced by the complete
|
||||
filename matched by the input file glob. So
|
||||
|
||||
*.c *.Z
|
||||
|
||||
The second is
|
||||
|
||||
Output FileGlobs take the
|
||||
|
||||
=over 5
|
||||
|
||||
=item "*"
|
||||
|
||||
The "*" character will be replaced with the complete input filename.
|
||||
|
||||
=item #1
|
||||
|
||||
Patterns of the form /#\d/ will be replaced with the
|
||||
|
||||
=back
|
||||
|
||||
=head2 Returned Data
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
=head2 A Rename script
|
||||
|
||||
Below is a simple "rename" script that uses C<globmap> to determine the
|
||||
source and destination filenames.
|
||||
|
||||
use File::GlobMapper qw(globmap) ;
|
||||
use File::Copy;
|
||||
|
||||
die "rename: Usage rename 'from' 'to'\n"
|
||||
unless @ARGV == 2 ;
|
||||
|
||||
my $fromGlob = shift @ARGV;
|
||||
my $toGlob = shift @ARGV;
|
||||
|
||||
my $pairs = globmap($fromGlob, $toGlob)
|
||||
or die $File::GlobMapper::Error;
|
||||
|
||||
for my $pair (@$pairs)
|
||||
{
|
||||
my ($from, $to) = @$pair;
|
||||
move $from => $to ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Here is an example that renames all c files to cpp.
|
||||
|
||||
$ rename '*.c' '#1.cpp'
|
||||
|
||||
=head2 A few example globmaps
|
||||
|
||||
Below are a few examples of globmaps
|
||||
|
||||
To copy all your .c file to a backup directory
|
||||
|
||||
'</my/home/*.c>' '</my/backup/#1.c>'
|
||||
|
||||
If you want to compress all
|
||||
|
||||
'</my/home/*.[ch]>' '<*.gz>'
|
||||
|
||||
To uncompress
|
||||
|
||||
'</my/home/*.[ch].gz>' '</my/home/#1.#2>'
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<File::Glob|File::Glob>
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
The I<File::GlobMapper> module was written by Paul Marquess, F<pmqs@cpan.org>.
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (c) 2005 Paul Marquess. All rights reserved.
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the same terms as Perl itself.
|
||||
1287
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Path.pm
Normal file
1287
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Path.pm
Normal file
File diff suppressed because it is too large
Load diff
3721
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Temp.pm
Normal file
3721
Agent-Windows/OGP64/usr/share/perl5/5.40/File/Temp.pm
Normal file
File diff suppressed because it is too large
Load diff
350
Agent-Windows/OGP64/usr/share/perl5/5.40/File/stat.pm
Normal file
350
Agent-Windows/OGP64/usr/share/perl5/5.40/File/stat.pm
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
package File::stat 1.14;
|
||||
use v5.38;
|
||||
|
||||
use warnings::register;
|
||||
use Carp;
|
||||
use constant _IS_CYGWIN => $^O eq "cygwin";
|
||||
|
||||
BEGIN { *warnif = \&warnings::warnif }
|
||||
|
||||
our ( $st_dev, $st_ino, $st_mode,
|
||||
$st_nlink, $st_uid, $st_gid,
|
||||
$st_rdev, $st_size,
|
||||
$st_atime, $st_mtime, $st_ctime,
|
||||
$st_blksize, $st_blocks
|
||||
);
|
||||
|
||||
use Exporter 'import';
|
||||
our @EXPORT = qw(stat lstat);
|
||||
our @fields = qw( $st_dev $st_ino $st_mode
|
||||
$st_nlink $st_uid $st_gid
|
||||
$st_rdev $st_size
|
||||
$st_atime $st_mtime $st_ctime
|
||||
$st_blksize $st_blocks
|
||||
);
|
||||
our @EXPORT_OK = ( @fields, "stat_cando" );
|
||||
our %EXPORT_TAGS = ( FIELDS => [ @fields, @EXPORT ] );
|
||||
|
||||
use Fcntl qw(S_IRUSR S_IWUSR S_IXUSR);
|
||||
|
||||
BEGIN {
|
||||
# These constants will croak on use if the platform doesn't define
|
||||
# them. It's important to avoid inflicting that on the user.
|
||||
no strict 'refs';
|
||||
for (qw(suid sgid svtx)) {
|
||||
my $val = eval { &{"Fcntl::S_I\U$_"} };
|
||||
*{"_$_"} = defined $val ? sub { $_[0] & $val ? 1 : "" } : sub { "" };
|
||||
}
|
||||
for (qw(SOCK CHR BLK REG DIR LNK)) {
|
||||
*{"S_IS$_"} = defined eval { &{"Fcntl::S_IF$_"} }
|
||||
? \&{"Fcntl::S_IS$_"} : sub { "" };
|
||||
}
|
||||
# FIFO flag and macro don't quite follow the S_IF/S_IS pattern above
|
||||
# RT #111638
|
||||
*{"S_ISFIFO"} = defined &Fcntl::S_IFIFO
|
||||
? \&Fcntl::S_ISFIFO : sub { "" };
|
||||
}
|
||||
|
||||
# from doio.c
|
||||
sub _ingroup {
|
||||
my ($gid, $eff) = @_;
|
||||
|
||||
# I am assuming that since VMS doesn't have getgroups(2), $) will
|
||||
# always only contain a single entry.
|
||||
$^O eq "VMS" and return $_[0] == $);
|
||||
|
||||
my ($egid, @supp) = split " ", $);
|
||||
my ($rgid) = split " ", $(;
|
||||
|
||||
$gid == ($eff ? $egid : $rgid) and return 1;
|
||||
grep $gid == $_, @supp and return 1;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
# VMS uses the Unix version of the routine, even though this is very
|
||||
# suboptimal. VMS has a permissions structure that doesn't really fit
|
||||
# into struct stat, and unlike on Win32 the normal -X operators respect
|
||||
# that, but unfortunately by the time we get here we've already lost the
|
||||
# information we need. It looks to me as though if we were to preserve
|
||||
# the st_devnam entry of vmsish.h's fake struct stat (which actually
|
||||
# holds the filename) it might be possible to do this right, but both
|
||||
# getting that value out of the struct (perl's stat doesn't return it)
|
||||
# and interpreting it later would require this module to have an XS
|
||||
# component (at which point we might as well just call Perl_cando and
|
||||
# have done with it).
|
||||
|
||||
if (grep $^O eq $_, qw/os2 MSWin32/) {
|
||||
|
||||
# from doio.c
|
||||
*cando = sub { ($_[0][2] & $_[1]) ? 1 : "" };
|
||||
}
|
||||
else {
|
||||
|
||||
# from doio.c
|
||||
*cando = sub {
|
||||
my ($s, $mode, $eff) = @_;
|
||||
my $uid = $eff ? $> : $<;
|
||||
my ($stmode, $stuid, $stgid) = @$s[2,4,5];
|
||||
|
||||
# This code basically assumes that the rwx bits of the mode are
|
||||
# the 0777 bits, but so does Perl_cando.
|
||||
|
||||
if (_IS_CYGWIN ? _ingroup(544, $eff) : ($uid == 0 && $^O ne "VMS")) {
|
||||
# If we're root on unix
|
||||
# not testing for executable status => all file tests are true
|
||||
return 1 if !($mode & 0111);
|
||||
# testing for executable status =>
|
||||
# for a file, any x bit will do
|
||||
# for a directory, always true
|
||||
return 1 if $stmode & 0111 || S_ISDIR($stmode);
|
||||
return "";
|
||||
}
|
||||
|
||||
if ($stuid == $uid) {
|
||||
$stmode & $mode and return 1;
|
||||
}
|
||||
elsif (_ingroup($stgid, $eff)) {
|
||||
$stmode & ($mode >> 3) and return 1;
|
||||
}
|
||||
else {
|
||||
$stmode & ($mode >> 6) and return 1;
|
||||
}
|
||||
return "";
|
||||
};
|
||||
}
|
||||
|
||||
# alias for those who don't like objects
|
||||
*stat_cando = \&cando;
|
||||
|
||||
my %op = (
|
||||
r => sub { cando($_[0], S_IRUSR, 1) },
|
||||
w => sub { cando($_[0], S_IWUSR, 1) },
|
||||
x => sub { cando($_[0], S_IXUSR, 1) },
|
||||
o => sub { $_[0][4] == $> },
|
||||
|
||||
R => sub { cando($_[0], S_IRUSR, 0) },
|
||||
W => sub { cando($_[0], S_IWUSR, 0) },
|
||||
X => sub { cando($_[0], S_IXUSR, 0) },
|
||||
O => sub { $_[0][4] == $< },
|
||||
|
||||
e => sub { 1 },
|
||||
z => sub { $_[0][7] == 0 },
|
||||
s => sub { $_[0][7] },
|
||||
|
||||
f => sub { S_ISREG ($_[0][2]) },
|
||||
d => sub { S_ISDIR ($_[0][2]) },
|
||||
l => sub { S_ISLNK ($_[0][2]) },
|
||||
p => sub { S_ISFIFO($_[0][2]) },
|
||||
S => sub { S_ISSOCK($_[0][2]) },
|
||||
b => sub { S_ISBLK ($_[0][2]) },
|
||||
c => sub { S_ISCHR ($_[0][2]) },
|
||||
|
||||
u => sub { _suid($_[0][2]) },
|
||||
g => sub { _sgid($_[0][2]) },
|
||||
k => sub { _svtx($_[0][2]) },
|
||||
|
||||
M => sub { ($^T - $_[0][9] ) / 86400 },
|
||||
C => sub { ($^T - $_[0][10]) / 86400 },
|
||||
A => sub { ($^T - $_[0][8] ) / 86400 },
|
||||
);
|
||||
|
||||
use constant HINT_FILETEST_ACCESS => 0x00400000;
|
||||
|
||||
# we need fallback=>1 or stringifying breaks
|
||||
use overload
|
||||
fallback => 1,
|
||||
-X => sub {
|
||||
my ($s, $op) = @_;
|
||||
|
||||
if (index("rwxRWX", $op) >= 0) {
|
||||
(caller 0)[8] & HINT_FILETEST_ACCESS
|
||||
and warnif("File::stat ignores use filetest 'access'");
|
||||
|
||||
$^O eq "VMS" and warnif("File::stat ignores VMS ACLs");
|
||||
|
||||
# It would be nice to have a warning about using -l on a
|
||||
# non-lstat, but that would require an extra member in the
|
||||
# object.
|
||||
}
|
||||
|
||||
if ($op{$op}) {
|
||||
return $op{$op}->($_[0]);
|
||||
}
|
||||
else {
|
||||
croak "-$op is not implemented on a File::stat object";
|
||||
}
|
||||
};
|
||||
|
||||
use Class::Struct qw(struct);
|
||||
struct 'File::stat' => [
|
||||
map { $_ => '$' } qw{
|
||||
dev ino mode nlink uid gid rdev size
|
||||
atime mtime ctime blksize blocks
|
||||
}
|
||||
];
|
||||
|
||||
sub populate {
|
||||
return unless @_;
|
||||
my $stob = new();
|
||||
@$stob = (
|
||||
$st_dev, $st_ino, $st_mode, $st_nlink, $st_uid, $st_gid, $st_rdev,
|
||||
$st_size, $st_atime, $st_mtime, $st_ctime, $st_blksize, $st_blocks )
|
||||
= @_;
|
||||
return $stob;
|
||||
}
|
||||
|
||||
sub lstat :prototype($) { populate(CORE::lstat(shift)) }
|
||||
|
||||
sub stat :prototype($) {
|
||||
my $arg = shift;
|
||||
my $st = populate(CORE::stat $arg);
|
||||
return $st if defined $st;
|
||||
my $fh;
|
||||
{
|
||||
local $!;
|
||||
no strict 'refs';
|
||||
require Symbol;
|
||||
$fh = \*{ Symbol::qualify( $arg, caller() )};
|
||||
return unless defined fileno $fh;
|
||||
}
|
||||
return populate(CORE::stat $fh);
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
File::stat - by-name interface to Perl's built-in stat() functions
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use File::stat;
|
||||
my $st = stat($file) or die "No $file: $!";
|
||||
if ( ($st->mode & 0111) && ($st->nlink > 1) ) {
|
||||
print "$file is executable with lotsa links\n";
|
||||
}
|
||||
|
||||
if ( -x $st ) {
|
||||
print "$file is executable\n";
|
||||
}
|
||||
|
||||
use Fcntl "S_IRUSR";
|
||||
if ( $st->cando(S_IRUSR, 1) ) {
|
||||
print "My effective uid can read $file\n";
|
||||
}
|
||||
|
||||
use File::stat qw(:FIELDS);
|
||||
stat($file) or die "No $file: $!";
|
||||
if ( ($st_mode & 0111) && ($st_nlink > 1) ) {
|
||||
print "$file is executable with lotsa links\n";
|
||||
}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module's default exports override the core stat()
|
||||
and lstat() functions, replacing them with versions that return
|
||||
"File::stat" objects. This object has methods that
|
||||
return the similarly named structure field name from the
|
||||
stat(2) function; namely,
|
||||
dev,
|
||||
ino,
|
||||
mode,
|
||||
nlink,
|
||||
uid,
|
||||
gid,
|
||||
rdev,
|
||||
size,
|
||||
atime,
|
||||
mtime,
|
||||
ctime,
|
||||
blksize,
|
||||
and
|
||||
blocks.
|
||||
|
||||
As of version 1.02 (provided with perl 5.12) the object provides C<"-X">
|
||||
overloading, so you can call filetest operators (C<-f>, C<-x>, and so
|
||||
on) on it. It also provides a C<< ->cando >> method, called like
|
||||
|
||||
$st->cando( ACCESS, EFFECTIVE )
|
||||
|
||||
where I<ACCESS> is one of C<S_IRUSR>, C<S_IWUSR> or C<S_IXUSR> from the
|
||||
L<Fcntl|Fcntl> module, and I<EFFECTIVE> indicates whether to use
|
||||
effective (true) or real (false) ids. The method interprets the C<mode>,
|
||||
C<uid> and C<gid> fields, and returns whether or not the current process
|
||||
would be allowed the specified access.
|
||||
|
||||
If you don't want to use the objects, you may import the C<< ->cando >>
|
||||
method into your namespace as a regular function called C<stat_cando>.
|
||||
This takes an arrayref containing the return values of C<stat> or
|
||||
C<lstat> as its first argument, and interprets it for you.
|
||||
|
||||
You may also import all the structure fields directly into your namespace
|
||||
as regular variables using the :FIELDS import tag. (Note that this still
|
||||
overrides your stat() and lstat() functions.) Access these fields as
|
||||
variables named with a preceding C<st_> in front their method names.
|
||||
Thus, C<$stat_obj-E<gt>dev()> corresponds to $st_dev if you import
|
||||
the fields.
|
||||
|
||||
To access this functionality without the core overrides,
|
||||
pass the C<use> an empty import list, and then access
|
||||
function functions with their full qualified names.
|
||||
On the other hand, the built-ins are still available
|
||||
via the C<CORE::> pseudo-package.
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
As of Perl 5.8.0 after using this module you cannot use the implicit
|
||||
C<$_> or the special filehandle C<_> with stat() or lstat(), trying
|
||||
to do so leads into strange errors. The workaround is for C<$_> to
|
||||
be explicit
|
||||
|
||||
my $stat_obj = stat $_;
|
||||
|
||||
and for C<_> to explicitly populate the object using the unexported
|
||||
and undocumented populate() function with CORE::stat():
|
||||
|
||||
my $stat_obj = File::stat::populate(CORE::stat(_));
|
||||
|
||||
=head1 ERRORS
|
||||
|
||||
=over 4
|
||||
|
||||
=item -%s is not implemented on a File::stat object
|
||||
|
||||
The filetest operators C<-t>, C<-T> and C<-B> are not implemented, as
|
||||
they require more information than just a stat buffer.
|
||||
|
||||
=back
|
||||
|
||||
=head1 WARNINGS
|
||||
|
||||
These can all be disabled with
|
||||
|
||||
no warnings "File::stat";
|
||||
|
||||
=over 4
|
||||
|
||||
=item File::stat ignores use filetest 'access'
|
||||
|
||||
You have tried to use one of the C<-rwxRWX> filetests with C<use
|
||||
filetest 'access'> in effect. C<File::stat> will ignore the pragma, and
|
||||
just use the information in the C<mode> member as usual.
|
||||
|
||||
=item File::stat ignores VMS ACLs
|
||||
|
||||
VMS systems have a permissions structure that cannot be completely
|
||||
represented in a stat buffer, and unlike on other systems the builtin
|
||||
filetest operators respect this. The C<File::stat> overloads, however,
|
||||
do not, since the information required is not available.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTE
|
||||
|
||||
While this class is currently implemented using the Class::Struct
|
||||
module to build a struct-like class, you shouldn't rely upon this.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Tom Christiansen
|
||||
Loading…
Add table
Add a link
Reference in a new issue