sys-filesystem 1.3.3 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,34 +1,16 @@
1
1
  require 'rake'
2
2
  require 'rake/clean'
3
- require 'rake/testtask'
3
+ require 'rspec/core/rake_task'
4
4
 
5
- CLEAN.include('**/*.gem', '**/*.rbc', '**/*.rbx')
6
-
7
- desc "Run the test suite"
8
- Rake::TestTask.new("test") do |t|
9
- if File::ALT_SEPARATOR
10
- t.libs << 'lib/windows'
11
- else
12
- t.libs << 'lib/unix'
13
- end
14
-
15
- t.warning = true
16
- t.verbose = true
17
- t.test_files = FileList['test/test_sys_filesystem.rb']
18
- end
19
-
20
- desc "Run the example program"
21
- task :example do |t|
22
- sh "ruby -Ilib -Ilib/unix -Ilib/windows examples/example_stat.rb"
23
- end
5
+ CLEAN.include('**/*.gem', '**/*.rbc', '**/*.rbx', '**/*.lock')
24
6
 
25
7
  namespace :gem do
26
8
  desc "Build the sys-filesystem gem"
27
- task :create => [:clean] do |t|
9
+ task :create => [:clean] do
28
10
  require 'rubygems/package'
29
- spec = eval(IO.read('sys-filesystem.gemspec'))
11
+ spec = Gem::Specification.load('sys-filesystem.gemspec')
30
12
  spec.signing_key = File.join(Dir.home, '.ssh', 'gem-private_key.pem')
31
- Gem::Package.build(spec, true)
13
+ Gem::Package.build(spec)
32
14
  end
33
15
 
34
16
  desc "Install the sys-filesystem gem"
@@ -38,4 +20,12 @@ namespace :gem do
38
20
  end
39
21
  end
40
22
 
41
- task :default => :test
23
+ desc "Run the example program"
24
+ task :example do
25
+ sh "ruby -Ilib -Ilib/unix -Ilib/windows examples/example_stat.rb"
26
+ end
27
+
28
+ desc "Run the test suite"
29
+ RSpec::Core::RakeTask.new(:spec)
30
+
31
+ task :default => :spec
@@ -7,11 +7,12 @@
7
7
  require 'optparse'
8
8
 
9
9
  options = {:mount_options => []}
10
+
10
11
  OptionParser.new do |opts|
11
12
  opts.banner = "Usage: #$0 [-o options] [-t external_type] special node"
12
13
 
13
- opts.on("-o=OPTIONS", "Set one or many mount options (comma delimited)") do |opts|
14
- options[:mount_options] += opts.split(',')
14
+ opts.on("-o=OPTIONS", "Set one or many mount options (comma delimited)") do |cli_opts|
15
+ options[:mount_options] += cli_opts.split(',')
15
16
  end
16
17
 
17
18
  opts.on("-r", "Set readonly flag") do
@@ -1,7 +1,7 @@
1
1
  module Sys
2
2
  class Filesystem
3
3
  # The version of the sys-filesystem library
4
- VERSION = '1.3.3'.freeze
4
+ VERSION = '1.4.2'.freeze
5
5
  end
6
6
  end
7
7
 
@@ -11,44 +11,44 @@ module Sys
11
11
  include Sys::Filesystem::Structs
12
12
  extend Sys::Filesystem::Functions
13
13
 
14
- private
15
-
16
14
  # Readable versions of constant names
