リポジトリまでのパスに日本語を使用している場合の障害(cp932)

382 views
Skip to first unread message

フジワラ

unread,
May 18, 2012, 6:28:53 AM5/18/12
to mercur...@googlegroups.com
藤原です。

ちょっと面倒な条件になりますが、以下の条件を満たすケースでは、リポ
ジトリまでのパスに「ソ」や「能」といった 0x5c (バックスラッシュ)を含む
文字が使用された際に、正常に動作しない可能性があります。

  - 文字コードに cp932 を使用している

  - 日本語ファイル名を使用するために win32mbcs 拡張を使用している

  - リポジトリそのもののパスにも日本語を使用する可能性がある

  - リポジトリ位置に移動する操作『無し』で作業する可能性がある
    - TortoiseHg 等の GUI 経由での操作、ないし
    - -R/--cwd 等を明示的に指定しての操作

上記の条件に該当する可能性のある方は、Mercurial や TortoiseHg に同
梱されている win32mbcs ではなく、本エントリに添付されているものを
使用してください。

Windows ネイティブの Mercurial や TortoiseHg は、Python ライブラリ
群を zip アーカイブしてしまっているので、アーカイブをあれこれ書き
換えるよりは、以下の手順で添付の win32mbcs.py の読み込みを優先させ
るのが良いでしょう。

  1. win32mbcs.py を適当なディレクトリに保存する

  2. 設定ファイルを開く(「リポジトリ毎」設定ではなく、「グローバル」
     設定レベルを対象にした方が良いでしょう)

  3. [extensions] での設定で "win32mbcs=" ない
     し "hgext.win32mbcs=" となっている箇所を
     "win32mbcs = win32mbcs.py の保存先" と記述して、
     明示的に読み込みファイルを指定する

なお、本エントリは、早期の情報共有を優先して、コマンドライン版での
動作確認レベルで投函しています。

TortoiseHg での動作確認はこれから実施しますが、TortoiseHg の hg コ
マンド連携の実装次第(e.g.: TortoiseHg 側で chdir() してから
fork/exec)では、上記対応は不要な可能性がありますのでご了承ください。


win32mbcs.py

フジワラ

unread,
May 18, 2012, 6:58:00 AM5/18/12
to mercur...@googlegroups.com
藤原です。

ここから先は、例によって GOTO さんへの業務連絡です(笑)。

修正版 win32mbcs は、対処対象に os.path.abspath os.path.realpath
を加えたのですが、利用している箇所が結構あったので、意図的に除外していた
のか?と心配したりしてますが、どうなのでしょう?

========================================
diff -r 5983de86462c hgext/win32mbcs.py
--- a/hgext/win32mbcs.py    Thu May 03 16:03:08 2012 -0500
+++ b/hgext/win32mbcs.py    Fri May 18 19:44:17 2012 +0900
@@ -127,7 +127,8 @@
 # NOTE: os.path.dirname() and os.path.basename() are safe because
 #       they use result of os.path.split()
 funcs = '''os.path.join os.path.split os.path.splitext
- os.path.normpath os.makedirs
+ os.path.normpath os.path.abspath os.path.realpath
+ os.makedirs
  mercurial.util.endswithsep mercurial.util.splitpath mercurial.util.checkcase
  mercurial.util.fspath mercurial.util.pconvert mercurial.util.normpath
  mercurial.util.checkwinfilename mercurial.util.checkosfilename'''
========================================

あるいは、Python の版によって挙動が違うとか?

私の Python 2.7.2 @ win7 64bit 環境だと:

========================================
>> p = 'c:\\\x8b\x40\x94\x5c'
>> print p
c:\機能
>> os.path.abspath(p)
'c:\\\x8b@\x94'
>> print os.path.abspath(p)
c:\機(壊れた文字)
========================================

みたいな感じで、パス末尾のバックスラッシュが破棄されてしまうの
で、-R でリポジトリパスを指定すると、これらで処理済みのパスを探し
に行って、『リポジトリが無いよ』とエラー中断してしまいます。

