[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[FDclone-users:00235] ChangeLog for FDclone 2.04c
- Subject: [FDclone-users:00235] ChangeLog for FDclone 2.04c
- From: Takashi SHIRAI <shirai@unixusers.net>
- Date: Mon, 29 Sep 2003 23:24:23 +0900
しらいです。
来月に入ったら 2.04c を出そうと思っていますが、今回は変更
箇所が込み入った事情を抱えているので、先に変更点の解説をして
おきます。
1. Cygwin 対応。
以前から request があって、私自身はニーズが理解出来ないで
いたのですが、最近 installer が簡単になったと聞いたので試し
てみました。
やはり WIN32API を無理から UNIX 化しているので普通の UNIX
の常識からは想像のつかない制限が幾つかあるようですね。bug と
見なしても構わないようなものも幾つかあります。
1-1. select() 用の bitmap が小さ過ぎる。
OPEN_MAX が 256 なのに、select() の引数で用いる fd_set 構
造体の bitmap が 64 個分しか用意されていません。なので、沢山
file を open() したり dup2() で大きな番号に割振ったりすると、
select() で入出力状態を調べることが出来なくなってしまいます。
このことは header の comment にも触れられているんですけど、
判ってるんだったらとっとと対処すべきでしょうね。高々 32bytes
を 8bytes にケチったところで何が嬉しいんでしょう。
対処法としては、select() を用いている term.c の compile 時
のみ、-DFD_SETSIZE=256 として fd_set の bitmap size を必要な
分だけ用意するように指定しました。
opendir() したのが「/」かどうかは、DIR 構造体の __d_dirname
要素を見ています。ここには file system としての pathname が
格納されていますので、これが「C:\cygwin\*」ならば「/」という
ことになります。
但し、この値は Cygwin の install directory に依存するので、
getmntent() で「/」の mount する file system 名を調べ、それ
と比較するようにしています。
# 因みに「256」という数値は mkmfdos.c の中で算出しているの
#で、sysconf() 辺りの出した値になってます。OPEN_MAX そのも
#のの値を採用すると 8192 くらいになるんですが、POSIX の場合
#は OPEN_MAX ではなく sysconf() を使うように実装してるので、
#それに準じてあります。
1-2. /cygdrive が readdir() で探せない。
Cygwin では /cygwin/a とか /cygwin/c とかいう pathname で
Windows で言うところの A: とか C: とかを access 出来るのです
が、opendir("/") しても readdir() の結果に「cygdrive」が含ま
れません。
FDclone では全ての path は「/」から readdir() を recursive
に繰返すことで辿り着けることを前提に構築されているので、この
前提が通用しないとあちこちで支障を来たします。
特に tree 画面では「/」から辿れない path を tree 構造で表
現することが出来ないので SIGSEGV で core を吐いてしまいます。
たとえ path が辿れなくとも core を吐くのはさすがにまずいの
で、その辺りの coding は CWD を無視して tree 表示するように
改めました。
その一方で、opendir("/") した時には最後に「cygdrive」を追
加で返すようにしました。DIR 構造体に __flags という要素があ
って、標準では下 2bits しか使われていませんでしたので、最上
位から 2bit 目を flag に使って処理しています。
将来、Cygwin 側で改良されて「cygdrive」を返して貰えるよう
になった時の用意に、readdir() の返り値に「cygdrive」を見つけ
た場合はこの flag を立てることで、重複して「cygdrive」を返さ
ないよう配慮しています。
1-3. DIR 構造体が独特の構造をしている。
一般の UNIX の実装では、DIR 構造体の先頭要素は open された
directory に対する file descriptor を指しているので、負数に
はなり得ないのですが、Cygwin の実装では、DIR 構造体の先頭要
素に cookie の magic number を置いていて、これが signed では
負数になります。
DOSDRIVE 環境の wrapper でもこれと似たようなことをやってい
て、先頭要素が負数ならば DOSDRIVE、正数ならば一般の directory
と判断しています。
Cygwin の cookie の値が負数だったために、DOSDRIVE 機能を有
効にして build した場合には全ての directory が DOSDRIVE 扱い
になってしまって、どの directory も中身を見られない状態にな
っていました。
この対処には、正負の比較ではなく、FDclone の magic number
(-1) かどうかで判断するようにして、Cygwin の magic number が
引っかからないようにしました。
1-3. dirent 構造体が独特の構造をしている。
DIR 構造体同様 dirent 構造体も独特の構造で、d_reclen 要素
が存在しません。
普通は readdir() の返り値は d_name くらいしか使わないので
すが、DOSDRIVE 環境では LFN の有無により directory entry の
大きさが異なるので、これを d_reclen に入れて返すようにしてい
ます。
他の要素を見てみると、一般の UNIX の実装には無い d_fd とい
う要素が見つかったので、こいつに d_reclen の代用をさせるとい
う方法で逃げています。
1-4. pathname が case insensitive。
これは Windows の filesystem を代用している以上避けられな
いところなんでしょうね。
FDclone には元々 IGNORECASE という識別子で case insensitive
にする機能がついていますので、Cygwin 環境ではこの既定値を 1
にしました。
1-5. /cygdrive が open() 出来ない。
通常の UNIX では、chdir() 出来る directory は全て O_RDONLY
で open() 出来る筈です。なので FDclone の実装では、open() 出
来ないような場合は敢えて chdir() しないようにしています。
これは chdir() したはいいけど directory の中身が見えずに何
も操作出来なくなってしまうことを回避するための措置なのですが、
Cygwin 環境では /cygdrive が疑似 pathname なので open() に失
敗します。
対処としては、Cygwin 環境で /cygdrive に chdir() する時の
み、open() の結果に依存しないようにしました。
2. 標準入力リダイレクト時に挙動がおかしかった点を修正。
fd <foo とか bar | fd とかいう形で起動した場合、FDclone の
標準入力は端末でなくなりますが、FDclone はキー入力を端末から
のみ受付けるので、この標準入力の変化に依存してはいけません。
この前提がうまく効いていない箇所が幾つかありました。
2-1. 入力を受付けない。
これは 2.04b で embug した箇所です。標準入力が端末でないの
で non interactive shell と見なされ、端末の初期化を回避して
しまっていました。
端末初期化が邪魔になるのは fdsh として起動された時だけです
ので、fd として起動された時には初期化を回避しないように実装
を改めました。
2-2. EXECUTE_SH が non interactive shell として動く。
多分 2.00 からずっとこうなっていたと思います。job 制御だと
か alias だとか、non interactive shell では不要となる機能が
使えない状態がずっと続いていました。
これも 2-1. と同じことで、fd として起動された時には、常に
interactive shell として動く必要があるので、そのように実装を
改めました。
2-3. ESC で始まるキーコードが判別出来ない。
カーソルキーや機能キーは ESC で始まるシーケンスをキーコー
ドとして吐くのですが、標準入力リダイレクト時にはこれらのキー
が全て ESC キーとして扱われてしまっていました。
これは多分 1.xx の時代からずっと続いている支障だと思います。
原因は select() で見ている file descriptor が端末ではなくて
標準入力になってしまっていた点にあります。
これは単なる実装ミスなのですが、これに関して OS 依存の二つ
の現象が明らかになっています。
一つは Cygwin 環境で、標準入力が端末であるような場合にでも
select() が標準入力に対して効かなくなるという現象が見られま
した。
これまでの実装では、標準入力を select() で監視した結果、端
末から入力を read() していた訳ですが、一般の UNIX ではこれで
も正しくキー入力の感知が可能です。
ところが Cygwin の実装では、端末から read() で一文字拾って
来ると、read() し切れない入力がまだ残っていても標準入力に対
する select() が「入力無し」と判断してしまうのです。
実体が同じ筈なのに整合性が取れていないのは、多分仮想デバイ
スとして実装されているからなんでしょうね。
もう一つは Mac OS X 環境で、O_RDWR で open() した file は
select() で感知出来ないという現象が見られました。これは一種
の bug と見なしても構わないように思います。
これまでの実装では、select() の対象は標準入力でしたので、
この file descriptor は O_RDONLY で open() されており、この
問題は表面化していませんでした。
O_RDINLY で open() して writefds が感知出来ないとか、その
逆とかならまだ理解出来るのですが、O_RDWR ということは読書き
共に可能な筈なので、select() には読書き共に感知して貰わない
と困ります。
多分この現象は対象が端末の時だけ生じていると思うので、一般
の file を対象にしている場合には問題はないのでしょうが、端末
に対する select() というのは割と定石なので何とかして欲しいも
のです。
多分、端末の実デバイスが入力と出力とで異なるためにこういう
ややこしい現象が起こってしまっているんでしょうね。
で、対処法ですが、単に select() の対象を端末に変更しただけ
では Mac OS X 環境の問題が回避出来ないので、Mac OS X 環境で
は端末を O_RDONLY で open() するように実装しました。
Mac OS X 環境ではこれでも普通に書出し出来るようでしたので、
少なくとも Mac OS X 環境ではこの実装で問題なさそうです。
以上、長くなりましたが FDclone 2.04c の変更箇所に対する解
説でした。状況を十分に把握した上で対処した訳では箇所もありま
すので、もし対処法が適切でないという場合はご指摘下さい。
しらい たかし