There is a similar question on how to get a the filename in C, I will present here the answer to this question in a ruby way.
Getting the filename in Linux
Suppose io
is your IO Object. The following code gives you the filename.
File.readlink("/proc/self/fd/#{io.fileno}")
This does not work for example if the file was removed after the io object was created for it. With this solution you have the filename, but not an File object.
Getting a File object which does not know the filename
The method IO#for_fd
can create an IO and it's subclasses for any given integer filedescriptor. Your get your File object for your fd by doing:
File.for_fd(io.fileno)
Unfortunely this File object does not know the filename.
File.for_fd(io.fileno).path # => nil
I scanned through the ruby-1.9.2 sources. There seems to be no way in pure ruby to manipulate the path after the file object was created.
Getting a File object which does know the filename
An extension to ruby can be created in C which first calls File#for_fd
and afterwards manipulates the Files internal data structures. This sourcecode does work for ruby-1.9.2, for other versions of ruby it may has to be adjustet.
#include "ruby.h"
#include "ruby/io.h"
VALUE file_fd_filename(VALUE self, VALUE fd, VALUE filename) {
VALUE file= rb_funcall3(self, rb_intern("for_fd"), 1, &fd);
rb_io_t *fptr= RFILE(rb_io_taint_check(file))->fptr;
fptr->pathv= rb_str_dup(filename);
return file;
}
void Init_filename() {
rb_define_singleton_method(rb_cFile, "for_fd_with_filename", file_fd_filename, 2);
}
Now you can do after compiling:
require "./filename"
f= File.for_fd_with_filename(io.fileno, File.readlink("/proc/self/fd/#{io.fileno}"))
f.path # => the filename
The readlink could also be put into the File#for_fd_with_filename
definiton. This examples is just to show how it works.