CC: | "dmuey [...] cpan.org" <dmuey [...] cpan.org> |
Subject: | Cwd::abs_path modifies cwd on Windows drive being queried |
Date: | Wed, 27 Aug 2014 22:00:22 +0000 |
To: | "bug-PathTools [...] rt.cpan.org" <bug-PathTools [...] rt.cpan.org> |
From: | Greg Aloe <Greg.Aloe [...] mathworks.com> |
Here's a code snippet from Cwd::abs_path:
if (!CORE::chdir($path)) {
_croak("Cannot chdir to $path: $!");
}
my $realpath = getcwd();
if (! ((-d $cwd) && (CORE::chdir($cwd)))) {
_croak("Cannot chdir back to $cwd: $!");
}
In this code, there's an attempt to chdir to the path being queried. Then there's an attempt to chdir back to the original cwd. If there are no errors (the usual happy case), then the cwd for the drive of the queried path gets unexpectedly modified.
Consider the case where your cwd is H:\home and the path being queried is C:\Temp\blah. If my current Windows C drive is C:\Work\User, then a call to Cwd::abs_path('C:\\Temp\\blah') will actually change the current Windows C drive to that. The subsequent attempt to restore back to H:\home is successful. However, if I then query my current Windows C drive, it's no longer C:\Work\User. Here's a live example where the path being queried is subsequently deleted, but the original current path on the same Windows drive still exists:
use Cwd;
my $hcwd = "H:\\home\\";
my $ccwd = "C:\\Work\\User";
my $temp = "C:\\Temp\\blahblehblih";
mkdir $temp;
chdir($ccwd);
chdir($hcwd);
print "Found C: before abs_path\n" if -d 'C:';
abs_path($temp);
rmdir($temp);
print "Could not find C: after abs_path and rmdir\n" if !-d 'C:';
You might think it's crazy to work with current Windows drives, but I found this to be a root cause in my own code's usage of File::Copy::Recursive. Therefore, I've copied Daniel to let him know about a related bug as well. The pathmk routine splits a Windows path resulting in a list like this: ('C:', 'Temp', 'blahbleblih'). When iterating over that list and checking for the existence of each segment, you might find that a check for -d 'C:' returns undef! This is a separate bug in itself regardless of whether abs_path was used or not. I will report that separately. Here's the code with that bug:
sub pathmk {
my @parts = File::Spec->splitdir( shift() );
my $nofatal = shift;
my $pth = $parts[0];
my $zer = 0;
if(!$pth) {
$pth = File::Spec->catdir($parts[0],$parts[1]);
$zer = 1;
}
for($zer..$#parts) {
mkdir $pth or return if !-d $pth && !$nofatal;
mkdir $pth if !-d $pth && $nofatal;
$pth = File::Spec->catdir($pth, $parts[$_ + 1]) unless $_ == $#parts;
}
1;
}
Greg