sys-filesystem 1.1.6 → 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.
@@ -1,12 +1,83 @@
1
1
  module Sys
2
2
  class Filesystem
3
3
  # The version of the sys-filesystem library
4
- VERSION = '1.1.6'.freeze
4
+ VERSION = '1.4.3'.freeze
5
5
  end
6
6
  end
7
7
 
8
+ require 'rbconfig'
9
+
8
10
  if File::ALT_SEPARATOR
9
11
  require_relative 'windows/sys/filesystem'
10
12
  else
11
13
  require_relative 'unix/sys/filesystem'
12
14
  end
15
+
16
+ # Methods universal to all platforms
17
+
18
+ module Sys
19
+ class Filesystem
20
+ class Stat
21
+ # Returns true if the filesystem is case sensitive for the current path.
22
+ # Typically this will be any path on MS Windows or Macs using HFS.
23
+ #
24
+ # For a root path (really any path without actual a-z characters) we
25
+ # take a best guess based on the host operating system. However, as a
26
+ # general rule, I do not recommend using this method for a root path.
27
+ #
28
+ def case_insensitive?
29
+ if path !~ /\w+/
30
+ if RbConfig::CONFIG['host_os'] =~ /darwin|mac|windows|mswin|mingw/i
31
+ true # Assumes HFS
32
+ else
33
+ false
34
+ end
35
+ else
36
+ File.identical?(path, path.swapcase)
37
+ end
38
+ end
39
+
40
+ # Opposite of case_insensitive?
41
+ #
42
+ def case_sensitive?
43
+ !case_insensitive?
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ # Some convenient methods for converting bytes to kb, mb, and gb.
50
+ #
51
+ class Numeric
52
+ # call-seq:
53
+ # <tt>num</tt>.to_kb
54
+ #
55
+ # Returns +num+ in terms of kilobytes.
56
+ def to_kb
57
+ self / 1024
58
+ end
59
+
60
+ # call-seq:
61
+ # <tt>num</tt>.to_mb
62
+ #
63
+ # Returns +num+ in terms of megabytes.
64
+ def to_mb
65
+ self / 1048576
66
+ end
67
+
68
+ # call-seq:
69
+ # <tt>num</tt>.to_gb
70
+ #
71
+ # Returns +num+ in terms of gigabytes.
72
+ def to_gb
73
+ self / 1073741824
74
+ end
75
+
76
+ # call-seq:
77
+ # <tt>num</tt>.to_gb
78
+ #
79
+ # Returns +num+ in terms of terabytes.
80
+ def to_tb
81
+ self / 1099511627776
82
+ end
83
+ 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,9 +31,40 @@ 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
  )
37
+
38
+ MS_RDONLY = 1
39
+ MS_NOSUID = 2
40
+ MS_NODEV = 4
41
+ MS_NOEXEC = 8
42
+ MS_SYNCHRONOUS = 16
43
+ MS_REMOUNT = 32
44
+ MS_MANDLOCK = 64
45
+ MS_DIRSYNC = 128
46
+ MS_NOATIME = 1024
47
+ MS_NODIRATIME = 2048
48
+ MS_BIND = 4096
49
+ MS_MOVE = 8192
50
+ MS_REC = 16384
51
+ MS_SILENT = 32768
52
+ MS_POSIXACL = 1 << 16
53
+ MS_UNBINDABLE = 1 << 17
54
+ MS_PRIVATE = 1 << 18
55
+ MS_SLAVE = 1 << 19
56
+ MS_SHARED = 1 << 20
57
+ MS_RELATIME = 1 << 21
58
+ MS_KERNMOUNT = 1 << 22
59
+ MS_I_VERSION = 1 << 23
60
+ MS_STRICTATIME = 1 << 24
61
+ MS_ACTIVE = 1 << 30
62
+ MS_NOUSER = 1 << 31
63
+
64
+ MNT_FORCE = 1
65
+ MNT_DETACH = 2
66
+ MNT_EXPIRE = 4
67
+ UMOUNT_NOFOLLOW = 8
39
68
  end
