@@ -6,17 +6,15 @@ use crate::tpm::Swtpm;
6
6
use crate :: util:: command_to_string;
7
7
use crate :: { net, platform} ;
8
8
use anyhow:: { bail, Context , Result } ;
9
+ use ovmf_prebuilt:: { FileType , Prebuilt , Source } ;
9
10
use regex:: bytes:: Regex ;
10
11
use serde_json:: { json, Value } ;
11
- use sha2:: { Digest , Sha256 } ;
12
12
use std:: env;
13
13
use std:: ffi:: OsString ;
14
- use std:: io:: { BufRead , BufReader , Cursor , Read , Write } ;
14
+ use std:: io:: { BufRead , BufReader , Read , Write } ;
15
15
use std:: path:: { Path , PathBuf } ;
16
16
use std:: process:: { Child , Command , Stdio } ;
17
- use tar:: Archive ;
18
17
use tempfile:: TempDir ;
19
- use ureq:: Agent ;
20
18
#[ cfg( target_os = "linux" ) ]
21
19
use { std:: fs:: Permissions , std:: os:: unix:: fs:: PermissionsExt } ;
22
20
@@ -38,161 +36,41 @@ const ENV_VAR_OVMF_VARS: &str = "OVMF_VARS";
38
36
/// Environment variable for overriding the path of the OVMF shell file.
39
37
const ENV_VAR_OVMF_SHELL : & str = "OVMF_SHELL" ;
40
38
41
- /// Download `url` and return the raw data.
42
- fn download_url ( url : & str ) -> Result < Vec < u8 > > {
43
- let agent: Agent = ureq:: AgentBuilder :: new ( )
44
- . user_agent ( "uefi-rs-ovmf-downloader" )
45
- . build ( ) ;
46
-
47
- // Limit the size of the download.
48
- let max_size_in_bytes = 5 * 1024 * 1024 ;
49
-
50
- // Download the file.
51
- println ! ( "downloading {url}" ) ;
52
- let resp = agent. get ( url) . call ( ) ?;
53
- let mut data = Vec :: with_capacity ( max_size_in_bytes) ;
54
- resp. into_reader ( )
55
- . take ( max_size_in_bytes. try_into ( ) . unwrap ( ) )
56
- . read_to_end ( & mut data) ?;
57
- println ! ( "received {} bytes" , data. len( ) ) ;
58
-
59
- Ok ( data)
60
- }
61
-
62
- // Extract the tarball's files into `prebuilt_dir`.
63
- //
64
- // `tarball_data` is raw decompressed tar data.
65
- fn extract_prebuilt ( tarball_data : & [ u8 ] , prebuilt_dir : & Path ) -> Result < ( ) > {
66
- let cursor = Cursor :: new ( tarball_data) ;
67
- let mut archive = Archive :: new ( cursor) ;
68
-
69
- // Extract each file entry.
70
- for entry in archive. entries ( ) ? {
71
- let mut entry = entry?;
72
-
73
- // Skip directories.
74
- if entry. size ( ) == 0 {
75
- continue ;
39
+ impl From < UefiArch > for ovmf_prebuilt:: Arch {
40
+ fn from ( arch : UefiArch ) -> Self {
41
+ match arch {
42
+ UefiArch :: AArch64 => Self :: Aarch64 ,
43
+ UefiArch :: IA32 => Self :: Ia32 ,
44
+ UefiArch :: X86_64 => Self :: X64 ,
76
45
}
77
-
78
- let path = entry. path ( ) ?;
79
- // Strip the leading directory, which is the release name.
80
- let path: PathBuf = path. components ( ) . skip ( 1 ) . collect ( ) ;
81
-
82
- let dir = path. parent ( ) . unwrap ( ) ;
83
- let dst_dir = prebuilt_dir. join ( dir) ;
84
- let dst_path = prebuilt_dir. join ( path) ;
85
- println ! ( "unpacking to {}" , dst_path. display( ) ) ;
86
- fs_err:: create_dir_all ( dst_dir) ?;
87
- entry. unpack ( dst_path) ?;
88
46
}
89
-
90
- Ok ( ( ) )
91
47
}
92
48
93
- /// Update the local copy of the prebuilt OVMF files. Does nothing if the local
94
- /// copy is already up to date.
95
- fn update_prebuilt ( ) -> Result < PathBuf > {
96
- let prebuilt_dir = Path :: new ( OVMF_PREBUILT_DIR ) ;
97
- let hash_path = prebuilt_dir . join ( "sha256" ) ;
98
-
99
- // Check if the hash file already has the expected hash in it. If so, assume
100
- // that we've already got the correct prebuilt downloaded and unpacked.
101
- if let Ok ( current_hash ) = fs_err :: read_to_string ( & hash_path ) {
102
- if current_hash == OVMF_PREBUILT_HASH {
103
- return Ok ( prebuilt_dir . to_path_buf ( ) ) ;
49
+ /// Get a user-provided path for the given OVMF file type.
50
+ ///
51
+ /// This uses the command-line arg if present, otherwise it falls back to an
52
+ /// environment variable. If neither is present, returns `None`.
53
+ fn get_user_provided_path ( file_type : FileType , opt : & QemuOpt ) -> Option < PathBuf > {
54
+ let opt_path ;
55
+ let var_name ;
56
+ match file_type {
57
+ FileType :: Code => {
58
+ opt_path = & opt . ovmf_code ;
59
+ var_name = ENV_VAR_OVMF_CODE ;
104
60
}
105
- }
106
-
107
- let base_url = "https://github.com/rust-osdev/ovmf-prebuilt/releases/download" ;
108
- let url = format ! (
109
- "{base_url}/{release}/{release}-bin.tar.xz" ,
110
- release = OVMF_PREBUILT_TAG
111
- ) ;
112
-
113
- let data = download_url ( & url) ?;
114
-
115
- // Validate the hash.
116
- let actual_hash = format ! ( "{:x}" , Sha256 :: digest( & data) ) ;
117
- if actual_hash != OVMF_PREBUILT_HASH {
118
- bail ! (
119
- "file hash {actual_hash} does not match {}" ,
120
- OVMF_PREBUILT_HASH
121
- ) ;
122
- }
123
-
124
- // Unpack the tarball.
125
- println ! ( "decompressing tarball" ) ;
126
- let mut decompressed = Vec :: new ( ) ;
127
- let mut compressed = Cursor :: new ( data) ;
128
- lzma_rs:: xz_decompress ( & mut compressed, & mut decompressed) ?;
129
-
130
- // Clear out the existing prebuilt dir, if present.
131
- let _ = fs_err:: remove_dir_all ( prebuilt_dir) ;
132
-
133
- // Extract the files.
134
- extract_prebuilt ( & decompressed, prebuilt_dir) ?;
135
-
136
- // Rename the x64 directory to x86_64, to match `Arch::as_str`.
137
- fs_err:: rename ( prebuilt_dir. join ( "x64" ) , prebuilt_dir. join ( "x86_64" ) ) ?;
138
-
139
- // Write out the hash file. When we upgrade to a new release of
140
- // ovmf-prebuilt, the hash will no longer match, triggering a fresh
141
- // download.
142
- fs_err:: write ( & hash_path, actual_hash) ?;
143
-
144
- Ok ( prebuilt_dir. to_path_buf ( ) )
145
- }
146
-
147
- #[ derive( Clone , Copy , Debug ) ]
148
- enum OvmfFileType {
149
- Code ,
150
- Vars ,
151
- Shell ,
152
- }
153
-
154
- impl OvmfFileType {
155
- fn as_str ( & self ) -> & ' static str {
156
- match self {
157
- Self :: Code => "code" ,
158
- Self :: Vars => "vars" ,
159
- Self :: Shell => "shell" ,
61
+ FileType :: Vars => {
62
+ opt_path = & opt. ovmf_vars ;
63
+ var_name = ENV_VAR_OVMF_VARS ;
160
64
}
161
- }
162
-
163
- fn extension ( & self ) -> & ' static str {
164
- match self {
165
- Self :: Code | Self :: Vars => "fd" ,
166
- Self :: Shell => "efi" ,
65
+ FileType :: Shell => {
66
+ opt_path = & None ;
67
+ var_name = ENV_VAR_OVMF_SHELL ;
167
68
}
168
69
}
169
-
170
- /// Get a user-provided path for the given OVMF file type.
171
- ///
172
- /// This uses the command-line arg if present, otherwise it falls back to an
173
- /// environment variable. If neither is present, returns `None`.
174
- fn get_user_provided_path ( self , opt : & QemuOpt ) -> Option < PathBuf > {
175
- let opt_path;
176
- let var_name;
177
- match self {
178
- Self :: Code => {
179
- opt_path = & opt. ovmf_code ;
180
- var_name = ENV_VAR_OVMF_CODE ;
181
- }
182
- Self :: Vars => {
183
- opt_path = & opt. ovmf_vars ;
184
- var_name = ENV_VAR_OVMF_VARS ;
185
- }
186
- Self :: Shell => {
187
- opt_path = & None ;
188
- var_name = ENV_VAR_OVMF_SHELL ;
189
- }
190
- }
191
- if let Some ( path) = opt_path {
192
- Some ( path. clone ( ) )
193
- } else {
194
- env:: var_os ( var_name) . map ( PathBuf :: from)
195
- }
70
+ if let Some ( path) = opt_path {
71
+ Some ( path. clone ( ) )
72
+ } else {
73
+ env:: var_os ( var_name) . map ( PathBuf :: from)
196
74
}
197
75
}
198
76
@@ -210,8 +88,8 @@ impl OvmfPaths {
210
88
/// 1. Command-line arg
211
89
/// 2. Environment variable
212
90
/// 3. Prebuilt file (automatically downloaded)
213
- fn find_ovmf_file ( file_type : OvmfFileType , opt : & QemuOpt , arch : UefiArch ) -> Result < PathBuf > {
214
- if let Some ( path) = file_type . get_user_provided_path ( opt) {
91
+ fn find_ovmf_file ( file_type : FileType , opt : & QemuOpt , arch : UefiArch ) -> Result < PathBuf > {
92
+ if let Some ( path) = get_user_provided_path ( file_type , opt) {
215
93
// The user provided an exact path to use; verify that it
216
94
// exists.
217
95
if path. exists ( ) {
@@ -224,22 +102,21 @@ impl OvmfPaths {
224
102
) ;
225
103
}
226
104
} else {
227
- let prebuilt_dir = update_prebuilt ( ) ?;
105
+ let prebuilt = Prebuilt :: fetch ( Source {
106
+ tag : OVMF_PREBUILT_TAG ,
107
+ sha256 : OVMF_PREBUILT_HASH ,
108
+ } , OVMF_PREBUILT_DIR ) ?;
228
109
229
- Ok ( prebuilt_dir. join ( format ! (
230
- "{arch}/{}.{}" ,
231
- file_type. as_str( ) ,
232
- file_type. extension( )
233
- ) ) )
110
+ Ok ( prebuilt. get_file ( arch. into ( ) , file_type) )
234
111
}
235
112
}
236
113
237
114
/// Find path to OVMF files by the strategy documented for
238
115
/// [`Self::find_ovmf_file`].
239
116
fn find ( opt : & QemuOpt , arch : UefiArch ) -> Result < Self > {
240
- let code = Self :: find_ovmf_file ( OvmfFileType :: Code , opt, arch) ?;
241
- let vars = Self :: find_ovmf_file ( OvmfFileType :: Vars , opt, arch) ?;
242
- let shell = Self :: find_ovmf_file ( OvmfFileType :: Shell , opt, arch) ?;
117
+ let code = Self :: find_ovmf_file ( FileType :: Code , opt, arch) ?;
118
+ let vars = Self :: find_ovmf_file ( FileType :: Vars , opt, arch) ?;
119
+ let shell = Self :: find_ovmf_file ( FileType :: Shell , opt, arch) ?;
243
120
244
121
Ok ( Self { code, vars, shell } )
245
122
}
0 commit comments