rfuse 1.0.0 → 1.0.2

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/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ -
2
+ CHANGES.md
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ 1.0.2- 2012/08/09
2
+ -----------------
3
+
4
+ Support Ruby 1.8 (tested with 1.8.7)
5
+
6
+ Bugfixes
7
+
8
+ * {RFuse::Fuse#utimens} fixed to correctly convert time to nanoseconds
9
+ * Exceptions in {RFuse::Fuse#getattr} fixed to output backtrace etc
1
10
 
2
11
  1.0.0
3
12
  ----------------
data/README.md CHANGED
@@ -3,7 +3,7 @@ RFuse
3
3
 
4
4
  http://rubygems.org/gems/rfuse
5
5
 
6
- FUSE bindings for Ruby 1.9
6
+ FUSE bindings for Ruby
7
7
 
8
8
  FUSE (Filesystem in USErspace) is a simple interface for userspace programs to export a virtual filesystem to the linux kernel. FUSE aims to provide a secure method for non privileged users to create and mount their own filesystem implementations.
9
9
 
@@ -14,7 +14,7 @@ For a more ruby-ish API for creating filesystems see {http://rubygems.org/gems/r
14
14
  Dependencies
15
15
  --------------
16
16
 
17
- * Ruby 1.9
17
+ * Ruby 1.8 or 1.9
18
18
  * Fuse 2.8
19
19
 
20
20
  Installation
data/Rakefile CHANGED
@@ -5,8 +5,6 @@ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
8
- YARD::Rake::YardocTask.new do |t|
9
- t.files = ['lib/**/*.rb', 'ext/**/*.c','-','CHANGES.md'] # optional
10
- end
8
+ YARD::Rake::YardocTask.new
11
9
 
12
10
  task :default => :spec
data/ext/rfuse/extconf.rb CHANGED
@@ -5,6 +5,11 @@ $CFLAGS << ' -Wall'
5
5
  $CFLAGS << ' -D_FILE_OFFSET_BITS=64'
6
6
  $CFLAGS << ' -DFUSE_USE_VERSION=26'
7
7
 
8
+
9
+ if have_func("rb_errinfo")
10
+ puts "Have rb_errinfo"
11
+ end
12
+
8
13
  if have_library('fuse')
9
14
  create_makefile('rfuse/rfuse')
10
15
  else
data/ext/rfuse/rfuse.c CHANGED
@@ -14,7 +14,6 @@
14
14
  #include <sys/xattr.h>
15
15
  //#endif
16
16
 
17
- #include <ruby/encoding.h>
18
17
  #include "helper.h"
19
18
  #include "intern_rfuse.h"
20
19
  #include "filler.h"
@@ -24,13 +23,32 @@
24
23
  #include "pollhandle.h"
25
24
  #include "bufferwrapper.h"
26
25
 
26
+ #ifdef HAVE_RUBY_ENCODING_H
27
+ #include <ruby/encoding.h>
28
+ #endif
29
+
30
+ #ifndef HAVE_RB_ERRINFO
31
+ static VALUE rb_errinfo()
32
+ {
33
+ return ruby_errinfo;
34
+ }
35
+ #endif
27
36
 
28
37
  static VALUE mRFuse;
29
38
  static VALUE eRFuse_Error;
30
39
 
40
+ static VALUE rb_filesystem_encode(VALUE str)
41
+ {
42
+ #ifdef HAVE_RUBY_ENCODING_H
43
+ return rb_enc_associate(str,rb_filesystem_encoding());
44
+ #else
45
+ return str;
46
+ #endif
47
+ }
48
+
31
49
  static int unsafe_return_error(VALUE *args)
32
50
  {
33
-
51
+
34
52
  if (rb_respond_to(rb_errinfo(),rb_intern("errno"))) {
35
53
  //We expect these and they get passed on the fuse so be quiet...
36
54
  return rb_funcall(rb_errinfo(),rb_intern("errno"),0);
@@ -73,7 +91,7 @@ static void init_context_path_args(VALUE *args,struct fuse_context *ctx,const ch
73
91
  args[0] = ctx->private_data;
74
92
  args[1] = wrap_context(ctx);
75
93
  args[2] = rb_str_new2(path);
76
- rb_enc_associate(args[2],rb_filesystem_encoding());
94
+ rb_filesystem_encode(args[2]);
77
95
  }
78
96
  /*
79
97
  @overload readdir(context,path,filler,offset,ffi)
@@ -275,13 +293,14 @@ static int rf_getattr(const char *path, struct stat *stbuf)
275
293
 
276
294
  res=rb_protect((VALUE (*)())unsafe_getattr,(VALUE) args,&error);
277
295
 
278
- if (res == Qnil) {
279
- return -ENOENT;
280
- }
281
296
  if (error)
282
297
  {
283
298
  return -(return_error(ENOENT));
284
299
  }
300
+
301
+ if (res == Qnil) {
302
+ return -ENOENT;
303
+ }
285
304
  else
286
305
  {
287
306
  rstat2stat(res,stbuf);
@@ -733,7 +752,7 @@ static int rf_symlink(const char *path,const char *as)
733
752
  init_context_path_args(args,ctx,path);
734
753
 
735
754
  args[3]=rb_str_new2(as);
736
- rb_enc_associate(args[3],rb_filesystem_encoding());
755
+ rb_filesystem_encode(args[3]);
737
756
 
738
757
  res=rb_protect((VALUE (*)())unsafe_symlink,(VALUE) args,&error);
739
758
 
@@ -768,7 +787,7 @@ static int rf_rename(const char *path,const char *as)
768
787
  init_context_path_args(args,ctx,path);
769
788
 
770
789
  args[3]=rb_str_new2(as);
771
- rb_enc_associate(args[3],rb_filesystem_encoding());
790
+ rb_filesystem_encode(args[3]);
772
791
 
773
792
  res=rb_protect((VALUE (*)())unsafe_rename,(VALUE) args,&error);
774
793
 
@@ -802,7 +821,7 @@ static int rf_link(const char *path,const char * as)
802
821
  struct fuse_context *ctx=fuse_get_context();
803
822
  init_context_path_args(args,ctx,path);
804
823
  args[3]=rb_str_new2(as);
805
- rb_enc_associate(args[3],rb_filesystem_encoding());
824
+ rb_filesystem_encode(args[3]);
806
825
  res=rb_protect((VALUE (*)())unsafe_link,(VALUE) args,&error);
807
826
 
808
827
  return error ? -(return_error(ENOENT)) : 0;
@@ -1585,17 +1604,17 @@ static int rf_utimens(const char * path, const struct timespec tv[2])
1585
1604
  struct fuse_context *ctx = fuse_get_context();
1586
1605
  init_context_path_args(args,ctx,path);
1587
1606
 
1588
- // tv_sec * 1000000 + tv_nsec
1607
+ // tv_sec * 1000000000 + tv_nsec
1589
1608
  args[3] = rb_funcall(
1590
1609
  rb_funcall(
1591
- INT2NUM(tv[0].tv_sec), rb_intern("*"), 1, INT2NUM(1000000)
1610
+ INT2NUM(tv[0].tv_sec), rb_intern("*"), 1, INT2NUM(1000000000)
1592
1611
  ),
1593
1612
  rb_intern("+"), 1, INT2NUM(tv[0].tv_nsec)
1594
1613
  );
1595
1614
 
1596
1615
  args[4] = rb_funcall(
1597
1616
  rb_funcall(
1598
- INT2NUM(tv[1].tv_sec), rb_intern("*"), 1, INT2NUM(1000000)
1617
+ INT2NUM(tv[1].tv_sec), rb_intern("*"), 1, INT2NUM(1000000000)
1599
1618
  ),
1600
1619
  rb_intern("+"), 1, INT2NUM(tv[1].tv_nsec)
1601
1620
  );
@@ -1675,7 +1694,7 @@ static int rf_ioctl(const char *path, int cmd, void *arg,
1675
1694
  int error = 0;
1676
1695
 
1677
1696
  args[0] = rb_str_new2(path);
1678
- rb_enc_associate(args[0],rb_filesystem_encoding());
1697
+ rb_filesystem_encode(args[0]);
1679
1698
  args[1] = INT2NUM(cmd);
1680
1699
  args[2] = wrap_buffer(arg);
1681
1700
  args[3] = get_file_info(ffi);
@@ -1715,7 +1734,7 @@ static int rf_poll(const char *path, struct fuse_file_info *ffi,
1715
1734
  int error = 0;
1716
1735
 
1717
1736
  args[0] = rb_str_new2(path);
1718
- rb_enc_associate(args[0],rb_filesystem_encoding());
1737
+ rb_filesystem_encode(args[0]);
1719
1738
  args[1] = get_file_info(ffi);
1720
1739
  args[2] = wrap_pollhandle(ph);
1721
1740
  args[3] = INT2NUM(*reventsp);
@@ -1756,7 +1775,11 @@ VALUE rf_unmount(VALUE self)
1756
1775
  struct intern_fuse *inf;
1757
1776
  Data_Get_Struct(self,struct intern_fuse,inf);
1758
1777
 
1759
- fuse_exit(inf->fuse);
1778
+ rb_funcall(self,rb_intern("ruby_unmount"),0);
1779
+
1780
+ if (inf->fuse != NULL) {
1781
+ fuse_exit(inf->fuse);
1782
+ }
1760
1783
 
1761
1784
  if (inf->fc != NULL) {
1762
1785
  fuse_unmount(inf->mountpoint, inf->fc);
@@ -1773,7 +1796,7 @@ VALUE rf_mountname(VALUE self)
1773
1796
  struct intern_fuse *inf;
1774
1797
  Data_Get_Struct(self,struct intern_fuse,inf);
1775
1798
  VALUE result = rb_str_new2(inf->mountpoint);
1776
- rb_enc_associate(result,rb_filesystem_encoding());
1799
+ rb_filesystem_encode(result);
1777
1800
 
1778
1801
  return result;
1779
1802
  }
@@ -0,0 +1,20 @@
1
+
2
+ unless IO.instance_methods.include?(:autoclose?)
3
+ class IO
4
+ def self.for_fd(fd, mode_string, options = {})
5
+ IO.new(fd,mode_string)
6
+ end
7
+
8
+ def autoclose?
9
+ true
10
+ end
11
+ end
12
+ end
13
+
14
+ unless Time.instance_methods.include?(:nsec)
15
+ class Time
16
+ def nsec
17
+ usec * 1000
18
+ end
19
+ end
20
+ end
data/lib/rfuse/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module RFuse
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.2"
3
3
  end
data/lib/rfuse.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'fcntl'
2
2
  require 'rfuse/version'
3
3
  require 'rfuse/rfuse'
4
+ require 'rfuse/compat'
4
5
 
5
6
  # Ruby FUSE (Filesystem in USErspace) binding
6
7
  module RFuse
@@ -30,7 +31,6 @@ module RFuse
30
31
  #
31
32
  # @return [void]
32
33
  # @raise [RFuse::Error] if already running or not mounted
33
- #
34
34
  def loop()
35
35
  raise RFuse::Error, "Already running!" if @running
36
36
  raise RFuse::Error, "FUSE not mounted" unless mounted?
@@ -80,6 +80,18 @@ module RFuse
80
80
  # ruby to do anything with it during GC
81
81
  @fuse_io = IO.for_fd(fd(),"r",:autoclose => false)
82
82
  end
83
+
84
+ # Called by C unmount before doing all the FUSE stuff
85
+ def ruby_unmount
86
+ @pr.close if @pr && !@pr.closed?
87
+ @pw.close if @pw && !@pw.closed?
88
+
89
+ # Ideally we want this IO to avoid autoclosing at GC, but
90
+ # in Ruby 1.8 we have no way to do that. A work around is to close
91
+ # the IO here. FUSE won't necessarily like that but it is the best
92
+ # we can do
93
+ @fuse_io.close() if @fuse_io && !@fuse_io.closed? && @fuse_io.autoclose?
94
+ end
83
95
  end
84
96
 
85
97
  #This class is useful to make your filesystem implementation
data/rfuse.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.email = ["grant@lastweekend.com.au"]
11
11
  s.homepage = "http://rubygems.org/gems/rfuse"
12
12
  s.summary = %q{Ruby language binding for FUSE}
13
- s.description = %q{Ruby language binding for FUSE. It was forked from rfuse and modified for Ruby 1.9.2.}
13
+ s.description = %q{Write userspace filesystems in Ruby}
14
14
 
15
15
  s.files = `git ls-files`.split("\n")
16
16
  s.extensions = 'ext/rfuse/extconf.rb'
@@ -18,6 +18,9 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
+ s.has_rdoc = 'yard'
22
+ s.extra_rdoc_files = 'CHANGES.md'
23
+
21
24
  s.add_development_dependency("rake")
22
25
  s.add_development_dependency("rspec")
23
26
  s.add_development_dependency("yard")
data/spec/basic_spec.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'pathname'
3
+ require 'tempfile'
3
4
 
4
5
  describe RFuse::Fuse do
5
-
6
+
6
7
  let(:dir_stat) { RFuse::Stat.directory(0444) }
7
8
  let(:file_stat) { RFuse::Stat.file(0444) }
8
9
  let!(:mockfs) { m = mock("fuse"); m.stub(:getattr).and_return(nil); m }
@@ -26,7 +27,7 @@ describe RFuse::Fuse do
26
27
  fuse.mounted?.should be_false
27
28
  lambda { fuse.loop }.should raise_error(RFuse::Error)
28
29
  end
29
-
30
+
30
31
  it "should handle a Pathname as a mountpoint" do
31
32
  fuse = RFuse::FuseDelegator.new(mockfs,Pathname.new(mountpoint))
32
33
  fuse.mounted?.should be_true
@@ -57,7 +58,7 @@ describe RFuse::Fuse do
57
58
 
58
59
  mockfs.should_receive(:readdir) do | ctx, path, filler,offset,ffi |
59
60
  filler.push("hello",nil,0)
60
- filler.push("world",nil,0)
61
+ filler.push("world",nil,0)
61
62
  end
62
63
 
63
64
  with_fuse(mountpoint,mockfs) do
@@ -83,38 +84,50 @@ describe RFuse::Fuse do
83
84
 
84
85
  context "timestamps" do
85
86
 
87
+
86
88
  it "should support stat with subsecond resolution" do
87
- begin
88
- atime = Time.now() + 60
89
- sleep(0.001)
90
- end until atime.usec != 0
91
-
92
- begin
93
- mtime = Time.now() + 600
94
- sleep(0.001)
95
- end until mtime.usec != 0
96
-
97
- begin
98
- ctime = Time.now() + 3600
99
- sleep(0.001)
100
- end until ctime.usec != 0
101
-
102
- file_stat.atime = atime
103
- file_stat.mtime = mtime
104
- file_stat.ctime = ctime
105
-
106
-
107
- # ruby can't set file times with ns res, o we are limited to usecs
108
- mockfs.stub(:getattr).with(anything(),"/nanos").and_return(file_stat)
109
-
110
- with_fuse(mountpoint,mockfs) do
111
- stat = File.stat("#{mountpoint}/nanos")
112
- stat.atime.should == atime
113
- stat.ctime.should == ctime
114
- stat.mtime.should == mtime
115
- end
89
+ testns = Tempfile.new("testns")
90
+ stat = File.stat(testns.path)
91
+
92
+ # so if this Ruby has usec resolution for File.stat
93
+ # we'd expect to skip this test 1 in 100,000 times...
94
+ no_usecs = (stat.mtime.usec == 0)
95
+
96
+ if no_usecs
97
+ puts "Skipping due to no usec resolution for File.stat"
98
+ else
99
+ atime,mtime,ctime = usec_times(60,600,3600)
100
+
101
+ file_stat.atime = atime
102
+ file_stat.mtime = mtime
103
+ file_stat.ctime = ctime
104
+
105
+ # ruby can't set file times with ns res, o we are limited to usecs
106
+ mockfs.stub(:getattr).with(anything(),"/nanos").and_return(file_stat)
107
+
108
+ with_fuse(mountpoint,mockfs) do
109
+ stat = File.stat("#{mountpoint}/nanos")
110
+ stat.atime.usec.should == atime.usec
111
+ stat.atime.should == atime
112
+ stat.ctime.should == ctime
113
+ stat.mtime.should == mtime
114
+ end
115
+ end
116
116
  end
117
117
 
118
+ it "should set file access and modification times subsecond resolution" do
119
+ atime,mtime = usec_times(60,600)
120
+
121
+ atime_ns = (atime.to_i * (10**9)) + (atime.nsec)
122
+ mtime_ns = (mtime.to_i * (10**9)) + (mtime.nsec)
123
+
124
+ mockfs.stub(:getattr).with(anything(),"/usec").and_return(file_stat)
125
+ mockfs.should_receive(:utimens).with(anything,"/usec",atime_ns,mtime_ns)
126
+
127
+ with_fuse(mountpoint,mockfs) do
128
+ File.utime(atime,mtime,"#{mountpoint}/usec").should == 1
129
+ end
130
+ end
118
131
  it "should set file access and modification times" do
119
132
 
120
133
  atime = Time.now()
@@ -134,12 +147,12 @@ describe RFuse::Fuse do
134
147
 
135
148
  it "should create files" do
136
149
 
137
- mockfs.stub(:getattr).with(anything(),"/newfile").and_return(nil,file_stat)
138
- mockfs.should_receive(:mknod).with(anything(),"/newfile",file_mode(0644),0,0)
139
-
140
- with_fuse(mountpoint,mockfs) do
150
+ mockfs.stub(:getattr).with(anything(),"/newfile").and_return(nil,file_stat)
151
+ mockfs.should_receive(:mknod).with(anything(),"/newfile",file_mode(0644),0,0)
152
+
153
+ with_fuse(mountpoint,mockfs) do
141
154
  File.open("#{mountpoint}/newfile","w",0644) { |f| }
142
- end
155
+ end
143
156
  end
144
157
 
145
158
  # ruby doesn't seem to have a native method to create these
@@ -158,7 +171,7 @@ describe RFuse::Fuse do
158
171
  end
159
172
 
160
173
  }
161
-
174
+
162
175
  reads = 0
163
176
  mockfs.stub(:read) { |ctx,path,size,offset,ffi|
164
177
  reads += 2
@@ -173,4 +186,22 @@ describe RFuse::Fuse do
173
186
  end
174
187
  end
175
188
  end
189
+
190
+ context "exceptions" do
191
+
192
+ it "should capture exceptions appropriately" do
193
+
194
+ mockfs.should_receive(:getattr).with(anything(),"/exceptions").and_raise(RuntimeError)
195
+
196
+ with_fuse(mountpoint,mockfs) do
197
+ begin
198
+ File.stat("#{mountpoint}/exceptions")
199
+ raise "should not get here"
200
+ rescue Errno::ENOENT
201
+ #all good
202
+ end
203
+ end
204
+ end
205
+
206
+ end
176
207
  end
data/spec/spec_helper.rb CHANGED
@@ -47,5 +47,17 @@ module RFuseHelper
47
47
  def tempmount()
48
48
  Dir.mktmpdir("rfuse-spec")
49
49
  end
50
+
51
+ # Generate a set of times with non-zero usec values
52
+ def usec_times(*increments)
53
+ increments.collect { |inc|
54
+ begin
55
+ time = Time.now() + inc
56
+ sleep(0.001)
57
+ end until time.usec != 0
58
+ time
59
+ }
60
+ end
61
+
50
62
  end
51
63
  include RFuseHelper
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rfuse
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-06 00:00:00.000000000 Z
12
+ date: 2012-08-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -91,16 +91,17 @@ dependencies:
91
91
  - - ! '>='
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
- description: Ruby language binding for FUSE. It was forked from rfuse and modified
95
- for Ruby 1.9.2.
94
+ description: Write userspace filesystems in Ruby
96
95
  email:
97
96
  - grant@lastweekend.com.au
98
97
  executables: []
99
98
  extensions:
100
99
  - ext/rfuse/extconf.rb
101
- extra_rdoc_files: []
100
+ extra_rdoc_files:
101
+ - CHANGES.md
102
102
  files:
103
103
  - .gitignore
104
+ - .yardopts
104
105
  - CHANGES.md
105
106
  - Gemfile
106
107
  - LICENSE
@@ -127,6 +128,7 @@ files:
127
128
  - ext/rfuse/rfuse_mod.c
128
129
  - lib/rfuse-ng.rb
129
130
  - lib/rfuse.rb
131
+ - lib/rfuse/compat.rb
130
132
  - lib/rfuse/version.rb
131
133
  - lib/rfuse_ng.rb
132
134
  - rfuse.gemspec
@@ -161,4 +163,4 @@ signing_key:
161
163
  specification_version: 3
162
164
  summary: Ruby language binding for FUSE
163
165
  test_files: []
164
- has_rdoc:
166
+ has_rdoc: yard