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,1008 @@
1
+ require 'pp'
2
+ require 'ffi/win32/extensions'
3
+ require_relative 'windows/constants'
4
+ require_relative 'windows/structs'
5
+ require_relative 'windows/functions'
6
+
7
+ class File::Stat
8
+ include Windows::Stat::Constants
9
+ include Windows::Stat::Structs
10
+ include Windows::Stat::Functions
11
+ include Comparable
12
+
13
+ # We have to undefine these first in order to avoid redefinition warnings.
14
+ undef_method :atime, :ctime, :mtime, :blksize, :blockdev?, :blocks, :chardev?
15
+ undef_method :dev, :dev_major, :dev_minor, :directory?, :executable?
16
+ undef_method :executable_real?, :file?
17
+ undef_method :ftype, :gid, :grpowned?, :ino, :mode, :nlink, :owned?
18
+ undef_method :pipe?, :readable?, :readable_real?, :rdev, :rdev_major
19
+ undef_method :rdev_minor, :setuid?, :setgid?
20
+ undef_method :size, :size?, :socket?, :sticky?, :symlink?, :uid
21
+ undef_method :world_readable?, :world_writable?, :writable?, :writable_real?
22
+ undef_method :<=>, :inspect, :pretty_print, :zero?
23
+
24
+ # A Time object containing the last access time.
25
+ attr_reader :atime
26
+
27
+ # A Time object indicating when the file was last changed.
28
+ attr_reader :ctime
29
+
30
+ # A Time object containing the last modification time.
31
+ attr_reader :mtime
32
+
33
+ # The native filesystems' block size.
34
+ attr_reader :blksize
35
+
36
+ # The number of native filesystem blocks allocated for this file.
37
+ attr_reader :blocks
38
+
39
+ # The serial number of the file's volume.
40
+ attr_reader :rdev
41
+
42
+ # The file's unique identifier. Only valid for regular files.
43
+ attr_reader :ino
44
+
45
+ # Integer representing the permission bits of the file.
46
+ attr_reader :mode
47
+
48
+ # The number of hard links to the file.
49
+ attr_reader :nlink
50
+
51
+ # The size of the file in bytes.
52
+ attr_reader :size
53
+
54
+ # Nil on Windows
55
+ attr_reader :dev_major, :dev_minor, :rdev_major, :rdev_minor
56
+
57
+ # Alternate streams
58
+ attr_reader :streams
59
+
60
+ # The version of the win32-file-stat library
61
+ WIN32_FILE_STAT_VERSION = '1.5.5'
62
+
63
+ # Creates and returns a File::Stat object, which encapsulate common status
64
+ # information for File objects on MS Windows sytems. The information is
65
+ # recorded at the moment the File::Stat object is created; changes made to
66
+ # the file after that point will not be reflected.
67
+ #
68
+ def initialize(file)
69
+ file = string_check(file)
70
+
71
+ path = file.tr('/', "\\")
72
+ @path = path
73
+
74
+ @user_sid = get_file_sid(file, OWNER_SECURITY_INFORMATION)
75
+ @grp_sid = get_file_sid(file, GROUP_SECURITY_INFORMATION)
76
+
77
+ @uid = @user_sid.split('-').last.to_i
78
+ @gid = @grp_sid.split('-').last.to_i
79
+
80
+ @owned = @user_sid == get_current_process_sid(TokenUser)
81
+ @grpowned = @grp_sid == get_current_process_sid(TokenGroups)
82
+
83
+ begin
84
+ # The handle returned will be used by other functions
85
+ handle = get_handle(path)
86
+
87
+ @blockdev = get_blockdev(path)
88
+ @blksize = get_blksize(path)
89
+
90
+ if handle
91
+ @filetype = get_filetype(handle)
92
+ @streams = get_streams(handle)
93
+ @chardev = @filetype == FILE_TYPE_CHAR
94
+ @regular = @filetype == FILE_TYPE_DISK
95
+ @pipe = @filetype == FILE_TYPE_PIPE
96
+
97
+ if @pipe
98
+ @socket = !GetNamedPipeInfo(handle, nil, nil, nil, nil)
99
+ else
100
+ @socket = false
101
+ end
102
+ else
103
+ @chardev = false
104
+ @regular = false
105
+ @pipe = false
106
+ @socket = false
107
+ end
108
+
109
+ fpath = path.wincode
110
+
111
+ if handle == nil || ((@blockdev || @chardev || @pipe) && GetDriveType(fpath) != DRIVE_REMOVABLE)
112
+ data = WIN32_FIND_DATA.new
113
+ CloseHandle(handle) if handle
114
+
115
+ handle = FindFirstFile(fpath, data)
116
+
117
+ if handle == INVALID_HANDLE_VALUE
118
+ raise SystemCallError.new('FindFirstFile', FFI.errno)
119
+ end
120
+
121
+ FindClose(handle)
122
+ handle = nil
123
+
124
+ @nlink = 1 # Default from stat/wstat function.
125
+ @ino = nil
126
+ @rdev = nil
127
+ else
128
+ data = BY_HANDLE_FILE_INFORMATION.new
129
+
130
+ unless GetFileInformationByHandle(handle, data)
131
+ raise SystemCallError.new('GetFileInformationByHandle', FFI.errno)
132
+ end
133
+
134
+ @nlink = data[:nNumberOfLinks]
135
+ @ino = (data[:nFileIndexHigh] << 32) | data[:nFileIndexLow]
136
+ @rdev = data[:dwVolumeSerialNumber]
137
+ end
138
+
139
+ # Not supported and/or meaningless on MS Windows
140
+ @dev_major = nil
141
+ @dev_minor = nil
142
+ @rdev_major = nil
143
+ @rdev_minor = nil
144
+ @setgid = false
145
+ @setuid = false
146
+ @sticky = false
147
+
148
+ # Originally used GetBinaryType, but it only worked
149
+ # for .exe files, and it could return false positives.
150
+ @executable = %w[.bat .cmd .com .exe].include?(File.extname(@path).downcase)
151
+
152
+ # Set blocks equal to size / blksize, rounded up
153
+ case @blksize
154
+ when nil
155
+ @blocks = nil
156
+ when 0
157
+ @blocks = 0
158
+ else
159
+ @blocks = (data.size.to_f / @blksize.to_f).ceil
160
+ end
161
+
162
+ @attr = data[:dwFileAttributes]
163
+ @atime = Time.at(data.atime)
164
+ @ctime = Time.at(data.ctime)
165
+ @mtime = Time.at(data.mtime)
166
+ @size = data.size
167
+
168
+ @archive = @attr & FILE_ATTRIBUTE_ARCHIVE > 0
169
+ @compressed = @attr & FILE_ATTRIBUTE_COMPRESSED > 0
170
+ @directory = @attr & FILE_ATTRIBUTE_DIRECTORY > 0
171
+ @encrypted = @attr & FILE_ATTRIBUTE_ENCRYPTED > 0
172
+ @hidden = @attr & FILE_ATTRIBUTE_HIDDEN > 0
173
+ @indexed = @attr & ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED > 0
174
+ @normal = @attr & FILE_ATTRIBUTE_NORMAL > 0
175
+ @offline = @attr & FILE_ATTRIBUTE_OFFLINE > 0
176
+ @readonly = @attr & FILE_ATTRIBUTE_READONLY > 0
177
+ @reparse_point = @attr & FILE_ATTRIBUTE_REPARSE_POINT > 0
178
+ @sparse = @attr & FILE_ATTRIBUTE_SPARSE_FILE > 0
179
+ @system = @attr & FILE_ATTRIBUTE_SYSTEM > 0
180
+ @temporary = @attr & FILE_ATTRIBUTE_TEMPORARY > 0
181
+
182
+ @mode = get_mode
183
+
184
+ @readable = access_check(path, GENERIC_READ)
185
+ @readable_real = @readable
186
+
187
+ # The MSDN docs say that the readonly attribute is honored for directories
188
+ if @directory
189
+ @writable = access_check(path, GENERIC_WRITE)
190
+ else
191
+ @writable = access_check(path, GENERIC_WRITE) && !@readonly
192
+ end
193
+
194
+ @writable_real = @writable
195
+
196
+ @world_readable = access_check_world(path, FILE_READ_DATA)
197
+ @world_writable = access_check_world(path, FILE_WRITE_DATA) && !@readonly
198
+
199
+ if @reparse_point
200
+ @symlink = get_symlink(path)
201
+ else
202
+ @symlink = false
203
+ end
204
+ ensure
205
+ CloseHandle(handle) if handle
206
+ end
207
+ end
208
+
209
+ ## Comparable
210
+
211
+ # Compares two File::Stat objects using modification time.
212
+ #--
213
+ # Custom implementation necessary since we altered File::Stat.
214
+ #
215
+ def <=>(other)
216
+ @mtime.to_i <=> other.mtime.to_i
217
+ end
218
+
219
+ ## Other
220
+
221
+ # Returns whether or not the file is an archive file.
222
+ #
223
+ def archive?
224
+ @archive
225
+ end
226
+
227
+ # Returns whether or not the file is a block device. For MS Windows a
228
+ # block device is a removable drive, cdrom or ramdisk.
229
+ #
230
+ def blockdev?
231
+ @blockdev
232
+ end
233
+
234
+ # Returns whether or not the file is a character device.
235
+ #
236
+ def chardev?
237
+ @chardev
238
+ end
239
+
240
+ # Returns whether or not the file is compressed.
241
+ #
242
+ def compressed?
243
+ @compressed
244
+ end
245
+
246
+ # Returns whether or not the file is a directory.
247
+ #
248
+ def directory?
249
+ @directory
250
+ end
251
+
252
+ # Returns whether or not the file in encrypted.
253
+ #
254
+ def encrypted?
255
+ @encrypted
256
+ end
257
+
258
+ # Returns whether or not the file is executable. Generally speaking, this
259
+ # means .bat, .cmd, .com, and .exe files.
260
+ #
261
+ def executable?
262
+ @executable
263
+ end
264
+
265
+ alias executable_real? executable?
266
+
267
+ # Returns whether or not the file is a regular file, as opposed to a pipe,
268
+ # socket, etc.
269
+ #
270
+ def file?
271
+ @regular && !@directory && !@reparse_point
272
+ end
273
+
274
+ # Returns the user ID of the file. If full_sid is true, then the full
275
+ # string sid is returned instead.
276
+ #--
277
+ # The user id is the RID of the SID.
278
+ #
279
+ def gid(full_sid = false)
280
+ full_sid ? @grp_sid : @gid
281
+ end
282
+
283
+ # Returns true if the process owner's ID is the same as one of the file's groups.
284
+ #--
285
+ # Internally we're checking the process sid against the TokenGroups sid.
286
+ #
287
+ def grpowned?
288
+ @grpowned
289
+ end
290
+
291
+ # Returns whether or not the file is hidden.
292
+ #
293
+ def hidden?
294
+ @hidden
295
+ end
296
+
297
+ # Returns whether or not the file is content indexed.
298
+ #
299
+ def indexed?
300
+ @indexed
301
+ end
302
+
303
+ alias content_indexed? indexed?
304
+
305
+ # Returns whether or not the file is 'normal'. This is only true if
306
+ # virtually all other attributes are false.
307
+ #
308
+ def normal?
309
+ @normal
310
+ end
311
+
312
+ # Returns whether or not the file is offline.
313
+ #
314
+ def offline?
315
+ @offline
316
+ end
317
+
318
+ # Returns whether or not the current process owner is the owner of the file.
319
+ #--
320
+ # Internally we're checking the process sid against the owner's sid.
321
+ def owned?
322
+ @owned
323
+ end
324
+
325
+ # Returns the drive number of the disk containing the file, or -1 if there
326
+ # is no associated drive number.
327
+ #
328
+ # If the +letter+ option is true, returns the drive letter instead. If there
329
+ # is no drive letter, it will return nil.
330
+ #--
331
+ # This differs slightly from MRI in that it will return -1 if the path
332
+ # does not have a drive letter.
333
+ #
334
+ # Note: Bug in JRuby as of JRuby 1.7.8, which does not expand NUL properly.
335
+ #
336
+ def dev(letter = false)
337
+ fpath = File.expand_path(@path).wincode
338
+ num = PathGetDriveNumber(fpath)
339
+
340
+ if letter
341
+ if num == -1
342
+ nil
343
+ else
344
+ (num + 'A'.ord).chr + ':'
345
+ end
346
+ else
347
+ num
348
+ end
349
+ end
350
+
351
+ # Returns whether or not the file is readable by the process owner.
352
+ #--
353
+ # In Windows terms, we're checking for GENERIC_READ privileges.
354
+ #
355
+ def readable?
356
+ @readable
357
+ end
358
+
359
+ # A synonym for File::Stat#readable?
360
+ #
361
+ def readable_real?
362
+ @readable_real
363
+ end
364
+
365
+ # Returns whether or not the file is readonly.
366
+ #
367
+ def readonly?
368
+ @readonly
369
+ end
370
+
371
+ alias read_only? readonly?
372
+
373
+ # Returns whether or not the file is a pipe.
374
+ #
375
+ def pipe?
376
+ @pipe
377
+ end
378
+
379
+ # Returns whether or not the file is a socket.
380
+ def socket?
381
+ @socket
382
+ end
383
+
384
+ # Returns whether or not the file is a reparse point.
385
+ #
386
+ def reparse_point?
387
+ @reparse_point
388
+ end
389
+
390
+ # Returns false on MS Windows.
391
+ #--
392
+ # I had to explicitly define this because of a bug in JRuby.
393
+ #
394
+ def setgid?
395
+ @setgid
396
+ end
397
+
398
+ # Returns false on MS Windows.
399
+ #--
400
+ # I had to explicitly define this because of a bug in JRuby.
401
+ #
402
+ def setuid?
403
+ @setuid
404
+ end
405
+
406
+ # Returns whether or not the file size is zero.
407
+ #
408
+ def size?
409
+ @size > 0 ? @size : nil
410
+ end
411
+
412
+ # Returns whether or not the file is a sparse file. In most cases a sparse
413
+ # file is an image file.
414
+ #
415
+ def sparse?
416
+ @sparse
417
+ end
418
+
419
+ # Returns false on MS Windows.
420
+ #--
421
+ # I had to explicitly define this because of a bug in JRuby.
422
+ #
423
+ def sticky?
424
+ @sticky
425
+ end
426
+
427
+ # Returns whether or not the file is a symlink.
428
+ #
429
+ def symlink?
430
+ @symlink
431
+ end
432
+
433
+ # Returns whether or not the file is a system file.
434
+ #
435
+ def system?
436
+ @system
437
+ end
438
+
439
+ # Returns whether or not the file is being used for temporary storage.
440
+ #
441
+ def temporary?
442
+ @temporary
443
+ end
444
+
445
+ # Returns the user ID of the file. If the +full_sid+ is true, then the
446
+ # full string sid is returned instead.
447
+ #--
448
+ # The user id is the RID of the SID.
449
+ #
450
+ def uid(full_sid = false)
451
+ full_sid ? @user_sid : @uid
452
+ end
453
+
454
+ # Returns whether or not the file is readable by others. Note that this
455
+ # merely returns true or false, not permission bits (or nil).
456
+ #--
457
+ # In Windows terms, this is checking the access right FILE_READ_DATA against
458
+ # the well-known SID "S-1-1-0", aka "Everyone".
459
+ #
460
+ #
461
+ def world_readable?
462
+ @world_readable
463
+ end
464
+
465
+ # Returns whether or not the file is writable by others. Note that this
466
+ # merely returns true or false, not permission bits (or nil).
467
+ #--
468
+ # In Windows terms, this is checking the access right FILE_WRITE_DATA against
469
+ # the well-known SID "S-1-1-0", aka "Everyone".
470
+ #
471
+ def world_writable?
472
+ @world_writable
473
+ end
474
+
475
+ # Returns whether or not the file is writable by the current process owner.
476
+ #--
477
+ # In Windows terms, we're checking for GENERIC_WRITE privileges.
478
+ #
479
+ def writable?
480
+ @writable
481
+ end
482
+
483
+ # A synonym for File::Stat#readable?
484
+ #
485
+ def writable_real?
486
+ @writable_real
487
+ end
488
+
489
+ # Returns whether or not the file size is zero.
490
+ #
491
+ def zero?
492
+ @size == 0
493
+ end
494
+
495
+ # Identifies the type of file. The return string is one of 'file',
496
+ # 'directory', 'characterSpecial', 'socket' or 'unknown'.
497
+ #
498
+ def ftype
499
+ return 'directory' if @directory
500
+
501
+ case @filetype
502
+ when FILE_TYPE_CHAR
503
+ 'characterSpecial'
504
+ when FILE_TYPE_DISK
505
+ 'file'
506
+ when FILE_TYPE_PIPE
507
+ 'socket'
508
+ else
509
+ if blockdev?
510
+ 'blockSpecial'
511
+ else
512
+ 'unknown'
513
+ end
514
+ end
515
+ end
516
+
517
+ # Returns a stringified version of a File::Stat object.
518
+ #
519
+ def inspect
520
+ members = %w[
521
+ archive? atime blksize blockdev? blocks compressed? ctime dev
522
+ encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
523
+ offline? readonly? reparse_point? size sparse? system? streams
524
+ temporary? uid
525
+ ]
526
+
527
+ str = "#<#{self.class}"
528
+
529
+ members.sort.each{ |mem|
530
+ if mem == 'mode'
531
+ str << " #{mem}=" << sprintf("0%o", send(mem.intern))
532
+ elsif mem[-1].chr == '?' # boolean methods
533
+ str << " #{mem.chop}=" << send(mem.intern).to_s
534
+ else
535
+ str << " #{mem}=" << send(mem.intern).to_s
536
+ end
537
+ }
538
+
539
+ str
540
+ end
541
+
542
+ # A custom pretty print method. This was necessary not only to handle
543
+ # the additional attributes, but to work around an error caused by the
544
+ # builtin method for the current File::Stat class (see pp.rb).
545
+ #
546
+ def pretty_print(q)
547
+ members = %w[
548
+ archive? atime blksize blockdev? blocks compressed? ctime dev
549
+ encrypted? gid hidden? indexed? ino mode mtime rdev nlink normal?
550
+ offline? readonly? reparse_point? size sparse? streams system? temporary?
551
+ uid
552
+ ]
553
+
554
+ q.object_group(self){
555
+ q.breakable
556
+ members.each{ |mem|
557
+ q.group{
558
+ q.text("#{mem}".ljust(15) + "=> ")
559
+ if mem == 'mode'
560
+ q.text(sprintf("0%o", send(mem.intern)))
561
+ else
562
+ val = self.send(mem.intern)
563
+ if val.nil?
564
+ q.text('nil')
565
+ else
566
+ q.text(val.to_s)
567
+ end
568
+ end
569
+ }
570
+ q.comma_breakable unless mem == members.last
571
+ }
572
+ }
573
+ end
574
+
575
+ private
576
+
577
+ # Workaround for bug in 64-big JRuby. Hope to remove it some day.
578
+ def get_ptr_type
579
+ if RUBY_PLATFORM == 'java' && ENV_JAVA['sun.arch.data.model'] == '64'
580
+ :ulong_long
581
+ else
582
+ :uintptr_t
583
+ end
584
+ end
585
+
586
+ # Allow stringy arguments
587
+ def string_check(arg)
588
+ return arg if arg.is_a?(String)
589
+ return arg.send(:to_str) if arg.respond_to?(:to_str, true) # MRI honors private to_str
590
+ return arg.to_path if arg.respond_to?(:to_path)
591
+ raise TypeError
592
+ end
593
+
594
+ # This is based on fileattr_to_unixmode in win32.c
595
+ #
596
+ def get_mode
597
+ mode = 0
598
+
599
+ s_iread = 0x0100; s_iwrite = 0x0080; s_iexec = 0x0040
600
+ s_ifreg = 0x8000; s_ifdir = 0x4000; s_iwusr = 0200
601
+ s_iwgrp = 0020; s_iwoth = 0002;
602
+
603
+ if @readonly
604
+ mode |= s_iread
605
+ else
606
+ mode |= s_iread | s_iwrite | s_iwusr
607
+ end
608
+
609
+ if @directory
610
+ mode |= s_ifdir | s_iexec
611
+ else
612
+ mode |= s_ifreg
613
+ end
614
+
615
+ if @executable
616
+ mode |= s_iexec
617
+ end
618
+
619
+ mode |= (mode & 0700) >> 3;
620
+ mode |= (mode & 0700) >> 6;
621
+
622
+ mode &= ~(s_iwgrp | s_iwoth)
623
+
624
+ mode
625
+ end
626
+
627
+ # Returns whether or not +path+ is a block device.
628
+ #
629
+ def get_blockdev(path)
630
+ ptr = FFI::MemoryPointer.from_string(path.wincode)
631
+
632
+ if PathStripToRoot(ptr)
633
+ fpath = ptr.read_bytes(path.size * 2).split("\000\000").first
634
+ else
635
+ fpath = nil
636
+ end
637
+
638
+ case GetDriveType(fpath)
639
+ when DRIVE_REMOVABLE, DRIVE_CDROM, DRIVE_RAMDISK
640
+ true
641
+ else
642
+ false
643
+ end
644
+ end
645
+
646
+ # Returns the blksize for +path+.
647
+ #---
648
+ # The jruby-ffi gem (as of 1.9.3) reports a failure here where it shouldn't.
649
+ # Consequently, this method returns 4096 automatically for now on JRuby.
650
+ #
651
+ def get_blksize(path)
652
+ return 4096 if RUBY_PLATFORM == 'java' # Bug in jruby-ffi
653
+
654
+ ptr = FFI::MemoryPointer.from_string(path.wincode)
655
+
656
+ if PathStripToRoot(ptr)
657
+ fpath = ptr.read_bytes(path.size * 2).split("\000\000").first
658
+ else
659
+ fpath = nil
660
+ end
661
+
662
+ size = nil
663
+
664
+ sectors = FFI::MemoryPointer.new(:ulong)
665
+ bytes = FFI::MemoryPointer.new(:ulong)
666
+ free = FFI::MemoryPointer.new(:ulong)
667
+ total = FFI::MemoryPointer.new(:ulong)
668
+
669
+ if GetDiskFreeSpace(fpath, sectors, bytes, free, total)
670
+ size = sectors.read_ulong * bytes.read_ulong
671
+ else
672
+ unless PathIsUNC(fpath)
673
+ raise SystemCallError.new('GetDiskFreeSpace', FFI.errno)
674
+ end
675
+ end
676
+
677
+ size
678
+ end
679
+
680
+ # Generic method for retrieving a handle.
681
+ #
682
+ def get_handle(path)
683
+ fpath = path.wincode
684
+
685
+ handle = CreateFile(
686
+ fpath,
687
+ GENERIC_READ,
688
+ FILE_SHARE_READ,
689
+ nil,
690
+ OPEN_EXISTING,
691
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
692
+ 0
693
+ )
694
+
695
+ if handle == INVALID_HANDLE_VALUE
696
+ return nil if FFI.errno == 32 # ERROR_SHARING_VIOLATION. Locked files.
697
+ raise SystemCallError.new('CreateFile', FFI.errno)
698
+ end
699
+
700
+ handle
701
+ end
702
+
703
+ # Determines whether or not +file+ is a symlink.
704
+ #
705
+ def get_symlink(file)
706
+ bool = false
707
+ fpath = File.expand_path(file).wincode
708
+
709
+ begin
710
+ data = WIN32_FIND_DATA.new
711
+ handle = FindFirstFile(fpath, data)
712
+
713
+ if handle == INVALID_HANDLE_VALUE
714
+ raise SystemCallError.new('FindFirstFile', FFI.errno)
715
+ end
716
+
717
+ if data[:dwReserved0] == IO_REPARSE_TAG_SYMLINK
718
+ bool = true
719
+ end
720
+ ensure
721
+ FindClose(handle) if handle
722
+ end
723
+
724
+ bool
725
+ end
726
+
727
+ # Returns the filetype for the given +handle+.
728
+ #
729
+ def get_filetype(handle)
730
+ file_type = GetFileType(handle)
731
+
732
+ if file_type == FILE_TYPE_UNKNOWN && FFI.errno != NO_ERROR
733
+ raise SystemCallError.new('GetFileType', FFI.errno)
734
+ end
735
+
736
+ file_type
737
+ end
738
+
739
+ def get_streams(handle)
740
+ io_status = IO_STATUS_BLOCK.new
741
+ ptr = FFI::MemoryPointer.new(:uchar, 1024 * 64)
742
+
743
+ NtQueryInformationFile(handle, io_status, ptr, ptr.size, FileStreamInformation)
744
+
745
+ if FFI.errno != 0
746
+ raise SystemCallError.new('NtQueryInformationFile', FFI.errno)
747
+ end
748
+
749
+ arr = []
750
+
751
+ while true
752
+ info = FILE_STREAM_INFORMATION.new(ptr)
753
+ break if info[:StreamNameLength] == 0
754
+ arr << info[:StreamName].to_ptr.read_bytes(info[:StreamNameLength]).delete(0.chr)
755
+ break if info[:NextEntryOffset] == 0
756
+ info = FILE_STREAM_INFORMATION.new(ptr += info[:NextEntryOffset])
757
+ end
758
+
759
+ arr
760
+ end
761
+
762
+ # Return a sid of the file's owner.
763
+ #
764
+ def get_file_sid(file, info)
765
+ wfile = file.wincode
766
+ size_needed_ptr = FFI::MemoryPointer.new(:ulong)
767
+
768
+ # First pass, get the size needed
769
+ bool = GetFileSecurity(wfile, info, nil, 0, size_needed_ptr)
770
+
771
+ size_needed = size_needed_ptr.read_ulong
772
+ security_ptr = FFI::MemoryPointer.new(size_needed)
773
+
774
+ # Second pass, this time with the appropriately sized security pointer
775
+ bool = GetFileSecurity(wfile, info, security_ptr, security_ptr.size, size_needed_ptr)
776
+
777
+ unless bool
778
+ error = FFI.errno
779
+ return "S-1-5-80-0" if error == 32 # ERROR_SHARING_VIOLATION. Locked files, etc.
780
+ raise SystemCallError.new("GetFileSecurity", error)
781
+ end
782
+
783
+ sid_ptr = FFI::MemoryPointer.new(:pointer)
784
+ defaulted = FFI::MemoryPointer.new(:bool)
785
+
786
+ if info == OWNER_SECURITY_INFORMATION
787
+ bool = GetSecurityDescriptorOwner(security_ptr, sid_ptr, defaulted)
788
+ meth = "GetSecurityDescriptorOwner"
789
+ else
790
+ bool = GetSecurityDescriptorGroup(security_ptr, sid_ptr, defaulted)
791
+ meth = "GetSecurityDescriptorGroup"
792
+ end
793
+
794
+ raise SystemCallError.new(meth, FFI.errno) unless bool
795
+
796
+ ptr = FFI::MemoryPointer.new(:string)
797
+
798
+ unless ConvertSidToStringSid(sid_ptr.read_pointer, ptr)
799
+ raise SystemCallError.new("ConvertSidToStringSid")
800
+ end
801
+
802
+ ptr.read_pointer.read_string
803
+ end
804
+
805
+ # Return the sid of the current process.
806
+ #
807
+ def get_current_process_sid(token_type)
808
+ token = FFI::MemoryPointer.new(get_ptr_type)
809
+ sid = nil
810
+
811
+ # Get the current process sid
812
+ unless OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token)
813
+ raise SystemCallError.new("OpenProcessToken", FFI.errno)
814
+ end
815
+
816
+ begin
817
+ token = token.read_pointer.to_i
818
+ rlength = FFI::MemoryPointer.new(:ulong)
819
+
820
+ if token_type == TokenUser
821
+ info = TOKEN_USER.new
822
+ else
823
+ info = TOKEN_GROUP.new
824
+ end
825
+
826
+ bool = GetTokenInformation(token, token_type, info, info.size, rlength)
827
+
828
+ if !bool && FFI.errno == ERROR_INSUFFICIENT_BUFFER
829
+ info = FFI::MemoryPointer.new(rlength.read_ulong)
830
+ rlength.clear
831
+ bool = GetTokenInformation(token, token_type, info, info.size, rlength)
832
+
833
+ if bool
834
+ if token_type == TokenUser
835
+ info = TOKEN_USER.new(info)
836
+ else
837
+ info = TOKEN_GROUP.new(info)
838
+ end
839
+ end
840
+ end
841
+
842
+ raise SystemCallError.new('GetTokenInformation', FFI.errno) unless bool
843
+
844
+ if token_type == TokenUser
845
+ tsid = info[:User][:Sid]
846
+ else
847
+ tsid = info[:Groups][0][:Sid]
848
+ end
849
+
850
+ ptr = FFI::MemoryPointer.new(:string)
851
+
852
+ unless ConvertSidToStringSid(tsid, ptr)
853
+ raise SystemCallError.new("ConvertSidToStringSid")
854
+ end
855
+
856
+ sid = ptr.read_pointer.read_string
857
+ ensure
858
+ CloseHandle(token)
859
+ end
860
+
861
+ sid
862
+ end
863
+
864
+ # Returns whether or not the current process has given access rights for +path+.
865
+ #
866
+ def access_check(path, access_rights)
867
+ wfile = path.wincode
868
+ check = false
869
+ size_needed_ptr = FFI::MemoryPointer.new(:ulong)
870
+
871
+ flags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
872
+ DACL_SECURITY_INFORMATION
873
+
874
+ # First attempt, get the size needed
875
+ bool = GetFileSecurity(wfile, flags, nil, 0, size_needed_ptr)
876
+
877
+ # If it fails horribly here, assume the answer is no.
878
+ if !bool && FFI.errno != ERROR_INSUFFICIENT_BUFFER
879
+ return false
880
+ end
881
+
882
+ size_needed = size_needed_ptr.read_ulong
883
+ security_ptr = FFI::MemoryPointer.new(size_needed)
884
+
885
+ # Second attempt, now with the needed size
886
+ if GetFileSecurity(wfile, flags, security_ptr, size_needed, size_needed_ptr)
887
+ token = FFI::MemoryPointer.new(get_ptr_type)
888
+
889
+ pflags = TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ
890
+
891
+ if OpenProcessToken(GetCurrentProcess(), pflags, token)
892
+ begin
893
+ token = token.read_pointer.to_i
894
+ token2 = FFI::MemoryPointer.new(get_ptr_type)
895
+
896
+ if DuplicateToken(token, SecurityImpersonation, token2)
897
+ begin
898
+ token2 = token2.read_pointer.to_i
899
+ mapping = GENERIC_MAPPING.new
900
+ privileges = PRIVILEGE_SET.new
901
+ privileges[:PrivilegeCount] = 0
902
+ privileges_length = privileges.size
903
+
904
+ mapping[:GenericRead] = FILE_GENERIC_READ
905
+ mapping[:GenericWrite] = FILE_GENERIC_WRITE
906
+ mapping[:GenericExecute] = FILE_GENERIC_EXECUTE
907
+ mapping[:GenericAll] = FILE_ALL_ACCESS
908
+
909
+ rights_ptr = FFI::MemoryPointer.new(:ulong)
910
+ rights_ptr.write_ulong(access_rights)
911
+
912
+ MapGenericMask(rights_ptr, mapping)
913
+ rights = rights_ptr.read_ulong
914
+
915
+ result_ptr = FFI::MemoryPointer.new(:ulong)
916
+ privileges_length_ptr = FFI::MemoryPointer.new(:ulong)
917
+ privileges_length_ptr.write_ulong(privileges_length)
918
+ granted_access_ptr = FFI::MemoryPointer.new(:ulong)
919
+
920
+ bool = AccessCheck(
921
+ security_ptr,
922
+ token2,
923
+ rights,
924
+ mapping,
925
+ privileges,
926
+ privileges_length_ptr,
927
+ granted_access_ptr,
928
+ result_ptr
929
+ )
930
+
931
+ if bool
932
+ check = result_ptr.read_ulong == 1
933
+ else
934
+ raise SystemCallError.new('AccessCheck', FFI.errno)
935
+ end
936
+ ensure
937
+ CloseHandle(token2)
938
+ end
939
+ end
940
+ ensure
941
+ CloseHandle(token)
942
+ end
943
+ end
944
+ end
945
+
946
+ check
947
+ end
948
+
949
+ # Returns whether or not the Everyone has given access rights for +path+.
950
+ #
951
+ def access_check_world(path, access_rights)
952
+ wfile = path.wincode
953
+ check = false
954
+ size_needed_ptr = FFI::MemoryPointer.new(:ulong)
955
+
956
+ flags = DACL_SECURITY_INFORMATION
957
+
958
+ # First attempt, get the size needed
959
+ bool = GetFileSecurity(wfile, flags, nil, 0, size_needed_ptr)
960
+
961
+ # If it fails horribly here, assume the answer is no.
962
+ if !bool && FFI.errno != ERROR_INSUFFICIENT_BUFFER
963
+ return false
964
+ end
965
+
966
+ size_needed = size_needed_ptr.read_ulong
967
+ security_ptr = FFI::MemoryPointer.new(size_needed)
968
+
969
+ # Second attempt, now with the needed size
970
+ if GetFileSecurity(wfile, flags, security_ptr, size_needed, size_needed_ptr)
971
+ present_ptr = FFI::MemoryPointer.new(:ulong)
972
+ pdacl_ptr = FFI::MemoryPointer.new(:pointer)
973
+ defaulted_ptr = FFI::MemoryPointer.new(:ulong)
974
+
975
+ bool = GetSecurityDescriptorDacl(
976
+ security_ptr,
977
+ present_ptr,
978
+ pdacl_ptr,
979
+ defaulted_ptr
980
+ )
981
+
982
+ # If it fails, or the dacl isn't present, return false.
983
+ if !bool || present_ptr.read_ulong == 0
984
+ return false
985
+ end
986
+
987
+ pdacl = pdacl_ptr.read_pointer
988
+ psid_ptr = FFI::MemoryPointer.new(:pointer)
989
+
990
+ # S-1-1-0 is the well known SID for "Everyone".
991
+ ConvertStringSidToSid('S-1-1-0', psid_ptr)
992
+
993
+ psid = psid_ptr.read_pointer
994
+ trustee_ptr = FFI::MemoryPointer.new(TRUSTEE)
995
+
996
+ BuildTrusteeWithSid(trustee_ptr, psid)
997
+
998
+ rights_ptr = FFI::MemoryPointer.new(:ulong)
999
+
1000
+ if GetEffectiveRightsFromAcl(pdacl, trustee_ptr, rights_ptr) == NO_ERROR
1001
+ rights = rights_ptr.read_ulong
1002
+ check = (rights & access_rights) == access_rights
1003
+ end
1004
+ end
1005
+
1006
+ check
1007
+ end
1008
+ end