40
69
  end
41
70
  end
@@ -7,33 +7,60 @@ module Sys
7
7
 
8
8
  ffi_lib FFI::Library::LIBC
9
9
 
10
+ def self.linux64?
11
+ if RUBY_PLATFORM == 'java'
12
+ ENV_JAVA['sun.arch.data.model'].to_i == 64
13
+ else
14
+ RbConfig::CONFIG['host_os'] =~ /linux/i &&
15
+ (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
16
+ end
17
+ end
18
+
19
+ private_class_method :linux64?
20
+
10
21
  if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
11
- attach_function(:statvfs, :statvfs64, [:string, :pointer], :int)
22
+ attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
23
+ elsif linux64?
24
+ attach_function(:statvfs, :statvfs64, %i[string pointer], :int)
12
25
  else
13
- attach_function(:statvfs, [:string, :pointer], :int)
26
+ attach_function(:statvfs, %i[string pointer], :int)
14
27
  end
15
28
 
16
29
  attach_function(:strerror, [:int], :string)
30
+ attach_function(:mount_c, :mount, %i[string string string ulong string], :int)
31
+
32
+ begin
33
+ attach_function(:umount_c, :umount, [:string], :int)
34
+ rescue FFI::NotFoundError
35
+ if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach|bsd/i
36
+ attach_function(:umount_c, :unmount, [:string], :int)
37
+ end
38
+ end
17
39
 
18
- private_class_method :statvfs, :strerror
40
+ private_class_method :statvfs, :strerror, :mount_c, :umount_c
19
41
 
20
42
  begin
21
43
  if RbConfig::CONFIG['host_os'] =~ /sunos|solaris/i
22
- attach_function(:fopen, [:string, :string], :pointer)
44
+ attach_function(:fopen, %i[string string], :pointer)
23
45
  attach_function(:fclose, [:pointer], :int)
24
- attach_function(:getmntent, [:pointer, :pointer], :int)
46
+ attach_function(:getmntent, %i[pointer pointer], :int)
25
47
  private_class_method :fopen, :fclose, :getmntent
26
48
  else
27
49
  attach_function(:getmntent, [:pointer], :pointer)
28
- attach_function(:setmntent, [:string, :string], :pointer)
50
+ attach_function(:setmntent, %i[string string], :pointer)
29
51
  attach_function(:endmntent, [:pointer], :int)
30
- private_class_method :getmntent, :setmntent, :endmntent
52
+ attach_function(:umount2, %i[string int], :int)
53
+ private_class_method :getmntent, :setmntent, :endmntent, :umount2
31
54
  end
32
55
  rescue FFI::NotFoundError
33
56
  if RbConfig::CONFIG['host_os'] =~ /darwin|osx|mach/i
34
- attach_function(:getmntinfo, :getmntinfo64, [:pointer, :int], :int)
57
+ begin
58
+ attach_function(:getmntinfo, :getmntinfo64, %i[pointer int], :int)
59
+ rescue FFI::NotFoundError
60
+ attach_function(:getmntinfo, %i[pointer int], :int) # Big Sur and later
61
+ end
35
62
  else
36
- attach_function(:getmntinfo, [:pointer, :int], :int)
63
+ attach_function(:getmntinfo, %i[pointer int], :int)
37
64
  end
38
65
  private_class_method :getmntinfo
39
66
  end
@@ -5,6 +5,26 @@ module Sys
5
5
  class Filesystem
6
6
  module Structs
7
7
  class Statfs < FFI::Struct
8
+
9
+ def self.linux64?
10
+ if RUBY_PLATFORM == 'java'
11
+ ENV_JAVA['sun.arch.data.model'].to_i == 64
12
+ else
13
+ RbConfig::CONFIG['host_os'] =~ /linux/i &&
14
+ (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
15
+ end
16
+ end
17
+
18
+ private_class_method :linux64?
19
+
20
+ # FreeBSD 12.0 MNAMELEN from 88 => 1024.
21
+ MNAMELEN =
22
+ if RbConfig::CONFIG['host_os'] =~ /freebsd(.*)/i
23
+ $1.to_f < 12.0 ? 88 : 1024
24
+ else
25
+ 88
26
+ end
27
+
8
28
  if RbConfig::CONFIG['host_os'] =~ /bsd/i
9
29
  layout(
10
30
  :f_version, :uint32,
@@ -27,9 +47,41 @@ module Sys
27
47
  :f_fsid, [:int32, 2],
28
48
  :f_charspare, [:char, 80],
29
49
  :f_fstypename, [:char, 16],
30
- :f_mntfromname, [:char, 88],
31
- :f_mntonname, [:char, 88]
50
+ :f_mntfromname, [:char, MNAMELEN],
51
+ :f_mntonname, [:char, MNAMELEN]
32
52
  )
53
+ elsif RbConfig::CONFIG['host_os'] =~ /linux/i
54
+ if linux64?
55
+ layout(
56
+ :f_type, :ulong,
57
+ :f_bsize, :ulong,
58
+ :f_blocks, :uint64,
59
+ :f_bfree, :uint64,
60
+ :f_bavail, :uint64,
61
+ :f_files, :uint64,
62
+ :f_ffree, :uint64,
63
+ :f_fsid, [:int, 2],
64
+ :f_namelen, :ulong,
65
+ :f_frsize, :ulong,
66
+ :f_flags, :ulong,
67
+ :f_spare, [:ulong, 4]
68
+ )
69
+ else
70
+ layout(
71
+ :f_type, :ulong,
72
+ :f_bsize, :ulong,
73
+ :f_blocks, :uint32,
74
+ :f_bfree, :uint32,
75
+ :f_bavail, :uint32,
76
+ :f_files, :uint32,
77
+ :f_ffree, :uint32,
78
+ :f_fsid, [:int, 2],
79
+ :f_namelen, :ulong,
80
+ :f_frsize, :ulong,
81
+ :f_flags, :ulong,
82
+ :f_spare, [:ulong, 4]
83
+ )
84
+ end
33
85
  else
34
86
  layout(
35
87
  :f_bsize, :uint32,
@@ -99,22 +151,36 @@ module Sys
99
151
  :f_fstr, [:char, 32],
100
152
  :f_filler, [:ulong, 16]
101
153
  )
154
+ elsif RbConfig::CONFIG['host'] =~ /i686/i
155
+ layout(
156
+ :f_bsize, :ulong,
157
+ :f_frsize, :ulong,
158
+ :f_blocks, :uint,
159
+ :f_bfree, :uint,
160
+ :f_bavail, :uint,
161
+ :f_files, :uint,
162
+ :f_ffree, :uint,
163
+ :f_favail, :uint,
164
+ :f_fsid, :ulong,
165
+ :f_unused, :int,
166
+ :f_flag, :ulong,
167
+ :f_namemax, :ulong,
168
+ :f_spare, [:int, 6]
169
+ )
102
170
  else
103
171
  layout(
104
172
  :f_bsize, :ulong,
105
173
  :f_frsize, :ulong,
106
- :f_blocks, :ulong,
107
- :f_bfree, :ulong,
108
- :f_bavail, :ulong,
109
- :f_files, :ulong,
110
- :f_ffree, :ulong,
111
- :f_favail, :ulong,
174
+ :f_blocks, :uint64,
175
+ :f_bfree, :uint64,
176
+ :f_bavail, :uint64,
177
+ :f_files, :uint64,
178
+ :f_ffree, :uint64,
179
+ :f_favail, :uint64,
112
180
  :f_fsid, :ulong,
113
181
  :f_flag, :ulong,
114
182
  :f_namemax, :ulong,
115
- :f_ftype, :ulong,
116
- :f_basetype, [:char, 16],
117
- :f_str, [:char, 16]
183
+ :f_spare, [:int, 6]
118
184
  )
119
185
  end
120
186
  end
@@ -11,42 +11,46 @@ module Sys
11
11
  include Sys::Filesystem::Structs
12
12
  extend Sys::Filesystem::Functions
13
13
 
14
- private
14
+ private_class_method :new
15
15
 
16
16
  # Readable versions of constant names
17
- @@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',
17
+ 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',
32
32
  MNT_IGNORE_OWNERSHIP => 'noowners',
33
- MNT_AUTOMOUNTED => 'automounted',
34
- MNT_JOURNALED => 'journaled',
35
- MNT_NOUSERXATTR => 'nouserxattr',
36
- MNT_DEFWRITE => 'defwrite',
37
- MNT_NOATIME => 'noatime'
38
- }
33
+ MNT_AUTOMOUNTED => 'automounted',
34
+ MNT_JOURNALED => 'journaled',
35
+ MNT_NOUSERXATTR => 'nouserxattr',
36
+ MNT_DEFWRITE => 'defwrite',
37
+ MNT_NOATIME => 'noatime'
38
+ }.freeze
39
+
40
+ private_constant :OPT_NAMES
39
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
47
+ elsif File.exist?('/proc/mounts')
48
+ MOUNT_FILE = '/proc/mounts'.freeze
45
49
  else
