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

I have a function that accepts a filehandle from the calling code. Is there anyway by which I can get the original filename the filehandle is opened on?

--
The Snowman
snowman@notreally.co.uk

Replies are listed 'Best First'.
Re: Retriving Filename from Filehandle
by grinder (Bishop) on Dec 18, 2001 at 22:29 UTC
    I'm not aware that it is possible. I have build hashrefs in the past to keep the two pieces of information together. In the simplest case, it looks something like this (warning, untested code ahead):

    use IO::File; my $file; $file->{name} = '/tmp/foo'; $file->{fd} = IO::File->new( $file->{name} ) or die "$!\n"; # TODO: +more explicit error message # this lets me do stuff like $file->{fd}->print( "The name of this file is $file->{name}\n" ); $file->{fd}->close();

    But that means that you have to start passing these hashrefs around, instead of raw IO::File objects, so that may mean major surgery on your code.

    And now I will probably be tarred and feathered for not knowing that the IO::File or one of its ancestors has some really useful method, like name() or something.

    --
    g r i n d e r
    just another bofh

    print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u';
      You could just write a subclass of IO::File which keeps track of this stuff for you. Since an IO::File object is a glob reference, you can stuff the additional info in the hash portion of the glob (I believe...).

      It's really a shame that a filehandle can't be supplied as the filename parameter to open(). As it is, many (most?) Perl modules don't work correctly under Windows because their interfaces use filename parameters and can't handle Unicode filenames.

        So, behaving as if the mode was <& instead of < when a handle is provided? Interesting. You could submit the idea to the Perl devs (perl5-porters@perl.org).

Re: Retriving Filename from Filehandle
by ikegami (Patriarch) on Jan 28, 2019 at 02:07 UTC

    Yes, it's possible on some systems (assuming the Perl file handle is associated with a system file handle). For example, the following works on (some?) Linux systems:

    $ perl -e' open(my $fh, "<", "/etc/passwd") or die $!; my $fileno = fileno($fh); defined($fileno) or die "Not a file handle"; $fileno >= 0 or die "Not system file handle"; my $qfn = readlink("/proc/$$/fd/$fileno") or die $!; CORE::say $qfn; ' /etc/passwd

    It would be better if your program tracked this itself, though.

    Note that Perl provides $ARGV when reading from ARGV (e.g. using <>).

Re: Retriving Filename from Filehandle
by derby (Abbot) on Dec 18, 2001 at 23:16 UTC
    TSM,

    As others have pointed out, you should keep track up front but if that isn't possible a brute force approach would be to use find and the inode number:

    #!/usr/bin/perl -w use File::Find; open( FH, "/etc/motd" ) || die "cannot open file ($!)\n"; $INO = (lstat(FH))[1]; close( FH ); find( \&wanted, '/etc' ); sub wanted { my( $ino ) = (lstat($_))[1]; if( $ino == $INO ) { print $File::Find::name, "\n"; } }

    Caveats to this approach apply all over the place but it could be usefull if you have some inkling of where in the filesytem to start looking

    -derby

Re: Retriving Filename from Filehandle
by belg4mit (Prior) on Dec 18, 2001 at 22:18 UTC
    I'm pretty sure I've done this before but don't remember. If you're doing the calling one thing to consider is using the filename as the filehandle in the form of a scalar.
    $filename = '/etc/hosts'; open($filename, $filename);

    It is left as an excercies for the reader to worry about potential security pitfalls (Hint: not specifying the mode).

    --
    perl -p -e "s/(?:\w);([st])/'\$1/mg"

Re: Retriving Filename from Filehandle
by SpongeBob (Novice) on Dec 18, 2001 at 22:15 UTC
    No. Filehandles are not neccessarily attached to a physical file with a filename. But maybe it would help to know why you want the filename, and then maybe we can offer alternate suggestions.

      The reason I ask is that a friend asked why if you can do

       stat <filehandle> 
      and have it return the files inode and other infromation, why not it's filename?

      Maybe this is an idea for a new module. but not one I would know how to write

      --
      The Snowman
      snowman@notreally.co.uk 

        Given a file name, it is nearly trivial to find the i-node and other information (that is part of the purpose of a file name, after all). Given an i-node number (and device number), finding the file name(s) requires searching the entire file system (once you've determined which file system from the device number). That is, the mapping is one-way.

        And an i-node can have no file name or can have hundreds of file names.

        Why? Because the mapping needs to be efficient in the one direction but the "need" to go the other direction doesn't justify the extra overhead and complexity so most file systems don't implement the other direction.

                - tye (but my friends call me "Tye")