sys-filesystem 0.2.0 → 0.3.0

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/CHANGES CHANGED
@@ -1,3 +1,9 @@
1
+ == 0.3.0 - 26-Feb-2009
2
+ * Added support for OS X and FreeBSD thanks to an awesome patch by Nobuyoshi
3
+ Miyokawa.
4
+ * Added the Filesystem.mount_point method that takes a file and returns
5
+ the mount point its sitting on.
6
+
1
7
  == 0.2.0 - 30-Dec-2008
2
8
  * Added the Filesystem.mounts method for iterating over mount or volume
3
9
  information.
data/README CHANGED
@@ -13,7 +13,8 @@
13
13
  require 'sys/filesystem'
14
14
  include Sys
15
15
 
16
- p Filesystem.stat("/")
16
+ # Display information about a particular filesystem.
17
+ p Filesystem.stat('/')
17
18
 
18
19
  # Sample output
19
20
 
@@ -33,11 +34,15 @@
33
34
  @blocks_free = 20301129
34
35
  >
35
36
 
37
+ # Describe all mount points on the system
36
38
  Filesystem.mounts{ |mount| p mount }
39
+
40
+ # Find the mount point of any particular file
41
+ puts Filesystem.mount_point('/home/djberge/some_file.txt') => '/home'
37
42
 
38
43
  = Notes
39
44
  === MS Windows
40
- This is a pure Ruby implementation using the windows-pr package, which in
45
+ This is a pure Ruby implementation using the windows-pr library, which in
41
46
  turn wraps native Windows functions.
42
47
  === UNIX
43
48
  This is a C extension that wraps statvfs, etc.
@@ -54,11 +59,15 @@
54
59
  Suggestions welcome.
55
60
 
56
61
  = Acknowledgements
57
- Mike Hall, for ideas and code that I borrowed from his 'filesystem' package.
62
+ Mike Hall, for ideas and code that I borrowed from his 'filesystem'
63
+ library.
64
+
58
65
  Park Heesob, for implementation and API ideas for the MS Windows version.
66
+
67
+ Nobuyoshi Miyokawa, for adding FreeBSD and OS X support.
59
68
 
60
69
  = Copyright
61
- (C) 2003-2008 Daniel J. Berger
70
+ (C) 2003-2009 Daniel J. Berger
62
71
  All Rights Reserved
63
72
 
64
73
  = Warranty
data/Rakefile CHANGED
@@ -58,6 +58,10 @@ Rake::TestTask.new("test") do |t|
58
58
  t.test_files = FileList['test/test_sys_filesystem.rb']
59
59
  end
60
60
 
61
+ task :test do
62
+ Rake.application[:clean].execute
63
+ end
64
+
61
65
  desc "Run the example program"
62
66
  task :example => [:build] do |t|
63
67
  Dir.chdir('examples') do
data/ext/extconf.rb CHANGED
@@ -7,6 +7,11 @@ have_header("sys/mnttab.h") || have_header("mntent.h")
7
7
  have_func("statvfs")
8
8
  have_func("getextmntent")
9
9
 
10
+ if have_func("getmntinfo")
11
+ have_macro("MNT_NOATIME", "sys/mount.h")
12
+ have_macro("MNT_MULTILABEL", "sys/mount.h")
13
+ end
14
+
10
15
  if have_header("sys/statvfs.h")
11
16
  have_struct_member("struct statvfs", "f_basetype", "sys/statvfs.h")
12
17
  else
data/ext/sys/filesystem.c CHANGED
@@ -19,17 +19,35 @@
19
19
  #ifdef HAVE_SYS_MNTTAB_H /* Solaris */
20
20
 
21
21
  #include <sys/mnttab.h>
22
- #define MNTENT mnttab
22
+ #define MNTENT mnttab
23
23
  #define START_MNT(F,M) fopen(F,M)
24
24
  #define GET_MNT(FP,MP) (getmntent(FP,MP) == 0)
25
25
  #define END_MNT(F) fclose(F)
