Dangerous when using catfile for path ending in directory?
The module File::Spec
provides a way to create valid paths for different operating systems. It works as you would expect:
use strict;
use warnings;
use File::Spec;
my $file = 'ghi.xml';
my $path = File::Spec->catfile(('abc', 'def'), $file);
print $path;
# Windows: abc/def/ghi.xml
There is also a method available catdir
that will make the directory not a file path.
My problem is that I don't know in advance if $file
is a file name or a directory name. As far as I have checked, the results are still correct when using the dirname, e.g .:
use strict;
use warnings;
use File::Spec;
my $file = 'ghi';
my $path = File::Spec->catfile(('abc', 'def'), $file);
print $path;
# Windows: abc/def/ghi
But I'm wondering if this might cause problems. I assume yes, because I don't understand why the creators of the module would build two interfaces for the same functionality. However, I cannot find any further explanation in the documentation.
Can it be used catfile
to create paths to files as well as directories? If not, what are the caveats?
source to share
Difference catdir
and catfile
is usually very small ( depending on the operating system ). On UNIX, catfile
executes catdir
anyway for directory entries (for example, minus last (file)) and then appends part of the file. catdir
performs some path clearing logic. On the Windows platform, the differences are even smaller.
You can check the source of modules for different OS-es yourself .
The main point is that these routines do not have access to the file system, they just do some cleanup of logical paths.
Alternative:
If you don't like other OSs like UNIX-like (eg Linux, FreeBSD, Mac OS X, etc.) and Windows, I personally recommend using Path :: Tiny . From it doc:
This module provides a small, fast utility for manipulating the path file. This is more convenient to use than File :: Spec, and provides easy access to functions from several other kernel file processing modules. It aims to be smaller and faster than many CPAN alternatives, while helping people do a lot of the same in a consistent and less error-prone way.
Path :: Tiny doesn't try to work for anything other than Unix-like and Win32.
IMHO is one of the best CPAN modules - a real treasure. For example, to create a path, you have to use a method child
- again from the docs:
$file = path("/tmp")->child("foo.txt"); # "/tmp/foo.txt" $file = path("/tmp")->child(@parts);
Returns a new Path :: Tiny object relative to the original. Works like
catfile
orcatdir
from file :: Spec, but doesn't care about file or directories.
In addition to the above, the Path :: Tiny module provides easy access to the contents of the file (also when handling Unicode) and each normal "path" "operation. Disadvantage: unfortunately, this is not a CORE module, eg you need to install it from CPAN.
EDIT
Is it safe to use catfile
for directories? For me: yes (but maybe some experts will know more or more). On unix,
-
catdir
callscanonpath
(which does some logical path cleanup). -
catfile
calls twicecanonpath
, once for part of the file and once for directories (if provided), and concatenates the two results. Concatenation can lead to some strange paths, but they are generally harmless.
On Windows the difference is even smaller, both will invoke the path cleanup routine.
Demo - The following script will generate many combinations of different parts and will use catdir
and catfile
(and even two options Path::Tiny
)
use strict;
use warnings;
use File::Spec::Functions;
use Path::Tiny;
my @parts = qw(x / /x /x/ /x// // //x //x/ //x// /./ /./x /x/./ );
my $cwidth=16;
print pr(qw(first second catdir catfile path-child path-list)), "\n";
print '-' x ($cwidth*6),"\n";
for my $first (map { s/x/first/r } @parts) {
for my $second ( map { s/x/second/r } @parts) {
print pr(
$first,
$second,
catdir($first,$second),
catfile($first,$second),
path($first)->child($second),
path($first,$second),
), "\n";
}
}
sub pr {
my $str;
$str .= sprintf "%-${cwidth}s",$_ for @_;
return $str;
}
It prints a long result. As you can see below, all paths are safe to use for directories and files, only some of the paths catfile
are not "nice".
"Path :: Tiny" results are clear and consistent. On the contrary, catfile
and catdir
will allow undefined parts (not shown in the demo) - and even with such erroneous arguments some results will be obtained, Path :: Tiny will die if you pass undef or null-string to its method child
.
first second catdir catfile path-child path-list
------------------------------------------------------------------------------------------------
first second first/second first/second first/second first/second
first / first first// first first
first /second first/second first//second first/second first/second
first /second/ first/second first//second first/second first/second
first /second// first/second first//second first/second first/second
first // first first// first first
first //second first/second first//second first/second first/second
first //second/ first/second first//second first/second first/second
first //second// first/second first//second first/second first/second
first /./ first first// first first
first /./second first/second first//second first/second first/second
first /second/./ first/second first//second first/second first/second
/ second /second /second /second /second
/ / / // / /
/ /second /second //second /second /second
/ /second/ /second //second /second /second
/ /second// /second //second /second /second
/ // / // / /
/ //second /second //second /second /second
/ //second/ /second //second /second /second
/ //second// /second //second /second /second
/ /./ / // / /
/ /./second /second //second /second /second
/ /second/./ /second //second /second /second
/first second /first/second /first/second /first/second /first/second
/first / /first /first// /first /first
/first /second /first/second /first//second /first/second /first/second
/first /second/ /first/second /first//second /first/second /first/second
/first /second// /first/second /first//second /first/second /first/second
/first // /first /first// /first /first
/first //second /first/second /first//second /first/second /first/second
/first //second/ /first/second /first//second /first/second /first/second
/first //second// /first/second /first//second /first/second /first/second
/first /./ /first /first// /first /first
/first /./second /first/second /first//second /first/second /first/second
/first /second/./ /first/second /first//second /first/second /first/second
/first/ second /first/second /first/second /first/second /first/second
/first/ / /first /first// /first /first
/first/ /second /first/second /first//second /first/second /first/second
/first/ /second/ /first/second /first//second /first/second /first/second
/first/ /second// /first/second /first//second /first/second /first/second
/first/ // /first /first// /first /first
/first/ //second /first/second /first//second /first/second /first/second
/first/ //second/ /first/second /first//second /first/second /first/second
/first/ //second// /first/second /first//second /first/second /first/second
/first/ /./ /first /first// /first /first
/first/ /./second /first/second /first//second /first/second /first/second
/first/ /second/./ /first/second /first//second /first/second /first/second
/first// second /first/second /first/second /first/second /first/second
/first// / /first /first// /first /first
/first// /second /first/second /first//second /first/second /first/second
/first// /second/ /first/second /first//second /first/second /first/second
/first// /second// /first/second /first//second /first/second /first/second
/first// // /first /first// /first /first
/first// //second /first/second /first//second /first/second /first/second
/first// //second/ /first/second /first//second /first/second /first/second
/first// //second// /first/second /first//second /first/second /first/second
/first// /./ /first /first// /first /first
/first// /./second /first/second /first//second /first/second /first/second
/first// /second/./ /first/second /first//second /first/second /first/second
// second /second /second /second /second
// / / // / /
// /second /second //second /second /second
// /second/ /second //second /second /second
// /second// /second //second /second /second
// // / // / /
// //second /second //second /second /second
// //second/ /second //second /second /second
// //second// /second //second /second /second
// /./ / // / /
// /./second /second //second /second /second
// /second/./ /second //second /second /second
//first second /first/second /first/second /first/second /first/second
//first / /first /first// /first /first
//first /second /first/second /first//second /first/second /first/second
//first /second/ /first/second /first//second /first/second /first/second
//first /second// /first/second /first//second /first/second /first/second
//first // /first /first// /first /first
//first //second /first/second /first//second /first/second /first/second
//first //second/ /first/second /first//second /first/second /first/second
//first //second// /first/second /first//second /first/second /first/second
//first /./ /first /first// /first /first
//first /./second /first/second /first//second /first/second /first/second
//first /second/./ /first/second /first//second /first/second /first/second
//first/ second /first/second /first/second /first/second /first/second
//first/ / /first /first// /first /first
//first/ /second /first/second /first//second /first/second /first/second
//first/ /second/ /first/second /first//second /first/second /first/second
//first/ /second// /first/second /first//second /first/second /first/second
//first/ // /first /first// /first /first
//first/ //second /first/second /first//second /first/second /first/second
//first/ //second/ /first/second /first//second /first/second /first/second
//first/ //second// /first/second /first//second /first/second /first/second
//first/ /./ /first /first// /first /first
//first/ /./second /first/second /first//second /first/second /first/second
//first/ /second/./ /first/second /first//second /first/second /first/second
//first// second /first/second /first/second /first/second /first/second
//first// / /first /first// /first /first
//first// /second /first/second /first//second /first/second /first/second
//first// /second/ /first/second /first//second /first/second /first/second
//first// /second// /first/second /first//second /first/second /first/second
//first// // /first /first// /first /first
//first// //second /first/second /first//second /first/second /first/second
//first// //second/ /first/second /first//second /first/second /first/second
//first// //second// /first/second /first//second /first/second /first/second
//first// /./ /first /first// /first /first
//first// /./second /first/second /first//second /first/second /first/second
//first// /second/./ /first/second /first//second /first/second /first/second
/./ second /second /second /second /second
/./ / / // / /
/./ /second /second //second /second /second
/./ /second/ /second //second /second /second
/./ /second// /second //second /second /second
/./ // / // / /
/./ //second /second //second /second /second
/./ //second/ /second //second /second /second
/./ //second// /second //second /second /second
/./ /./ / // / /
/./ /./second /second //second /second /second
/./ /second/./ /second //second /second /second
/./first second /first/second /first/second /first/second /first/second
/./first / /first /first// /first /first
/./first /second /first/second /first//second /first/second /first/second
/./first /second/ /first/second /first//second /first/second /first/second
/./first /second// /first/second /first//second /first/second /first/second
/./first // /first /first// /first /first
/./first //second /first/second /first//second /first/second /first/second
/./first //second/ /first/second /first//second /first/second /first/second
/./first //second// /first/second /first//second /first/second /first/second
/./first /./ /first /first// /first /first
/./first /./second /first/second /first//second /first/second /first/second
/./first /second/./ /first/second /first//second /first/second /first/second
/first/./ second /first/second /first/second /first/second /first/second
/first/./ / /first /first// /first /first
/first/./ /second /first/second /first//second /first/second /first/second
/first/./ /second/ /first/second /first//second /first/second /first/second
/first/./ /second// /first/second /first//second /first/second /first/second
/first/./ // /first /first// /first /first
/first/./ //second /first/second /first//second /first/second /first/second
/first/./ //second/ /first/second /first//second /first/second /first/second
/first/./ //second// /first/second /first//second /first/second /first/second
/first/./ /./ /first /first// /first /first
/first/./ /./second /first/second /first//second /first/second /first/second
/first/./ /second/./ /first/second /first//second /first/second /first/second
source to share