46
- MOUNT_FILE = 'getmntinfo'
50
+ MOUNT_FILE = 'getmntinfo'.freeze
47
51
  end
48
52
 
49
- public
53
+ private_constant :MOUNT_FILE
50
54
 
51
55
  # The error raised if any of the Filesystem methods fail.
52
56
  class Error < StandardError; end
@@ -126,12 +130,17 @@ module Sys
126
130
 
127
131
  # Returns the total space on the partition.
128
132
  def bytes_total
129
- blocks * block_size
133
+ blocks * fragment_size
130
134
  end
131
135
 
132
136
  # Returns the total amount of free space on the partition.
133
137
  def bytes_free
134
- blocks_available * block_size
138
+ blocks_free * fragment_size
139
+ end
140
+
141
+ # Returns the amount of free space available to unprivileged processes.
142
+ def bytes_available
143
+ blocks_available * fragment_size
135
144
  end
136
145
 
137
146
  # Returns the total amount of used space on the partition.
@@ -191,7 +200,27 @@ module Sys
191
200
  # Returns a Sys::Filesystem::Stat object containing information about the
192
201
  # +path+ on the filesystem.
193
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
+ #
194
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
+
195
224
  fs = Statvfs.new
196
225
 
197
226
  if statvfs(path, fs) < 0
