sys-filesystem 1.4.3 → 1.5.5

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.
@@ -105,6 +105,24 @@ module Sys
105
105
  # The filesystem type, e.g. UFS.
106
106
  attr_accessor :base_type
107
107
 
108
+ # The filesystem type
109
+ attr_accessor :filesystem_type
110
+
111
+ # The user that mounted the filesystem
112
+ attr_accessor :owner
113
+
114
+ # Count of sync reads since mount
115
+ attr_accessor :sync_reads
116
+
117
+ # Count of sync writes since mount
118
+ attr_accessor :sync_writes
119
+
120
+ # Count of async reads since mount
121
+ attr_accessor :async_reads
122
+
123
+ # Count of async writes since mount
124
+ attr_accessor :async_writes
125
+
108
126
  alias inodes files
109
127
  alias inodes_free files_free
110
128
  alias inodes_available files_available
@@ -224,7 +242,7 @@ module Sys
224
242
  fs = Statvfs.new
225
243
 
226
244
  if statvfs(path, fs) < 0
227
- raise Error, 'statvfs() function failed: ' + strerror(FFI.errno)
245
+ raise Error, "statvfs() function failed: #{strerror(FFI.errno)}"
228
246
  end
229
247
 
230
248
  obj = Sys::Filesystem::Stat.new
@@ -250,6 +268,16 @@ module Sys
250
268
  obj.base_type = fs[:f_basetype].to_s
251
269
  end
252
270
 
271
+ # DragonFlyBSD has additional struct members
272
+ if RbConfig::CONFIG['host_os'] =~ /dragonfly/i
273
+ obj.owner = fs[:f_owner]
274
+ obj.filesystem_type = fs[:f_type]
275
+ obj.sync_reads = fs[:f_syncreads]
276
+ obj.async_reads = fs[:f_asyncreads]
277
+ obj.sync_writes = fs[:f_syncwrites]
278
+ obj.async_writes = fs[:f_asyncwrites]
279
+ end
280
+
253
281
  obj.freeze
254
282
  end
255
283
 
@@ -275,7 +303,7 @@ module Sys
275
303
  num = getmntinfo(buf, 2)
276
304
 
277
305
  if num == 0
278
- raise Error, 'getmntinfo() function failed: ' + strerror(FFI.errno)
306
+ raise Error, "getmntinfo() function failed: #{strerror(FFI.errno)}"
279
307
  end
280
308
 
281
309
  ptr = buf.get_pointer(0)
@@ -293,9 +321,9 @@ module Sys
293
321
  OPT_NAMES.each do |key, val|
294
322
  if flags & key > 0
295
323
  if string.empty?
296
- string << val
324
+ string += val
297
325
  else
298
- string << ", #{val}"
326
+ string += ", #{val}"
299
327
  end
300
328
  end
301
329
  flags &= ~key
@@ -325,41 +353,23 @@ module Sys
325
353
  raise SystemCallError.new(method_name, FFI.errno)
326
354
  end
327
355
 
328
- if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
329
- mt = Mnttab.new
330
- while getmntent(fp, mt) == 0
331
- obj = Sys::Filesystem::Mount.new
332
- obj.name = mt[:mnt_special].to_s
333
- obj.mount_point = mt[:mnt_mountp].to_s
334
- obj.mount_type = mt[:mnt_fstype].to_s
335
- obj.options = mt[:mnt_mntopts].to_s
336
- obj.mount_time = Time.at(Integer(mt[:mnt_time]))
337
-
338
- if block_given?
339
- yield obj.freeze
340
- else
341
- array << obj.freeze
342
- end
343
- end
344
- else
345
- while ptr = getmntent(fp)
346
- break if ptr.null?
347
- mt = Mntent.new(ptr)
348
-
349
- obj = Sys::Filesystem::Mount.new
350
- obj.name = mt[:mnt_fsname]
351
- obj.mount_point = mt[:mnt_dir]
352
- obj.mount_type = mt[:mnt_type]
353
- obj.options = mt[:mnt_opts]
354
- obj.mount_time = nil
355
- obj.dump_frequency = mt[:mnt_freq]
356
- obj.pass_number = mt[:mnt_passno]
357
-
358
- if block_given?
359
- yield obj.freeze
360
- else
361
- array << obj.freeze
362
- end
356
+ while ptr = getmntent(fp)
357
+ break if ptr.null?
358
+ mt = Mntent.new(ptr)
359
+
360
+ obj = Sys::Filesystem::Mount.new
361
+ obj.name = mt[:mnt_fsname]
362
+ obj.mount_point = mt[:mnt_dir]
363
+ obj.mount_type = mt[:mnt_type]
364
+ obj.options = mt[:mnt_opts]
365
+ obj.mount_time = nil
366
+ obj.dump_frequency = mt[:mnt_freq]
367
+ obj.pass_number = mt[:mnt_passno]
368
+
369
+ if block_given?
370
+ yield obj.freeze
371
+ else
372
+ array << obj.freeze
363
373
  end
