]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/EfiLdrImage/EfiLdrImage.c
There is a limitation on WINDOWS OS for the length of entire file path can’t be large...
[mirror_edk2.git] / BaseTools / Source / C / EfiLdrImage / EfiLdrImage.c
1 /** @file
2
3 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 efildrimage.c
15
16 Abstract:
17
18 Creates and EFILDR image.
19 This tool combines several PE Image files together using following format denoted as EBNF:
20 FILE := EFILDR_HEADER
21 EFILDR_IMAGE +
22 <PeImageFileContent> +
23 The order of EFILDR_IMAGE is same as the order of placing PeImageFileContent.
24
25 Revision History
26
27 **/
28
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "ParseInf.h"
34 #include "CommonLib.h"
35 #include "EfiUtilityMsgs.h"
36
37 #define MAX_PE_IMAGES 63
38 #define FILE_TYPE_FIXED_LOADER 0
39 #define FILE_TYPE_RELOCATABLE_PE_IMAGE 1
40
41 typedef struct {
42 UINT32 CheckSum;
43 UINT32 Offset;
44 UINT32 Length;
45 UINT8 FileName[52];
46 } EFILDR_IMAGE;
47
48 typedef struct {
49 UINT32 Signature;
50 UINT32 HeaderCheckSum;
51 UINT32 FileLength;
52 UINT32 NumberOfImages;
53 } EFILDR_HEADER;
54
55 //
56 // Utility Name
57 //
58 #define UTILITY_NAME "EfiLdrImage"
59
60 //
61 // Utility version information
62 //
63 #define UTILITY_MAJOR_VERSION 0
64 #define UTILITY_MINOR_VERSION 1
65
66 void
67 Version (
68 void
69 )
70 /*++
71
72 Routine Description:
73
74 Displays the standard utility information to SDTOUT
75
76 Arguments:
77
78 None
79
80 Returns:
81
82 None
83
84 --*/
85 {
86 printf ("%s v%d.%d %s -Utility to break a file into two pieces at the request offset.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
87 printf ("Copyright (c) 1999-2014 Intel Corporation. All rights reserved.\n");
88 }
89
90 VOID
91 Usage (
92 VOID
93 )
94 {
95 printf ("Usage: EfiLdrImage -o OutImage LoaderImage PeImage1 PeImage2 ... PeImageN\n");
96 exit (1);
97 }
98
99 EFI_STATUS
100 CountVerboseLevel (
101 IN CONST CHAR8* VerboseLevelString,
102 IN CONST UINT64 Length,
103 OUT UINT64 *ReturnValue
104 )
105 {
106 UINT64 i = 0;
107 for (;i < Length; ++i) {
108 if (VerboseLevelString[i] != 'v' && VerboseLevelString[i] != 'V') {
109 return EFI_ABORTED;
110 }
111 ++(*ReturnValue);
112 }
113
114 return EFI_SUCCESS;
115 }
116
117 UINT64
118 FCopyFile (
119 FILE *in,
120 FILE *out
121 )
122 /*++
123 Routine Description:
124 Write all the content of input file to output file.
125
126 Arguments:
127 in - input file pointer
128 out - output file pointer
129
130 Return:
131 UINT64 : file size of input file
132 --*/
133 {
134 UINT32 filesize, offset, length;
135 CHAR8 Buffer[8*1024];
136
137 fseek (in, 0, SEEK_END);
138 filesize = ftell(in);
139
140 fseek (in, 0, SEEK_SET);
141
142 offset = 0;
143 while (offset < filesize) {
144 length = sizeof(Buffer);
145 if (filesize-offset < length) {
146 length = filesize-offset;
147 }
148
149 fread (Buffer, length, 1, in);
150 fwrite (Buffer, length, 1, out);
151 offset += length;
152 }
153
154 return filesize;
155 }
156
157
158 int
159 main (
160 int argc,
161 char *argv[]
162 )
163 /*++
164
165 Routine Description:
166
167
168 Arguments:
169
170
171 Returns:
172
173
174 --*/
175 {
176 UINT64 i;
177 UINT64 filesize;
178 FILE *fpIn, *fpOut;
179 EFILDR_HEADER EfiLdrHeader;
180 EFILDR_IMAGE EfiLdrImage[MAX_PE_IMAGES];
181 CHAR8* OutputFileName = NULL;
182 CHAR8* InputFileNames[MAX_PE_IMAGES + 1];
183 UINT8 InputFileCount = 0;
184 UINT64 DebugLevel = 0;
185 UINT64 VerboseLevel = 0;
186 EFI_STATUS Status = EFI_SUCCESS;
187
188 SetUtilityName (UTILITY_NAME);
189
190 if (argc == 1) {
191 Usage();
192 return STATUS_ERROR;
193 }
194
195 argc --;
196 argv ++;
197
198 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
199 Usage();
200 return STATUS_SUCCESS;
201 }
202
203 if (stricmp (argv[0], "--version") == 0) {
204 Version();
205 return STATUS_SUCCESS;
206 }
207
208 while (argc > 0) {
209
210 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
211 OutputFileName = argv[1];
212 if (OutputFileName == NULL) {
213 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be null");
214 return STATUS_ERROR;
215 }
216 argc -= 2;
217 argv += 2;
218 continue;
219 }
220
221 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
222 argc --;
223 argv ++;
224 continue;
225 }
226
227 if ((strlen(argv[0]) >= 2 && argv[0][0] == '-' && (argv[0][1] == 'v' || argv[0][1] == 'V')) || (stricmp (argv[0], "--verbose") == 0)) {
228 VerboseLevel = 1;
229 if (strlen(argv[0]) > 2) {
230 Status = CountVerboseLevel (&argv[0][2], strlen(argv[0]) - 2, &VerboseLevel);
231 if (EFI_ERROR (Status)) {
232 Error (NULL, 0, 1003, "Invalid option value", argv[0]);
233 return STATUS_ERROR;
234 }
235 }
236
237 argc --;
238 argv ++;
239 continue;
240 }
241
242 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
243 Status = AsciiStringToUint64 (argv[1], FALSE, &DebugLevel);
244 if (EFI_ERROR (Status)) {
245 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
246 return STATUS_ERROR;
247 }
248 argc -= 2;
249 argv += 2;
250 continue;
251 }
252 //
253 // Don't recognize the parameter, should be regarded as the input file name.
254 //
255 InputFileNames[InputFileCount] = argv[0];
256 InputFileCount++;
257 argc--;
258 argv++;
259 }
260
261 if (InputFileCount == 0) {
262 Error (NULL, 0, 1001, "Missing option", "No input file");
263 return STATUS_ERROR;
264 }
265 //
266 // Open output file for write
267 //
268 if (OutputFileName == NULL) {
269 Error (NULL, 0, 1001, "Missing option", "No output file");
270 return STATUS_ERROR;
271 }
272
273 fpOut = fopen (LongFilePath (OutputFileName), "w+b");
274 if (!fpOut) {
275 Error (NULL, 0, 0001, "Could not open output file", OutputFileName);
276 return STATUS_ERROR;
277 }
278
279 memset (&EfiLdrHeader, 0, sizeof (EfiLdrHeader));
280 memset (&EfiLdrImage, 0, sizeof (EFILDR_IMAGE) * (InputFileCount));
281
282 memcpy (&EfiLdrHeader.Signature, "EFIL", 4);
283 EfiLdrHeader.FileLength = sizeof(EFILDR_HEADER) + sizeof(EFILDR_IMAGE)*(InputFileCount);
284
285 //
286 // Skip the file header first
287 //
288 fseek (fpOut, EfiLdrHeader.FileLength, SEEK_SET);
289
290 //
291 // copy all the input files to the output file
292 //
293 for(i=0;i<InputFileCount;i++) {
294 //
295 // Copy the content of PeImage file to output file
296 //
297 fpIn = fopen (LongFilePath (InputFileNames[i]), "rb");
298 if (!fpIn) {
299 Error (NULL, 0, 0001, "Could not open input file", InputFileNames[i]);
300 fclose (fpOut);
301 return STATUS_ERROR;
302 }
303 filesize = FCopyFile (fpIn, fpOut);
304 fclose(fpIn);
305
306 //
307 // And in the same time update the EfiLdrHeader and EfiLdrImage array
308 //
309 EfiLdrImage[i].Offset = EfiLdrHeader.FileLength;
310 EfiLdrImage[i].Length = (UINT32) filesize;
311 strncpy ((CHAR8*) EfiLdrImage[i].FileName, InputFileNames[i], sizeof (EfiLdrImage[i].FileName) - 1);
312 EfiLdrHeader.FileLength += (UINT32) filesize;
313 EfiLdrHeader.NumberOfImages++;
314 }
315
316 //
317 // Write the image header to the output file finally
318 //
319 fseek (fpOut, 0, SEEK_SET);
320 fwrite (&EfiLdrHeader, sizeof(EFILDR_HEADER) , 1, fpOut);
321 fwrite (&EfiLdrImage , sizeof(EFILDR_IMAGE)*(InputFileCount), 1, fpOut);
322
323 fclose (fpOut);
324 printf ("Created %s\n", OutputFileName);
325 return 0;
326 }
327