Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get a filename from an IO object in ruby

Tags:

io

ruby

In ruby...

I have an IO object created by an external process, which I need to get the file name from. However I only seem to be able to get the File descriptor (3), which is not very useful to me.

Is there a way to get the filename from this object or even to get a File Object?

I am getting the IO object from notifier. So this may be a way of getting the file path as well?

like image 886
Yule Avatar asked Oct 25 '11 10:10

Yule


People also ask

What is __ file __ in Ruby?

__FILE__ is the name of the current file. The script bellow test if the current file is the one we use on the command line, with : ruby script.rb if __FILE__ == $0 puts "we are running this file (it's not included somewhere)" end.

What is an IO object Ruby?

An IO object is a bidirectional channel between a Ruby program and some external resource. [For those who just have to know the implementation details, this means that a single IO object can sometimes be managing more than one operating system file descriptor.

What is EOF in Ruby?

Raised by some IO operations when reaching the end of file. Many IO methods exist in two forms, one that returns nil when the end of file is reached, the other raises EOFError . EOFError is a subclass of IOError .


1 Answers

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.

like image 58
johannes Avatar answered Sep 27 '22 18:09

johannes