vagrant-unbundled 2.0.3.0 → 2.0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -10
  3. data/Gemfile.lock +16 -2
  4. data/README.md +1 -0
  5. data/bin/vagrant +1 -1
  6. data/lib/vagrant/action/builtin/handle_box.rb +1 -1
  7. data/lib/vagrant/action/general/package.rb +1 -1
  8. data/lib/vagrant/action.rb +3 -1
  9. data/lib/vagrant/alias.rb +56 -0
  10. data/lib/vagrant/bundler.rb +1 -1
  11. data/lib/vagrant/capability_host.rb +1 -1
  12. data/lib/vagrant/cli.rb +8 -0
  13. data/lib/vagrant/config/version_base.rb +1 -1
  14. data/lib/vagrant/environment.rb +7 -1
  15. data/lib/vagrant/errors.rb +4 -0
  16. data/lib/vagrant/host.rb +1 -1
  17. data/lib/vagrant/machine.rb +1 -1
  18. data/lib/vagrant/machine_index.rb +1 -1
  19. data/lib/vagrant/plugin/v1/guest.rb +1 -1
  20. data/lib/vagrant/plugin/v1/host.rb +1 -1
  21. data/lib/vagrant/plugin/v1/plugin.rb +1 -1
  22. data/lib/vagrant/plugin/v1/provider.rb +1 -1
  23. data/lib/vagrant/plugin/v2/guest.rb +1 -1
  24. data/lib/vagrant/plugin/v2/host.rb +1 -1
  25. data/lib/vagrant/plugin/v2/plugin.rb +1 -1
  26. data/lib/vagrant/plugin/v2/provider.rb +1 -1
  27. data/lib/vagrant/shared_helpers.rb +30 -9
  28. data/lib/vagrant/util/checkpoint_client.rb +8 -0
  29. data/lib/vagrant/util/downloader.rb +1 -1
  30. data/lib/vagrant/util/platform.rb +11 -3
  31. data/lib/vagrant/util/powershell.rb +17 -1
  32. data/lib/vagrant/util/safe_exec.rb +1 -1
  33. data/lib/vagrant/util/ssh.rb +4 -1
  34. data/lib/vagrant/util/stacked_proc_runner.rb +1 -1
  35. data/lib/vagrant/util/template_renderer.rb +2 -2
  36. data/lib/vagrant/vagrantfile.rb +1 -1
  37. data/lib/vagrant.rb +8 -0
  38. data/plugins/commands/plugin/gem_helper.rb +1 -1
  39. data/plugins/commands/powershell/command.rb +2 -2
  40. data/plugins/commands/powershell/scripts/enable_psremoting.ps1 +1 -1
  41. data/plugins/communicators/ssh/communicator.rb +10 -1
  42. data/plugins/communicators/winrm/command_filters/mkdir.rb +4 -2
  43. data/plugins/communicators/winrm/command_filters/rm.rb +5 -3
  44. data/plugins/communicators/winrm/command_filters/test.rb +3 -1
  45. data/plugins/communicators/winrm/command_filters/which.rb +4 -2
  46. data/plugins/communicators/winrm/communicator.rb +3 -3
  47. data/plugins/guests/amazon/cap/flavor.rb +1 -1
  48. data/plugins/guests/coreos/cap/configure_networks.rb +1 -1
  49. data/plugins/guests/coreos/guest.rb +1 -1
  50. data/plugins/guests/debian/cap/configure_networks.rb +1 -1
  51. data/plugins/guests/freebsd/cap/configure_networks.rb +1 -1
  52. data/plugins/guests/photon/guest.rb +1 -1
  53. data/plugins/guests/windows/cap/change_host_name.rb +6 -1
  54. data/plugins/guests/windows/cap/mount_shared_folder.rb +1 -1
  55. data/plugins/hosts/alt/plugin.rb +1 -1
  56. data/plugins/hosts/arch/plugin.rb +1 -1
  57. data/plugins/hosts/gentoo/plugin.rb +1 -1
  58. data/plugins/hosts/linux/plugin.rb +1 -1
  59. data/plugins/hosts/redhat/plugin.rb +1 -1
  60. data/plugins/hosts/slackware/plugin.rb +2 -2
  61. data/plugins/kernel_v2/config/push.rb +1 -1
  62. data/plugins/kernel_v2/config/vm.rb +1 -1
  63. data/plugins/providers/docker/action/compare_synced_folders.rb +1 -1
  64. data/plugins/providers/virtualbox/action/network.rb +9 -5
  65. data/plugins/providers/virtualbox/action/network_fix_ipv6.rb +1 -1
  66. data/plugins/provisioners/chef/config/chef_zero.rb +1 -1
  67. data/plugins/provisioners/chef/provisioner/chef_solo.rb +2 -2
  68. data/plugins/provisioners/chef/provisioner/chef_zero.rb +3 -3
  69. data/plugins/provisioners/puppet/config/puppet.rb +2 -0
  70. data/plugins/provisioners/puppet/provisioner/puppet.rb +18 -1
  71. data/plugins/provisioners/salt/config.rb +6 -0
  72. data/plugins/provisioners/salt/provisioner.rb +11 -1
  73. data/templates/locales/command_ps.yml +1 -1
  74. data/templates/locales/en.yml +13 -4
  75. data/templates/locales/guest_windows.yml +1 -1
  76. data/templates/locales/providers_docker.yml +1 -1
  77. data/templates/locales/synced_folder_smb.yml +2 -2
  78. data/vagrant.gemspec +2 -0
  79. data/vendor/bundle/ruby/2.5.0/bundler/gems/vagrant-spec-f3daedaac493/vagrant-spec.gemspec +1 -1
  80. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/.document +5 -0
  81. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/.gitignore +17 -0
  82. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/.travis.yml +21 -0
  83. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/CHANGELOG.md +209 -0
  84. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/Gemfile +4 -0
  85. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/LICENSE.txt +78 -0
  86. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/README.md +67 -0
  87. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/Rakefile +88 -0
  88. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/data/public_suffix_list.dat +12440 -0
  89. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/domain_name.gemspec +36 -0
  90. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/lib/domain_name/etld_data.rb +8474 -0
  91. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/lib/domain_name/etld_data.rb.erb +11 -0
  92. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/lib/domain_name/punycode.rb +283 -0
  93. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/lib/domain_name/version.rb +3 -0
  94. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/lib/domain_name.rb +297 -0
  95. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/test/helper.rb +17 -0
  96. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/test/test_domain_name-punycode.rb +97 -0
  97. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/test/test_domain_name.rb +317 -0
  98. data/vendor/bundle/ruby/2.5.0/gems/domain_name-0.5.20180417/tool/gen_etld_data.rb +63 -0
  99. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/CHANGES +13 -0
  100. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/LICENSE +201 -0
  101. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/MANIFEST +9 -0
  102. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/README +48 -0
  103. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/Rakefile +42 -0
  104. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/certs/djberg96_pub.pem +21 -0
  105. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/ffi-win32-extensions.gemspec +25 -0
  106. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/lib/ffi/win32/extensions.rb +96 -0
  107. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/lib/ffi-win32-extensions.rb +1 -0
  108. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/test/test_ffi_extensions.rb +41 -0
  109. data/vendor/bundle/ruby/2.5.0/gems/ffi-win32-extensions-1.0.3/test/test_string_extensions.rb +20 -0
  110. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/CHANGES +235 -0
  111. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/MANIFEST +16 -0
  112. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/README +73 -0
  113. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/Rakefile +49 -0
  114. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/appveyor.yml +50 -0
  115. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/certs/djberg96_pub.pem +21 -0
  116. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/lib/win32/file/constants.rb +33 -0
  117. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/lib/win32/file/functions.rb +42 -0
  118. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/lib/win32/file/structs.rb +54 -0
  119. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/lib/win32/file.rb +585 -0
  120. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/lib/win32-file.rb +1 -0
  121. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/test/test_win32_file_link.rb +141 -0
  122. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/test/test_win32_file_misc.rb +16 -0
  123. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/test/test_win32_file_path.rb +282 -0
  124. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/test/test_win32_file_stat.rb +330 -0
  125. data/vendor/bundle/ruby/2.5.0/gems/win32-file-0.8.1/win32-file.gemspec +33 -0
  126. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/CHANGES +63 -0
  127. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/MANIFEST +18 -0
  128. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/README +47 -0
  129. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/Rakefile +66 -0
  130. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/appveyor.yml +53 -0
  131. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/certs/djberg96_pub.pem +21 -0
  132. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/lib/win32/file/security/constants.rb +149 -0
  133. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/lib/win32/file/security/functions.rb +63 -0
  134. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/lib/win32/file/security/structs.rb +68 -0
  135. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/lib/win32/file/security.rb +963 -0
  136. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/lib/win32-file-security.rb +1 -0
  137. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_acls.rb +34 -0
  138. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_constants.rb +54 -0
  139. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_encryption.rb +90 -0
  140. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_ffi.rb +33 -0
  141. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_ownership.rb +174 -0
  142. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_permissions.rb +88 -0
  143. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/test/test_win32_file_security_version.rb +14 -0
  144. data/vendor/bundle/ruby/2.5.0/gems/win32-file-security-1.0.10/win32-file-security.gemspec +28 -0
  145. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/CHANGES +169 -0
  146. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/MANIFEST +12 -0
  147. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/README +94 -0
  148. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/Rakefile +28 -0
  149. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/appveyor.yml +48 -0
  150. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/certs/djberg96_pub.pem +21 -0
  151. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/lib/win32/file/stat.rb +1008 -0
  152. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/lib/win32/file/windows/constants.rb +94 -0
  153. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/lib/win32/file/windows/functions.rb +68 -0
  154. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/lib/win32/file/windows/structs.rb +196 -0
  155. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/lib/win32-file-stat.rb +1 -0
  156. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/test/test_file_stat.rb +677 -0
  157. data/vendor/bundle/ruby/2.5.0/gems/win32-file-stat-1.5.5/win32-file-stat.gemspec +30 -0
  158. data/vendor/bundle/ruby/2.5.0/specifications/domain_name-0.5.20180417.gemspec +46 -0
  159. data/vendor/bundle/ruby/2.5.0/specifications/ffi-win32-extensions-1.0.3.gemspec +38 -0
  160. data/vendor/bundle/ruby/2.5.0/specifications/win32-file-0.8.1.gemspec +51 -0
  161. data/vendor/bundle/ruby/2.5.0/specifications/win32-file-security-1.0.10.gemspec +47 -0
  162. data/vendor/bundle/ruby/2.5.0/specifications/win32-file-stat-1.5.5.gemspec +48 -0
  163. data/version.txt +1 -1
  164. metadata +114 -2