17
15
  OPT_NAMES = {
18
- MNT_RDONLY => 'read-only',
19
- MNT_SYNCHRONOUS => 'synchronous',
20
- MNT_NOEXEC => 'noexec',
21
- MNT_NOSUID => 'nosuid',
22
- MNT_NODEV => 'nodev',
23
- MNT_UNION => 'union',
24
- MNT_ASYNC => 'asynchronous',
25
- MNT_CPROTECT => 'content-protection',
26
- MNT_EXPORTED => 'exported',
27
- MNT_QUARANTINE => 'quarantined',
28
- MNT_LOCAL => 'local',
29
- MNT_QUOTA => 'quotas',
30
- MNT_ROOTFS => 'rootfs',
31
- MNT_DONTBROWSE => 'nobrowse',
16
+ MNT_RDONLY => 'read-only',
17
+ MNT_SYNCHRONOUS => 'synchronous',
18
+ MNT_NOEXEC => 'noexec',
19
+ MNT_NOSUID => 'nosuid',
20
+ MNT_NODEV => 'nodev',
21
+ MNT_UNION => 'union',
22
+ MNT_ASYNC => 'asynchronous',
23
+ MNT_CPROTECT => 'content-protection',
24
+ MNT_EXPORTED => 'exported',
25
+ MNT_QUARANTINE => 'quarantined',
26
+ MNT_LOCAL => 'local',
27
+ MNT_QUOTA => 'quotas',
28
+ MNT_ROOTFS => 'rootfs',
29
+ MNT_DONTBROWSE => 'nobrowse',
32
30
  MNT_IGNORE_OWNERSHIP => 'noowners',
33
- MNT_AUTOMOUNTED => 'automounted',
34
- MNT_JOURNALED => 'journaled',
35
- MNT_NOUSERXATTR => 'nouserxattr',
36
- MNT_DEFWRITE => 'defwrite',
37
- MNT_NOATIME => 'noatime'
31
+ MNT_AUTOMOUNTED => 'automounted',
32
+ MNT_JOURNALED => 'journaled',
33
+ MNT_NOUSERXATTR => 'nouserxattr',
34
+ MNT_DEFWRITE => 'defwrite',
35
+ MNT_NOATIME => 'noatime'
38
36
  }.freeze
39
37
 
38
+ private_constant :OPT_NAMES
39
+
40
40
  # File used to read mount informtion from.
41
41
  if File.exist?('/etc/mtab')
42
- MOUNT_FILE = '/etc/mtab'
42
+ MOUNT_FILE = '/etc/mtab'.freeze
43
43
  elsif File.exist?('/etc/mnttab')
44
- MOUNT_FILE = '/etc/mnttab'
44
+ MOUNT_FILE = '/etc/mnttab'.freeze
45
45
  elsif File.exist?('/proc/mounts')
46
- MOUNT_FILE = '/proc/mounts'
46
+ MOUNT_FILE = '/proc/mounts'.freeze
47
47
  else
48
- MOUNT_FILE = 'getmntinfo'
48
+ MOUNT_FILE = 'getmntinfo'.freeze
49
49
  end
50
50
 
51
- public
51
+ private_constant :MOUNT_FILE
52
52
 
53
53
  # The error raised if any of the Filesystem methods fail.
54
54
  class Error < StandardError; end
@@ -198,7 +198,27 @@ module Sys
198
198
  # Returns a Sys::Filesystem::Stat object containing information about the
199
199
  # +path+ on the filesystem.
200
200
  #
201
+ # Examples:
202
+ #
203
+ # # path
204
+ # Sys::Filesystem.stat("path")
205
+ #
206
+ # # Pathname
207
+ # pathname = Pathname.new("path")
208
+ # Sys::Filesystem.stat(pathname)
209
+ #
210
+ # # File
211
+ # file = File.open("file", "r")
212
+ # Sys::Filesystem.stat(file)
213
+ #
214
+ # # Dir
215
+ # dir = Dir.open("/")
216
+ # Sys::Filesystem.stat(dir)
217
+ #
201
218
  def self.stat(path)
219
+ path = path.path if path.respond_to?(:path) # File, Dir
220
+ path = path.to_s if path.respond_to?(:to_s) # Pathname
221
+
202
222
  fs = Statvfs.new
203
223
 
204
224
  if statvfs(path, fs) < 0
@@ -258,17 +278,17 @@ module Sys
258
278
 
259
279
  ptr = buf.get_pointer(0)
260
280
 
