@@ -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,43 @@ 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
+ def self . windows?
133
+ ENV [ 'OS' ] === 'Windows_NT'
134
+ end
135
+
136
+ require 'win32ole' if windows?
137
+
138
+ def windows_copy_file ( source , dest )
139
+ begin
140
+ # First, try Ruby copy
141
+ FileUtils . cp ( source , dest )
142
+ rescue Errno ::EACCES
143
+ # Access denied, try with elevated privileges
144
+ windows_copy_file_elevated ( source , dest )
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ def windows_copy_file_elevated ( source , dest )
151
+ # copy command only supports backslashes as separators
152
+ source , dest = [ source , dest ] . map { |s | s . to_s . gsub ( /\/ / , '\\' ) }
153
+
154
+ # run 'cmd /C copy ...' with elevated privilege, minimized
155
+ copy_cmd = "copy \" #{ source } \" \" #{ dest } \" "
156
+ WIN32OLE . new ( 'Shell.Application' ) . ShellExecute ( 'cmd' , "/C #{ copy_cmd } " , nil , 'runas' , 7 )
157
+
158
+ # Unfortunately, ShellExecute does not give us a status code,
159
+ # and it is non-blocking so we can't reliably compare the file contents
160
+ # to see if they were copied.
161
+ #
162
+ # If the user rejects the UAC prompt, vagrant will silently continue
163
+ # without updating the hostsfile.
164
+ end
165
+ end
125
166
end
126
167
end
127
168
end
0 commit comments