@@ -34,19 +34,23 @@ def update_guest(machine)
34
34
def update_host
35
35
# copy and modify hosts file on host with Vagrant-managed entries
36
36
file = @global_env . tmp_path . join ( 'hosts.local' )
37
- # add a "if windows..."
38
- hosts_location = '/etc/hosts'
39
- copy_cmd = 'sudo cp'
40
- # handles the windows hosts file...
41
- if ENV [ 'SystemRoot' ] != nil
37
+
38
+ if WindowsSupport . windows?
39
+ # lazily include windows Module
40
+ class << self
41
+ include WindowsSupport unless include? WindowsSupport
42
+ end
43
+
42
44
hosts_location = "#{ ENV [ 'WINDIR' ] } \\ System32\\ drivers\\ etc\\ hosts"
43
- copy_cmd = 'cp'
45
+ copy_proc = Proc . new { windows_copy_file ( file , hosts_location ) }
46
+ else
47
+ hosts_location = '/etc/hosts'
48
+ copy_proc = Proc . new { `sudo cp #{ file } #{ hosts_location } ` }
44
49
end
50
+
45
51
FileUtils . cp ( hosts_location , file )
46
52
update_file ( file )
47
-
48
- # copy modified file using sudo for permission
49
- `#{ copy_cmd } #{ file } #{ hosts_location } `
53
+ copy_proc . call
50
54
end
51
55
52
56
private
@@ -122,6 +126,45 @@ def get_machines
122
126
@global_env . active_machines
123
127
end
124
128
end
129
+
130
+ ## Windows support for copying files, requesting elevated privileges if necessary
131
+ module WindowsSupport
132
+ require 'rbconfig'
133
+
134
+ def self . windows?
135
+ RbConfig ::CONFIG [ 'host_os' ] =~ /mswin|mingw|cygwin/
136
+ end
137
+
138
+ require 'win32ole' if windows?
139
+
140
+ def windows_copy_file ( source , dest )
141
+ begin
142
+ # First, try Ruby copy
143
+ FileUtils . cp ( source , dest )
144
+ rescue Errno ::EACCES
145
+ # Access denied, try with elevated privileges
146
+ windows_copy_file_elevated ( source , dest )
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def windows_copy_file_elevated ( source , dest )
153
+ # copy command only supports backslashes as separators
154
+ source , dest = [ source , dest ] . map { |s | s . to_s . gsub ( /\/ / , '\\' ) }
155
+
156
+ # run 'cmd /C copy ...' with elevated privilege, minimized
157
+ copy_cmd = "copy \" #{ source } \" \" #{ dest } \" "
158
+ WIN32OLE . new ( 'Shell.Application' ) . ShellExecute ( 'cmd' , "/C #{ copy_cmd } " , nil , 'runas' , 7 )
159
+
160
+ # Unfortunately, ShellExecute does not give us a status code,
161
+ # and it is non-blocking so we can't reliably compare the file contents
162
+ # to see if they were copied.
163
+ #
164
+ # If the user rejects the UAC prompt, vagrant will silently continue
165
+ # without updating the hostsfile.
166
+ end
167
+ end
125
168
end
126
169
end
127
170
end
0 commit comments