Obtaining mode information on a File object

J

Jos Backus

Another question... How do I access the File open mode ("w" in this case) on a
File object? Example:

class Foo
def initialize(file)
begin
yield self
ensure
# We only want to call finalize when the file was opened for writing;
# The following doesn't work, but how _do_ you do this?
finalize(file) if file.mode.writable? # file was opened with mode "w"
end
end
def finalize(file)
file.puts "END"
end
end

File.open("foo", "w") do |file|
a = Foo.new(file) do
# ... Use a ...
end
end

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
R

Robert Klemme

Jos Backus said:
Another question... How do I access the File open mode ("w" in this case)
on a
File object? Example:

class Foo
def initialize(file)
begin
yield self
ensure
# We only want to call finalize when the file was opened for writing;
# The following doesn't work, but how _do_ you do this?
finalize(file) if file.mode.writable? # file was opened with mode "w"
end
end
def finalize(file)
file.puts "END"
end
end

File.open("foo", "w") do |file|
a = Foo.new(file) do
# ... Use a ...
end
end

First of all, I know no other way than to just try to write to the file and
see what happens. Maybe writing an empty string is a solution on some
(all?) platforms.

But I think usually you don't need that info: if a method requires an IO
object open for writing then it simply uses it that way and you get bitten
by an exception if it's not open for writing. Similar applies for files
needed for reading.

What is the scenario where you need that?

Kind regards

robert
 
J

Jos Backus

First of all, I know no other way than to just try to write to the file and
see what happens. Maybe writing an empty string is a solution on some
(all?) platforms.

I hadn't thought of that. It seems... wrong. This information is available
already, it's a matter of making it accessible using an attribute reader.
But I think usually you don't need that info: if a method requires an IO
object open for writing then it simply uses it that way and you get bitten
by an exception if it's not open for writing. Similar applies for files
needed for reading.

What is the scenario where you need that?

I'm writing a class to handle CPIO archives. Iff the file passed in was opened
for writing I want to call a finalizer that appends a trailer, as in the above
code snippet.

I'm currently looking at io.c to see if the vmode variable in rb_open_file
can't be exported somehow, like filename. One issue is that the mode argument
can be either a String or Fixnum (things like O_RDONLY), which complicates
matters.

Thanks,
--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
T

Tanaka Akira

Jos Backus said:
Another question... How do I access the File open mode ("w" in this case) on a
File object? Example:

% ruby -rfcntl -e '
open("/dev/null") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
open("/dev/null", "w") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
open("/dev/null", "r+") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
'
0
1
2

0 means O_RDONLY. 1 means O_WRONLY. 2 means O_RDWR.

I don't know this is portable enough.

Note that this doesn't work for duplex pipe.

% ruby -rfcntl -e '
open("|echo", "r+") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
'
0
 
J

Jos Backus

% ruby -rfcntl -e '
open("/dev/null") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
open("/dev/null", "w") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
open("/dev/null", "r+") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
'
0
1
2

0 means O_RDONLY. 1 means O_WRONLY. 2 means O_RDWR.

I don't know this is portable enough.

This is good enough for my purposes (it only needs to run on Linux), thanks.

Otoh, how about creating an IO.mode instance method that returns the opposite
of what rb_io_mode_flags() produces? rb_io_mode_flags() turns a mode string
into a flags value which OR's some FMODE_* constants. What if we would have a
method which would take fptr->mode and return this as a String? It would be
as portable as Ruby's idea of the file's mode. If there's interest, I can whip
up a patch which should be pretty small.
Note that this doesn't work for duplex pipe.

% ruby -rfcntl -e '
open("|echo", "r+") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
'
0

Okay. I also notice this asymmetry:

irb(main):001:0> require 'fcntl'
=> true
irb(main):002:0> open("|echo", "r") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
2
=> nil
irb(main):003:0> open("|echo", "w") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
2

=> nil
irb(main):004:0> open("echo|", "r") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
0
=> nil
irb(main):005:0> open("echo|", "w") {|f| p f.fcntl(Fcntl::F_GETFL) & Fcntl::O_ACCMODE }
1
=> nil
irb(main):006:0>

Thanks!

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 
J

Jos Backus

I can whip up a patch which should be pretty small.

Fyi: I just submitted a small patch to ruby-core.

--
Jos Backus _/ _/_/_/ Sunnyvale, CA
_/ _/ _/
_/ _/_/_/
_/ _/ _/ _/
jos at catnook.com _/_/ _/_/_/ require 'std/disclaimer'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top