akishin999の日記

調べた事などを書いて行きます。

Ruby から Windows の共有フォルダにアクセスする

Linux 上で Samba マウントせずに Windows の共有フォルダにアクセスしたかったので、Ruby の sambal というライブラリを使ってみました。

johnae/sambal
https://github.com/johnae/sambal

試した環境は以下です。

  • CentOS 6.4 / 6.5(どちらも x86_64)
  • Ruby 2.0.0p247
  • bundler 1.5.3

Ruby が 2.0 なのは単に手元で 2.1 の RPM をまだ作成していないだけです^^;

インストール

sambal は smbclient コマンドのラッパーなので、動作には smbclient コマンドが必要になります。
smbclient は yum から samba-client コマンドを実行するとインストールできます。

# yum install -y samba-client

インストールしたら Windows の共有フォルダにアクセスできるかを確認。

$ smbclient //PC001/Share "shakiyamain" -U akishin -p 445

smb: \> というプロンプトが表示されていれば接続は成功です。
ls と打つと共有フォルダ内のファイルを確認する事が出来ます。
プロンプトは exit で抜ける事ができます。

smb: \> ls
  .                                   D        0  Tue Feb 18 22:43:37 2014
  ..                                  D        0  Tue Feb 18 22:43:37 2014
  test.txt                            A        0  Tue Feb 18 22:43:36 2014

                62499 blocks of size 16777216. 33957 blocks available
smb: \> exit

ちなみに WORKGROUP ではなくドメインに参加している場合は以下のような感じ。

$ smbclient //PC001.example.co.jp/Share "p@ssword" -W example.co.jp -U akishin -p 445

これで sambal を使う準備は整いました。
ここでは bundler でインストールするので、まずは Gemfile を作成します。

$ bundle init

実行したディレクトリ内に Gemfile が生成されるので編集します。

$ vi Gemfile

本来なら配布されている gem を使えばいいので「gem 'sambal'」と書けばいいのですが、試したところ CentOS では以下のようなエラーになってしまい上手く動きません。

$ bundle exec ruby sambal_example.rb
Failed to connect
Unknown Process Failed!! (exit): "exit"
/root/vendor/bundle/ruby/2.0.0/gems/sambal-0.1.2/lib/sambal.rb:70:in `exit'
/root/vendor/bundle/ruby/2.0.0/gems/sambal-0.1.2/lib/sambal.rb:70:in `initialize'
sambal_example.rb:9:in `new'
sambal_example.rb:9:in `<main>'

どうも smbclient コマンドのプロンプト文字列をパースしている正規表現が若干異なるようです。
仕方ないので取りあえず Fork してエラーにならないように修正したものを使用しました。

https://github.com/akishin/sambal

上記を使う場合、 Gemfile には以下のように記述します。

gem 'sambal', github: "akishin/sambal"

bundle install 実行。

bundle install --path=vendor/bundle

これで sambal のインストールは完了です。

使ってみる

以下のような感じで接続して ls を実行してみます。

require 'sambal'

begin
  HOST   = 'PC001'
  DIR    = 'Share'
  USER   = 'akishin'
  PASS   = 'p@ssword'

  client = Sambal::Client.new(host:     HOST,
                              share:    DIR,
                              user:     USER,
                              password: PASS)
  puts client.ls
  client.close
rescue => e
  puts e
end

ドメインに参加している Windows に接続する場合は以下のようにしてドメインを指定します。

require 'sambal'

begin
  DOMAIN = 'example.co.jp'
  HOST   = 'PC001.example.co.jp'
  DIR    = 'Share'
  USER   = 'akishin'
  PASS   = 'p@ssword'

  client = Sambal::Client.new(domain:   DOMAIN,
                              host:     HOST,
                              share:    DIR,
                              user:     USER,
                              password: PASS)
  puts client.ls
  client.close
rescue => e
  puts e
end

実行すると以下のような結果が表示されました。

$ bundle exec ruby sambal_example.rb
{"."=>{:type=>:directory, :size=>"0", :modified=>2014-02-18 22:43:37 +0900}, ".."=>{:type=>:directory, :size=>"0", :modified=>2014-02-18 22:43:37 +0900}, "test.txt"=>{:type=>:file, :size=>"0", :modified=>2014-02-18 22:43:36 +0900}}

ちゃんと共有フォルダの内容が読み取れているようです。

次は何かファイルを置いてみます。
Sambal::Client#put メソッドでローカルのファイルを共有フォルダに配置することができます。

require 'sambal'

begin
  HOST   = 'PC001'
  DIR    = 'Share'
  USER   = 'akishin'
  PASS   = 'p@ssword'

  client = Sambal::Client.new(host:     HOST,
                              share:    DIR,
                              user:     USER,
                              password: PASS)
  client.put('/home/akishin/image.png', 'image.png')    # <- 追記
  puts client.ls
  client.close
rescue => e
  puts e
end

実行すると以下のように image.png が結果に含まれている事がわかります。
また、実際に共有フォルダを確認するとファイルが配置されていました。

$ bundle exec ruby sambal_example.rb
{"."=>{:type=>:directory, :size=>"0", :modified=>2014-02-18 23:06:46 +0900}, ".."=>{:type=>:directory, :size=>"0", :modified=>2014-02-18 23:06:46 +0900}, "image.png"=>{:type=>:file, :size=>"29618", :modified=>2014-02-18 23:06:46 +0900}, "test.txt"=>{:type=>:file, :size=>"0", :modified=>2014-02-18 22:43:36 +0900}}

当然ですが Windows の共有フォルダに接続ユーザで書込み権限が必要なので、もし上手く行かない場合には確認してみて下さい。


というわけで、こんな感じでわざわざマウントしなくても Windows の共有フォルダに簡単にアクセスする事が出来ました。
Windows, Linux が混在しているような環境でスクリプトを書く際には結構重宝しそうです。