@@ -217,11 +246,6 @@ module Sys
217
246
  obj.block_size /= 256
218
247
  end
219
248
 
220
- # FreeBSD 10 does things a little differently too
221
- if RbConfig::CONFIG['host_os'] =~ /freebsd10/i
222
- obj.block_size = obj.fragment_size
223
- end
224
-
225
249
  if fs.members.include?(:f_basetype)
226
250
  obj.base_type = fs[:f_basetype].to_s
227
251
  end
@@ -256,17 +280,17 @@ module Sys
256
280
 
257
281
  ptr = buf.get_pointer(0)
258
282
 
259
- num.times{ |i|
283
+ num.times do
260
284
  mnt = Statfs.new(ptr)
261
285
  obj = Sys::Filesystem::Mount.new
262
286
  obj.name = mnt[:f_mntfromname].to_s
263
287
  obj.mount_point = mnt[:f_mntonname].to_s
264
288
  obj.mount_type = mnt[:f_fstypename].to_s
265
289
 
266
- string = ""
290
+ string = ''
267
291
  flags = mnt[:f_flags] & MNT_VISFLAGMASK
268
292
 
269
- @@opt_names.each{ |key,val|
293
+ OPT_NAMES.each do |key, val|
270
294
  if flags & key > 0
271
295
  if string.empty?
272
296
  string << val
@@ -275,7 +299,7 @@ module Sys
275
299
  end
276
300
  end
277
301
  flags &= ~key
278
- }
302
+ end
279
303
 
280
304
  obj.options = string
281
305
 
@@ -286,7 +310,7 @@ module Sys
286
310
  end
287
311
 
288
312
  ptr += Statfs.size
289
- }
313
+ end
290
314
  else
