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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGES.md +44 -0
- data/README.md +8 -5
- data/Rakefile +22 -1
- data/lib/sys/filesystem.rb +17 -16
- data/lib/sys/unix/sys/filesystem/constants.rb +4 -0
- data/lib/sys/unix/sys/filesystem/functions.rb +20 -24
- data/lib/sys/unix/sys/filesystem/structs.rb +143 -94
- data/lib/sys/unix/sys/filesystem.rb +66 -54
- data/lib/sys/windows/sys/filesystem/functions.rb +1 -0
- data/lib/sys/windows/sys/filesystem/helper.rb +3 -0
- data/lib/sys/windows/sys/filesystem.rb +25 -23
- data/lib/sys-filesystem.rb +2 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/sys_filesystem_shared.rb +14 -0
- data/spec/sys_filesystem_unix_spec.rb +481 -136
- data/spec/sys_filesystem_windows_spec.rb +264 -152
- data/sys-filesystem.gemspec +17 -8
- data.tar.gz.sig +0 -0
- metadata +37 -8
- metadata.gz.sig +0 -0
|
@@ -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,
|
|
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,
|
|
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
|
|
324
|
+
string += val
|
|
297
325
|
else
|
|
298
|
-
string
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
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,
|
|
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
|
-
#
|
|
430
|
-
#
|
|
439
|
+
# You may also specify bitwise OR'd +flags+ to control the precise behavior.
|
|
440
|
+
# The possible flags on Linux are:
|
|
431
441
|
#
|
|
432
|
-
#
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
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
|
|
@@ -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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
|
429
|
-
str
|
|
430
|
-
str
|
|
431
|
-
str
|
|
432
|
-
str
|
|
433
|
-
str
|
|
434
|
-
str
|
|
435
|
-
str
|
|
436
|
-
str
|
|
437
|
-
str
|
|
438
|
-
str
|
|
439
|
-
str
|
|
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
|
data/lib/sys-filesystem.rb
CHANGED
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
|