26
26
  #define MOUNTFILE "/etc/mnttab"
27
27
 
28
+ #elif HAVE_GETMNTINFO
29
+
30
+ struct _ment {
31
+ struct statfs *mntbufp;
32
+ int current;
33
+ int max;
34
+ };
35
+
36
+ #include <sys/param.h>
37
+ #include <sys/mount.h>
38
+ #include <sys/vnode.h>
39
+
40
+ #define MNTENT _ment
41
+ #define START_MNT(F,M) start_mnt(F,M)
42
+ #define GET_MNT(FP,MP) ((MP = get_mnt(MP)) != NULL)
43
+ #define END_MNT(F) end_mnt(F)
44
+ #define MOUNTFILE "getmntinfo"
45
+
28
46
  #else /* Most flavors of UNIX */
29
47
 
30
48
  #ifdef HAVE_MNTENT_H
31
49
  #include <mntent.h>
32
- #define MNTENT mntent
50
+ #define MNTENT mntent
33
51
  #define START_MNT(F,M) setmntent(F,M)
34
52
  #define GET_MNT(FP,MP) ((MP = getmntent(FP)) != NULL)
35
53
  #define END_MNT(F) endmntent(F)
@@ -38,6 +56,71 @@
38
56
 
39
57
  #endif
40
58
 
59
+ #ifdef HAVE_GETMNTINFO
60
+
61
+ /* below table comes from FreeBSD mount.c@1.105 */
62
+ static struct opt {
63
+ int o_opt;
64
+ const char *o_name;
65
+ } optnames[] = {
66
+ { MNT_ASYNC, "asynchronous" },
67
+ { MNT_EXPORTED, "NFS exported" },
68
+ { MNT_LOCAL, "local" },
69
+ { MNT_NOEXEC, "noexec" },
70
+ { MNT_NOSUID, "nosuid" },
71
+ { MNT_QUOTA, "with quotas" },
72
+ { MNT_RDONLY, "read-only" },
73
+ { MNT_SYNCHRONOUS, "synchronous" },
74
+ { MNT_UNION, "union" },
75
+ #ifdef HAVE_MNT_MULTILABEL
76
+ { MNT_MULTILABEL, "multilabel" },
77
+ #endif
78
+ #ifdef HAVE_MNT_NOATIME
79
+ { MNT_NOATIME, "noatime" },
80
+ #endif
81
+ #if !defined(__MACH__) || !defined(__APPLE__)
82
+ { MNT_NOSYMFOLLOW, "nosymfollow" },
83
+ { MNT_NOCLUSTERR, "noclusterr" },
84
+ { MNT_NOCLUSTERW, "noclusterw" },
85
+ { MNT_SUIDDIR, "suiddir" },
86
+ { MNT_SOFTDEP, "soft-updates" },
87
+ { MNT_ACLS, "acls" },
88
+ #endif
89
+ { 0, NULL }
90
+ };
91
+
92
+ static FILE* start_mnt(const char *filename, const char *type)
93
+ {
94
+ return (FILE*)!0; /* do nothing */
95
+ }
96
+
97
+ static struct _ment* get_mnt(struct _ment* m)
98
+ {
99
+ struct _ment* ret = m;
100
+
101
+ if (m->max == 0) {
102
+ if ((m->max = getmntinfo(&(m->mntbufp), MNT_NOWAIT)) == 0) {
103
+ return NULL; /* XXX */
104
+ }
105
+ m->current = 0;
106
+ }
107
+
108
+ if (m->current >= m->max) {
109
+ ret = NULL;
110
+ }
111
+ m->current++;
112
+
113
+ return ret;
114
+ }
115
+
116
+ static void end_mnt(FILE* fp)
117
+ {
118
+ /* do nothing */
119
+ }
120
+
121
+ #endif
122
+
123
+
41
124
  VALUE mSys, cFilesys, cStat, cMount;
42
125
 
43
126
  static VALUE create_mount_object(struct MNTENT*);