その場合でも、エラーメッセージ中に表示されるパスは処理前のパスなので、
『無いと言っているパスはちゃんと存在しているのに!?』などと驚く事態に。

2012年5月18日金曜日 19時28分53秒 UTC+9 フジワラ:

flied onion

unread,
May 18, 2012, 7:39:02 AM5/18/12
to mercur...@googlegroups.com
flied onionです。
 
自宅の環境でも再現したのでflash形式の動画で報告させていただきます。小さめに抑えたつもりですが、サイズなど問題がある場合はおっしゃっていただければ削除いたします。
(その場合、可能であれば管理者様から削除していただいてもかまいません。)
 
IEなどのブラウザにドロップすれば再生可能だと思います。
 
藤原さんの修正版ではまだためしていません。
win32mbcs_problem_tortoiseHg2_4.swf

Shun-ichi Goto

unread,
May 18, 2012, 8:11:41 AM5/18/12
to mercur...@googlegroups.com
2012年5月18日 19:58 フジワラ <flying...@gmail.com>:
> ここから先は、例によって GOTO さんへの業務連絡です(笑)。

ついったーではんのうできずにすみません。

> 修正版 win32mbcs は、対処対象に os.path.abspath os.path.realpath
> を加えたのですが、利用している箇所が結構あったので、意図的に除外していた
> のか?と心配したりしてますが、どうなのでしょう?

当時そこらをどう判断したかはきちんと思い出せませんが、意図的に除外したのかも
しれません。確か意図的に除いたものがあった記憶があるので。
おそらく、通常のwindows環境では nt._getfullpathname() が使え、
その場合は abspath()は _getfullpathname() と normpath() くらいしか呼んでないから。
とはいえ _getfullpathname()は当時どう判断したか記憶にないのですが。。。
_getfullpathname()が使えないケースでは isabs()とか使ってて、こいつはご判断しそう
ですが、そのケースは普通とおらないと思うし。

ところで、abspath()をフックすることで問題は解決したのでしょうか。
リポジトリパスに日本語が含まれる場合の問題は、extensionがロードされる前に
パス操作が行われてる部分があり、そこはextensionでは救えないというのが
あったのですが、そこは通過した以降に問題が発生してたということでしょうかね。

あと、 print os.path.abspath(p) の結果が壊れてても、 normapath() がラップされて
いれば、つまり mercurial 上で win32mbcsが聞いた状態ならば print os.path.abspath()
も正常な値を返すと思います。そんな判断をしたんだったかと。

--
Shun-ichi GOTO

Shun-ichi Goto

unread,
May 18, 2012, 8:27:21 AM5/18/12
to mercur...@googlegroups.com
2012年5月18日 21:11 Shun-ichi Goto <shunic...@gmail.com>:
> ところで、abspath()をフックすることで問題は解決したのでしょうか。
> リポジトリパスに日本語が含まれる場合の問題は、extensionがロードされる前に
> パス操作が行われてる部分があり、そこはextensionでは救えないというのが
> あったのですが、そこは通過した以降に問題が発生してたということでしょうかね。

あ、これは記憶違いだったかも。extsetup()を使ってフックを仕掛けるようにした時に、
副作用としてある程度解決してたかも。その当時に作った unitttest がそんな感じに
コメントが書いてあったw

今回のそれがテストケースに含まれてないものなのかちょっと確認してみます。
障害報告の動画もこれから見てみます。

--
Shun-ichi GOTO

フジワラ

unread,
May 18, 2012, 8:30:44 AM5/18/12
to mercur...@googlegroups.com
藤原です。

