device_number

今日はデバイス番号を格納する"PN" System Use Entryを実装しようと思ったのですが、アーカイバ毎にデバイス番号の持ち方が違うため、これらを抽象化するための構造体、device_numberを考えてみました。
<hamigaki/filesystem/device_number.hpp>


POSIXではファイルのデバイス番号はdev_t型で、stat()関数で取得したstat構造体のst_rdevメンバです。
dev_tがどんな型なのかは特に規定されていません。
Wikipedia:Device_nodeによると、通常はデバイスドライバを識別する「メジャー番号」と個々のデバイスを識別する「マイナー番号」を組み合わせた数値のようです。
伝統的には、メジャー番号=8ビット、マイナー番号=8ビットで、

# define major(x) (((x) >> 8) & 0xFF)
# define minor(x) ((x) & 0xFF)

のようなものでしたが、最近では、16ビットでは足りなくなったようで、Linuxなら、

# define major(x) (((x) >> 20) & 0xFFF)
# define minor(x) ((x) & 0xFFFFF)

HP-UXなら、

# define major(x) (((x) >> 24) & 0xFF)
# define minor(x) ((x) & 0xFFFFFF)

のようになっています。
FreeBSD等では、

# define major(x) (((x) >> 8) & 0xFF)
# define minor(x) ((x) & 0xFFFF00FF)

という奇妙な配置です。


さらに、デバイス/メジャー/マイナー番号が環境によって符号付き整数だったり、符号なし整数だったりで、環境に依存しないコードを書きにくくなっています。
device_numberでは仕方なくメジャー/マイナー番号にboost::intmax_tを使っています。
バイス番号とメジャー/マイナー番号の相互変換は環境に大きく左右されるため、POSIX外のマクロ(または関数)で行うことにしました。
本当は変換時にオーバーフローを検知したいのですが、仕様がバラバラすぎて対応できていません。
いっそのこと、環境ごとに別実装を持ったほうがよいかもしれません。