sys-filesystem 1.3.4 → 1.4.3
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.rdoc → CHANGES.md} +50 -25
- data/Gemfile +2 -0
- data/{MANIFEST.rdoc → MANIFEST.md} +8 -6
- data/README.md +92 -0
- data/Rakefile +14 -24
- data/examples/example_mount.rb +3 -2
- data/lib/sys/filesystem.rb +1 -1
- data/lib/sys/unix/sys/filesystem/constants.rb +2 -4
- data/lib/sys/unix/sys/filesystem/functions.rb +27 -10
- data/lib/sys/unix/sys/filesystem/structs.rb +58 -14
- data/lib/sys/unix/sys/filesystem.rb +54 -32
- data/lib/sys/windows/sys/filesystem/functions.rb +10 -10
- data/lib/sys/windows/sys/filesystem/helper.rb +1 -1
- data/lib/sys/windows/sys/filesystem.rb +45 -29
- data/spec/spec_helper.rb +6 -0
- data/spec/sys_filesystem_unix_spec.rb +396 -0
- data/spec/sys_filesystem_windows_spec.rb +348 -0
- data/sys-filesystem.gemspec +6 -8
- data.tar.gz.sig +0 -0
- metadata +41 -55
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -77
- data/test/test_sys_filesystem.rb +0 -7
- data/test/test_sys_filesystem_unix.rb +0 -329
- data/test/test_sys_filesystem_windows.rb +0 -303
@@ -11,44 +11,46 @@ module Sys
|
|
11
11
|
include Sys::Filesystem::Structs
|
12
12
|
extend Sys::Filesystem::Functions
|
13
13
|
|
14
|
-
|
14
|
+
private_class_method :new
|
15
15
|
|
16
16
|
# Readable versions of constant names
|
17
17
|
OPT_NAMES = {
|
18
|
-
MNT_RDONLY
|
19
|
-
MNT_SYNCHRONOUS
|
20
|
-
MNT_NOEXEC
|
21
|
-
MNT_NOSUID
|
22
|
-
MNT_NODEV
|
23
|
-
MNT_UNION
|
24
|
-
MNT_ASYNC
|
25
|
-
MNT_CPROTECT
|
26
|
-
MNT_EXPORTED
|
27
|
-
MNT_QUARANTINE
|
28
|
-
MNT_LOCAL
|
29
|
-
MNT_QUOTA
|
30
|
-
MNT_ROOTFS
|
31
|
-
MNT_DONTBROWSE
|
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',
|
32
32
|
MNT_IGNORE_OWNERSHIP => 'noowners',
|
33
|
-
MNT_AUTOMOUNTED
|
34
|
-
MNT_JOURNALED
|
35
|
-
MNT_NOUSERXATTR
|
36
|
-
MNT_DEFWRITE
|
37
|
-
MNT_NOATIME
|
33
|
+
MNT_AUTOMOUNTED => 'automounted',
|
34
|
+
MNT_JOURNALED => 'journaled',
|
35
|
+
MNT_NOUSERXATTR => 'nouserxattr',
|
36
|
+
MNT_DEFWRITE => 'defwrite',
|
37
|
+
MNT_NOATIME => 'noatime'
|
38
38
|
}.freeze
|
39
39
|
|
40
|
+
private_constant :OPT_NAMES
|
41
|
+
|
40
42
|
# File used to read mount informtion from.
|
41
43
|
if File.exist?('/etc/mtab')
|
42
|
-
MOUNT_FILE = '/etc/mtab'
|
44
|
+
MOUNT_FILE = '/etc/mtab'.freeze
|
43
45
|
elsif File.exist?('/etc/mnttab')
|
44
|
-
MOUNT_FILE = '/etc/mnttab'
|
46
|
+
MOUNT_FILE = '/etc/mnttab'.freeze
|
45
47
|
elsif File.exist?('/proc/mounts')
|
46
|
-
MOUNT_FILE = '/proc/mounts'
|
48
|
+
MOUNT_FILE = '/proc/mounts'.freeze
|
47
49
|
else
|
48
|
-
MOUNT_FILE = 'getmntinfo'
|
50
|
+
MOUNT_FILE = 'getmntinfo'.freeze
|
49
51
|
end
|
50
52
|
|
51
|
-
|
53
|
+
private_constant :MOUNT_FILE
|
52
54
|
|
53
55
|
# The error raised if any of the Filesystem methods fail.
|
54
56
|
class Error < StandardError; end
|
@@ -198,7 +200,27 @@ module Sys
|
|
198
200
|
# Returns a Sys::Filesystem::Stat object containing information about the
|
199
201
|
# +path+ on the filesystem.
|
200
202
|
#
|
203
|
+
# Examples:
|
204
|
+
#
|
205
|
+
# # path
|
206
|
+
# Sys::Filesystem.stat("path")
|
207
|
+
#
|
208
|
+
# # Pathname
|
209
|
+
# pathname = Pathname.new("path")
|
210
|
+
# Sys::Filesystem.stat(pathname)
|
211
|
+
#
|
212
|
+
# # File
|
213
|
+
# file = File.open("file", "r")
|
214
|
+
# Sys::Filesystem.stat(file)
|
215
|
+
#
|
216
|
+
# # Dir
|
217
|
+
# dir = Dir.open("/")
|
218
|
+
# Sys::Filesystem.stat(dir)
|
219
|
+
#
|
201
220
|
def self.stat(path)
|
221
|
+
path = path.path if path.respond_to?(:path) # File, Dir
|
222
|
+
path = path.to_s if path.respond_to?(:to_s) # Pathname
|
223
|
+
|
202
224
|
fs = Statvfs.new
|
203
225
|
|
204
226
|
if statvfs(path, fs) < 0
|
@@ -258,17 +280,17 @@ module Sys
|
|
258
280
|
|
259
281
|
ptr = buf.get_pointer(0)
|
260
282
|
|
261
|
-
num.times
|
283
|
+
num.times do
|
262
284
|
mnt = Statfs.new(ptr)
|
263
285
|
obj = Sys::Filesystem::Mount.new
|
264
286
|
obj.name = mnt[:f_mntfromname].to_s
|
265
287
|
obj.mount_point = mnt[:f_mntonname].to_s
|
266
288
|
obj.mount_type = mnt[:f_fstypename].to_s
|
267
289
|
|
268
|
-
string =
|
290
|
+
string = ''
|
269
291
|
flags = mnt[:f_flags] & MNT_VISFLAGMASK
|
270
292
|
|
271
|
-
OPT_NAMES.each
|
293
|
+
OPT_NAMES.each do |key, val|
|
272
294
|
if flags & key > 0
|
273
295
|
if string.empty?
|
274
296
|
string << val
|
@@ -277,7 +299,7 @@ module Sys
|
|
277
299
|
end
|
278
300
|
end
|
279
301
|
flags &= ~key
|
280
|
-
|
302
|
+
end
|
281
303
|
|
282
304
|
obj.options = string
|
283
305
|
|
@@ -288,7 +310,7 @@ module Sys
|
|
288
310
|
end
|
289
311
|
|
290
312
|
ptr += Statfs.size
|
291
|
-
|
313
|
+
end
|
292
314
|
else
|
293
315
|
begin
|
294
316
|
if respond_to?(:setmntent, true)
|
@@ -365,7 +387,7 @@ module Sys
|
|
365
387
|
dev = File.stat(file).dev
|
366
388
|
val = file
|
367
389
|
|
368
|
-
|
390
|
+
mounts.each do |mnt|
|
369
391
|
mp = mnt.mount_point
|
370
392
|
begin
|
371
393
|
if File.stat(mp).dev == dev
|
@@ -375,7 +397,7 @@ module Sys
|
|
375
397
|
rescue Errno::EACCES
|
376
398
|
next
|
377
399
|
end
|
378
|
-
|
400
|
+
end
|
379
401
|
|
380
402
|
val
|
381
403
|
end
|
@@ -15,21 +15,21 @@ module Sys
|
|
15
15
|
end
|
16
16
|
|
17
17
|
attach_pfunc :DeleteVolumeMountPointA, [:string], :bool
|
18
|
-
attach_pfunc :GetDiskFreeSpaceW, [
|
19
|
-
attach_pfunc :GetDiskFreeSpaceExW, [
|
20
|
-
attach_pfunc :GetLogicalDriveStringsA, [
|
18
|
+
attach_pfunc :GetDiskFreeSpaceW, %i[buffer_in pointer pointer pointer pointer], :bool
|
19
|
+
attach_pfunc :GetDiskFreeSpaceExW, %i[buffer_in pointer pointer pointer], :bool
|
20
|
+
attach_pfunc :GetLogicalDriveStringsA, %i[ulong pointer], :ulong
|
21
21
|
|
22
22
|
attach_pfunc :GetVolumeInformationA,
|
23
|
-
|
24
|
-
|
23
|
+
%i[buffer_in pointer ulong pointer pointer pointer pointer ulong],
|
24
|
+
:bool
|
25
25
|
|
26
26
|
attach_pfunc :GetVolumeInformationW,
|
27
|
-
|
28
|
-
|
27
|
+
%i[buffer_in pointer ulong pointer pointer pointer pointer ulong],
|
28
|
+
:bool
|
29
29
|
|
30
|
-
attach_pfunc :GetVolumeNameForVolumeMountPointW, [
|
31
|
-
attach_pfunc :QueryDosDeviceA, [
|
32
|
-
attach_pfunc :SetVolumeMountPointW, [
|
30
|
+
attach_pfunc :GetVolumeNameForVolumeMountPointW, %i[buffer_in buffer_in ulong], :bool
|
31
|
+
attach_pfunc :QueryDosDeviceA, %i[buffer_in buffer_out ulong], :ulong
|
32
|
+
attach_pfunc :SetVolumeMountPointW, %i[buffer_in buffer_in], :bool
|
33
33
|
|
34
34
|
ffi_lib :shlwapi
|
35
35
|
|
@@ -2,6 +2,6 @@ class String
|
|
2
2
|
# Convenience method for converting strings to UTF-16LE for wide character
|
3
3
|
# functions that require it.
|
4
4
|
def wincode
|
5
|
-
(
|
5
|
+
(tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
|
6
6
|
end
|
7
7
|
end
|
@@ -18,6 +18,8 @@ module Sys
|
|
18
18
|
# Error typically raised if any of the Sys::Filesystem methods fail.
|
19
19
|
class Error < StandardError; end
|
20
20
|
|
21
|
+
private_class_method :new
|
22
|
+
|
21
23
|
class Mount
|
22
24
|
# The name of the volume. This is the device mapping.
|
23
25
|
attr_reader :name
|
@@ -181,7 +183,7 @@ module Sys
|
|
181
183
|
|
182
184
|
boot_time = get_boot_time
|
183
185
|
|
184
|
-
drives.each
|
186
|
+
drives.each do |drive|
|
185
187
|
mount = Mount.new
|
186
188
|
volume = FFI::MemoryPointer.new(:char, MAXPATH)
|
187
189
|
fsname = FFI::MemoryPointer.new(:char, MAXPATH)
|
@@ -206,7 +208,7 @@ module Sys
|
|
206
208
|
|
207
209
|
# Skip unmounted floppies or cd-roms, or inaccessible drives
|
208
210
|
unless bool
|
209
|
-
if [5,21].include?(FFI.errno) # ERROR_NOT_READY or ERROR_ACCESS_DENIED
|
211
|
+
if [5, 21].include?(FFI.errno) # ERROR_NOT_READY or ERROR_ACCESS_DENIED
|
210
212
|
next
|
211
213
|
else
|
212
214
|
raise SystemCallError.new('GetVolumeInformation', FFI.errno)
|
@@ -218,7 +220,7 @@ module Sys
|
|
218
220
|
|
219
221
|
name = 0.chr * MAXPATH
|
220
222
|
|
221
|
-
if QueryDosDeviceA(drive[0,2], name, name.size) == 0
|
223
|
+
if QueryDosDeviceA(drive[0, 2], name, name.size) == 0
|
222
224
|
raise SystemCallError.new('QueryDosDevice', FFI.errno)
|
223
225
|
end
|
224
226
|
|
@@ -231,7 +233,7 @@ module Sys
|
|
231
233
|
else
|
232
234
|
mounts << mount
|
233
235
|
end
|
234
|
-
|
236
|
+
end
|
235
237
|
|
236
238
|
mounts # Nil if the block form was used.
|
237
239
|
end
|
@@ -259,10 +261,25 @@ module Sys
|
|
259
261
|
#
|
260
262
|
# Examples:
|
261
263
|
#
|
264
|
+
# # Regular directory
|
262
265
|
# Sys::Filesystem.stat("C:\\")
|
263
266
|
# Sys::Filesystem.stat("C:\\Documents and Settings\\some_user")
|
264
267
|
#
|
268
|
+
# # Pathname
|
269
|
+
# pathname = Pathname.new("C:\\")
|
270
|
+
# Sys::Filesystem.stat(pathname)
|
271
|
+
#
|
272
|
+
# # Dir
|
273
|
+
# dir = Dir.open("C:\\")
|
274
|
+
# Sys::Filesystem.stat(dir)
|
275
|
+
#
|
276
|
+
# Note that on Windows you cannot stat a regular file because
|
277
|
+
# Windows won't like it. It must be a directory in some form.
|
278
|
+
#
|
265
279
|
def self.stat(path)
|
280
|
+
path = path.path if path.respond_to?(:path) # Dir
|
281
|
+
path = path.to_s if path.respond_to?(:to_s) # Pathname
|
282
|
+
|
266
283
|
bytes_avail = FFI::MemoryPointer.new(:ulong_long)
|
267
284
|
bytes_free = FFI::MemoryPointer.new(:ulong_long)
|
268
285
|
total_bytes = FFI::MemoryPointer.new(:ulong_long)
|
@@ -270,7 +287,7 @@ module Sys
|
|
270
287
|
mpoint = mount_point(path).to_s
|
271
288
|
mpoint << '/' unless mpoint.end_with?('/')
|
272
289
|
|
273
|
-
wpath
|
290
|
+
wpath = path.to_s.wincode
|
274
291
|
|
275
292
|
# We need this call for the 64 bit support
|
276
293
|
unless GetDiskFreeSpaceExW(wpath, bytes_avail, total_bytes, bytes_free)
|
@@ -382,8 +399,6 @@ module Sys
|
|
382
399
|
self
|
383
400
|
end
|
384
401
|
|
385
|
-
private
|
386
|
-
|
387
402
|
# This method is used to get the boot time of the system, which is used
|
388
403
|
# for the mount_time attribute within the File.mounts method.
|
389
404
|
#
|
@@ -396,36 +411,37 @@ module Sys
|
|
396
411
|
raise Error, e
|
397
412
|
else
|
398
413
|
query = 'select LastBootupTime from Win32_OperatingSystem'
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
return Time.mktime(*time_array)
|
403
|
-
}
|
414
|
+
ole = wmi.ExecQuery(query).ItemIndex(0)
|
415
|
+
time_array = Time.parse(ole.LastBootupTime.split('.').first)
|
416
|
+
Time.mktime(*time_array)
|
404
417
|
end
|
405
418
|
end
|
406
419
|
|
420
|
+
private_class_method :get_boot_time
|
421
|
+
|
407
422
|
# Private method that converts filesystem flags into a comma separated
|
408
423
|
# list of strings. The presentation is meant as a rough analogue to the
|
409
424
|
# way options are presented for Unix filesystems.
|
410
425
|
#
|
411
426
|
def self.get_options(flags)
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
str
|
427
|
+
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
|
440
|
+
|
441
|
+
str.tr!(' ', ',')
|
442
|
+
str[1..-1] # Ignore the first comma
|
429
443
|
end
|
444
|
+
|
445
|
+
private_class_method :get_options
|
430
446
|
end
|
431
447
|
end
|