とりあえず、結論を先に…… orz

    お騒がせしました!
     リポジトリへのパスに 0x5c("\") を含む日本語文字が使用されていても
    同梱版の win32mbcs が有効になっていれば大丈夫です!

以下、業務連絡。

2012年5月18日金曜日 21時11分41秒 UTC+9 Shun-ichi GOTO:
2012年5月18日 19:58 フジワラ <flying...@gmail.com>:
 
> 修正版 win32mbcs は、対処対象に os.path.abspath os.path.realpath
> を加えたのですが、利用している箇所が結構あったので、意図的に除外していた
> のか?と心配したりしてますが、どうなのでしょう?

当時そこらをどう判断したかはきちんと思い出せませんが、意図的に除外したのかも
しれません。確か意図的に除いたものがあった記憶があるので。
おそらく、通常のwindows環境では nt._getfullpathname() が使え、
その場合は abspath()は _getfullpathname() と normpath() くらいしか呼んでないから。
とはいえ _getfullpathname()は当時どう判断したか記憶にないのですが。。。
_getfullpathname()が使えないケースでは isabs()とか使ってて、こいつはご判断しそう
ですが、そのケースは普通とおらないと思うし。

ところで、abspath()をフックすることで問題は解決したのでしょうか。
リポジトリパスに日本語が含まれる場合の問題は、extensionがロードされる前に
パス操作が行われてる部分があり、そこはextensionでは救えないというのが
あったのですが、そこは通過した以降に問題が発生してたということでしょうかね。

localrepository のコンストラクタ上で、self.root にパスを代入する際に、
os.path.abspath/realpath を適用するところでコケていました。
 
あと、  print os.path.abspath(p)  の結果が壊れてても、 normapath() がラップされて
いれば、つまり mercurial 上で win32mbcsが聞いた状態ならば print os.path.abspath()
も正常な値を返すと思います。そんな判断をしたんだったかと。

あれ?と思って、素の win32mbcs で確認してみたら、確かにちゃんと
動作しました…… orz

多分動作確認する際に、手順を間違えて win32mbcs の有効化設定まで
無効になっていたのだと思います。 内部的に normpath が呼ばれることで、
abspath/realpath の問題が解消されているみたいです。

毎度毎度お騒がせしました。

ちなみに、備忘録代わりに twitter でつぶやいたのですが、以下の箇所は
対応修正が必要ですよね?

    - subrepo.py の reporelpath() で rstrip(os.sep)
    - util.py の uirepr()

Yuya Nishihara

unread,
May 18, 2012, 8:47:13 AM5/18/12
to mercur...@googlegroups.com
西原です。こんばんは。

On 05/18/2012 08:39 PM, flied onion wrote:
> 自宅の環境でも再現したのでflash形式の動画で報告させていただきます。
> 小さめに抑えたつもりですが、サイズなど問題がある場合はおっしゃっていただければ削除いたします。
> (その場合、可能であれば管理者様から削除していただいてもかまいません。)

メニューから rollback した時に win32mbcs のエラーが表示される件は、 TortoiseHg の
バグです。

https://bitbucket.org/tortoisehg/thg/changeset/8bfcdef2a3b8

リストのところに文字列なんか渡してるので、各バイトに分割されてしまい、結果として
win32mbcs が不正なバイト列を検出していました。

では。

Shun-ichi Goto

unread,
May 18, 2012, 9:20:25 AM5/18/12
to mercur...@googlegroups.com
2012年5月18日 21:30 フジワラ <flying...@gmail.com>:
> ちなみに、備忘録代わりに twitter でつぶやいたのですが、以下の箇所は
> 対応修正が必要ですよね?
>
> - subrepo.py の reporelpath() で rstrip(os.sep)

これはモロに該当しますね。
しばらくは split とか os.sep とか、直接使われるとヤバイものを定期的に
grepしてたのですが、久しくしてないや

> - util.py の uirepr()

これはなんかよくわからんです。
uirepr()が導入されたのは %r だと困るからなのなのはわかりますが、
そもそもなんで %r だったんでしょね。
これだと 0x5cとか関係なくsjisコードはエスケープされちゃいますし、
utf-8 な環境であっても同じではないかと。

でもって、これは win32mbcsでラップしたところで、sjisバイト列が
エスケープ表現された文字列が出る代わりに unicode のエスケープ表現が
得られるだけなのでラップする意味は無いんじゃないかな。

なので、どう直すのが正しいんですかねぇ。
本来やりたいことは何だったのやら。
日本語パスはそのまま日本語として出して、
イリーガルな文字はエスケープして、というのが欲しいのかな?

--
Shun-ichi GOTO
Reply all
Reply to author
Forward
0 new messages