sys-filesystem 1.3.3 → 1.4.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/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