364
374
  end
365
375
  ensure
@@ -419,29 +429,31 @@ module Sys
419
429
  #
420
430
  def self.mount(source, target, fstype = 'ext2', flags = 0, data = nil)
421
431
  if mount_c(source, target, fstype, flags, data) != 0
422
- raise Error, 'mount() function failed: ' + strerror(FFI.errno)
432
+ raise Error, "mount() function failed: #{strerror(FFI.errno)}"
423
433
  end
424
434
 
425
435
  self
426
436
  end
427
437
 
428
438
  # Removes the attachment of the (topmost) filesystem mounted on target.
429
- # Additional flags may be provided for operating systems that support
430
- # the umount2 function. Otherwise this argument is ignored.
439
+ # You may also specify bitwise OR'd +flags+ to control the precise behavior.
440
+ # The possible flags on Linux are:
431
441
  #
432
- # Typically requires admin privileges.
442
+ # * MNT_FORCE - Abort pending requests, may cause data loss.
443
+ # * MNT_DETACH - Lazy umount, waits until the mount point is no longer busy.
444
+ # * MNT_EXPIRE - Mark mount point as expired, but don't actually remove it until
445
+ # a second call MNT_EXPIRE call is made.
433
446
  #
434
- def self.umount(target, flags = nil)
435
- if flags && respond_to?(:umount2)
436
- function = 'umount2'
437
- rv = umount2_c(target, flags)
438
- else
439
- function = 'umount'
440
- rv = umount_c(target)
441
- end
442
-
443
- if rv != 0
444
- raise Error, "#{function} function failed: " + strerror(FFI.errno)
447
+ # * UMOUNT_NOFOLLOW - Don't dereference the target if it's a symbolic link.
448
+ #
449
+ # Note that BSD platforms may support different flags. Please see the man
450
+ # pages for details.
451
+ #
452
+ # Typically this method requires admin privileges.
453
+ #
454
+ def self.umount(target, flags = 0)
455
+ if umount_c(target, flags) != 0
456
+ raise Error, "umount function failed: #{strerror(FFI.errno)}"
445
457
  end
446
458
 
447
459
  self
@@ -2,6 +2,7 @@ require 'ffi'
2
2
 
3
3
  module Sys
4
4
  class Filesystem
5
+ # Wrapper module for Windows related FFI functions.
5
6
  module Functions
6
7
  extend FFI::Library
7
8
  ffi_lib :kernel32
@@ -1,6 +1,9 @@
1
+ # Reopen core Ruby classes here and add some custom methods.
1
2
  class String
2
3
  # Convenience method for converting strings to UTF-16LE for wide character
3
4
  # functions that require it.
5
+ #--
6
+ # TODO: Use a refinement.
4
7
  def wincode
