書いた人:西山
Ruby には便利な標準添付ライブラリがたくさんありますが、なかなか知られていないのが現状です。そこで、この連載では Ruby の標準添付ライブラリを紹介していきます。
今回は tmpdir と tempfile についてです。 名前が似ていますが、歴史的理由により tmpdir は e なしの tmp で tempfile は e ありの temp になっています。 tmpdir は dir が 3 文字なので tmp も 3 文字、tempfile は file が 4 文字なので temp も 4 文字と覚えると良いかもしれません。
詳細は後述しますが、安全に一時ファイルを作成するのは素人には難しいので、一時ファイルなどを使うときは、自分で独自実装をせず既存のライブラリを使うことをおすすめします。
テンポラリディレクトリ (一時ディレクトリ) を扱うためのライブラリです。
一般的には、何か一時的な作業をするディレクトリとして “/tmp” などを使うべきではありません。 OS によっては存在しなかったり、使い方を間違えるとセキュリティホールの原因になったりします。
そういう場合に ruby では tmpdir ライブラリを使います。
Dir.tmpdir を使うと OS や環境変数や $SAFE に応じて、テンポラリディレクトリとして使うのに適切な絶対パスを取得できます。
Linux での実行例:
Windows での実行例:
ユーザが環境変数を設定している場合:
さらに safe level が 1 以上の場合:
セキュリティを考慮するなら symlink attack などの可能性があるため、Dir.tmpdir の直下に直接ファイルを作ったりせず、次の Dir.mktmpdir を使ったり、後述の tempfile を使う方がおすすめです。
詳しくは後述のセキュリティのところで紹介しているリンク先を参照してください。
ruby 1.8.7 以降の tmpdir には Dir.mktmpdir が追加されています。
Dir.mktmpdir を使うと一時ディレクトリを作成できます。 作られるディレクトリのパーミッションは 0700 になっています。
ブロック付きで Dir.mktmpdir を使うと、ブロックの引数に作成された一時ディレクトリのパスが渡されて、作成された一時ディレクトリやその中のファイルが Dir.mktmpdir から返るときに FileUtils.remove_entry_secure で削除されます。 カレントディレクトリは変わらないので、必要ならブロック付きの Dir.chdir と組み合わせると便利でしょう。
例:
第一引数に文字列を渡すと作成するディレクトリの prefix を指定できます。(指定しなかった場合は “d” になります。)
例:
第一引数に 2 要素の配列を渡すと作成するディレクトリの prefix と suffix を指定できます。
例:
第二引数にパスを指定すると、そのディレクトリの中に一時ディレクトリを作成します。 指定しなかった場合には Dir.tmpdir の中に作成されます。
第二引数だけ指定したい場合は第一引数に nil を渡します。
例:
ブロックなしで Dir.mktmpdir を呼びだすと、作成されたディレクトリを返します。 このとき、 Dir.mktmpdir はディレクトリを消さないので、自分でどうにかする必要があります。
例:
tempfile ライブラリはテンポラリファイル (一時ファイル) を扱うためのライブラリです。
Tempfile は Dir.mktmpdir と違って finalizer でファイルの削除をするようになっているため、 GC や ruby の終了時に自動でファイルが削除されます。 しかし、開いたファイルは閉じるのが行儀が良いように、Tempfile も使い終わったらちゃんと消すのがおすすめです。
例:
ruby 1.8.7 以降の tempfile では Dir.mktmpdir と同様に第一引数に 2 要素の配列を渡すと prefix と suffix を指定できます。 拡張子によって処理内容が決まるコマンドの引数に使うなど、一時ファイルの拡張子を指定する必要があるときに使います。
ブロックなしで呼び出した場合は Tempfile.new と同じです。
ブロック付きで呼び出した場合は File.open と同じように Tempfile オブジェクトを引数としてブロックが呼ばれ、 ブロックから抜けるときにファイルは自動的に閉じて削除されます。
一時ファイルを閉じます。 引数に true を指定すると、一時ファイルの削除もします。
Tempfile#close(true) と同じです。
close した後、再度開くのに使います。
一時ファイルを削除します。
Unix 系の OS では open したまま unlink することにより、
という状態になります。
詳しくは http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c603.html の「ファイルを作成したら unlink する」を参照してください。
Windows では開いているファイルを削除することが出来ないので、 いろいろな環境で動かしたいプログラムを作成する場合には注意してください。
一時ファイルのパスを返します。
一時ファイルを別プログラムとの連携に使う場合などに使います。
一時ファイルの主な用途としては、
などがあるようです。
という条件で子プロセスを起動したいことがありました。
そのとき、いくつか方法を考えてみたところ、
#{cmd} 2>&1
」だと標準出力と標準エラー出力が混ざるという問題がありました。
そこで Tempfile で作成したファイルにリダイレクトするという方法を使いました。 そのときのプログラムの tempfile を使用した部分を再現したものが以下のプログラムです。
安全に一時ファイルを作成するのは素人には難しく、http://www.ipa.go.jp/security/awareness/vendor/programmingv2/contents/c603.html の「使用を避けた方がよい関数」にあるように問題がある実装になりがちなので、普通はライブラリを使いましょう。 ライブラリを使っていれば、問題がある可能性は自分で実装するより低く、問題がみつかった場合もきちんと修正されることが期待できます。
また、どのような問題があり、どう対処すれば良いのかは http://www.ipa.go.jp/security/fy20/reports/tech1-tg/2_05.html も参考になります。
今回は tmpdir と tempfile を紹介しました。 一時ファイルなどを使うときは、自分で独自実装をせず既存のライブラリを使い、セキュリティや削除されずにゴミファイルが残る可能性を考慮した使い方をすると良いと思います。
西山和広。 最近は文字コード関連やフォント関連も勉強中。