Dokan : Windows版FUSEみたいなもの

面白そうなのがあったのでメモ.

Dokanライブラリは、Windowsファイルシステムを簡単に書くためのライブラリです。Windows XPWindows Vistaの32ビット版に対応しています。

http://decas-dev.net/2008/02/05/dokan-library-024-released/

んで,これのRubyバインドもある様子.

そしてこのライブラリの作者自身が作ってるWindows版sshfsのような感じのアプリもいい感じ.
挙動が若干怪しいところもあるけれど,結構いい感じ.
これは使えそうだ.

しかしWindowsアプリを作ったことがないのでDokanで何か作るのはまだ先になりそうだ.

Dictionary Tooltip の英辞郎を新しいサイトの方にする

http://d.hatena.ne.jp/daftbeats/20070906/1189065163 の再掲載+αです。差分としてはVista,Macの対応と怪しい日本語の修正。


英文を読む機会が多い人にとっては、Firefox拡張機能Dictionary Tooltipは便利ですよね。英語のPDFファイルをHTML形式に直したくなるような拡張機能です。

背景

んで、このDictionay Tooltipの和英・英和機能として使われているのが「英辞郎on the WEB」ってやつなんですが、それがURLも変わってイロイロ新しくなりました。

問題

Dictionary Tooltipは、新しい英辞郎には自動的に飛んでくれません。「No definitions found for the selected word」としか表示されません。
原因は英次郎のURL(ホスト)が変わっちゃってるんですね。(http://www2.alc.co.jp/ejr/index.php?word_in=hogehoge → http://eow.alc.co.jp/hogehoge)

解決方法

  1. エクスプローラーにて、以下のように辿る(WindowsXP限定)

    • C(ここは人によって違うかも)
    • → Documents and Settings
    • → (ユーザー名)
    • → Application Data
    • Mozilla
    • Firefox
    • → Profiles
    • → (ランダムな文字列).default
    • → dictionarytip

    *注意! Application Dataは隠しファイルになってます。エクスプローラーの設定で隠しファイルを表示するようにしてください。


    WindowsVistaの場合は C:\Users\(ユーザ名)\AppData\Roaming\Mozilla\Firefox\Profiles\(ランダムな文字列).default\dictionarytip です。こちらのケースでは AppData が隠しファイルになっています。


    Macの場合は。。。

    /Users/ユーザ名/Library/Application Support/Firefox/Profiles/2hasy80n.default/dictionarytip/



    を編集Winとは少しディレクトリ構成が違うみたいだ。デフォルト設定でも見れてるし。

    http://sarusarusarusa.blog119.fc2.com/blog-entry-10.html

    だそうです。なるほど。Macには隠しファイルってのはないのかな。。頭に「.」つけると隠れるとかかな。


  2. dictionarytipフォルダの中のdictionarytip_dictScript.jsをメモ帳なり何なりのテキストエディタで開く。
  3. 578行目辺りにて、

    url = " http://www2.alc.co.jp/ejr/index.php?word_in=" + escape(selectedText) + "&word_in2=%e3%81%82%e3%81%84%e3%81%86%e3%81%88%e3%81%8a&word_in3=l2zdy6LhJvo58XPPQk"; 
    

    って書いてあるところの先頭に「//」つけてコメントアウト。んで次の行にコードを書き加える。

    //url = " http://www2.alc.co.jp/ejr/index.php?word_in=" + escape(selectedText) + "&word_in2=%e3%81%82%e3%81%84%e3%81%86%e3%81%88%e3%81%8a&word_in3=l2zdy6LhJvo58XPPQk"; 
    url = " http://eow.alc.co.jp/" + escape(selectedText) ;
    

    って感じにする。


  4. Firefox再起動

  5. 動作確認する

以上です。

論文がヤバイ

自作ファイルシステムをRedHat系で動かす時注意すべきこと

卒論のために作ってるFuseFSを用いたファイルシステムをFedora8とCentOSで動かしてみようとしました。が、うまくいかなかった。今までの開発はDebianでした。


やはりカーネル(?)の知識無しにファイルシステム構築なんて、どこかしらに弊害が生じますね。


原因がわかったので、メモ代わりに書いておく。

環境

サンプルスクリプト hello.rb を用意します。

require 'fusefs'

class HelloDir
  def contents(path)
    ['hello.txt']
  end
  def file?(path)
    path == '/hello.txt'
  end
  def read_file(path)
    "Hello, World!\n"
  end
end

hellodir = HelloDir.new
FuseFS.set_root( hellodir )

# Mount under a directory given on the command line.
FuseFS.mount_under ARGV.shift
FuseFS.run

問題点

上記のスクリプトをFedora8,CentOS5で動かし、構築されたhello.txtに対するコマンドの挙動があやしくなります。
まずはDebian4で動かしてみました。このときは特に問題ありません。

$ ls
hello.rb  mnt
$ ruby hello.rb mnt &
[1] 1972
$ ls -l mnt
合計 0
-r--r--r-- 1 kui kui 0 2007-12-20 20:16 hello.txt
$ cp mnt/hello.txt .
$ ls -l
合計 8
-rw-r--r-- 1 kui kui  330 2007-12-20 20:14 hello.rb
-r--r--r-- 1 kui kui   14 2007-12-20 20:19 hello.txt
dr-xr-xr-x 1 kui kui 4096 2007-12-20 20:16 mnt
$ cat
Hello, World!
$ 

こんな感じ。
しかしFedora8,CentOS5で同様のことをすると、、、

$ ls
hello.rb  mnt
$ ruby hello.rb mnt &
[1] 1972
$ ls -l mnt
合計 0
-r--r--r-- 1 kui kui 0 2007-12-20 20:16 hello.txt
$ cp mnt/hello.txt .
$ ls -l
合計 8
-rw-r--r-- 1 kui kui  330 2007-12-20 20:14 hello.rb
-r--r--r-- 1 kui kui    0 2007-12-20 20:19 hello.txt
dr-xr-xr-x 1 kui kui 4096 2007-12-20 20:16 mnt
$ cat hello.txt
$

となる。
つまり、cp をした時に、RedHatの方は空コピーしかしてくれない。

原因

ファイルシステムとして動いているクラス HelloDir が、hello.txtのファイルサイズを定義していないせいである。どうやら、RedHatな方は、cp をする前にコピー元が空ファイルかどうかチェックするようです。

解法

hello.txtのサイズを与えてあげましょう。

require 'fusefs'

class HelloDir
  def contents(path)
    ['hello.txt']
  end
  def file?(path)
    path == '/hello.txt'
  end
  def read_file(path)
    "Hello, World!\n"
  end
  # ここから!
  def size(path)
    "Hello, World!\n".size # 1 だけでも問題ない
  end
  # ここまで!
end

hellodir = HelloDir.new
FuseFS.set_root( hellodir )

# Mount under a directory given on the command line.
FuseFS.mount_under ARGV.shift
FuseFS.run

コメントにも書きましたが、ようするにマシンに「hello.txt は空じゃない」と認識させればいいため、1 と直接書いてしまっても問題無いです。

結論

カーネルの知識なしにファイルシステム構築なんて、後々面倒になるだけなんだろうなぁ。今回の cp の件はおそらく氷山の一角と思われる。

Rubyである必要のないFizzBuzz

(foo = Proc.new{ | arg |
   (arg<=1) ?  1 : foo.call(arg-1)
   bar  = (arg%3)==0 ? 'Fizz' : ''
   bar += (arg%5)==0 ? 'Buzz' : ''
   puts bar=='' ? arg.to_s : bar
}).call(100)

再帰が好きだけど、Rubyでやるものじゃないんだろうな。

FuseFSの実行ユーザ限定アクセスを解除

FuseFSで構築したファイルシステムは初期設定のままだと、スクリプト実行ユーザしかFuseFSファイルシステムにアクセスできない。この制限の解除の仕方をメモ。

FuseFSの初期設定のままの問題点

たとえば。。。サンプルスクリプトの hello.rb だと。

% whoami
user1
% pwd
/home/user1
% ls -l
合計 8
-rw-r--r-- 1 user1 user1  329 2005-10-11 16:23 hello.rb
drwxr-xr-x 2 user1 user1 4096 2007-11-06 23:21 mnt
% ruby hello.rb mnt
(プロンプト返ってこない)

別端末の別ユーザでログインして、mntにアクセスを試みると。。。

% whoami
user2
% cd /home/user1
% ls
% ls -l
合計 4
-rw-r--r-- 1 user1 user1  329 2005-10-11 16:23 hello.rb
?--------- ? ?     ?      ?                  ? mnt
% ls mnt
ls: mnt: 許可がありません
%

っといった感じ。実はこれは、FuseFSのソースをダウンロードすると、API.txtってのがついてきて、そのAPI.txtの中にこれに関する記述が載っていた。

解法


  1. /etc/fuse.conf を以下の内容で作成する。(初期設定ではこのファイルは作成されない)

    % cat /etc/fuse.conf
    user_allow_other
    %



  2. ソースコードを少し書き換える。hello.rbを編集しましょう。
    マウントポイントを指定する部分にて。。。

    # Mount under a directory given on the command line.
    FuseFS.mount_under ARGV.shift
    FuseFS.run

    と書いてあるところを。。。

    # Mount under a directory given on the command line.
    FuseFS.mount_under ARGV.shift, 'allow_other'
    FuseFS.run



  3. これでうまくいっているはずです。動作確認を行ってください

以上でした。
メモメモ

Fuseを一般ユーザ権限で(修正版)

手を出したばかりとは言え、FUSEを一般ユーザ権限での記事はあまりにも酷かった。ココに修正版を記そうと思う。

まずFUSE・FuseFSのインストールに関しては、「FuseFSをyumでインストール」や、「DebianにFUSE・FuseFSを入れるまで」で言及してみた。。。けど、今見返すと前者の記事の内容がカナーリ怪しげ。

また今回FuseFSのスクリプトを動かすのが目的としているが、FUSEを使ったプログラム全般において適応できる内容だと思う。

問題

上記によってFuseFSをインストールした後、一般ユーザ権限でさっそくFuseFSのサンプルを使おうすると。。。

$ sudo modprobe fuse   # fuseモジュールを有効に
$ ruby hello.rb mnt
fuse: failed to exec fusermount: Permission denied
/usr/lib/ruby/site_ruby/1.8/fusefs.rb:13:in `for_fd': no implicit conversion from nil to integer (TypeError)
        from /usr/lib/ruby/site_ruby/1.8/fusefs.rb:13:in `run'
        from hello.rb:20

となる。
当然だがroot権限で実行する分にはこの問題は起きない。

解法

自分なりの注釈を加えつつ順に記述していく。
目的としては、ユーザ「hoge」がFuseFSのサンプル「hello.rb」を実行できることが目標。


  1. まず現在のスタート時の環境を示しておく。

    # whoami
    root
    # uname -a
    Linux debian 2.6.18-5-686 #1 SMP Wed Oct 3 00:12:50 UTC 2007 i686 GNU/Linux
    # 

    また、上のサンプルはroot権限で実行する限りでは問題無く動作する環境。



  2. グループfuseに、ユーザを追加する。

    # adduser hoge fuse

    これで、/usr/bin/fusermountと、/dev/fuseへのアクセス権限を手に入れたことになる。



  3. /usr/bin/fusermountと、/dev/fuseパーミッションを確認します。

    # ls -l /usr/bin/fusermount
    -rwsr-x--- 1 root fuse 18368 2007-03-11 22:22 /usr/bin/fusermount
    # ls -l /dev/fuse
    crw-rw---- 1 root fuse 10, 229 2007-12-02 11:29 /dev/fuse
    #


    違っていたら。。。


    • /usr/bin/fusermountに対しては、

      # chmod 4750 /usr/bin/fusermount
      #



    • /dev/fuseに対しては、単純に、

      # chmod 660 /dev/fuse
      #

      のみでもかまいませんが、これだとシステムの再起動が行われた時に元に戻ってしまいます。
      修正するには、udevの設定ファイルの中*1からfuseに関する設定を見つけ以下のように設定します。

      KERNEL=="fuse",                 MODE="0660",    OWNER="root",GROUP="fuse"

      この設定が効いてくるのは、次回システム起動時です。



  4. 動作テスト。サンプルのhello.rbを動かしてみませう。

    # mkdir mnt
    # ruby /usr/share/doc/libfusefs-ruby1.8/example/hello.rb mnt &  
    # ls mnt
    hello.txt
    # cat mnt/hello.txt
    Hello,World!
    # fg
    [1]  + 1984 runnning     ruby /usr/share/doc/libfusefs-ruby1.8/example/hello.rb mnt
    (Ctrl+Cで終了。なにやらメッセージが返ってくるけど問題無い。)
    #



  5. Debian4.0の人向けオマケ。
    fuseを使うたびにイチイチ

    # modprobe fuse

    ってやるのが面倒な人は、/etc/modulesって設定ファイルの末尾に「fuse」と入力し、改行し、ファイルを保存してみてください。これで次回システム起動時に「/etc/init.d/module-init-tools」と言うスクリプトがmodprobeしてくれます。


以上でした。


次書くのは、FuseFSのスクリプトでマウントしたディレクトリに、スクリプト実行者以外のユーザがアクセスする方法について書けたらいいなと思う。

*1:Debian4.0だと/etc/udev/rules.d/020_permissions.rulesです。RedHat系は調査中

VMware起動時に「致命的なアプリケーション エラーです:・・・」

新たなマシンにVMWareを入れる機械があったのですが、仮想マシンを立ち上げるたびに、

致命的なアプリケーション エラーです: 文字列のエンコード中にエラーが発生しました。(class cui::Error)。

なんて出て来て、かつググってもこのケースに適切な解法がなかったので書き書き。
真っ先に気がつくべき事実に気がつかず、無駄に苦労してしまった。。。(計12時間)
また、この記事を書いた時点では、「致命的なアプリケーション エラーです: 文字列のエンコード中にエラーが発生しました。(class cui::Error)。」に関してググっても2007年10月に修正されたバグの話しか見当たらなかったため、この記事を書いてみた。

問題点

仮想マシンを立ち上げて少しすると、「致命的なアプリケーション エラーです: 文字列のエンコード中にエラーが発生しました。(class cui::Error)。」とエラーウィンドウが出力され、[ OK ]ボタンを押すとVMware仮想マシンとともに強制終了される。
(このときVMwareのプロセス(タスク?)が残っているので、タスクマネージャで強制的に終了しておいたほうがいいかもしれない。)
(また、このエラーウィンド、自分のケースでは無視していても仮想マシンは正常に動いていた。なのでエラーウィンドが気にならない人は以下を読まないくてもいいかもしれない。)

解法

問題のxmvファイルと同じフォルダに移動。.log のファイルがあるはずなので、テキストエディタで開きましょう。一通り目を通すと、どこかに文字化けしている箇所があるはずです。僕のケースでは、、

Dec 09 22:28:56.435: vcpu-0| BUSLOGIC: Store HAL[18] = 0xfe01
Dec 09 22:28:57.433: vmx| VMXVmdbLoadUsbDevices: New set of 2 USB devices
Dec 09 22:28:57.433: vmx| USB: Found device [name:USBデバイス147e:2016 vid:147e pid:2016 path:1/0/0 speed:full family:vendor]
Dec 09 22:28:57.433: vmx| USB: Found device [name:Ricoh\ USB繝・ヰ繧、繧ケ vid:05ca pid:183a path:1/2/1 speed:high family:other]
Dec 09 22:29:01.007: vcpu-0| BUSLOGIC: Store HAL[16] = 0xffff
Dec 09 22:29:01.007: vcpu-0| BUSLOGIC: Store HAL[18] = 0xfe01
Dec 09 22:29:01.007: vcpu-0| BUSLOGIC: Store HAL[16] = 0xffff

こんな感じ。
USBデバイスが二つ認識されたは良いけど、一方が文字化けしてしまっています。なので、vmxファイルを弄ってUSBデバイスを読み込まないように変更します。このケースでは、vmxファイルの一部は。。。

ethernet0.connectionType = "nat"
usb.present = "TRUE"
sound.present = "TRUE"

となっていたので、usb.presentの値を書き換えます

ethernet0.connectionType = "nat"
usb.present = "FALSE"
sound.present = "TRUE"

これで解決。

つまり、「致命的なアプリケーション エラーです: 文字列のエンコード中にエラーが発生しました。(class cui::Error)。」とでてきたら、ログファイルを見ろということ。。。。当然な話にまとまってしまう。