261
- num.times{ |i|
281
+ num.times do
262
282
  mnt = Statfs.new(ptr)
263
283
  obj = Sys::Filesystem::Mount.new
264
284
  obj.name = mnt[:f_mntfromname].to_s
265
285
  obj.mount_point = mnt[:f_mntonname].to_s
266
286
  obj.mount_type = mnt[:f_fstypename].to_s
267
287
 
268
- string = ""
288
+ string = ''
269
289
  flags = mnt[:f_flags] & MNT_VISFLAGMASK
270
290
 
271
- OPT_NAMES.each{ |key,val|
291
+ OPT_NAMES.each do |key, val|
272
292
  if flags & key > 0
273
293
  if string.empty?
274
294
  string << val
@@ -277,7 +297,7 @@ module Sys
277
297
  end
278
298
  end
279
299
  flags &= ~key
280
- }
300
+ end
281
301
 
282
302
  obj.options = string
283
303
 
@@ -288,7 +308,7 @@ module Sys
288
308
  end
289
309
 
290
310
  ptr += Statfs.size
291
- }
311
+ end
292
312
  else
293
313
  begin
294
314
  if respond_to?(:setmntent, true)
@@ -365,7 +385,7 @@ module Sys
365
385
  dev = File.stat(file).dev
366
386
  val = file
367
387
 
368
- self.mounts.each{ |mnt|
388
+ mounts.each do |mnt|
369
389
  mp = mnt.mount_point
370
390
  begin
371
391
  if File.stat(mp).dev == dev
@@ -375,7 +395,7 @@ module Sys
375
395
  rescue Errno::EACCES
376
396
  next
377
397
  end
378
- }
398
+ end
379
399
 
380
400
  val
381
401
  end
@@ -1,8 +1,6 @@
1
1
  module Sys
2
2
  class Filesystem
3
3
  module Constants
4
- private
5
-
6
4
  MNT_RDONLY = 0x00000001 # read only filesystem
7
5
  MNT_SYNCHRONOUS = 0x00000002 # file system written synchronously
8
6
  MNT_NOEXEC = 0x00000004 # can't exec from filesystem
@@ -33,7 +31,7 @@ module Sys
33
31
  MNT_LOCAL | MNT_QUOTA |
34
32
  MNT_ROOTFS | MNT_DOVOLFS | MNT_DONTBROWSE |
35
33
  MNT_IGNORE_OWNERSHIP | MNT_AUTOMOUNTED | MNT_JOURNALED |
36
- MNT_NOUSERXATTR | MNT_DEFWRITE | MNT_MULTILABEL |
34
+ MNT_NOUSERXATTR | MNT_DEFWRITE | MNT_MULTILABEL |
37
35
  MNT_NOATIME | MNT_CPROTECT
38
36
  )
39
37
 
@@ -58,7 +56,7 @@ module Sys
58
56
  MS_SHARED = 1 << 20
59
57
  MS_RELATIME = 1 << 21
60
58
  MS_KERNMOUNT = 1 << 22
61
- MS_I_VERSION = 1 << 23
59
+ MS_I_VERSION = 1 << 23
62
60
  MS_STRICTATIME = 1 << 24
63
61
  MS_ACTIVE = 1 << 30
64
62
  MS_NOUSER = 1 << 31
@@ -7,14 +7,16 @@ module Sys
7
7
 
8
8
  ffi_lib FFI::Library::LIBC
9
9
 
10
- if RbConfig::CONFIG['host_os'] =~ /sunos|solaris|linux/i
11
- attach_function(:statvfs, :statvfs64, [:string, :pointer], :int)
10
+ if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
11
+ attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
12
+ elsif RbConfig::CONFIG['host_os'] =~ /linux/i && RbConfig::CONFIG['arch'] =~ /64/
13
+ attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
12
14
  else
13
- attach_function(:statvfs, [:string, :pointer], :int)
15
+ attach_function(:statvfs, %i[string pointer], :int)
14
16
  end