@@ -0,0 +1,585 @@
1
+ require_relative 'file/constants'
2
+ require_relative 'file/structs'
3
+ require_relative 'file/functions'
4
+ require 'ffi/win32/extensions'
5
+ require 'win32/file/stat'
6
+
7
+ class File
8
+ include Windows::File::Constants
9
+ include Windows::File::Structs
10
+ extend Windows::File::Functions
11
+
12
+ # The version of the win32-file library
13
+ WIN32_FILE_VERSION = '0.8.1'
14
+
15
+ class << self
16
+ alias_method :join_orig, :join
17
+ alias_method :realpath_orig, :realpath
18
+ alias_method :realdirpath_orig, :realdirpath
19
+
20
+ remove_method :atime, :basename, :blockdev?, :chardev?, :ctime, :dirname
21
+ remove_method :directory?, :executable?, :executable_real?, :file?
22
+ remove_method :ftype, :grpowned?, :join, :lstat, :owned?, :pipe?, :socket?
23
+ remove_method :readable?, :readable_real?, :readlink, :realpath
24
+ remove_method :realdirpath
25
+ remove_method :split, :stat
26
+ remove_method :symlink
27
+ remove_method :symlink?
28
+ remove_method :world_readable?, :world_writable?
29
+ remove_method :writable?, :writable_real?
30
+ end
31
+
32
+ ## Path methods
33
+
34
+ # Returns the last component of the filename given in +filename+. If
35
+ # +suffix+ is given and present at the end of +filename+, it is removed.
36
+ # Any extension can be removed by giving an extension of ".*".
37
+ #
38
+ # This was reimplemented because the current version does not handle UNC
39
+ # paths properly, i.e. it should not return anything less than the root.
40
+ # In most other respects it is identical to the current implementation,
41
+ # except that it does not strip the drive letter on a root path.
42
+ #
43
+ # Unlike MRI, this version will convert all forward slashes to
44
+ # backslashes automatically.
45
+ #
46
+ # Examples:
47
+ #
48
+ # File.basename("C:\\foo\\bar.txt") -> "bar.txt"
49
+ # File.basename("C:\\foo\\bar.txt", ".txt") -> "bar"
50
+ # File.basename("\\\\foo\\bar") -> "\\\\foo\\bar"
51
+ #
52
+ def self.basename(file, suffix = nil)
53
+ file = string_check(file)
54
+ suffix = string_check(suffix) if suffix
55
+
56
+ return file if file.empty? # Return an empty path as-is.
57
+
58
+ encoding = file.encoding
59
+ wfile = file.wincode
60
+
61
+ # Return a root path as-is.
62
+ if PathIsRootW(wfile)
63
+ return file.tr(File::SEPARATOR, File::ALT_SEPARATOR)
64
+ end
65
+
66
+ ptr = FFI::MemoryPointer.from_string(wfile)
67
+
68
+ PathStripPathW(ptr) # Gives us the basename
69
+
70
+ if suffix
71
+ if suffix == '.*'
72
+ PathRemoveExtensionW(ptr)
73
+ else
74
+ ext = PathFindExtensionW(ptr).read_string(suffix.length * 2).wstrip
75
+
76
+ if ext == suffix
77
+ PathRemoveExtensionW(ptr)
78
+ end
79
+ end
80
+ end
81
+
82
+ wfile = ptr.read_bytes(wfile.size * 2).split("\000\000").first.tr(0.chr, '')
83
+ file = wfile.encode(encoding)[/^[^\0]*/]
84
+ file.sub!(/\\+\z/, '') # Trim trailing slashes
85
+
86
+ ptr.free
87
+
88
+ file
89
+ end
90
+
91
+ # Returns all components of the filename given in +filename+ except the
92
+ # last one.
93
+ #
94
+ # This was reimplemented because the current version does not handle UNC
95
+ # paths properly, i.e. it should not return anything less than the root.
96
+ # In all other respects it is identical to the current implementation.
97
+ #
98
+ # Also, this method will convert all forward slashes to backslashes.
99
+ #
100
+ # Examples:
101
+ #
102
+ # File.dirname("C:\\foo\\bar\\baz.txt") -> "C:\\foo\\bar"
103
+ # File.dirname("\\\\foo\\bar") -> "\\\\foo\\bar"
104
+ #
105
+ def self.dirname(file)
106
+ file = string_check(file)
107
+
108
+ # Short circuit for empty paths
109
+ return '.' if file.empty?
110
+
111
+ # Store original encoding, restore it later
112
+ encoding = file.encoding
113
+
114
+ # Convert to UTF-16LE
115
+ wfile = file.wincode
116
+
117
+ # Return a root path as-is.
118
+ if PathIsRootW(wfile)
119
+ return file.tr(File::SEPARATOR, File::ALT_SEPARATOR)
120
+ end
121
+
122
+ ptr = FFI::MemoryPointer.from_string(wfile)
123
+
124
+ # Remove trailing slashes if present
125
+ while result = PathRemoveBackslashW(ptr)
126
+ break unless result.empty?
127
+ end
128
+
129
+ # Remove trailing file name if present
130
+ unless PathRemoveFileSpecW(ptr)
131
+ raise SystemCallError.new("PathRemoveFileSpec", FFI.errno)
132
+ end
133
+
134
+ wfile = ptr.read_bytes(wfile.size * 2).split("\000\000").first
135
+
136
+ # Empty paths, short relative paths
137
+ if wfile.nil? or wfile.empty?
138
+ return '.'
139
+ end
140
+
141
+ # Return to original encoding
142
+ file = wfile.tr(0.chr, '').encode(encoding)
143
+
144
+ ptr.free
145
+
146
+ file
147
+ end
148
+
149
+ # Join path string components together into a single string.
150
+ #
151
+ # This method was reimplemented so that it automatically converts
152
+ # forward slashes to backslashes. It is otherwise identical to
153
+ # the core File.join method.
154
+ #
155
+ # Examples:
156
+ #
157
+ # File.join("C:", "foo", "bar") # => C:\foo\bar
158
+ # File.join("foo", "bar") # => foo\bar
159
+ #
160
+ def self.join(*args)
161
+ return join_orig(*args).tr("/", "\\")
162
+ end
163
+
164
+ # Splits the given string into a directory and a file component and
165
+ # returns them in a two element array. This was reimplemented because
166
+ # the current version does not handle UNC paths properly.
167
+ #
168
+ def self.split(file)
169
+ file = string_check(file)
170
+ array = []
171
+
172
+ if file.empty? || PathIsRootW(file.wincode)
173
+ array.push(file, '')
174
+ else
175
+ array.push(File.dirname(file), File.basename(file))
176
+ end
177
+
178
+ array
179
+ end
180
+
181
+ # Returns +path+ in long format. For example, if 'SOMEFI~1.TXT'
182
+ # was the argument provided, and the short representation for
183
+ # 'somefile.txt', then this method would return 'somefile.txt'.
184
+ #
185
+ # Note that certain file system optimizations may prevent this method
186
+ # from working as expected. In that case, you will get back the file
187
+ # name in 8.3 format.
188
+ #
189
+ def self.long_path(file)
190
+ buffer = FFI::Buffer.new(:wint_t, 1024, true)
191
+ wfile = string_check(file).wincode
192
+
193
+ length = GetLongPathNameW(wfile, buffer, buffer.size)
194
+
195
+ if length == 0 || length > buffer.size / 2
196
+ raise SystemCallError.new('GetLongPathName', FFI.errno)
197
+ end
198
+
199
+ buffer.read_bytes(length * 2).wstrip
200
+ end
201
+
202
+ # Returns +path+ in 8.3 format. For example, 'c:\documentation.doc'
203
+ # would be returned as 'c:\docume~1.doc'.
204
+ #
205
+ def self.short_path(file)
206
+ buffer = FFI::Buffer.new(:wint_t, 1024, true)
207
+ wfile = string_check(file).wincode
208
+
209
+ length = GetShortPathNameW(wfile, buffer, buffer.size)
210
+
211
+ if length == 0 || length > buffer.size / 2
212
+ raise SystemCallError.new('GetShortPathName', FFI.errno)
213
+ end
214
+
215
+ buffer.read_bytes(length * 2).wstrip
216
+ end
217
+
218
+ # Creates a symbolic link called +new_name+ for the file or directory
219
+ # +old_name+.
220
+ #
221
+ # This method requires Windows Vista or later to work. Otherwise, it
222
+ # returns nil as per MRI.
223
+ #
224
+ def self.symlink(target, link)
225
+ target = string_check(target)
226
+ link = string_check(link)
227
+
228
+ flags = File.directory?(target) ? 1 : 0
229
+
230
+ wlink = link.wincode
231
+ wtarget = target.wincode
232
+
233
+ unless CreateSymbolicLinkW(wlink, wtarget, flags)
234
+ raise SystemCallError.new('CreateSymbolicLink', FFI.errno)
235
+ end
236
+
237
+ 0 # Comply with spec
238
+ end
239
+
240
+ # Returns whether or not +file+ is a symlink.
241
+ #
242
+ def self.symlink?(file)
243
+ return false unless File.exist?(file)
244
+
245
+ bool = false
246
+ wfile = string_check(file).wincode
247
+
248
+ attrib = GetFileAttributesW(wfile)
249
+
250
+ if attrib == INVALID_FILE_ATTRIBUTES
251
+ raise SystemCallError.new('GetFileAttributes', FFI.errno)
252
+ end
253
+
254
+ if attrib & FILE_ATTRIBUTE_REPARSE_POINT > 0
255
+ begin
256
+ find_data = WIN32_FIND_DATA.new
257
+ handle = FindFirstFileW(wfile, find_data)
258
+
259
+ if handle == INVALID_HANDLE_VALUE
260
+ raise SystemCallError.new('FindFirstFile', FFI.errno)
261
+ end
262
+
263
+ if find_data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
264
+ bool = true
265
+ end
266
+ ensure
267
+ CloseHandle(handle)
268
+ end
269
+ end
270
+
271
+ bool
272
+ end
273
+
274
+ # Converts path to a full file path, with all symlinks resolved and relative
275
+ # paths made absolute. If a second parameter if present, it is used as the
276
+ # base for resolving leading relative path segments.
277
+ #
278
+ # Unlike File.realpath, an error is not raised if the final path created
279
+ # using a relative path argument doesn't exist.
280
+ #--
281
+ # On Windows we only modify the realpath method if the file is a symlink.
282
+ #
283
+ def self.realdirpath(file, relative_to = nil)
284
+ file = string_check(file)
285
+
286
+ if symlink?(file)
287
+ if relative_to
288
+ File.join(relative_to, File.basename(readlink(file)))
289
+ else
290
+ readlink(file)
291
+ end
292
+ else
293
+ realdirpath_orig(file, relative_to)
294
+ end
295
+ end
296
+
297
+ # Converts path to a full file path, with all symlinks resolved and relative
298
+ # paths made absolute. If a second parameter if present, it is used as the
299
+ # base for resolving leading relative path segments.
300
+ #--
301
+ # On Windows we only modify the realpath method if the file is a symlink.
302
+ #
303
+ def self.realpath(file, relative_to = nil)
304
+ file = string_check(file)
305
+ relative_to = string_check(relative_to) if relative_to
306
+
307
+ if symlink?(file)
308
+ if relative_to
309
+ result = File.join(relative_to, File.basename(readlink(file)))
310
+ if File.exist?(result)
311
+ result
312
+ else
313
+ raise SystemCallError.new(result, 2) # Errno::ENOENT
314
+ end
315
+ else
316
+ readlink(file)
317
+ end
318
+ else
319
+ realpath_orig(file, relative_to)
320
+ end
321
+ end
322
+
323
+ # Returns the path of the of the symbolic link referred to by +file+.
324
+ #
325
+ # Unlike unixy platforms, this will raise an error if the link is stale.
326
+ #
327
+ def self.readlink(file)
328
+ file = string_check(file)
329
+
330
+ if exist?(file) && !symlink?(file)
331
+ raise SystemCallError.new(22) # EINVAL, match the spec
332
+ end
333
+
334
+ wfile = file.wincode
335
+ path = 0.chr * 1024
336
+
337
+ if File.directory?(file)
338
+ flags = FILE_FLAG_BACKUP_SEMANTICS
339
+ else
340
+ flags = FILE_ATTRIBUTE_NORMAL
341
+ end
342
+
343
+ begin
344
+ handle = CreateFileW(
345
+ wfile,
346
+ GENERIC_READ,
347
+ FILE_SHARE_READ,
348
+ nil,
349
+ OPEN_EXISTING,
350
+ flags,
351
+ 0
352
+ )
353
+
354
+ if handle == INVALID_HANDLE_VALUE
355
+ raise SystemCallError.new('CreateFile', FFI.errno)
356
+ end
357
+
358
+ if GetFinalPathNameByHandleW(handle, path, path.size/2, 0) == 0
359
+ raise SystemCallError.new('GetFinalPathNameByHandle', FFI.errno)
360
+ end
361
+ ensure
362
+ CloseHandle(handle)
363
+ end
364
+
365
+ path.wstrip[4..-1] # Remove leading backslashes + question mark
366
+ end
367
+
368
+ ## STAT METHODS
369
+
370
+ # Returns the file's last access time. If a +time+ argument is provided, it
371
+ # sets the file's access time. The +time+ argument may be a Time object or
372
+ # a numeric value.
373
+ #
374
+ def self.atime(file, time = nil)
375
+ set_filetime(file, nil, time) if time
376
+ File::Stat.new(file).atime
377
+ end
378
+
379
+ # Returns the filesystem's block size.
380
+ #
381
+ def self.blksize(file)
382
+ File::Stat.new(file).blksize
383
+ end
384
+
385
+ # Returns whether or not the file is a block device. For MS Windows a
386
+ # block device is a removable drive, cdrom or ramdisk.
387
+ #
388
+ def self.blockdev?(file)
389
+ return false unless File.exist?(file)
390
+ File::Stat.new(file).blockdev?
391
+ end
392
+
393
+ # Returns whether or not the file is a character device.
394
+ #
395
+ def self.chardev?(file)
396
+ return false unless File.exist?(file)
397
+ File::Stat.new(file).chardev?
398
+ end
399
+
400
+ # Returns the file's creation time. If a +time+ argument is provided, it
401
+ # sets the file's creation time. The +time+ argument may be a Time object or
402
+ # a numeric value.
403
+ #
404
+ def self.ctime(file, time = nil)
405
+ set_filetime(file, time) if time
406
+ File::Stat.new(file).ctime
407
+ end
408
+
409
+ # Returns whether or not the file is a directory.
410
+ #
411
+ def self.directory?(file)
412
+ return false unless File.exist?(file)
413
+ File::Stat.new(file).directory?
414
+ end
415
+
416
+ # Returns whether or not the file is executable.
417
+ #
418
+ def self.executable?(file)
419
+ return false unless File.exist?(file)
420
+ File::Stat.new(file).executable?
421
+ end
422
+
423
+ # Returns whether or not the file is a regular file.
424
+ #
425
+ def self.file?(file)
426
+ return false unless File.exist?(file)
427
+ File::Stat.new(file).file?
428
+ end
429
+
430
+ # Identifies the type of file. The return string is one of 'file',
431
+ # 'directory', 'characterSpecial', 'socket' or 'unknown'.
432
+ #
433
+ def self.ftype(file)
434
+ File::Stat.new(file).ftype
435
+ end
436
+
437
+ # Returns true if the process owner's ID is the same as one of the file's groups.
438
+ #
439
+ def self.grpowned?(file)
440
+ return false unless File.exist?(file)
441
+ File::Stat.new(file).grpowned?
442
+ end
443
+
444
+ # Returns the file's creation time. If a +time+ argument is provided, it
445
+ # sets the file's creation time. The +time+ argument may be a Time object or
446
+ # a numeric value.
447
+ #
448
+ def self.mtime(file, time = nil)
449
+ set_filetime(file, nil, nil, time) if time
450
+ File::Stat.new(file).mtime
451
+ end
452
+
453
+ # Returns whether or not the current process owner is the owner of the file.
454
+ #
455
+ def self.owned?(file)
456
+ return false unless File.exist?(file)
457
+ File::Stat.new(file).owned?
458
+ end
459
+
460
+ # Returns whether or not the file is a pipe.
461
+ #
462
+ def self.pipe?(file)
463
+ return false unless File.exist?(file)
464
+ File::Stat.new(file).pipe?
465
+ end
466
+
467
+ # Returns whether or not the file is readable by the process owner.
468
+ #
469
+ def self.readable?(file)
470
+ return false unless File.exist?(file)
471
+ File::Stat.new(file).readable?
472
+ end
473
+
474
+ # Synonym for File.readable?
475
+ #
476
+ def self.readable_real?(file)
477
+ return false unless File.exist?(file)
478
+ File::Stat.new(file).readable_real?
479
+ end
480
+
481
+ # Returns a File::Stat object as defined in the win32-file-stat library.
482
+ #
483
+ def self.stat(file)
484
+ File::Stat.new(file)
485
+ end
486
+
487
+ # Returns whether or not the file is readable by others. Note that this
488
+ # merely returns true or false, not permission bits (or nil).
489
+ #
490
+ def self.world_readable?(file)
491
+ return false unless File.exist?(file)
492
+ File::Stat.new(file).world_readable?
493
+ end
494
+
495
+ # Returns whether or not the file is writable by others. Note that this
496
+ # merely returns true or false, not permission bits (or nil).
497
+ #
498
+ def self.world_writable?(file)
499
+ return false unless File.exist?(file)
500
+ File::Stat.new(file).world_writable?
501
+ end
502
+
503
+ # Returns whether or not the file is writable by the current process owner.
504
+ #
505
+ def self.writable?(file)
506
+ return false unless File.exist?(file)
507
+ File::Stat.new(file).writable?
508
+ end
509
+
510
+ # Synonym for File.writable?
511
+ #
512
+ def self.writable_real?(file)
513
+ return false unless File.exist?(file)
514
+ File::Stat.new(file).writable_real?
515
+ end
516
+
517
+ # Singleton aliases
518
+ class << self
519
+ alias lstat stat
520
+ alias executable_real? executable?
521
+ alias socket? pipe?
522
+ end
523
+
524
+ ## Instance Methods
525
+
526
+ # Same as MRI, except it returns a stat object using the win32-file-stat gem.
527
+ #
528
+ def stat
529
+ File::Stat.new(self.path)
530
+ end
531
+
532
+ # Private singleton methods
533
+ private
534
+
535
+ # Simulate Ruby's string checking
536
+ def self.string_check(arg)
537
+ return arg if arg.is_a?(String)
538
+ return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI allows private to_str
539
+ return arg.to_path if arg.respond_to?(:to_path)
540
+ raise TypeError
541
+ end
542
+
543
+ # Internal method for setting the file time.
544
+ def self.set_filetime(path, ctime = nil, atime = nil, mtime = nil)
545
+ begin
546
+ handle = CreateFileW(
547
+ path.wincode,
548
+ FILE_WRITE_ATTRIBUTES,
549
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
550
+ nil,
551
+ OPEN_EXISTING,
552
+ FILE_ATTRIBUTE_NORMAL,
553
+ 0
554
+ )
555
+
556
+ if handle == INVALID_HANDLE_VALUE
557
+ raise SystemCallError.new('CreateFile', FFI.errno)
558
+ end
559
+
560
+ ftimes = [] # 0 = ctime, 1 = atime, 2 = mtime
561
+
562
+ [ctime, atime, mtime].each{ |time|
563
+ if time.nil?
564
+ ftimes << nil
565
+ next
566
+ else
567
+ systime = SYSTEMTIME.new(time)
568
+ ftime = FILETIME.new
569
+
570
+ if SystemTimeToFileTime(systime, ftime)
571
+ ftimes << ftime
572
+ else
573
+ raise SystemCallError.new('SystemTimetoFileTime', FFI.errno)
574
+ end
575
+ end
576
+ }
577
+
578
+ unless SetFileTime(handle, ftimes[0], ftimes[1], ftimes[2])
579
+ raise SystemCallError.new('SetFileTime', FFI.errno)
580
+ end
581
+ ensure
582
+ CloseHandle(handle) if handle
583
+ end
584
+ end
585
+ end
@@ -0,0 +1 @@
1
+ require_relative 'win32/file'