Skip to content

Instantly share code, notes, and snippets.

@l15n
Created November 21, 2009 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save l15n/240212 to your computer and use it in GitHub Desktop.
Save l15n/240212 to your computer and use it in GitHub Desktop.
=======================================================
39606 [Feature:trunk] Dir instance methods for relative path
=======================================================
[ruby-dev:39606] Nobu suggests having an instance method on Dir for accessing relative paths, with an implementation in the mvm branch. He came up with this idea after reading Akira TANAKA's article on handling temporary files and symlink attacks (http://www.ipa.go.jp/security/fy20/reports/tech1-tg/2_05.html). Example usage:
$ ./ruby -v -e 'p Dir.open("ext"){|d|d.open("extmk.rb"){|f|f.gets}}'
ruby 1.9.1 (2008-12-25 mvm 20976) [i686-linux]
"#! /usr/local/bin/ruby¥n"
$ mkdir tmp
$ touch tmp/x tmp/y
$ ./ruby -e 'p Dir.open("tmp"){|d|d.unlink("x")}'
0
$ ls tmp/
y
[ruby-dev:39607] matz notes that open, unlink and various other methods exist for handling files in a directory.
[ruby-dev:39611] Motohiro KOSAKI comments that, from a security perspective, usage of openat() should be encouraged, and agrees that it should be easier to use. He also asks what is wrong with:
open(dir, relative-path)
[ruby-dev:39614] nobu asks Motohiro to clarify whether 'dir' in the example is an instance of Dir or File. Nobu also mentions that it may be hard to distinguish from Dir#to_path
[ruby-dev:39620] Motohiro feels that, when faced with the need to open a file via a relative path, most people would not think of looking up the API for the Dir class, but instead just attempt to use the regular file opening semantics, i.e.
open(dir, relative-path) or
openat(dir, relative-path)
As an aside, he asks whether openat is disliked because it is a clumsy name.
[ruby-dev:39620] matz agrees with Motohiro that the Dir class isn't the most intuitive place to look, but comments that open(dir, relative-path) is difficult for reasons nobu has mentioned earlier. open(relative-path, "rw", base: dir) may be possible, but is a bit verbose.
As for openat, matz says that he initially thought that openat was short for openate (as in create/creat) and tried to look it up in the dictionary!
[ruby-dev:39625] Yui NARUSE points out that new APIs should be based on real use cases or may never be used. The initial temporary directory example could be instead handled with fileutils. The other given example:
> ./ruby -v -e 'p Dir.open("ext"){|d|d.open("extmk.rb"){|f|f.gets}}'
isn't very likely to be used by ordinary users.
On the other hand,
> ./ruby -v -e 'p open(["ext", "extmk.rb"]){|f|f.gets}}'
> ./ruby -v -e 'p open([dir, "extmk.rb"]){|f|f.gets}}'
could be a good idea, if it removes the hassle of #join
[ruby-dev:39648] nobu asks whether Yui NARUSE is suggesting that a new class is perhaps needed.
He also points out that
> ./ruby -v -e 'p open(["ext", "extmk.rb"]){|f|f.gets}}'
> ./ruby -v -e 'p open([dir, "extmk.rb"]){|f|f.gets}}'
may be easier to type, but doesn't do anything about symlink attacks.
[ruby-dev:39649] Yui NARUSE suggest, perhaps, a Fileinfo class with a file handle to the parent directory and a relative path to that directory. For example, it could be used in the following way with Dir.foreach
Dir.foreach("/tmp") do |fileinfo|
fileinfo.open{|f| f.read} if fileinfo.file?
end
Yui NARUSE also clarifies that in
> ./ruby -v -e 'p open(["ext", "extmk.rb"]){|f|f.gets}}'
the join is not used on the array argument of open, but rather that open would first access ext, and then use openat to access extmk.rb.
That is, where you currenty write:
open(File.join(dir, "extmk.rb")){|f|f.gets}}
you could instead write:
open([dir, "extmk.rb"])
[rub-dev:39654] Akira TANAKA writes in reply to Yui NARUSE's [ruby-dev:39625] that although APIs optimized for common tasks are important, APIs that are capable doing everything necessary are also important. Ideally, APIs would be optimized to do common tasks, while also capable of everything necessary...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment