dokan-ruby 0.0.1-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/dokan-ruby.gemspec +66 -0
- data/ext/dokan-ruby-0.1.5.1229/API.txt +45 -0
- data/ext/dokan-ruby-0.1.5.1229/dokan_lib.c +1987 -0
- data/ext/dokan-ruby-0.1.5.1229/dokan_lib.so +0 -0
- data/ext/dokan-ruby-0.1.5.1229/extconf.rb +11 -0
- data/ext/dokan-ruby-0.1.5.1229/lib/dokanfs.rb +390 -0
- data/ext/dokan-ruby-0.1.5.1229/license.txt +19 -0
- data/ext/dokan-ruby-0.1.5.1229/list.h +144 -0
- data/ext/dokan-ruby-0.1.5.1229/readme.ja.txt +66 -0
- data/ext/dokan-ruby-0.1.5.1229/readme.txt +70 -0
- data/ext/dokan-ruby-0.1.5.1229/sample/hello.rb +39 -0
- data/ext/dokan-ruby-0.1.5.1229/sample/mirror.rb +178 -0
- data/ext/dokan-ruby-0.1.5.1229/sample/rssfs.rb +52 -0
- data/ext/dokan-ruby-0.1.5.1229/sample/sshfs.rb +163 -0
- data/ext/dokan-ruby-0.1.5.1229/sample/test.rb +115 -0
- data/lib/dokan-ruby.rb +1 -0
- data/test/dokan-ruby_test.rb +29 -0
- data/test/test_helper.rb +11 -0
- metadata +90 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
|
2
|
+
Dokan Ruby�o�C���f�B���O
|
3
|
+
|
4
|
+
Copyright(c) Hiroki Asakawa http://decas-dev.net
|
5
|
+
|
6
|
+
|
7
|
+
�� ���̃\�t�g�E�F�A�ɂ���
|
8
|
+
|
9
|
+
Windows �p�̉��z�t�@�C���V�X�e�� Dokan �� Ruby �o�C���f�B���O�ł��D
|
10
|
+
Ruby ����� Windows�p�̃t�@�C���V�X�e�����L�q���邱�Ƃ��\�ł��D
|
11
|
+
���s�ɂ� Dokan ���C�u�������K�v�ł��D
|
12
|
+
|
13
|
+
|
14
|
+
�� ���C�Z���X�ɂ���
|
15
|
+
|
16
|
+
MIT ���C�Z���X�ɏ]���܂��Dlicense.txt ���������������D
|
17
|
+
|
18
|
+
|
19
|
+
�� �����
|
20
|
+
|
21
|
+
dokan_lib.so �� VC6 �ŃR���p�C������Ă��܂��D
|
22
|
+
mswin32 Ruby�ƁCOne-Click Ruby�œ���m�F���s���Ă��܂��D
|
23
|
+
|
24
|
+
|
25
|
+
�� �g����
|
26
|
+
|
27
|
+
dokan_lib.so (���̃\�t�g�E�F�A�Ɋ܂܂��)
|
28
|
+
|
29
|
+
��f�B���N�g���ɔz�u���āCRuby�X�N���v�g�����s���܂��D
|
30
|
+
���s�ɂ� Administrator �������K�v�ł��D
|
31
|
+
|
32
|
+
> ruby sample\test.rb
|
33
|
+
|
34
|
+
�܂�
|
35
|
+
|
36
|
+
> dokanctl.exe /u DriveLetter
|
37
|
+
|
38
|
+
�ɂ��A���}�E���g���܂��D
|
39
|
+
Dokan ���C�u�����̃h�L�������g���K���Q�Ƃ��Ă��������D
|
40
|
+
|
41
|
+
�� �t�@�C���V�X�e���̍쐬���@
|
42
|
+
|
43
|
+
API.txt �ɋL�q����Ă��郁�\�b�h�� class Hello �Ɏ������C
|
44
|
+
Dokan.mount("d", Hello.new) �����s���邱�ƂŃ}�E���g���܂��D
|
45
|
+
�e���\�b�h�͐��������� true ���s������ false ��Ԃ��ĉ������D
|
46
|
+
|
47
|
+
open(path, fileinfo)
|
48
|
+
|
49
|
+
�ŏ��̈����͊J�����Ƃ��Ă���t�@�C���̃p�X���C���̈����͕⏕�I�ȏ�n����܂��D
|
50
|
+
FileInfo#directory?�CFileInfo#process_id�CFileInfo#context�CFileInfo#context=
|
51
|
+
����`����Ă��܂��DFileInfo#context �ɑ������ƁC����t�@�C���n���h���ɂ�鑀��
|
52
|
+
�̏ꍇ�ɁCFileInfo#context �ɑ�������l���n����Ă��܂��D
|
53
|
+
|
54
|
+
WindowsAPI �Ŏg�p���萔 FILE_ATTRIBUTE_* ����`����Ă��܂�
|
55
|
+
(Dokan::NORMAL�CDokan::DIRECTORY��)�Dstat �Ńt�@�C��������Ԃ��ꍇ�Ɏg�p���܂��D
|
56
|
+
|
57
|
+
Dokan.debug = true ���Z�b�g���邱�ƂŃf�o�b�O�����o�͂ł��܂��D
|
58
|
+
|
59
|
+
|
60
|
+
sample �ȉ��ɃT���v���X�N���v�g������܂��D
|
61
|
+
|
62
|
+
lib\dokanfs.rb �� FuseFS (Linux �p�̃��[�U���[�h�t�@�C���V�X�e���ł��� FUSE
|
63
|
+
�� Ruby �o�C���f�B���O) �݊����C�u�����ł��Drequire���邱�ƂŁCFuseFS�Ɠ���
|
64
|
+
�C���^�t�F�[�X�Ńt�@�C���V�X�e�����쐬�o���܂��D
|
65
|
+
dokanfs.rb �ɂ��ẮCsample\hello.rb ���Q�Ƃ��Ă��������D
|
66
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
Dokan Ruby Binding
|
3
|
+
|
4
|
+
Copyright(c) Hiroki Asakawa http://decas-dev.net
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
What is Dokan Ruby Binding
|
9
|
+
==========================
|
10
|
+
|
11
|
+
This program is a Ruby binding of Dokan that is a user mode file
|
12
|
+
system for Windows. Using this program, you can make a file system
|
13
|
+
in Ruby language.
|
14
|
+
|
15
|
+
|
16
|
+
Licensing
|
17
|
+
=========
|
18
|
+
|
19
|
+
Dokan Ruby Binding is distributed under a version of the "MIT License",
|
20
|
+
which is a BSD-like license. See the 'license.txt' file for details.
|
21
|
+
|
22
|
+
|
23
|
+
Environment
|
24
|
+
===========
|
25
|
+
|
26
|
+
'dokan_lib.so' is built using Visual C++ 6.0.
|
27
|
+
Dokan Ruby Binding is checked on mswin32 Ruby and One-Click Ruby.
|
28
|
+
|
29
|
+
|
30
|
+
How to use
|
31
|
+
==========
|
32
|
+
|
33
|
+
Place 'dokan_lib.so' in $LOAD_PATH directory and run a ruby script.
|
34
|
+
You can check $LOAD_PATH using "ruby -e 'puts $LOAD_PATH'" command.
|
35
|
+
|
36
|
+
> ruby sample\test.rb
|
37
|
+
|
38
|
+
Administrator privileges are required to run file system applications.
|
39
|
+
|
40
|
+
You can unmount following command.
|
41
|
+
|
42
|
+
> dokanctl.exe /u DriveLetter
|
43
|
+
|
44
|
+
'dokanctl.exe' is included in Dokan library.
|
45
|
+
|
46
|
+
You must see 'readme.txt' included in Dokan library.
|
47
|
+
|
48
|
+
|
49
|
+
How to make a file system
|
50
|
+
=========================
|
51
|
+
|
52
|
+
To make a file system, you need to implement methods described in 'API.txt'
|
53
|
+
file in 'class Hello' and call 'Dokan.mount("d", Hello.new)'.
|
54
|
+
Each method should return 'true' when the operations scuceeded, otherwise
|
55
|
+
it should return 'false'.
|
56
|
+
|
57
|
+
open(path, fileinfo)
|
58
|
+
|
59
|
+
The first argument is a path of opening file, the second is context information.
|
60
|
+
FileInfo#directory?, FileInfo#process_id, FileInfo#context and FileInfo#context=
|
61
|
+
methods are defined.
|
62
|
+
|
63
|
+
FILE_ATTRIBUTE_* used with WindowsAPI are defined (Dokan::NORMAL,
|
64
|
+
DOKAN::Directory ...). These constans are used in 'stat' method.
|
65
|
+
You can get debug information by setting 'Dokan.debug = true'.
|
66
|
+
|
67
|
+
There are sample scripts under 'sample' folder.
|
68
|
+
'lib\dokanfs.rb' is compatibility interface of FuseFS (Ruby binding of FUSE).
|
69
|
+
See 'sample\hello.rb' for details.
|
70
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'dokanfs'
|
2
|
+
|
3
|
+
class Hello
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@msg = "hello, world"
|
7
|
+
end
|
8
|
+
|
9
|
+
def contents path
|
10
|
+
puts "##contents " + path
|
11
|
+
["hello.txt"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def file? path
|
15
|
+
puts "##file? " + path
|
16
|
+
path =~ /hello.txt/
|
17
|
+
end
|
18
|
+
|
19
|
+
def directory? path
|
20
|
+
puts "##directory? " + path
|
21
|
+
path == "/"
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_file path
|
25
|
+
puts "##read_file " + path
|
26
|
+
@msg
|
27
|
+
end
|
28
|
+
|
29
|
+
def size path
|
30
|
+
puts "##size " + path
|
31
|
+
@msg.length
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
FuseFS.set_root(Hello.new)
|
37
|
+
FuseFS.mount_under("r")
|
38
|
+
FuseFS.run
|
39
|
+
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
require 'dokan_lib'
|
3
|
+
|
4
|
+
class Mirror
|
5
|
+
|
6
|
+
def initialize(dir)
|
7
|
+
@dir = dir
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_path(path)
|
11
|
+
@dir + path.sub("/", "\\")
|
12
|
+
end
|
13
|
+
|
14
|
+
def open(path, fileinfo)
|
15
|
+
puts "#open " + path
|
16
|
+
if path == "/"
|
17
|
+
true
|
18
|
+
else
|
19
|
+
File.file?(get_path(path))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create(path, fileinfo)
|
24
|
+
puts "#create " + path
|
25
|
+
File.open(get_path(path), File::CREAT|File::BINARY|File::WRONLY) { true }
|
26
|
+
rescue
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
def truncate(path, length, fileinfo)
|
31
|
+
puts "#truncate " + path
|
32
|
+
File.truncate(get_path(path), length)
|
33
|
+
true
|
34
|
+
rescue
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def opendir(path, fileinfo)
|
39
|
+
puts "#opendir " + path
|
40
|
+
if path == "/"
|
41
|
+
true
|
42
|
+
else
|
43
|
+
File.directory?(get_path(path))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def mkdir(path, fileinfo)
|
48
|
+
puts "#mkdir " + path
|
49
|
+
Dir.mkdir(get_path(path))
|
50
|
+
true
|
51
|
+
rescue
|
52
|
+
false
|
53
|
+
end
|
54
|
+
|
55
|
+
def close(path, fileinfo)
|
56
|
+
puts "#close " + path
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
def cleanup(path, fileinfo)
|
61
|
+
puts "#cleanup " + path
|
62
|
+
true
|
63
|
+
end
|
64
|
+
|
65
|
+
def read(path, offset, length, fileinfo)
|
66
|
+
puts "#read " + path + " length " + length.to_s + " offset " + offset.to_s;
|
67
|
+
if File.file?(get_path(path))
|
68
|
+
File.open(get_path(path), "rb") do |file|
|
69
|
+
file.seek(offset)
|
70
|
+
str = file.read(length)
|
71
|
+
str = "" if str == nil
|
72
|
+
str
|
73
|
+
end
|
74
|
+
# File.read(get_path(path), length, offset)
|
75
|
+
else
|
76
|
+
false
|
77
|
+
end
|
78
|
+
rescue
|
79
|
+
false
|
80
|
+
end
|
81
|
+
|
82
|
+
def write(path, offset, data, fileinfo)
|
83
|
+
puts "#write " + path
|
84
|
+
if File.writable?(get_path(path))
|
85
|
+
File.open(get_path(path), "r+") do |file|
|
86
|
+
file.seek(offset)
|
87
|
+
file.write(data)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
false
|
91
|
+
end
|
92
|
+
rescue
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
def flush(path, fileinfo)
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
def stat(path, fileinfo)
|
101
|
+
puts "#stat " + path
|
102
|
+
#[size, attr, ctime, atime, mtime]
|
103
|
+
if File.exist?(get_path(path))
|
104
|
+
s = File.stat(get_path(path))
|
105
|
+
[s.size,
|
106
|
+
s.directory? ? Dokan::DIRECTORY : Dokan::NORMAL,
|
107
|
+
s.ctime.to_i, s.atime.to_i, s.mtime.to_i]
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
rescue
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
# def readdira(path, fileinfo)
|
116
|
+
# end
|
117
|
+
|
118
|
+
def readdir(path, fileinfo)
|
119
|
+
puts "#readdir " + path
|
120
|
+
if File.directory?(get_path(path))
|
121
|
+
Dir.entries(get_path(path))
|
122
|
+
else
|
123
|
+
false
|
124
|
+
end
|
125
|
+
|
126
|
+
rescue
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
def setattr(path, attr, fileinfo)
|
131
|
+
puts "#setattr " + path
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def utime(path, ctime, atime, mtime, fileinfo)
|
136
|
+
puts "#utime " + path
|
137
|
+
false
|
138
|
+
end
|
139
|
+
|
140
|
+
def remove(path, fileinfo)
|
141
|
+
puts "#remove " + path
|
142
|
+
File.delete(get_path(path))
|
143
|
+
rescue
|
144
|
+
false
|
145
|
+
end
|
146
|
+
|
147
|
+
def rename(path, newpath, fileinfo)
|
148
|
+
File.rename(get_path(path), get_path(newpath))
|
149
|
+
true
|
150
|
+
rescue
|
151
|
+
false
|
152
|
+
end
|
153
|
+
|
154
|
+
def rmdir(path, fileinfo)
|
155
|
+
Dir.rmdir(get_path(path))
|
156
|
+
true
|
157
|
+
rescue
|
158
|
+
false
|
159
|
+
end
|
160
|
+
|
161
|
+
def lock(path, offset, length, fileinfo)
|
162
|
+
true
|
163
|
+
end
|
164
|
+
|
165
|
+
def unlock(path, offset, length, fileinfo)
|
166
|
+
true
|
167
|
+
end
|
168
|
+
|
169
|
+
def unmount(fileinfo)
|
170
|
+
puts "#unmount"
|
171
|
+
true
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
|
177
|
+
Dokan.mount("r", Mirror.new("e:\\"))
|
178
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rss'
|
2
|
+
require 'dokanfs'
|
3
|
+
|
4
|
+
class RSSFS
|
5
|
+
def initialize table
|
6
|
+
@files = Hash.new
|
7
|
+
@files["/"] = Array.new
|
8
|
+
table.each do |k,v|
|
9
|
+
rss = RSS::Parser.parse(v)
|
10
|
+
rss.output_encoding = "Shift_JIS"
|
11
|
+
@files["/"].push k
|
12
|
+
@files["/#{k}"] = Array.new
|
13
|
+
rss.items.each do |item|
|
14
|
+
@files["/#{k}"].push "#{item.title}.txt"
|
15
|
+
@files["/#{k}/#{item.title}.txt"] = item.description
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def file? path
|
21
|
+
@files[path].instance_of? String
|
22
|
+
end
|
23
|
+
|
24
|
+
def directory? path
|
25
|
+
@files[path.sub(/(.+)\/$/, '\1')].instance_of? Array
|
26
|
+
end
|
27
|
+
|
28
|
+
def contents path
|
29
|
+
if @files[path.sub(/(.+)\/$/, '\1')].instance_of? Array
|
30
|
+
@files[path.sub(/(.+)\/$/, '\1')]
|
31
|
+
else
|
32
|
+
false
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def read_file path
|
37
|
+
@files[path]
|
38
|
+
end
|
39
|
+
|
40
|
+
def size path
|
41
|
+
if @files[path].instance_of? String
|
42
|
+
@files[path].size
|
43
|
+
else
|
44
|
+
0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
rssfs = RSSFS.new( {"decas"=> "http://decas-dev.net/feed/", "hatena_hotentry" => "http://b.hatena.ne.jp/hotentry?mode=rss"} )
|
50
|
+
DokanFS.set_root(rssfs)
|
51
|
+
DokanFS.mount_under("r")
|
52
|
+
DokanFS.run
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'dokan_lib'
|
2
|
+
require 'net/sftp'
|
3
|
+
|
4
|
+
#GC.disable
|
5
|
+
|
6
|
+
class Sshfs
|
7
|
+
|
8
|
+
def initialize(sftp)
|
9
|
+
@sftp = sftp
|
10
|
+
end
|
11
|
+
|
12
|
+
def open(path, fileinfo)
|
13
|
+
puts "#open " + path
|
14
|
+
@sftp.open_handle(path, "r") do
|
15
|
+
true
|
16
|
+
end
|
17
|
+
rescue
|
18
|
+
p $!
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
def create(path, fileinfo)
|
23
|
+
puts "#create " + path
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
def truncate(path, length, fileinfo)
|
28
|
+
puts "#truncate " + path
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def opendir(path, fileinfo)
|
33
|
+
puts "#opendir " + path
|
34
|
+
if path == "/"
|
35
|
+
true
|
36
|
+
elsif directory?(path)
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
rescue
|
42
|
+
p $!
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def mkdir(path, fileinfo)
|
47
|
+
puts "#mkdir " + path
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def close(path, fileinfo)
|
52
|
+
puts "#close " + path
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def cleanup(path, fileinfo)
|
57
|
+
puts "#cleanup " + path
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def read(path, offset, length, fileinfo)
|
62
|
+
puts "#read " + path
|
63
|
+
data = nil
|
64
|
+
@sftp.open_handle(path, "r") do |handle|
|
65
|
+
data = @sftp.read(handle)
|
66
|
+
end
|
67
|
+
data != nil ? data[offset, length] : false
|
68
|
+
rescue
|
69
|
+
p $!
|
70
|
+
false
|
71
|
+
end
|
72
|
+
|
73
|
+
def write(path, offset, data, fileinfo)
|
74
|
+
puts "#write " + path
|
75
|
+
false
|
76
|
+
end
|
77
|
+
|
78
|
+
def flush(path, fileinfo)
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
def directory?(path)
|
83
|
+
0 < (@sftp.stat(path).permissions & 040000)
|
84
|
+
end
|
85
|
+
|
86
|
+
def stat(path, fileinfo)
|
87
|
+
puts "#stat " + path
|
88
|
+
#[size, attr, ctime, atime, mtime]
|
89
|
+
if path == "/"
|
90
|
+
[0, Dokan::DIRECTORY, 0, 0, 0]
|
91
|
+
else
|
92
|
+
s = @sftp.stat(path)
|
93
|
+
[s.size,
|
94
|
+
0 < (s.permissions & 040000) ? Dokan::DIRECTORY : Dokan::NORMAL,
|
95
|
+
s.mtime.to_i, s.atime.to_i, s.mtime.to_i]
|
96
|
+
end
|
97
|
+
rescue
|
98
|
+
p $!
|
99
|
+
false
|
100
|
+
end
|
101
|
+
|
102
|
+
# def readdira(path, fileinfo)
|
103
|
+
# end
|
104
|
+
|
105
|
+
def readdir(path, fileinfo)
|
106
|
+
puts "#readdir " + path
|
107
|
+
entries = []
|
108
|
+
handle = @sftp.opendir(path)
|
109
|
+
items = @sftp.readdir(handle)
|
110
|
+
items.each do |item|
|
111
|
+
entries.push item.filename
|
112
|
+
end
|
113
|
+
@sftp.close_handle(handle)
|
114
|
+
entries
|
115
|
+
rescue
|
116
|
+
p $!
|
117
|
+
false
|
118
|
+
end
|
119
|
+
|
120
|
+
def setattr(path, attr, fileinfo)
|
121
|
+
puts "#setattr " + path
|
122
|
+
false
|
123
|
+
end
|
124
|
+
|
125
|
+
def utime(path, ctime, atime, mtime, fileinfo)
|
126
|
+
puts "#utime " + path
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
def remove(path, fileinfo)
|
131
|
+
puts "#remove " + path
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
def rename(path, newpath, fileinfo)
|
136
|
+
false
|
137
|
+
end
|
138
|
+
|
139
|
+
def rmdir(path, fileinfo)
|
140
|
+
false
|
141
|
+
end
|
142
|
+
|
143
|
+
def unmount(fileinfo)
|
144
|
+
puts "#unmount"
|
145
|
+
true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
#if (ARGV.size != 4)
|
151
|
+
# puts "Usage: #{$0} letter host usr password"
|
152
|
+
# exit
|
153
|
+
#end
|
154
|
+
|
155
|
+
|
156
|
+
@host = "****"
|
157
|
+
@user = "****"
|
158
|
+
@passwd = "****"
|
159
|
+
Net::SFTP.start(@host, @user, @passwd) do |ssh|
|
160
|
+
Dokan.mount("s", Sshfs.new(ssh))
|
161
|
+
end
|
162
|
+
|
163
|
+
|