FunctionalPerl
view release on metacpan or search on metacpan
lib/Chj/IO/Tempfile.pm view on Meta::CPAN
sub attribute { # :lvalue does not work because of perl bugs. :-(
my $self = shift;
my $key = shift;
if (@_) {
($metadata{ pack "I", $self }[2]{$key}) = @_
} else {
$metadata{ pack "I", $self }[2]{$key}
}
}
sub _xlinkrename {
my ($from, $to) = @_; # to must be file path, not dir.
my $tobase = $to;
$tobase =~ s{/?([^/]+)\z}{} or croak "_xlinkrename: missing to parameter";
my $toname = $1;
$tobase .= "/" if length $tobase;
for (1 .. 10) {
my $tmppath = "$tobase.$toname." . rand(10000);
if (link $from, $tmppath) {
if (rename $tmppath, $to) {
return;
} else {
croak "_xlinkrename: rename "
. Chj::singlequote($tmppath) . ", "
. Chj::singlequote($to) . ": $!";
}
} else {
if ($! == EEXIST) {
next;
} else {
croak "_xlinkrename: link "
. Chj::singlequote($from) . ", "
. Chj::singlequote($tmppath) . ": $!";
}
}
}
croak "_xlinkrename: too many attempts to make a link from "
. Chj::singlequote($from)
. " to a random name around "
. Chj::singlequote($to) . ": $!";
}
our $warn_all_failures = 1;
sub xreplace_or_withmode {
my $self = shift;
my ($targetpath, $orwithmode) = @_;
# $orwithmode can be an integer, an octal string, or a stat
# object; in case of a stat object and if running as root, it also
# keeps uid/gid.
my $path = $self->xpath;
my ($uid, $gid, $mode);
if (($uid, $gid, $mode) = (stat $targetpath)[4, 5, 2]) {
my $euid = (stat $path)[4]; # better than $> because of peculiarities
defined $euid
or croak "xreplace_or_withmode: ?? can't stat own file "
. Chj::singlequote($path) . ": $!";
if ($euid == 0) {
$! = undef;
chown $uid, $gid, $path
or croak "xreplace_or_withmode: chown "
. Chj::singlequote($path) . ": $!";
} else {
if ($uid != $euid) {
carp "xreplace_or_withmode: warning: cannot set owner of "
. Chj::singlequote($path)
. " to $uid since we are not root"
if $warn_all_failures;
$mode &= 0777; # see below
}
$! = undef;
chown $euid, $gid, $path or do {
# only a warning, ok?
carp "xreplace_or_withmode: warning: could not set group of "
. Chj::singlequote($path)
. " to $gid: $!"
if $warn_all_failures;
$mode &= 0777; # mask off setuid and such stuff. correct?
};
}
# keep backup:
# we need it atomic, thus link. but a 'replacing link'.
eval {
_xlinkrename $targetpath, "$targetpath~"; # make configurable?
1
} || do {
warn "xreplace_or_withmode: warning: could not make backup file: $@"
if $warn_all_failures;
}
} else {
if (defined $orwithmode) {
if (ref $orwithmode) {
# assuming stat object
$mode = $orwithmode->permissions;
if ($> == 0) {
$! = undef;
chown $orwithmode->uid, $orwithmode->gid, $path
or croak "xreplace_or_withmode: chown "
. Chj::singlequote($path) . ": $!";
}
} else {
if ($orwithmode =~ /^0/) {
$orwithmode = oct $orwithmode;
defined($orwithmode)
or croak "xreplace_or_withmode: illegal octal "
. "withmode value given";
# ^ well, never happens when givint numbers not strings
}
$mode = $orwithmode
; # & 0777; # mask off dito, since we do not know which uid/gid the programmer meant. which is a bug in itself. wellll , programmer should know what he's doing then, right?
}
} else {
croak "xreplace_or_withmode: error getting target permissions"
. " and no default mode given, stat "
. Chj::singlequote($targetpath) . ": $!";
}
}
$! = undef;
chmod $mode, $path
or croak "xreplace_or_withmode: chmod "
. Chj::singlequote($path) . ": $!";
$self->xrename($targetpath);
}
sub xputback { # better name?
my $self = shift;
my ($maybe_orwithmode) = @_;
croak "xputback: file " . $self->quotedname . " is still open"
if $self->opened;
my $basepath = $metadata{ pack "I", $self }[0];
$self->xreplace_or_withmode($basepath, $maybe_orwithmode);
}
sub basepath {
my $self = shift;
$metadata{ pack "I", $self }[0]
}
1
( run in 2.038 seconds using v1.01-cache-2.11-cpan-71847e10f99 )