5
8
  (tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
6
9
  end
@@ -9,7 +9,6 @@ require 'time'
9
9
 
10
10
  # The Sys module serves as a namespace only.
11
11
  module Sys
12
-
13
12
  # The Filesystem class encapsulates information about your filesystem.
14
13
  class Filesystem
15
14
  include Sys::Filesystem::Constants
@@ -20,6 +19,7 @@ module Sys
20
19
 
21
20
  private_class_method :new
22
21
 
22
+ # Mount objects are returned by the Sys::Filesystem.mounts method.
23
23
  class Mount
24
24
  # The name of the volume. This is the device mapping.
25
25
  attr_reader :name
@@ -50,6 +50,7 @@ module Sys
50
50
  alias freq frequency
51
51
  end
52
52
 
53
+ # Stat objects are returned by the Sys::Filesystem.stat method.
53
54
  class Stat
54
55
  # The path of the file system.
55
56
  attr_reader :path
@@ -160,6 +161,8 @@ module Sys
160
161
  #--
161
162
  # I couldn't really find a good reason to use the wide functions for this
162
163
  # method. If you have one, patches welcome.
164
+ #--
165
+ # rubocop:disable Metrics/BlockLength
163
166
  #
164
167
  def self.mounts
165
168
  # First call, get needed buffer size
@@ -196,14 +199,14 @@ module Sys
196
199
  filesystem_flags = FFI::MemoryPointer.new(:ulong)
197
200
 
198
201
  bool = GetVolumeInformationA(
199
- drive,
200
- volume,
201
- volume.size,
202
- volume_serial_number,
203
- max_component_length,
204
- filesystem_flags,
205
- fsname,
206
- fsname.size
202
+ drive,
203
+ volume,
204
+ volume.size,
205
+ volume_serial_number,
206
+ max_component_length,
207
+ filesystem_flags,
208
+ fsname,
209
+ fsname.size
207
210
  )
208
211
 
209
212
  # Skip unmounted floppies or cd-roms, or inaccessible drives
@@ -237,6 +240,7 @@ module Sys
237
240
 
238
241
  mounts # Nil if the block form was used.
239
242
  end
243
+ # rubocop:enable Metrics/BlockLength
240
244
 
241
245
  # Returns the mount point for the given +file+. For MS Windows this
242
246
  # means the root of the path.
@@ -250,8 +254,6 @@ module Sys
250
254
 
251
255
  if PathStripToRootW(wfile)
252
256
  wfile.read_string(wfile.size).split("\000\000").first.tr(0.chr, '')
253
- else
254
- nil
255
257
  end
256
258
  end
257
259
 
@@ -425,18 +427,18 @@ module Sys
425
427
  #
426
428
  def self.get_options(flags)
427
429
  str = ''
428
- str << ' casepres' if CASE_PRESERVED_NAMES & flags > 0
429
- str << ' casesens' if CASE_SENSITIVE_SEARCH & flags > 0
430
- str << ' compression' if FILE_COMPRESSION & flags > 0
431
- str << ' namedstreams' if NAMED_STREAMS & flags > 0
432
- str << ' pacls' if PERSISTENT_ACLS & flags > 0
433
- str << ' ro' if READ_ONLY_VOLUME & flags > 0
434
- str << ' encryption' if SUPPORTS_ENCRYPTION & flags > 0
435
- str << ' objids' if SUPPORTS_OBJECT_IDS & flags > 0
436
- str << ' rpoints' if SUPPORTS_REPARSE_POINTS & flags > 0
437
- str << ' sparse' if SUPPORTS_SPARSE_FILES & flags > 0
438
- str << ' unicode' if UNICODE_ON_DISK & flags > 0
439
- str << ' compressed' if VOLUME_IS_COMPRESSED & flags > 0
430
+ str += ' casepres' if CASE_PRESERVED_NAMES & flags > 0
431
+ str += ' casesens' if CASE_SENSITIVE_SEARCH & flags > 0
432
+ str += ' compression' if FILE_COMPRESSION & flags > 0
433
+ str += ' namedstreams' if NAMED_STREAMS & flags > 0
434
+ str += ' pacls' if PERSISTENT_ACLS & flags > 0
435
+ str += ' ro' if READ_ONLY_VOLUME & flags > 0
436
+ str += ' encryption' if SUPPORTS_ENCRYPTION & flags > 0
437
+ str += ' objids' if SUPPORTS_OBJECT_IDS & flags > 0
438
+ str += ' rpoints' if SUPPORTS_REPARSE_POINTS & flags > 0
439
+ str += ' sparse' if SUPPORTS_SPARSE_FILES & flags > 0
440
+ str += ' unicode' if UNICODE_ON_DISK & flags > 0
441
+ str += ' compressed' if VOLUME_IS_COMPRESSED & flags > 0
440
442
 
441
443
  str.tr!(' ', ',')
442
444
  str[1..-1] # Ignore the first comma
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'sys/filesystem'
data/spec/spec_helper.rb CHANGED
@@ -1,6 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rspec'
4
+ require 'sys_filesystem_shared'
2
5
 
3
6
  RSpec.configure do |config|
7
+ config.include_context(Sys::Filesystem)
4
8
  config.filter_run_excluding(:windows) unless Gem.win_platform?
5
9
  config.filter_run_excluding(:unix) if Gem.win_platform?
10
+ config.filter_run_excluding(:dragonfly) unless RbConfig::CONFIG['host_os'] =~ /dragonfly/i
6
11
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sys-filesystem'
4
+
5
+ RSpec.shared_examples Sys::Filesystem do
6
+ example 'version number is set to the expected value' do
7
+ expect(Sys::Filesystem::VERSION).to eq('1.5.5')
8
+ expect(Sys::Filesystem::VERSION).to be_frozen
9
+ end
10
+
11
+ example 'you cannot instantiate an instance' do
12
+ expect{ described_class.new }.to raise_error(NoMethodError)
13
+ end
14
+ end