@@ -63,7 +146,7 @@ static VALUE fs_stat(VALUE klass, VALUE v_path){
63
146
  struct proc p;
64
147
 
65
148
  if(VFS_STATFS(&mp, &fs, &p) < 0)
66
- rb_sys_fail("VFS_STATFS");
149
+ rb_sys_fail("VFS_STATFS");
67
150
  #endif
68
151
 
69
152
  v_stat = rb_funcall(cStat, rb_intern("new"), 0, 0);
@@ -148,8 +231,12 @@ static VALUE fs_mounts(VALUE klass){
148
231
  FILE* fp;
149
232
  struct MNTENT* mp;
150
233
  #ifdef HAVE_SYS_MNTTAB_H
151
- struct MNTENT mt;
152
- mp = &mt;
234
+ struct MNTENT mt;
235
+ mp = &mt;
236
+ #elif HAVE_GETMNTINFO
237
+ struct MNTENT mt;
238
+ mt.max = 0;
239
+ mp = &mt;
153
240
  #endif
154
241
 
155
242
  v_array = Qnil;
@@ -168,7 +255,7 @@ static VALUE fs_mounts(VALUE klass){
168
255
  }
169
256
 
170
257
  END_MNT(fp);
171
-
258
+
172
259
  return v_array; /* nil in block form */
173
260
  }
174
261
 
@@ -184,6 +271,32 @@ static VALUE create_mount_object(struct MNTENT* mp){
184
271
  rb_iv_set(v_mount, "@mount_time", rb_time_new(atoi(mp->mnt_time), 0));
185
272
  rb_iv_set(v_mount, "@dump_frequency", Qnil);
186
273
  rb_iv_set(v_mount, "@pass_number", Qnil);
274
+ #elif HAVE_GETMNTINFO
275
+ {
276
+ struct statfs *p = mp->mntbufp + (mp->current-1);
277
+ struct opt *o;
278
+ int flags, mul;
279
+ char ostr[BUFSIZ];
280
+
281
+ flags = p->f_flags & MNT_VISFLAGMASK;
282
+ ostr[0] = '\0';
283
+
284
+ for (mul = 0, o = optnames; flags && o->o_opt; o++) {
285
+ if (flags & o->o_opt) {
286
+ strlcat(ostr, ((mul++) ? "," : ""), BUFSIZ);
287
+ strlcat(ostr, o->o_name, BUFSIZ);
288
+ flags &= ~o->o_opt;
289
+ }
290
+ }
291
+
292
+ rb_iv_set(v_mount, "@name", rb_tainted_str_new2(p->f_mntfromname));
293
+ rb_iv_set(v_mount, "@mount_point", rb_tainted_str_new2(p->f_mntonname));
294
+ rb_iv_set(v_mount, "@mount_type", rb_tainted_str_new2(p->f_fstypename));
295
+ rb_iv_set(v_mount, "@options", rb_tainted_str_new2(ostr));
296
+ rb_iv_set(v_mount, "@mount_time", Qnil);
297
+ rb_iv_set(v_mount, "@dump_frequency", Qnil);
298
+ rb_iv_set(v_mount, "@pass_number", Qnil);
299
+ }
187
300
  #else
188
301
  rb_iv_set(v_mount, "@name", rb_tainted_str_new2(mp->mnt_fsname));
189
302
  rb_iv_set(v_mount, "@mount_point", rb_tainted_str_new2(mp->mnt_dir));
@@ -197,6 +310,48 @@ static VALUE create_mount_object(struct MNTENT* mp){
197
310
  return v_mount;
198
311
  }
199
312
 
313
+ /*
314
+ * call-seq:
315
+ * Filesystem.mount_point(file)
316
+ *
317
+ * Returns the mount point of the given +file+, or itself if it cannot be
318
+ * determined.
319
+ *
320
+ * Example:
321
+ *
322
+ * Filesystem.mount_point('/home/djberge/some_file.txt') => '/home'
323
+ */
324
+ static VALUE fs_mount_point(VALUE klass, VALUE v_file){
325
+ VALUE v_stat, v_stat_m, v_mounts, v_mount_pt, v_mount;
326
+ VALUE v_found = Qfalse;
327
+ long dev1, dev2;
328
+ int i = 0;
329
+
330
+ v_stat = rb_funcall(rb_cFile, rb_intern("stat"), 1, v_file);
331
+ v_mounts = fs_mounts(klass);
332
+ dev1 = FIX2LONG(rb_funcall(v_stat, rb_intern("dev"), 0, 0));
333
+
334
+ /* Stat each mount point and compare its device number with the device
335
+ * number of the file provided. If they match, we have a winner.
336
+ */
337
+ for(i = 0; i < RARRAY(v_mounts)->len; i++){
338
+ v_mount = RARRAY(v_mounts)->ptr[i];
339
+ v_mount_pt = rb_funcall(v_mount, rb_intern("mount_point"), 0, 0);
340
+ v_stat_m = rb_funcall(rb_cFile, rb_intern("stat"), 1, v_mount_pt);
341
+ dev2 = FIX2LONG(rb_funcall(v_stat_m, rb_intern("dev"), 0, 0));
342
+
343
+ if(dev1 == dev2){
344
+ v_found = Qtrue;
345
+ break;
346
+ }
347
+ }
348
+
349
+ if(v_found == Qtrue)
350
+ return v_mount_pt;
351
+ else
352
+ return v_file;
353
+ }
354
+
200
355
  void Init_filesystem(){
201
356
  /* The toplevel namespace */
202
357
  mSys = rb_define_module("Sys");
@@ -210,9 +365,10 @@ void Init_filesystem(){
210
365
  cMount = rb_define_class_under(cFilesys, "Mount", rb_cObject);
211
366
 
212
367
  /* Instances of this class are returned by the Filesystem.stat method */
213
- cStat = rb_define_class_under(cFilesys, "Stat", rb_cObject);
368
+ cStat = rb_define_class_under(cFilesys, "Stat", rb_cObject);
214
369
 
215
370
  /* Singleton methods */
371
+ rb_define_singleton_method(cFilesys, "mount_point", fs_mount_point, 1);
216
372
  rb_define_singleton_method(cFilesys, "mounts", fs_mounts, 0);
217
373
  rb_define_singleton_method(cFilesys, "stat", fs_stat, 1);
218
374
 
@@ -290,8 +446,8 @@ void Init_filesystem(){
290
446
 
291
447
  /* Constants */
292
448
 
293
- /* 0.2.0: The version of this library (a String) */
294
- rb_define_const(cFilesys, "VERSION", rb_str_new2("0.2.0"));
449
+ /* 0.3.0: The version of this library (a String) */
450
+ rb_define_const(cFilesys, "VERSION", rb_str_new2("0.3.0"));
295
451
 
296
452
  /* 0x00000001: Read only file system */
297
453
  rb_define_const(cStat, "RDONLY", INT2FIX(ST_RDONLY));
@@ -15,6 +15,8 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
15
15
  def self.startup
16
16
  @@solaris = Config::CONFIG['host_os'] =~ /solaris/i
17
17
  @@linux = Config::CONFIG['host_os'] =~ /linux/i
18
+ @@freebsd = Config::CONFIG['host_os'] =~ /freebsd/i
19
+ @@darwin = Config::CONFIG['host_os'] =~ /darwin/i
18
20
  end
19
21
 
20
22
  def setup
@@ -26,7 +28,7 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
26
28
  end
27
29
 
28
30
  def test_version
29
- assert_equal('0.2.0', Filesystem::VERSION)
31
+ assert_equal('0.3.0', Filesystem::VERSION)
30
32
  end
31
33
 
32
34
  def test_stat_path
@@ -105,7 +107,8 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
105
107
  end
106
108
 
107
109
  def test_stat_base_type
108
- omit_unless(@@solaris, "NOTRUNC test skipped except on Solaris")
110
+ omit_unless(@@solaris, "base_type test skipped except on Solaris")
111
+
109
112
  assert_respond_to(@stat, :base_type)
110
113
  assert_kind_of(String, @stat.base_type)
111
114
  end
@@ -113,7 +116,9 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
113
116
  def test_stat_constants
114
117
  assert_not_nil(Filesystem::Stat::RDONLY)
115
118
  assert_not_nil(Filesystem::Stat::NOSUID)
119
+
116
120
  omit_unless(@@solaris, "NOTRUNC test skipped except on Solaris")
121
+
117
122
  assert_not_nil(Filesystem::Stat::NOTRUNC)
118
123
  end
119
124
 
@@ -192,15 +197,16 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
192
197
 
193
198
  def test_mount_time
194
199
  assert_respond_to(@mnt, :mount_time)
200
+
195
201
  if @@solaris
196
- assert_kind_of(String, @mnt.mount_time)
202
+ assert_kind_of(Time, @mnt.mount_time)
197
203
  else
198
204
  assert_nil(@mnt.mount_time)
199
205
  end
200
206
  end
201
207
 
202
208
  def test_mount_dump_frequency
203
- omit_if(@@solaris, 'dump_frequency test skipped on Solaris')
209
+ omit_if(@@solaris || @@freebsd || @@darwin, 'dump_frequency test skipped on this platform')
204
210
  assert_respond_to(@mnt, :dump_frequency)
205
211
  assert_kind_of(Fixnum, @mnt.dump_frequency)
206
212
  end
@@ -211,7 +217,7 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
211
217
  end
212
218
 
213
219
  def test_mount_pass_number
214
- omit_if(@@solaris, 'pass_number test skipped on Solaris')
220
+ omit_if(@@solaris || @@freebsd || @@darwin, 'pass_number test skipped on this platform')
215
221
  assert_respond_to(@mnt, :pass_number)
216
222
  assert_kind_of(Fixnum, @mnt.pass_number)
217
223
  end
@@ -221,6 +227,12 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
221
227
  assert_true(@mnt.method(:passno) == @mnt.method(:pass_number))
222
228
  end
223
229
 
230
+ def test_mount_point_singleton
231
+ assert_respond_to(Filesystem, :mount_point)
232
+ assert_nothing_raised{ Filesystem.mount_point(Dir.pwd) }
233
+ assert_kind_of(String, Filesystem.mount_point(Dir.pwd))
234
+ end
235
+
224
236
  def teardown
225
237
  @dir = nil
226
238
  @stat = nil
@@ -230,5 +242,7 @@ class TC_Sys_Filesystem_Unix < Test::Unit::TestCase
230
242
  def self.shutdown
231
243
  @@solaris = nil
232
244
  @@linux = nil
245
+ @@freebsd = nil
246
+ @@darwin = nil
233
247
  end
234
248
  end
@@ -22,7 +22,7 @@ class TC_Sys_Filesystem_Windows < Test::Unit::TestCase
22
22
  end
23
23
 
24
24
  def test_version
25
- assert_equal('0.2.0', Filesystem::VERSION)
25
+ assert_equal('0.3.0', Filesystem::VERSION)
26
26
  end
27
27
 
28
28
  def test_stat_path
@@ -93,6 +93,12 @@ class TC_Sys_Filesystem_Windows < Test::Unit::TestCase
93
93
  assert_kind_of(String, @stat.base_type)
94
94
  end
95
95
 
96
+ def test_mount_point_singleton
97
+ assert_respond_to(Filesystem, :mount_point)
98
+ assert_nothing_raised{ Filesystem.mount_point(Dir.pwd) }
99
+ assert_kind_of(String, Filesystem.mount_point(Dir.pwd))
100
+ end
101
+
96
102
  def test_constants
97
103
  assert_not_nil(Filesystem::CASE_SENSITIVE_SEARCH)
98
104
  assert_not_nil(Filesystem::CASE_PRESERVED_NAMES)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sys-filesystem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel J. Berger
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-12-13 00:00:00 -07:00
12
+ date: 2009-01-26 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15