@@ -37,14 +37,15 @@ use anyhow::Context;
37
37
use tempfile:: NamedTempFile ;
38
38
39
39
pub use bootloader_boot_config:: BootConfig ;
40
+ use crate :: file_data_source:: FileDataSource ;
40
41
41
42
const KERNEL_FILE_NAME : & str = "kernel-x86_64" ;
42
43
const RAMDISK_FILE_NAME : & str = "ramdisk" ;
43
44
const CONFIG_FILE_NAME : & str = "boot.json" ;
44
45
45
46
#[ derive( Clone ) ]
46
47
struct DiskImageFile {
47
- source : PathBuf ,
48
+ source : FileDataSource ,
48
49
destination : String ,
49
50
}
50
51
@@ -69,64 +70,48 @@ impl DiskImageBuilder {
69
70
70
71
/// Add or replace a kernel to be included in the final image.
71
72
pub fn set_kernel ( & mut self , path : & Path ) -> & mut Self {
72
- self . add_or_replace_file ( path, KERNEL_FILE_NAME )
73
+ self . add_or_replace_file ( FileDataSource :: File ( path. to_path_buf ( ) ) , KERNEL_FILE_NAME )
73
74
}
74
75
75
76
/// Add or replace a ramdisk to be included in the final image.
76
77
pub fn set_ramdisk ( & mut self , path : & Path ) -> & mut Self {
77
- self . add_or_replace_file ( path, RAMDISK_FILE_NAME )
78
+ self . add_or_replace_file ( FileDataSource :: File ( path. to_path_buf ( ) ) , RAMDISK_FILE_NAME )
78
79
}
79
80
80
81
/// Configures the runtime behavior of the bootloader.
81
82
pub fn set_boot_config ( & mut self , boot_config : & BootConfig ) -> & mut Self {
82
83
let json =
83
84
serde_json:: to_string_pretty ( boot_config) . expect ( "failed to serialize BootConfig" ) ;
84
85
let bytes = json. as_bytes ( ) ;
85
- self . add_or_replace_file_byte_content ( bytes, CONFIG_FILE_NAME )
86
+ self . add_or_replace_file ( FileDataSource :: Data ( bytes. to_vec ( ) ) , CONFIG_FILE_NAME )
86
87
}
87
-
88
- /// Add or replace a file from a byte array
89
- pub fn add_or_replace_file_byte_content ( & mut self , data : & [ u8 ] , target : & str ) -> & mut Self {
90
- let temp_path = temp_dir ( ) ;
91
- let file_name = temp_path. join ( "bytes.tmp" ) ;
92
- fs:: create_dir_all ( temp_path) . expect ( "Failed to create temp directory" ) ;
93
- let mut temp_file =
94
- fs:: File :: create ( file_name. clone ( ) ) . expect ( "Failed to create temp file" ) ;
95
- temp_file
96
- . write_all ( data)
97
- . expect ( "Failed to write data to temp file" ) ;
98
- temp_file
99
- . sync_all ( )
100
- . expect ( "Failed to flush temp file to disk" ) ;
101
-
102
- self . add_or_replace_file ( & file_name, target)
103
- }
104
-
88
+
105
89
/// Add or replace arbitrary files.
106
- /// NOTE: You can overwrite internal files if you choose, such as EFI/BOOT/BOOTX64.EFI
107
- /// This can be useful in situations where you want to generate an image, but not use the provided bootloader.
108
- pub fn add_or_replace_file ( & mut self , path : & Path , target : & str ) -> & mut Self {
90
+ pub fn add_or_replace_file ( & mut self , file_data_source : FileDataSource , target : & str ) -> & mut Self {
109
91
self . files . insert (
110
92
0 ,
111
93
DiskImageFile {
112
- source : path . to_path_buf ( ) ,
94
+ source : file_data_source ,
113
95
destination : target. to_string ( ) ,
114
96
} ,
115
97
) ;
116
98
self
117
99
}
118
100
fn create_fat_filesystem_image (
119
101
& self ,
120
- internal_files : BTreeMap < & str , & Path > ,
102
+ internal_files : BTreeMap < & str , FileDataSource > ,
121
103
) -> anyhow:: Result < NamedTempFile > {
122
104
let mut local_map = BTreeMap :: new ( ) ;
123
105
124
- for k in internal_files {
125
- local_map. insert ( k . 0 , k . 1 ) ;
106
+ for f in self . files . as_slice ( ) {
107
+ local_map. insert ( f . destination . as_str ( ) , f . source . clone ( ) ) ;
126
108
}
127
109
128
- for f in self . files . as_slice ( ) {
129
- local_map. insert ( & f. destination , f. source . as_path ( ) ) ;
110
+
111
+ for k in internal_files {
112
+ if let Some ( _) = local_map. insert ( k. 0 , k. 1 ) {
113
+ return Err ( anyhow:: Error :: msg ( format ! ( "Attempted to overwrite internal file: {}" , k. 0 ) ) ) ;
114
+ }
130
115
}
131
116
132
117
let out_file = NamedTempFile :: new ( ) . context ( "failed to create temp file" ) ?;
@@ -145,8 +130,8 @@ impl DiskImageBuilder {
145
130
let stage_3_path = Path :: new ( env ! ( "BIOS_STAGE_3_PATH" ) ) ;
146
131
let stage_4_path = Path :: new ( env ! ( "BIOS_STAGE_4_PATH" ) ) ;
147
132
let mut internal_files = BTreeMap :: new ( ) ;
148
- internal_files. insert ( BIOS_STAGE_3 , stage_3_path) ;
149
- internal_files. insert ( BIOS_STAGE_4 , stage_4_path) ;
133
+ internal_files. insert ( BIOS_STAGE_3 , FileDataSource :: File ( stage_3_path. to_path_buf ( ) ) ) ;
134
+ internal_files. insert ( BIOS_STAGE_4 , FileDataSource :: File ( stage_4_path. to_path_buf ( ) ) ) ;
150
135
151
136
let fat_partition = self
152
137
. create_fat_filesystem_image ( internal_files)
@@ -171,7 +156,7 @@ impl DiskImageBuilder {
171
156
const UEFI_BOOT_FILENAME : & str = "efi/boot/bootx64.efi" ;
172
157
let bootloader_path = Path :: new ( env ! ( "UEFI_BOOTLOADER_PATH" ) ) ;
173
158
let mut internal_files = BTreeMap :: new ( ) ;
174
- internal_files. insert ( UEFI_BOOT_FILENAME , bootloader_path) ;
159
+ internal_files. insert ( UEFI_BOOT_FILENAME , FileDataSource :: File ( bootloader_path. to_path_buf ( ) ) ) ;
175
160
let fat_partition = self
176
161
. create_fat_filesystem_image ( internal_files)
177
162
. context ( "failed to create FAT partition" ) ?;
@@ -189,11 +174,11 @@ impl DiskImageBuilder {
189
174
pub fn create_uefi_tftp_folder ( & self , tftp_path : & Path ) -> anyhow:: Result < ( ) > {
190
175
const UEFI_TFTP_BOOT_FILENAME : & str = "bootloader" ;
191
176
let bootloader_path = Path :: new ( env ! ( "UEFI_BOOTLOADER_PATH" ) ) ;
192
- std :: fs:: create_dir_all ( tftp_path)
177
+ fs:: create_dir_all ( tftp_path)
193
178
. with_context ( || format ! ( "failed to create out dir at {}" , tftp_path. display( ) ) ) ?;
194
179
195
180
let to = tftp_path. join ( UEFI_TFTP_BOOT_FILENAME ) ;
196
- std :: fs:: copy ( bootloader_path, & to) . with_context ( || {
181
+ fs:: copy ( bootloader_path, & to) . with_context ( || {
197
182
format ! (
198
183
"failed to copy bootloader from {} to {}" ,
199
184
bootloader_path. display( ) ,
@@ -203,7 +188,15 @@ impl DiskImageBuilder {
203
188
204
189
for f in self . files . as_slice ( ) {
205
190
let to = tftp_path. join ( f. destination . clone ( ) ) ;
206
- std:: fs:: copy ( f. source . clone ( ) , to) ?;
191
+
192
+ let mut new_file = fs:: OpenOptions :: new ( )
193
+ . read ( true )
194
+ . write ( true )
195
+ . create ( true )
196
+ . truncate ( true )
197
+ . open ( to) ?;
198
+
199
+ f. source . copy_to ( & mut new_file) ?;
207
200
}
208
201
209
202
Ok ( ( ) )
0 commit comments