291
315
  begin
292
316
  if respond_to?(:setmntent, true)
@@ -363,7 +387,7 @@ module Sys
363
387
  dev = File.stat(file).dev
364
388
  val = file
365
389
 
366
- self.mounts.each{ |mnt|
390
+ mounts.each do |mnt|
367
391
  mp = mnt.mount_point
368
392
  begin
369
393
  if File.stat(mp).dev == dev
@@ -373,31 +397,54 @@ module Sys
373
397
  rescue Errno::EACCES
374
398
  next
375
399
  end
376
- }
400
+ end
377
401
 
378
402
  val
379
403
  end
380
- end
381
- end
382
404
 
383
- class Numeric
384
- # Converts a number to kilobytes.
385
- def to_kb
386
- self / 1024
387
- end
405
+ # Attach the filesystem specified by +source+ to the location (a directory
406
+ # or file) specified by the pathname in +target+.
407
+ #
408
+ # Note that the +source+ is often a pathname referring to a device, but
409
+ # can also be the pathname of a directory or file, or a dummy string.
410
+ #
411
+ # By default this method will assume 'ext2' as the filesystem type, but
412
+ # you should update this as needed.
413
+ #
414
+ # Typically requires admin privileges.
415
+ #
416
+ # Example:
417
+ #
418
+ # Sys::Filesystem.mount('/dev/loop0', '/home/you/tmp', 'ext4', Sys::Filesystem::MNT_RDONLY)
419
+ #
420
+ def self.mount(source, target, fstype = 'ext2', flags = 0, data = nil)
421
+ if mount_c(source, target, fstype, flags, data) != 0
422
+ raise Error, 'mount() function failed: ' + strerror(FFI.errno)
423
+ end
388
424
 
389
- # Converts a number to megabytes.
390
- def to_mb
391
- self / 1048576
392
- end
425
+ self
426
+ end
393
427
 
394
- # Converts a number to gigabytes.
395
- def to_gb
396
- self / 1073741824
397
- end
428
+ # 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.
431
+ #
432
+ # Typically requires admin privileges.
433
+ #
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)
445
+ end
398
446
 
399
- # Converts a number to terabytes.
400
- def to_tb
401
- self / 1099511627776
447
+ self
448
+ end
402
449
  end
403
450
  end
@@ -14,19 +14,22 @@ module Sys
14
14
  end
15
15
  end
16
16
 
17
- attach_pfunc :GetDiskFreeSpaceW, [:buffer_in, :pointer, :pointer, :pointer, :pointer], :bool
18
- attach_pfunc :GetDiskFreeSpaceExW, [:buffer_in, :pointer, :pointer, :pointer], :bool
19
- attach_pfunc :GetLogicalDriveStringsA, [:ulong, :pointer], :ulong
17
+ attach_pfunc :DeleteVolumeMountPointA, [:string], :bool
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
20
21
 
21
22
  attach_pfunc :GetVolumeInformationA,
22
- [:buffer_in, :pointer, :ulong, :pointer, :pointer, :pointer, :pointer, :ulong],
23
- :bool
23
+ %i[buffer_in pointer ulong pointer pointer pointer pointer ulong],
24
+ :bool
24
25
 
25
26
  attach_pfunc :GetVolumeInformationW,
26
- [:buffer_in, :pointer, :ulong, :pointer, :pointer, :pointer, :pointer, :ulong],
27
- :bool
27
+ %i[buffer_in pointer ulong pointer pointer pointer pointer ulong],
28
+ :bool
28
29
 
29
- attach_pfunc :QueryDosDeviceA, [:buffer_in, :buffer_out, :ulong], :ulong
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
30
33
 
31
34
  ffi_lib :shlwapi
32
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
- (self.tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
5
+ (tr(File::SEPARATOR, File::ALT_SEPARATOR) + 0.chr).encode('UTF-16LE')
6
6
  end
7
7
  end