MSYS的「inode」

なんのこっちゃ。

MSYS がなんだかんだ「インチキな Unix もどき」であることは、ワタシは何度か言ってきた通り。色々と「妥協の産物」なのだが、ネイティブな Windows プログラマでもあったワタシにとっては、妥協の理由はいちいち納得出来ている。

ふと初めて気付いたことがあったので。

その前に、「inode」は説明必要かしら? 非常に当たり前の話なんだけれど、「ファイル「名」」というのはこれは「人間向け」に過ぎなくて、システム内部で「ファイル「名」」そのものをファイルのアイデンティティとして使う合理的な理由は特にない。これを Unix では伝統的に「inode」という ID で行ってきたわけだ。そして Windows にだって近いものがある。

Unix の inode も Windows の「それに似たもの」もともに、エンドユーザが自在に駆使できるようにはなってない。原則としてこれはシステム内部向けに使われるものである。つまり、エンドユーザとしては本当は「「ファイル「名」」が使える場所ならどこででも inode を」と願いたいのだが、実際これを受け付けてくれるものは非常に限られている。これが出来るとね、「日本語問題を起こすようなとらぶるさむなファイル名」を迂回出来てハッピーなんだけどね、そうもいかない。

で、今回気付いたこと。これね:

aaa.py
 1 # -*- coding: utf-8 -*-
 2 import sys
 3 import os
 4 
 5 def get_fileid(fn):
 6     import win32file  # needs pywin32
 7     #
 8     dwFlagsAndAttributes = 0
 9     if os.path.isdir(fn):
10         dwFlagsAndAttributes = win32file.FILE_FLAG_BACKUP_SEMANTICS
11     fh = win32file.CreateFileW(
12         fn,
13         win32file.GENERIC_READ,
14         win32file.FILE_SHARE_READ,
15         None,
16         win32file.OPEN_EXISTING,
17         dwFlagsAndAttributes,
18         None)
19     #
20     (
21         attributes,
22         created_at, accessed_at, written_at,
23         volume,
24         file_hi, file_lo,
25         n_links,
26         index_hi, index_lo
27     ) = win32file.GetFileInformationByHandle(fh)
28     fh.Close()
29     return index_hi, index_lo
30 
31 fn = sys.argv[1]
32 hi, lo = get_fileid(fn)
33 print(hi + lo)
34 
35 # MSYS stat (or you can use `ls -i')
36 os.system('''sh -c "stat -c %i '{}'"'''.format(fn))
1 [me@host: ~]$ ls -i zzz.txt
2 13045817 zzz.txt
3 [me@host: ~]$ python aaa.py zzz.txt
4 13045817
5 13045817

あらら…。hi + lo なのね…。

「Windows の「それに似たもの」」は、コードスニペットで示した通り、「GetFileInformationByHandle API」呼び出しで得られる「FileIndexHi」と「FileIndexLo」。これ、32bit Windows 時代の API だけれども 64bit で管理するために、32bit の High、32bit の Low に分割して収めてるわけね。なので本来は「これを 64bit として解釈」しなければならないし、それこそが「アイデンティティ」。high と low を足し算するのは間違いで、当然「意図しない衝突」がありえる。

今の最新の Unix ファミリがどう措置してるのかは知らないんだけど、当然元々の Unix の inode は 32bit。で、MSYS はこの仕様に合わせるために誤魔化した、てことか…。

たまに inode でアクセスしたいことがあってたまにそれを活用してたんだけど気付かなかった。どういう時に良く使いたくなるかは無論「日本語なんか嫌いだ」の時:

1 [me@host: ~]$ ls
2 ほげ.txt ほげ2.txt bbb.txt cc2.txt
3 [me@host: ~]$ ls *2.txt
4 ほげ2.txt cc2.txt
5 [me@host: ~]$ ls -i1 *2.txt
6  117611546 ほげ2.txt
7  118205519 cc2.txt
8 [me@host: ~]$ cat `find . -num 117611546`
9 はげ

ところで本題とは関係ないのだが、「windows file id」みたいなキーワードでググると日本語で「Windows でファイル ID が 2003/Vista から実装されている」なんて自信満々な「情報」が出てくる。どうしてこういう…。なんてーのかなぁ、「0.1秒以内でわかるガセ」を撒き散らさないで欲しい。GetFileInformationByHandle は Windows XP で使えたっての。