]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenBootSector/GenBootSector.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 / GenBootSector / GenBootSector.c
CommitLineData
30fdf114
LG
1/** @file\r
2\r
1be2ed90 3Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
40d841f6 4This program and the accompanying materials \r
30fdf114
LG
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 genbootsector.c\r
15 \r
16Abstract:\r
17 Reading/writing MBR/DBR.\r
18 NOTE:\r
19 If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written.\r
20 If we process DBR, we will patch MBR to set first partition active if no active partition exists.\r
21\r
22**/\r
23\r
24#include <windows.h>\r
25#include <stdio.h>\r
26#include <string.h>\r
27#include <Common/UefiBaseTypes.h>\r
28\r
fd171542 29#include "ParseInf.h"\r
30#include "EfiUtilityMsgs.h"\r
b36d134f 31#include "CommonLib.h"\r
fd171542 32\r
30fdf114
LG
33//\r
34// Utility Name\r
35//\r
36#define UTILITY_NAME "GenBootSector"\r
37\r
38//\r
39// Utility version information\r
40//\r
41#define UTILITY_MAJOR_VERSION 0\r
42#define UTILITY_MINOR_VERSION 1\r
43\r
44#define MAX_DRIVE 26\r
45#define PARTITION_TABLE_OFFSET 0x1BE\r
46\r
47#define SIZE_OF_PARTITION_ENTRY 0x10\r
48\r
49#define PARTITION_ENTRY_STARTLBA_OFFSET 8\r
50\r
51#define PARTITION_ENTRY_NUM 4\r
52\r
53INT\r
54GetDrvNumOffset (\r
55 IN VOID *BootSector\r
56 );\r
57\r
58typedef enum {\r
59 PatchTypeUnknown,\r
60 PatchTypeFloppy,\r
61 PatchTypeIde,\r
62 PatchTypeUsb,\r
63 PatchTypeFileImage // input and output are all file image, patching action is same as PatchTypeFloppy\r
64} PATCH_TYPE;\r
65\r
66typedef enum {\r
67 PathUnknown,\r
68 PathFile,\r
69 PathFloppy,\r
70 PathUsb,\r
71 PathIde\r
72} PATH_TYPE;\r
73\r
74typedef enum {\r
75 ErrorSuccess,\r
76 ErrorFileCreate,\r
77 ErrorFileReadWrite,\r
78 ErrorNoMbr,\r
79 ErrorFatType,\r
80 ErrorPath,\r
81} ERROR_STATUS;\r
82\r
83CHAR *ErrorStatusDesc[] = {\r
84 "Success",\r
85 "Failed to create files",\r
86 "Failed to read/write files",\r
87 "No MBR exists",\r
88 "Failed to detect Fat type",\r
89 "Inavlid path"\r
90};\r
91\r
92typedef struct _DRIVE_TYPE_DESC {\r
93 UINT Type;\r
94 CHAR *Description;\r
95} DRIVE_TYPE_DESC;\r
96\r
97#define DRIVE_TYPE_ITEM(x) {x, #x}\r
98DRIVE_TYPE_DESC DriveTypeDesc[] = {\r
99 DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),\r
100 DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),\r
101 DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),\r
102 DRIVE_TYPE_ITEM (DRIVE_FIXED),\r
103 DRIVE_TYPE_ITEM (DRIVE_REMOTE),\r
104 DRIVE_TYPE_ITEM (DRIVE_CDROM),\r
105 DRIVE_TYPE_ITEM (DRIVE_RAMDISK),\r
106 (UINT) -1, NULL\r
107};\r
108\r
109typedef struct _DRIVE_INFO {\r
110 CHAR VolumeLetter;\r
111 DRIVE_TYPE_DESC *DriveType;\r
112 UINT DiskNumber;\r
113} DRIVE_INFO;\r
114\r
115typedef struct _PATH_INFO {\r
116 CHAR *Path;\r
117 CHAR PhysicalPath[260];\r
118 PATH_TYPE Type;\r
119 BOOL Input;\r
120} PATH_INFO;\r
121\r
122#define BOOT_SECTOR_LBA_OFFSET 0x1FA\r
123\r
124#define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))\r
125\r
126BOOL\r
127GetDriveInfo (\r
128 CHAR VolumeLetter,\r
129 DRIVE_INFO *DriveInfo\r
130 )\r
131/*++\r
132Routine Description:\r
133 Get drive information including disk number and drive type,\r
134 where disknumber is useful for reading/writing disk raw data.\r
135 NOTE: Floppy disk doesn't have disk number but it doesn't matter because\r
136 we can reading/writing floppy disk without disk number.\r
137\r
138Arguments:\r
139 VolumeLetter : volume letter, e.g.: C for C:, A for A:\r
140 DriveInfo : pointer to DRIVE_INFO structure receiving drive information.\r
141\r
142Return:\r
143 TRUE : successful\r
144 FALSE : failed\r
145--*/\r
146{\r
147 HANDLE VolumeHandle;\r
148 STORAGE_DEVICE_NUMBER StorageDeviceNumber;\r
149 DWORD BytesReturned;\r
150 BOOL Success;\r
151 UINT DriveType;\r
152 UINT Index;\r
153\r
154 CHAR RootPath[] = "X:\\"; // "X:\" -> for GetDriveType\r
155 CHAR VolumeAccessPath[] = "\\\\.\\X:"; // "\\.\X:" -> to open the volume\r
156\r
157 RootPath[0] = VolumeAccessPath[4] = VolumeLetter;\r
158 DriveType = GetDriveType(RootPath);\r
159 if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) {\r
160 return FALSE;\r
161 }\r
162\r
163 DriveInfo->VolumeLetter = VolumeLetter;\r
164 VolumeHandle = CreateFile (\r
165 VolumeAccessPath,\r
166 0,\r
167 FILE_SHARE_READ | FILE_SHARE_WRITE,\r
168 NULL,\r
169 OPEN_EXISTING,\r
170 0,\r
171 NULL\r
172 );\r
173 if (VolumeHandle == INVALID_HANDLE_VALUE) {\r
174 fprintf (\r
175 stderr, \r
176 "error E0005: CreateFile failed: Volume = %s, LastError = 0x%x\n", \r
177 VolumeAccessPath, \r
178 GetLastError ()\r
179 );\r
180 return FALSE;\r
181 }\r
182\r
183 //\r
184 // Get Disk Number. It should fail when operating on floppy. That's ok \r
185 // because Disk Number is only needed when operating on Hard or USB disk.\r
186 //\r
187 // To direct write to disk:\r
188 // for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number\r
189 // for floppy: use path = \\.\X:, where X can be A or B\r
190 //\r
191 Success = DeviceIoControl(\r
192 VolumeHandle, \r
193 IOCTL_STORAGE_GET_DEVICE_NUMBER,\r
194 NULL, \r
195 0, \r
196 &StorageDeviceNumber, \r
197 sizeof(StorageDeviceNumber),\r
198 &BytesReturned, \r
199 NULL\r
200 );\r
201 //\r
202 // DeviceIoControl should fail if Volume is floppy or network drive.\r
203 //\r
204 if (!Success) {\r
205 DriveInfo->DiskNumber = (UINT) -1;\r
206 } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) {\r
207 //\r
208 // Only care about the disk.\r
209 //\r
210 return FALSE;\r
211 } else{\r
212 DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;\r
213 }\r
214 CloseHandle(VolumeHandle);\r
215 \r
216 //\r
217 // Fill in the type string\r
218 //\r
219 DriveInfo->DriveType = NULL;\r
220 for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {\r
221 if (DriveType == DriveTypeDesc[Index].Type) {\r
222 DriveInfo->DriveType = &DriveTypeDesc[Index];\r
223 break;\r
224 }\r
225 }\r
226\r
227 if (DriveInfo->DriveType == NULL) {\r
228 //\r
229 // Should have a type.\r
230 //\r
231 fprintf (stderr, "error E3005: Fatal Error!!!\n");\r
232 return FALSE;\r
233 }\r
234 return TRUE;\r
235}\r
236\r
237VOID\r
238ListDrive (\r
239 VOID\r
240 )\r
241/*++\r
242Routine Description:\r
243 List every drive in current system and their information.\r
244\r
245--*/\r
246{\r
247 UINT Index;\r
248 DRIVE_INFO DriveInfo;\r
249 \r
250 UINT Mask = GetLogicalDrives();\r
251\r
252 for (Index = 0; Index < MAX_DRIVE; Index++) {\r
253 if (((Mask >> Index) & 0x1) == 1) {\r
254 if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {\r
255 if (Index < 2) {\r
256 // Floppy will occupy 'A' and 'B'\r
257 fprintf (\r
258 stdout,\r
259 "%c: - Type: %s\n",\r
260 DriveInfo.VolumeLetter,\r
261 DriveInfo.DriveType->Description\r
262 );\r
263 } else {\r
264 fprintf (\r
265 stdout,\r
fd171542 266 "%c: - DiskNum: %u, Type: %s\n", \r
30fdf114 267 DriveInfo.VolumeLetter,\r
fd171542 268 (unsigned) DriveInfo.DiskNumber, \r
30fdf114
LG
269 DriveInfo.DriveType->Description\r
270 );\r
271 }\r
272 }\r
273 }\r
274 }\r
275\r
276}\r
277\r
278INT\r
279GetBootSectorOffset (\r
280 HANDLE DiskHandle,\r
281 PATH_INFO *PathInfo\r
282 )\r
283/*++\r
284Description:\r
285 Get the offset of boot sector.\r
286 For non-MBR disk, offset is just 0\r
287 for disk with MBR, offset needs to be caculated by parsing MBR\r
288\r
289 NOTE: if no one is active, we will patch MBR to select first partition as active.\r
290\r
291Arguments:\r
292 DiskHandle : HANDLE of disk\r
293 PathInfo : PATH_INFO structure.\r
294 WriteToDisk : TRUE indicates writing\r
295\r
296Return:\r
297 -1 : failed\r
298 o.w. : Offset to boot sector\r
299--*/\r
300{\r
301 BYTE DiskPartition[0x200];\r
302 DWORD BytesReturn;\r
303 DWORD DbrOffset;\r
304 DWORD Index;\r
305 BOOL HasMbr;\r
306\r
307 DbrOffset = 0;\r
308 HasMbr = FALSE;\r
309 \r
310 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);\r
311 if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
312 return -1;\r
313 }\r
314\r
315 //\r
316 // Check Signature, Jmp, and Boot Indicator.\r
317 // if all pass, we assume MBR found.\r
318 //\r
319\r
320 // Check Signature: 55AA\r
321 if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {\r
322 // Check Jmp: (EB ?? 90) or (E9 ?? ??)\r
323 if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&\r
324 (DiskPartition[0] != 0xE9)) {\r
325 // Check Boot Indicator: 0x00 or 0x80\r
326 // Boot Indicator is the first byte of Partition Entry\r
327 HasMbr = TRUE;\r
328 for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {\r
329 if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {\r
330 HasMbr = FALSE;\r
331 break;\r
332 }\r
333 }\r
334 }\r
335 }\r
336\r
337 if (HasMbr) {\r
338 //\r
339 // Skip MBR\r
340 //\r
341 for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {\r
342 //\r
343 // Found Boot Indicator.\r
344 //\r
345 if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {\r
346 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];\r
347 break;\r
348 }\r
349 }\r
350 //\r
351 // If no boot indicator, we manually select 1st partition, and patch MBR.\r
352 //\r
353 if (Index == PARTITION_ENTRY_NUM) {\r
354 DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];\r
355 if (!PathInfo->Input && (PathInfo->Type == PathUsb)) {\r
356 SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);\r
357 DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;\r
358 WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);\r
359 }\r
360 }\r
361 }\r
362\r
363 return DbrOffset;\r
364}\r
365\r
366/**\r
367 * Get window file handle for input/ouput disk/file. \r
368 * \r
369 * @param PathInfo\r
370 * @param ProcessMbr\r
371 * @param FileHandle\r
372 * \r
373 * @return ERROR_STATUS\r
374 */\r
375ERROR_STATUS\r
376GetFileHandle (\r
377 PATH_INFO *PathInfo,\r
378 BOOL ProcessMbr,\r
379 HANDLE *FileHandle,\r
380 DWORD *DbrOffset\r
381 )\r
382{\r
383 DWORD OpenFlag;\r
384\r
385 OpenFlag = OPEN_ALWAYS;\r
386 if (PathInfo->Input || PathInfo->Type != PathFile) {\r
387 OpenFlag = OPEN_EXISTING;\r
388 }\r
389\r
390 *FileHandle = CreateFile(\r
391 PathInfo->PhysicalPath,\r
392 GENERIC_READ | GENERIC_WRITE, \r
393 FILE_SHARE_READ, \r
394 NULL, \r
395 OpenFlag, \r
396 FILE_ATTRIBUTE_NORMAL, \r
397 NULL\r
398 );\r
399 if (*FileHandle == INVALID_HANDLE_VALUE) {\r
400 return ErrorFileCreate;\r
401 }\r
402\r
403 if ((PathInfo->Type == PathIde) || (PathInfo->Type == PathUsb)){\r
404 *DbrOffset = GetBootSectorOffset (*FileHandle, PathInfo);\r
405 if (!ProcessMbr) {\r
406 //\r
407 // 1. Process boot sector, set file pointer to the beginning of boot sector\r
408 //\r
409 SetFilePointer (*FileHandle, *DbrOffset * 0x200, NULL, FILE_BEGIN);\r
410 } else if(*DbrOffset == 0) {\r
411 //\r
412 // If user want to process Mbr, but no Mbr exists, simply return FALSE\r
413 //\r
414 return ErrorNoMbr;\r
415 } else {\r
416 //\r
417 // 2. Process MBR, set file pointer to 0\r
418 //\r
419 SetFilePointer (*FileHandle, 0, NULL, FILE_BEGIN);\r
420 }\r
421 }\r
422\r
423 return ErrorSuccess;\r
424}\r
425\r
426/**\r
427 Writing or reading boot sector or MBR according to the argument. \r
428 \r
429 @param InputInfo PATH_INFO instance for input path\r
430 @param OutputInfo PATH_INFO instance for output path\r
431 @param ProcessMbr TRUE is to process MBR, otherwise, processing boot sector\r
432 \r
433 @return ERROR_STATUS\r
434 **/\r
435ERROR_STATUS\r
436ProcessBsOrMbr (\r
437 PATH_INFO *InputInfo,\r
438 PATH_INFO *OutputInfo,\r
439 BOOL ProcessMbr\r
440 )\r
441{\r
442 BYTE DiskPartition[0x200] = {0};\r
443 BYTE DiskPartitionBackup[0x200] = {0};\r
444 DWORD BytesReturn;\r
30fdf114
LG
445 INT DrvNumOffset;\r
446 HANDLE InputHandle;\r
447 HANDLE OutputHandle;\r
30fdf114
LG
448 ERROR_STATUS Status;\r
449 DWORD InputDbrOffset;\r
450 DWORD OutputDbrOffset;\r
451\r
452 //\r
453 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr\r
454 //\r
455 Status = GetFileHandle(InputInfo, ProcessMbr, &InputHandle, &InputDbrOffset);\r
456 if (Status != ErrorSuccess) {\r
457 return Status;\r
458 }\r
459\r
460 //\r
461 // Create file Handle and move file Pointer is pointed to beginning of Mbr or Dbr\r
462 //\r
463 Status = GetFileHandle(OutputInfo, ProcessMbr, &OutputHandle, &OutputDbrOffset);\r
464 if (Status != ErrorSuccess) {\r
465 return Status;\r
466 }\r
467\r
468 //\r
469 // Read boot sector from source disk/file\r
470 // \r
471 if (!ReadFile (InputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
472 return ErrorFileReadWrite;\r
473 }\r
474\r
475 if (InputInfo->Type == PathUsb) {\r
476 // Manually set BS_DrvNum to 0x80 as window's format.exe has a bug which will clear this field discarding USB disk's MBR. \r
477 // offset of BS_DrvNum is 0x24 for FAT12/16\r
478 // 0x40 for FAT32\r
479 //\r
480 DrvNumOffset = GetDrvNumOffset (DiskPartition);\r
481 if (DrvNumOffset == -1) {\r
482 return ErrorFatType;\r
483 }\r
484 //\r
485 // Some legacy BIOS require 0x80 discarding MBR.\r
486 // Question left here: is it needed to check Mbr before set 0x80?\r
487 //\r
488 DiskPartition[DrvNumOffset] = ((InputDbrOffset > 0) ? 0x80 : 0);\r
489 }\r
490\r
491 if (InputInfo->Type == PathIde) {\r
492 //\r
493 // Patch LBAOffsetForBootSector\r
494 //\r
495 *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = InputDbrOffset;\r
496 }\r
497\r
498 if (OutputInfo->Type != PathFile) {\r
499 if (ProcessMbr) {\r
500 //\r
501 // Use original partition table\r
502 //\r
503 if (!ReadFile (OutputHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {\r
504 return ErrorFileReadWrite;\r
505 }\r
506 memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);\r
507 SetFilePointer (OutputHandle, 0, NULL, FILE_BEGIN);\r
508\r
509 }\r
510 }\r
511\r
512 //\r
513 // Write boot sector to taget disk/file\r
514 // \r
515 if (!WriteFile (OutputHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
516 return ErrorFileReadWrite;\r
517 }\r
518\r
519 CloseHandle (InputHandle);\r
520 CloseHandle (OutputHandle);\r
521\r
522 return ErrorSuccess;\r
523}\r
524\r
525void\r
526Version (\r
527 void\r
528 )\r
529/*++\r
530\r
531Routine Description:\r
532\r
533 Displays the standard utility information to SDTOUT\r
534\r
535Arguments:\r
536\r
537 None\r
538\r
539Returns:\r
540\r
541 None\r
542\r
543--*/\r
544{\r
4afd3d04 545 printf ("%s Version %d.%d Build%s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
30fdf114
LG
546}\r
547\r
548VOID\r
549PrintUsage (\r
550 void\r
551 )\r
552{\r
4afd3d04
LG
553 printf ("Usage: GenBootSector [options] --cfg-file CFG_FILE\n\n\\r
554Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.\n\n\\r
555 Utility to retrieve and update the boot sector or MBR.\n\n\\r
556optional arguments:\n\\r
557 -h, --help Show this help message and exit\n\\r
558 --version Show program's version number and exit\n\\r
559 -d [DEBUG], --debug [DEBUG]\n\\r
560 Output DEBUG statements, where DEBUG_LEVEL is 0 (min)\n\\r
561 - 9 (max)\n\\r
562 -v, --verbose Print informational statements\n\\r
563 -q, --quiet Returns the exit code, error messages will be\n\\r
564 displayed\n\\r
565 -s, --silent Returns only the exit code; informational and error\n\\r
566 messages are not displayed\n\\r
567 -l, --list List disk drives\n\\r
568 -i INPUT_FILENAME, --input INPUT_FILENAME\n\\r
569 Input file name\n\\r
570 -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\\r
571 Output file name\n\\r
572 -m, --mbr Also process the MBR\n\\r
573 --sfo Reserved for future use\n");\r
30fdf114
LG
574\r
575}\r
576\r
577/**\r
578 Get path information, including physical path for windows platform.\r
579\r
580 @param PathInfo Point to PATH_INFO structure.\r
581\r
582 @return whether path is valid.\r
583**/\r
584ERROR_STATUS\r
585GetPathInfo (\r
586 PATH_INFO *PathInfo\r
587 )\r
588{\r
589 DRIVE_INFO DriveInfo;\r
590 CHAR VolumeLetter;\r
591 CHAR DiskPathTemplate[] = "\\\\.\\PHYSICALDRIVE%u";\r
592 CHAR FloppyPathTemplate[] = "\\\\.\\%c:";\r
593 FILE *f;\r
594\r
595 //\r
596 // If path is disk path\r
597 //\r
598 if (IsLetter(PathInfo->Path[0]) && (PathInfo->Path[1] == ':') && (PathInfo->Path[2] == '\0')) {\r
599 VolumeLetter = PathInfo->Path[0];\r
600 if ((VolumeLetter == 'A') || (VolumeLetter == 'a') || \r
601 (VolumeLetter == 'B') || (VolumeLetter == 'b')) {\r
602 PathInfo->Type = PathFloppy;\r
603 sprintf (PathInfo->PhysicalPath, FloppyPathTemplate, VolumeLetter);\r
604 return ErrorSuccess;\r
605 }\r
606\r
607 if (!GetDriveInfo(VolumeLetter, &DriveInfo)) {\r
608 fprintf (stderr, "ERROR: GetDriveInfo - 0x%x\n", GetLastError ());\r
609 return ErrorPath;\r
610 }\r
611\r
612 if (!PathInfo->Input && (DriveInfo.DriveType->Type == DRIVE_FIXED)) {\r
613 fprintf (stderr, "ERROR: Could patch own IDE disk!\n");\r
614 return ErrorPath;\r
615 }\r
616\r
617 sprintf(PathInfo->PhysicalPath, DiskPathTemplate, DriveInfo.DiskNumber);\r
618 if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {\r
619 PathInfo->Type = PathUsb;\r
620 } else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {\r
621 PathInfo->Type = PathIde;\r
622 } else {\r
623 fprintf (stderr, "ERROR, Invalid disk path - %s", PathInfo->Path);\r
624 return ErrorPath;\r
625 }\r
626\r
627 return ErrorSuccess;\r
628 } \r
629\r
630 PathInfo->Type = PathFile;\r
631 if (PathInfo->Input) {\r
632 //\r
633 // If path is file path, check whether file is valid.\r
634 //\r
1be2ed90 635 f = fopen (LongFilePath (PathInfo->Path), "r");\r
30fdf114
LG
636 if (f == NULL) {\r
637 fprintf (stderr, "error E2003: File was not provided!\n");\r
638 return ErrorPath;\r
639 } \r
640 }\r
641 PathInfo->Type = PathFile;\r
642 strcpy(PathInfo->PhysicalPath, PathInfo->Path);\r
643\r
644 return ErrorSuccess;\r
645} \r
646\r
647INT\r
648main (\r
649 INT argc,\r
650 CHAR *argv[]\r
651 )\r
652{\r
653 CHAR8 *AppName;\r
654 INTN Index;\r
655 BOOLEAN ProcessMbr;\r
656 ERROR_STATUS Status;\r
657 EFI_STATUS EfiStatus;\r
658 PATH_INFO InputPathInfo = {0};\r
659 PATH_INFO OutputPathInfo = {0};\r
660 UINT64 LogLevel;\r
661\r
662 SetUtilityName (UTILITY_NAME);\r
663\r
664 AppName = *argv;\r
665 argv ++;\r
666 argc --;\r
667 \r
668 ProcessMbr = FALSE;\r
669\r
670 if (argc == 0) {\r
671 PrintUsage();\r
672 return 0;\r
673 }\r
674 \r
675 //\r
676 // Parse command line\r
677 //\r
678 for (Index = 0; Index < argc; Index ++) {\r
679 if ((stricmp (argv[Index], "-l") == 0) || (stricmp (argv[Index], "--list") == 0)) {\r
680 ListDrive ();\r
681 return 0;\r
682 } \r
683 \r
684 if ((stricmp (argv[Index], "-m") == 0) || (stricmp (argv[Index], "--mbr") == 0)) {\r
685 ProcessMbr = TRUE;\r
686 continue;\r
687 } \r
688 \r
689 if ((stricmp (argv[Index], "-i") == 0) || (stricmp (argv[Index], "--input") == 0)) {\r
690 InputPathInfo.Path = argv[Index + 1];\r
691 InputPathInfo.Input = TRUE;\r
692 if (InputPathInfo.Path == NULL) {\r
693 Error (NULL, 0, 1003, "Invalid option value", "Input file name can't be NULL");\r
694 return 1;\r
695 } \r
696 if (InputPathInfo.Path[0] == '-') {\r
697 Error (NULL, 0, 1003, "Invalid option value", "Input file is missing");\r
698 return 1; \r
699 }\r
700 ++Index;\r
701 continue;\r
702 }\r
703\r
704 if ((stricmp (argv[Index], "-o") == 0) || (stricmp (argv[Index], "--output") == 0)) {\r
705 OutputPathInfo.Path = argv[Index + 1];\r
706 OutputPathInfo.Input = FALSE;\r
707 if (OutputPathInfo.Path == NULL) {\r
708 Error (NULL, 0, 1003, "Invalid option value", "Output file name can't be NULL");\r
709 return 1;\r
710 } \r
711 if (OutputPathInfo.Path[0] == '-') {\r
712 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing");\r
713 return 1; \r
714 }\r
715 ++Index;\r
716 continue;\r
717 }\r
718 \r
719 if ((stricmp (argv[Index], "-h") == 0) || (stricmp (argv[Index], "--help") == 0)) {\r
720 PrintUsage ();\r
721 return 0;\r
722 } \r
723 \r
724 if (stricmp (argv[Index], "--version") == 0) {\r
725 Version ();\r
726 return 0;\r
727 } \r
728 \r
729 if ((stricmp (argv[Index], "-v") == 0) || (stricmp (argv[Index], "--verbose") == 0)) {\r
730 continue;\r
731 } \r
732 \r
733 if ((stricmp (argv[Index], "-q") == 0) || (stricmp (argv[Index], "--quiet") == 0)) {\r
734 continue;\r
735 } \r
736 \r
737 if ((stricmp (argv[Index], "-d") == 0) || (stricmp (argv[Index], "--debug") == 0)) {\r
738 EfiStatus = AsciiStringToUint64 (argv[Index + 1], FALSE, &LogLevel);\r
739 if (EFI_ERROR (EfiStatus)) {\r
740 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[Index], argv[Index + 1]);\r
741 return 1;\r
742 }\r
743 if (LogLevel > 9) {\r
fd171542 744 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, currnt input level is %d", (int) LogLevel);\r
30fdf114
LG
745 return 1;\r
746 }\r
747 SetPrintLevel (LogLevel);\r
748 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[Index + 1]);\r
749 ++Index;\r
750 continue;\r
751 }\r
752\r
753 //\r
754 // Don't recognize the parameter.\r
755 //\r
756 Error (NULL, 0, 1000, "Unknown option", "%s", argv[Index]);\r
757 return 1;\r
758 }\r
759 \r
760 if (InputPathInfo.Path == NULL) {\r
761 Error (NULL, 0, 1001, "Missing options", "Input file is missing");\r
762 return 1;\r
763 }\r
764\r
765 if (OutputPathInfo.Path == NULL) {\r
766 Error (NULL, 0, 1001, "Missing options", "Output file is missing");\r
767 return 1;\r
768 }\r
769 \r
770 if (GetPathInfo(&InputPathInfo) != ErrorSuccess) {\r
771 Error (NULL, 0, 1003, "Invalid option value", "Input file can't be found.");\r
772 return 1;\r
773 }\r
774\r
775 if (GetPathInfo(&OutputPathInfo) != ErrorSuccess) {\r
776 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be found.");\r
777 return 1;\r
778 }\r
779 \r
780 //\r
781 // Process DBR (Patch or Read)\r
782 //\r
783 Status = ProcessBsOrMbr (&InputPathInfo, &OutputPathInfo, ProcessMbr);\r
784\r
785 if (Status == ErrorSuccess) {\r
786 fprintf (\r
787 stdout, \r
788 "%s %s: successful!\n", \r
789 (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
790 ProcessMbr ? "MBR" : "DBR"\r
791 );\r
792 return 0;\r
793 } else {\r
794 fprintf (\r
795 stderr, \r
796 "%s: %s %s: failed - %s (LastError: 0x%x)!\n",\r
797 (Status == ErrorNoMbr) ? "WARNING" : "ERROR",\r
798 (OutputPathInfo.Type != PathFile) ? "Write" : "Read", \r
799 ProcessMbr ? "MBR" : "DBR", \r
800 ErrorStatusDesc[Status],\r
801 GetLastError ()\r
802 );\r
803 return 1;\r
804 }\r
805}\r