15
17
 
16
18
  attach_function(:strerror, [:int], :string)
17
- attach_function(:mount_c, :mount, [:string, :string, :string, :ulong, :string], :int)
19
+ attach_function(:mount_c, :mount, %i[string string string ulong string], :int)
18
20
 
19
21
  begin
20
22
  attach_function(:umount_c, :umount, [:string], :int)
@@ -28,22 +30,26 @@ module Sys
28
30
 
29
31
  begin
30
32
  if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
31
- attach_function(:fopen, [:string, :string], :pointer)
33
+ attach_function(:fopen, %i[string string], :pointer)
32
34
  attach_function(:fclose, [:pointer], :int)
33
- attach_function(:getmntent, [:pointer, :pointer], :int)
35
+ attach_function(:getmntent, %i[pointer pointer], :int)
34
36
  private_class_method :fopen, :fclose, :getmntent
35
37
  else
36
38
  attach_function(:getmntent, [:pointer], :pointer)
37
- attach_function(:setmntent, [:string, :string], :pointer)
39
+ attach_function(:setmntent, %i[string string], :pointer)
38
40
  attach_function(:endmntent, [:pointer], :int)
39
- attach_function(:umount2, [:string, :int], :int)
41
+ attach_function(:umount2, %i[string int], :int)
40
42
  private_class_method :getmntent, :setmntent, :endmntent, :umount2
41
43
  end
42
44
  rescue FFI::NotFoundError
43
45
  if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach/i
44
- attach_function(:getmntinfo, :getmntinfo64, [:pointer, :int], :int)
46
+ begin
47
+ attach_function(:getmntinfo, :getmntinfo64, %i[pointer int], :int)
48
+ rescue FFI::NotFoundError
49
+ attach_function(:getmntinfo, %i[pointer int], :int) # Big Sur and later
50
+ end
45
51
  else
46
- attach_function(:getmntinfo, [:pointer, :int], :int)
52
+ attach_function(:getmntinfo, %i[pointer int], :int)
47
53
  end
48
54
  private_class_method :getmntinfo
49
55
  end
@@ -40,20 +40,37 @@ module Sys
40
40
  :f_mntonname, [:char, MNAMELEN]
41
41
  )
42
42
  elsif RbConfig::CONFIG['host_os'] =~ /linux/i
43
- layout(
44
- :f_type, :ulong,
45
- :f_bsize, :ulong,
46
- :f_blocks, :uint64,
47
- :f_bfree, :uint64,
48
- :f_bavail, :uint64,
49
- :f_files, :uint64,
50
- :f_ffree, :uint64,
51
- :f_fsid, [:int, 2],
52
- :f_namelen, :ulong,
53
- :f_frsize, :ulong,
54
- :f_flags, :ulong,
55
- :f_spare, [:ulong, 4]
56
- )
43
+ if RbConfig::CONFIG['arch'] =~ /64/
44
+ layout(
45
+ :f_type, :ulong,
46
+ :f_bsize, :ulong,
47
+ :f_blocks, :uint64,
48
+ :f_bfree, :uint64,
49
+ :f_bavail, :uint64,
50
+ :f_files, :uint64,
51
+ :f_ffree, :uint64,
52
+ :f_fsid, [:int, 2],
53
+ :f_namelen, :ulong,
54
+ :f_frsize, :ulong,
55
+ :f_flags, :ulong,
56
+ :f_spare, [:ulong, 4]
57
+ )
58
+ else
59
+ layout(
60
+ :f_type, :ulong,
61
+ :f_bsize, :ulong,
62
+ :f_blocks, :uint32,
63
+ :f_bfree, :uint32,
64
+ :f_bavail, :uint32,
65
+ :f_files, :uint32,
66
+ :f_ffree, :uint32,
67
+ :f_fsid, [:int, 2],
68
+ :f_namelen, :ulong,
69
+ :f_frsize, :ulong,
70
+ :f_flags, :ulong,
71
+ :f_spare, [:ulong, 4]
72
+ )
73
+ end
57
74
  else
