Issue #15615 has been updated by nobu (Nobuyoshi Nakada).

Description updated

とりあえず`NotImplementedError`とも一番近そうな`ENOSYS`を投げるようにしましたが、本来セットされていない`errno`を装うよりは`RuntimeError`あたりのほうがいいのではないかと思います。
もしくは次点で`nil`。

----------------------------------------
Misc #15615: File.birthtimeがLinux環境で有効なファイル作成時刻を得られなかった場合の挙動について
https://bugs.ruby-lang.org/issues/15615#change-76879

* Author: Glass_saga (Masaki Matsushita)
* Status: Open
* Priority: Normal
* Assignee: 
----------------------------------------
`File.birthtime`はファイルの作成時刻を返すメソッドです。
これまでLinux環境ではこのメソッドは実装されておらず、呼び出すと`NotImplementedError`が発生していましたが、r67088から一部のLinux環境でも`File.birthtime`が動作するようになりました。
Linux環境での`File.birthtime`は、`statx()`というLinux 4.11から導入されたシステムコールを使うことで実装されています。

`statx()`には以下の特徴があります。
1. `stat()`では取得できなかった情報が取れる
  * ファイル作成時刻
  * 圧縮や暗号化の有無などの属性
2. どの情報に興味があるかをマスクで指定して使う
  * 指定した情報が返されるとは限らず、指定していない情報まで返される場合もある
  * 指定された情報の一部または全部を返せなかった場合でも戻り値は0であり、`errno`もセットされない
3. `struct statx`という`struct stat`とは異なる構造体を返す
4. 返された`statx`構造体のうち、どの情報が有効であるかは`stx_mask`というメンバに格納される

`statx()`でファイルの作成時刻が得られるかどうかはファイルシステム依存であり、有効な値が得られない場合があります。
2.に挙げたように、`statx()`はこの場合でも0を返し`errno`もセットされません。
r67088では、`stx_mask`を参照して作成時刻が有効であるかどうかを確かめ、無効であった場合は`NotImplementedError`を`raise`します。
`File.birthtime`は`Time`を返すことが期待されているので、値が無効だからといって`nil`を返す訳にもいかないと考えたからです。

しかし、`NotImplementedError`はプラットフォーム依存で機能の実装・未実装が異なる場合に用いられていることが多いようです。
少なくともfile.cの他の部分では`NotImplementedError`はそのように使われています。
また、spec/ruby/core/file/birthtime_spec.rbには以下のような部分があります。

```ruby
  platform_is :linux, :openbsd do
    it "raises an NotImplementedError" do
      lambda { File.birthtime(@file) }.should raise_error(NotImplementedError)
    end
  end
```

このテスト自体の是非はともかく、このように`NotImplementedError`がプラットフォーム依存で発生するものと期待されている面はあるのではないかと思います。
そう考えると、ファイルシステム依存で`NotImplementedError`を発生させることは好ましくないかもしれません。
※ r67115では`Errno::ENOSYS`を発生させるよう変更されました。

このような状況で、`statx()`で有効なファイル作成時刻が得られなかった場合`File.birthtime`はどのように動作すべきかをこのチケットで議論いただければと思います。



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>