sys-filesystem 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +6 -0
- data/README +13 -4
- data/Rakefile +4 -0
- data/ext/extconf.rb +5 -0
- data/ext/sys/filesystem.c +165 -9
- data/test/test_sys_filesystem_unix.rb +19 -5
- data/test/test_sys_filesystem_windows.rb +7 -1
- metadata +2 -2
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
|
-
|
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
|
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'
|
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-
|
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
|
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
|
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
|
-
|
152
|
-
|
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
|
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.
|
294
|
-
rb_define_const(cFilesys, "VERSION", rb_str_new2("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.
|
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, "
|
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(
|
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
|
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
|
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.
|
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.
|
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:
|
12
|
+
date: 2009-01-26 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|