58
75
  layout(
59
76
  :f_bsize, :uint32,
@@ -123,6 +140,22 @@ module Sys
123
140
  :f_fstr, [:char, 32],
124
141
  :f_filler, [:ulong, 16]
125
142
  )
143
+ elsif RbConfig::CONFIG['host'] =~ /i686/i
144
+ layout(
145
+ :f_bsize, :ulong,
146
+ :f_frsize, :ulong,
147
+ :f_blocks, :uint,
148
+ :f_bfree, :uint,
149
+ :f_bavail, :uint,
150
+ :f_files, :uint,
151
+ :f_ffree, :uint,
152
+ :f_favail, :uint,
153
+ :f_fsid, :ulong,
154
+ :f_unused, :int,
155
+ :f_flag, :ulong,
156
+ :f_namemax, :ulong,
157
+ :f_spare, [:int, 6]
158
+ )
126
159
  else
127
160
  layout(
128
161
  :f_bsize, :ulong,
@@ -181,7 +181,7 @@ module Sys
181
181
 
182
182
  boot_time = get_boot_time
183
183
 
184
- drives.each{ |drive|
184
+ drives.each do |drive|
185
185
  mount = Mount.new
186
186
  volume = FFI::MemoryPointer.new(:char, MAXPATH)
187
187
  fsname = FFI::MemoryPointer.new(:char, MAXPATH)
@@ -206,7 +206,7 @@ module Sys
206
206
 
207
207
  # Skip unmounted floppies or cd-roms, or inaccessible drives
208
208
  unless bool
209
- if [5,21].include?(FFI.errno) # ERROR_NOT_READY or ERROR_ACCESS_DENIED
209
+ if [5, 21].include?(FFI.errno) # ERROR_NOT_READY or ERROR_ACCESS_DENIED
210
210
  next
211
211
  else
212
212
  raise SystemCallError.new('GetVolumeInformation', FFI.errno)
@@ -218,7 +218,7 @@ module Sys
218
218
 
219
219
  name = 0.chr * MAXPATH
220
220
 
221
- if QueryDosDeviceA(drive[0,2], name, name.size) == 0
221
+ if QueryDosDeviceA(drive[0, 2], name, name.size) == 0
222
222
  raise SystemCallError.new('QueryDosDevice', FFI.errno)
223
223
  end
224
224
 
@@ -231,7 +231,7 @@ module Sys
231
231
  else
232
232
  mounts << mount
233
233
  end
234
- }
234
+ end
235
235
 
236
236
  mounts # Nil if the block form was used.
237
237
  end
@@ -259,10 +259,25 @@ module Sys
259
259
  #
260
260
  # Examples:
261
261
  #
262
+ # # Regular directory
262
263
  # Sys::Filesystem.stat("C:\\")
263
264
  # Sys::Filesystem.stat("C:\\Documents and Settings\\some_user")
264
265
  #
266
+ # # Pathname
267
+ # pathname = Pathname.new("C:\\")
268
+ # Sys::Filesystem.stat(pathname)
269
+ #
270
+ # # Dir
271
+ # dir = Dir.open("C:\\")
272
+ # Sys::Filesystem.stat(dir)
273
+ #
274
+ # Note that on Windows you cannot stat a regular file because
275
+ # Windows won't like it. It must be a directory in some form.
276
+ #
265
277
  def self.stat(path)
278
+ path = path.path if path.respond_to?(:path) # Dir
279
+ path = path.to_s if path.respond_to?(:to_s) # Pathname
280
+
266
281
  bytes_avail = FFI::MemoryPointer.new(:ulong_long)
267
282
  bytes_free = FFI::MemoryPointer.new(:ulong_long)
268
283
  total_bytes = FFI::MemoryPointer.new(:ulong_long)
@@ -270,7 +285,7 @@ module Sys
270
285
  mpoint = mount_point(path).to_s
271
286
  mpoint << '/' unless mpoint.end_with?('/')
272
287
 
273
- wpath = path.to_s.wincode
288
+ wpath = path.to_s.wincode
274
289
 
275
290
  # We need this call for the 64 bit support
276
291
  unless GetDiskFreeSpaceExW(wpath, bytes_avail, total_bytes, bytes_free)
@@ -382,8 +397,6 @@ module Sys
382
397
  self
383
398
  end
384
399
 
385
- private
386
-
387
400
  # This method is used to get the boot time of the system, which is used
388
401
  # for the mount_time attribute within the File.mounts method.
389
402
  #
@@ -396,36 +409,37 @@ module Sys
396
409
  raise Error, e
397
410
  else
398
411
  query = 'select LastBootupTime from Win32_OperatingSystem'
399
- results = wmi.ExecQuery(query)
400
- results.each{ |ole|
401
- time_array = Time.parse(ole.LastBootupTime.split('.').first)
402
- return Time.mktime(*time_array)
403
- }
412
+ ole = wmi.ExecQuery(query).ItemIndex(0)
413
+ time_array = Time.parse(ole.LastBootupTime.split('.').first)
414
+ Time.mktime(*time_array)
404
415
  end
405
416
  end
406
417
 
418
+ private_class_method :get_boot_time
419
+
407
420
  # Private method that converts filesystem flags into a comma separated
408
421
  # list of strings. The presentation is meant as a rough analogue to the
409
422
  # way options are presented for Unix filesystems.
410
423
  #
411
424
  def self.get_options(flags)
412
- str = ""
413
- str << " casepres" if CASE_PRESERVED_NAMES & flags > 0
414
- str << " casesens" if CASE_SENSITIVE_SEARCH & flags > 0
415
- str << " compression" if FILE_COMPRESSION & flags > 0
416
- str << " namedstreams" if NAMED_STREAMS & flags > 0
417
- str << " pacls" if PERSISTENT_ACLS & flags > 0
418
- str << " ro" if READ_ONLY_VOLUME & flags > 0
419
- str << " encryption" if SUPPORTS_ENCRYPTION & flags > 0
420
- str << " objids" if SUPPORTS_OBJECT_IDS & flags > 0
421
- str << " rpoints" if SUPPORTS_REPARSE_POINTS & flags > 0
422
- str << " sparse" if SUPPORTS_SPARSE_FILES & flags > 0
423
- str << " unicode" if UNICODE_ON_DISK & flags > 0
424
- str << " compressed" if VOLUME_IS_COMPRESSED & flags > 0
425
-
426
- str.tr!(' ', ',')
427
- str = str[1..-1] # Ignore the first comma
428
- str
425
+ str = ''
426
+ str << ' casepres' if CASE_PRESERVED_NAMES & flags > 0
427
+ str << ' casesens' if CASE_SENSITIVE_SEARCH & flags > 0
428
+ str << ' compression' if FILE_COMPRESSION & flags > 0
429
+ str << ' namedstreams' if NAMED_STREAMS & flags > 0
430
+ str << ' pacls' if PERSISTENT_ACLS & flags > 0
431
+ str << ' ro' if READ_ONLY_VOLUME & flags > 0
432
+ str << ' encryption' if SUPPORTS_ENCRYPTION & flags > 0
433
+ str << ' objids' if SUPPORTS_OBJECT_IDS & flags > 0
434
+ str << ' rpoints' if SUPPORTS_REPARSE_POINTS & flags > 0
435
+ str << ' sparse' if SUPPORTS_SPARSE_FILES & flags > 0
436
+ str << ' unicode' if UNICODE_ON_DISK & flags > 0
437
+ str << ' compressed' if VOLUME_IS_COMPRESSED & flags > 0
438
+
439
+ str.tr!(' ', ',')
440
+ str[1..-1] # Ignore the first comma
429
441
  end
442
+
443
+ private_class_method :get_options
430
444
  end
431
445
  end