rovf has asked for the wisdom of the Perl Monks concerning the following question:

Consider I have two string $x and $y, for which

-d $x && -d $y
is true. Is there an easy way (speak: a standard function, a CPAN module etc.) to find out whether $x and $y denote the same directory?

I have considered File::Spec::Functions::canonpath, but even if the canonical path differes, the directories could be the same, although their string representation is different.

On Unix, for instance, $y could be a symlink to $x.

On Windows, $x might be a representation of the directory using a drive letter, and $y might be the same directory using the UNC path notation (if it is a networked directory).

-- 
Ronald Fischer <ynnor@mm.st>

Replies are listed 'Best First'.
Re: Finding out whether two directories are the same
by Corion (Patriarch) on Aug 28, 2008 at 08:54 UTC

    This is basically the same philosophical problem as determining whether two URLs point to "the same page". You can't really tell.

    You can check the device and inode field of the results of stat for both directories, but that will only work for file systems that follow the idea the inventors originally had. This likely won't detect file systems that are mounted in two separate places into the same directory tree and won't work where the inode field is always empty or zero.

    You can readdir the directories and consider them to be the same if they contain the same files. Possibly you can also check and compare the sizes and timestamps of all directory entries.

    But in the end, you can never be exactly sure.

      Thanks for filling in those details, Corion. Now I can just skip to the crazy ideas:

      my $rand= md5_hash_hex( rand() . $$ . $x . "super secret" ); mkdir( "$x/$rand" ); if( -d "$y/$rand" ) { warn "$x == $y\n"; } rmdir( "$x/$rand" );

      I only created a subdirectory instead of a file because it makes for more concise Perl code. Or you could lock a file you find in $x and see if you hold the lock on that file in $y? (But that assumes that all of your file system exporting technologies convey lock information, which is not always the case, of course.) You could create a pipe in one... etc.

      - tye        

        Or you could lock a file you find in $x and see if you hold the lock on that file in $y

        Or, then, I could create a tempfile (File::Temp) in one, and see whether the tempfile exists in the other!!!

        -- 
        Ronald Fischer <ynnor@mm.st>
      You can check the device and inode field of the results of stat for both directories, but that will only work for file systems that follow the idea the inventors originally had.

      I guess this means "the usual file systems on Unix and Linux". Do you happen to know to what extent this is fulfilled for networked file systems on Windows?

      You can readdir the directories and consider them to be the same if they contain the same files.
      In my case, this would mean I would have to actually compare the content of the files, because even the sizes could be the same :-(
      Thanks a lot for clarification.

      Update: I just made a test on Windows, and the inode number indeed comes up as zero.
      -- 
      Ronald Fischer <ynnor@mm.st>

        You might take a gander at how rsync for inspiration. Or maybe use rsync -n and see if it thinks there's a difference.

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Re: Finding out whether two directories are the same
by Khen1950fx (Canon) on Aug 28, 2008 at 14:44 UTC
    I tried File::DirCompare and got some interesting results. It'll tell you which files differ, and, if $x and $y are the same directory, it'll simply return a prompt.

    #!/usr/bin/perl use strict; use warnings; use File::Basename; use File::DirCompare; my $dir1 = '/path/to/dir1'; my $dir2 = '/path/to/dir2'; File::DirCompare->compare($dir1, $dir2, sub { my ($a, $b) = @_; if (! $b) { printf "Only in %s: %s\n", dirname($a), basename($a); } elsif (! $a) { printf "Only in %s: %s\n", dirname($b), basename($b); } else { print "Files $a and $b differ\n"; } });