]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Sample/Tools/Source/GenBootsector/genbootsector.c
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / GenBootsector / genbootsector.c
diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/GenBootsector/genbootsector.c b/EdkCompatibilityPkg/Sample/Tools/Source/GenBootsector/genbootsector.c
new file mode 100644 (file)
index 0000000..8438502
--- /dev/null
@@ -0,0 +1,652 @@
+/*++\r
+\r
+Copyright 2006 - 2007, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  genbootsector.c\r
+  \r
+Abstract:\r
+  Reading/writing MBR/DBR.\r
+  NOTE:\r
+    If we write MBR to disk, we just update the MBR code and the partition table wouldn't be over written.\r
+    If we process DBR, we will patch MBR to set first partition active if no active partition exists.\r
+\r
+--*/\r
+\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#define MAX_DRIVE                             26\r
+#define PARTITION_TABLE_OFFSET                0x1BE\r
+\r
+#define SIZE_OF_PARTITION_ENTRY               0x10\r
+\r
+#define PARTITION_ENTRY_STARTLBA_OFFSET       8\r
+\r
+#define PARTITION_ENTRY_NUM                   4\r
+\r
+INT\r
+GetDrvNumOffset (\r
+  IN VOID *BootSector\r
+  );\r
+\r
+typedef enum {\r
+  PatchTypeUnknown,\r
+  PatchTypeFloppy,\r
+  PatchTypeIde,\r
+  PatchTypeUsb,\r
+} PATCH_TYPE;\r
+\r
+typedef enum {\r
+  ErrorSuccess,\r
+  ErrorFileCreate,\r
+  ErrorFileReadWrite,\r
+  ErrorNoMbr,\r
+  ErrorFatType\r
+} ERROR_STATUS;\r
+\r
+CHAR *ErrorStatusDesc[] = {\r
+  "Success",\r
+  "Failed to create files",\r
+  "Failed to read/write files",\r
+  "No MBR exists",\r
+  "Failed to detect Fat type"\r
+};\r
+\r
+typedef struct _DRIVE_TYPE_DESC {\r
+  UINT  Type;\r
+  CHAR  *Description;\r
+} DRIVE_TYPE_DESC;\r
+\r
+#define DRIVE_TYPE_ITEM(x) {x, #x}\r
+DRIVE_TYPE_DESC DriveTypeDesc[] = {\r
+  DRIVE_TYPE_ITEM (DRIVE_UNKNOWN),\r
+  DRIVE_TYPE_ITEM (DRIVE_NO_ROOT_DIR),\r
+  DRIVE_TYPE_ITEM (DRIVE_REMOVABLE),\r
+  DRIVE_TYPE_ITEM (DRIVE_FIXED),\r
+  DRIVE_TYPE_ITEM (DRIVE_REMOTE),\r
+  DRIVE_TYPE_ITEM (DRIVE_CDROM),\r
+  DRIVE_TYPE_ITEM (DRIVE_RAMDISK),\r
+  (UINT) -1, NULL\r
+};\r
+\r
+typedef struct _DRIVE_INFO {\r
+  CHAR              VolumeLetter;\r
+  DRIVE_TYPE_DESC   *DriveType;\r
+  UINT              DiskNumber;\r
+} DRIVE_INFO;\r
+\r
+#define BOOT_SECTOR_LBA_OFFSET 0x1FA\r
+\r
+#define IsLetter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))\r
+\r
+BOOL\r
+GetDriveInfo (\r
+  CHAR       VolumeLetter,\r
+  DRIVE_INFO *DriveInfo\r
+  )\r
+/*++\r
+Routine Description:\r
+  Get drive information including disk number and drive type,\r
+  where disknumber is useful for reading/writing disk raw data.\r
+  NOTE: Floppy disk doesn't have disk number but it doesn't matter because\r
+        we can reading/writing floppy disk without disk number.\r
+\r
+Arguments:\r
+  VolumeLetter : volume letter, e.g.: C for C:, A for A:\r
+  DriveInfo    : pointer to DRIVE_INFO structure receiving drive information.\r
+\r
+Return:\r
+  TRUE  : successful\r
+  FALSE : failed\r
+--*/\r
+{\r
+  HANDLE                  VolumeHandle;\r
+  STORAGE_DEVICE_NUMBER   StorageDeviceNumber;\r
+  DWORD                   BytesReturned;\r
+  BOOL                    Success;\r
+  UINT                    DriveType;\r
+  UINT                    Index;\r
+\r
+  CHAR RootPath[]         = "X:\\";       // "X:\"  -> for GetDriveType\r
+  CHAR VolumeAccessPath[] = "\\\\.\\X:";  // "\\.\X:"  -> to open the volume\r
+\r
+  RootPath[0] = VolumeAccessPath[4] = VolumeLetter;\r
+  DriveType = GetDriveType(RootPath);\r
+  if (DriveType != DRIVE_REMOVABLE && DriveType != DRIVE_FIXED) {\r
+    return FALSE;\r
+  }\r
+\r
+  DriveInfo->VolumeLetter = VolumeLetter;\r
+  VolumeHandle = CreateFile (\r
+                   VolumeAccessPath,\r
+                   0,\r
+                   FILE_SHARE_READ | FILE_SHARE_WRITE,\r
+                   NULL,\r
+                   OPEN_EXISTING,\r
+                   0,\r
+                   NULL\r
+                   );\r
+  if (VolumeHandle == INVALID_HANDLE_VALUE) {\r
+    fprintf (\r
+      stderr, \r
+      "ERROR: CreateFile failed: Volume = %s, LastError = 0x%x\n", \r
+      VolumeAccessPath, \r
+      GetLastError ()\r
+      );\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get Disk Number. It should fail when operating on floppy. That's ok \r
+  //  because Disk Number is only needed when operating on Hard or USB disk.\r
+  //\r
+  // To direct write to disk:\r
+  //   for USB and HD: use path = \\.\PHYSICALDRIVEx, where x is Disk Number\r
+  //   for floppy:     use path = \\.\X:, where X can be A or B\r
+  //\r
+  Success = DeviceIoControl(\r
+              VolumeHandle, \r
+              IOCTL_STORAGE_GET_DEVICE_NUMBER,\r
+              NULL, \r
+              0, \r
+              &StorageDeviceNumber, \r
+              sizeof(StorageDeviceNumber),\r
+              &BytesReturned, \r
+              NULL\r
+              );\r
+  //\r
+  // DeviceIoControl should fail if Volume is floppy or network drive.\r
+  //\r
+  if (!Success) {\r
+    DriveInfo->DiskNumber = (UINT) -1;\r
+  } else if (StorageDeviceNumber.DeviceType != FILE_DEVICE_DISK) {\r
+    //\r
+    // Only care about the disk.\r
+    //\r
+    return FALSE;\r
+  } else{\r
+    DriveInfo->DiskNumber = StorageDeviceNumber.DeviceNumber;\r
+  }\r
+  CloseHandle(VolumeHandle);\r
+  \r
+  //\r
+  // Fill in the type string\r
+  //\r
+  DriveInfo->DriveType = NULL;\r
+  for (Index = 0; DriveTypeDesc[Index].Description != NULL; Index ++) {\r
+    if (DriveType == DriveTypeDesc[Index].Type) {\r
+      DriveInfo->DriveType = &DriveTypeDesc[Index];\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (DriveInfo->DriveType == NULL) {\r
+    //\r
+    // Should have a type.\r
+    //\r
+    fprintf (stderr, "ERROR: fetal error!!!\n");\r
+    return FALSE;\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+VOID\r
+ListDrive (\r
+  VOID\r
+  )\r
+/*++\r
+Routine Description:\r
+  List every drive in current system and their information.\r
+\r
+--*/\r
+{\r
+  UINT       Index;\r
+  DRIVE_INFO DriveInfo;\r
+  \r
+  UINT Mask =  GetLogicalDrives();\r
+\r
+  for (Index = 0; Index < MAX_DRIVE; Index++) {\r
+    if (((Mask >> Index) & 0x1) == 1) {\r
+      if (GetDriveInfo ('A' + (CHAR) Index, &DriveInfo)) {\r
+        if (Index < 2) {\r
+          // Floppy will occupy 'A' and 'B'\r
+          fprintf (\r
+            stdout,\r
+            "%c: - Type: %s\n",\r
+            DriveInfo.VolumeLetter,\r
+            DriveInfo.DriveType->Description\r
+            );\r
+        }\r
+        else {\r
+          fprintf (\r
+            stdout,\r
+            "%c: - DiskNum: %d, Type: %s\n", \r
+            DriveInfo.VolumeLetter,\r
+            DriveInfo.DiskNumber, \r
+            DriveInfo.DriveType->Description\r
+            );\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+}\r
+\r
+INT\r
+GetBootSectorOffset (\r
+  HANDLE     DiskHandle,\r
+  BOOL       WriteToDisk,\r
+  PATCH_TYPE PatchType\r
+  )\r
+/*++\r
+Description:\r
+  Get the offset of boot sector.\r
+  For non-MBR disk, offset is just 0\r
+  for disk with MBR, offset needs to be caculated by parsing MBR\r
+\r
+  NOTE: if no one is active, we will patch MBR to select first partition as active.\r
+\r
+Arguments:\r
+  DiskHandle  : HANDLE of disk\r
+  WriteToDisk : TRUE indicates writing\r
+  PatchType   : PatchTypeFloppy, PatchTypeIde, PatchTypeUsb\r
+\r
+Return:\r
+  -1   : failed\r
+  o.w. : Offset to boot sector\r
+--*/\r
+{\r
+  BYTE    DiskPartition[0x200];\r
+  DWORD   BytesReturn;\r
+  DWORD   DbrOffset;\r
+  DWORD   Index;\r
+  BOOL    HasMbr;\r
+\r
+  DbrOffset = 0;\r
+  HasMbr    = FALSE;\r
+  \r
+  SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);\r
+  if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
+    return -1;\r
+  }\r
+\r
+  //\r
+  // Check Signature, Jmp, and Boot Indicator.\r
+  // if all pass, we assume MBR found.\r
+  //\r
+\r
+  // Check Signature: 55AA\r
+  if ((DiskPartition[0x1FE] == 0x55) && (DiskPartition[0x1FF] == 0xAA)) {\r
+    // Check Jmp: (EB ?? 90) or (E9 ?? ??)\r
+    if (((DiskPartition[0] != 0xEB) || (DiskPartition[2] != 0x90)) &&\r
+        (DiskPartition[0] != 0xE9)) {\r
+      // Check Boot Indicator: 0x00 or 0x80\r
+      // Boot Indicator is the first byte of Partition Entry\r
+      HasMbr = TRUE;\r
+      for (Index = 0; Index < PARTITION_ENTRY_NUM; ++Index) {\r
+        if ((DiskPartition[PARTITION_TABLE_OFFSET + Index * SIZE_OF_PARTITION_ENTRY] & 0x7F) != 0) {\r
+          HasMbr = FALSE;\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (HasMbr) {\r
+    //\r
+    // Skip MBR\r
+    //\r
+    for (Index = 0; Index < PARTITION_ENTRY_NUM; Index++) {\r
+      //\r
+      // Found Boot Indicator.\r
+      //\r
+      if (DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY)] == 0x80) {\r
+        DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + (Index * SIZE_OF_PARTITION_ENTRY) + PARTITION_ENTRY_STARTLBA_OFFSET];\r
+        break;\r
+      }\r
+    }\r
+    //\r
+    // If no boot indicator, we manually select 1st partition, and patch MBR.\r
+    //\r
+    if (Index == PARTITION_ENTRY_NUM) {\r
+      DbrOffset = *(DWORD *)&DiskPartition[PARTITION_TABLE_OFFSET + PARTITION_ENTRY_STARTLBA_OFFSET];\r
+      if (WriteToDisk && (PatchType == PatchTypeUsb)) {\r
+        SetFilePointer(DiskHandle, 0, NULL, FILE_BEGIN);\r
+        DiskPartition[PARTITION_TABLE_OFFSET] = 0x80;\r
+        WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL);\r
+      }\r
+    }\r
+  }\r
+\r
+  return DbrOffset;\r
+}\r
+\r
+ERROR_STATUS\r
+ProcessBsOrMbr (\r
+  CHAR        *DiskName,\r
+  CHAR        *FileName,\r
+  BOOL        WriteToDisk,\r
+  PATCH_TYPE  PatchType,\r
+  BOOL        ProcessMbr\r
+  )\r
+/*++\r
+Routine Description:\r
+  Writing or reading boot sector or MBR according to the argument.\r
+\r
+Arguments:\r
+  DiskName    : Win32 API recognized string name of disk\r
+  FileName    : file name\r
+  WriteToDisk : TRUE is to write content of file to disk, otherwise, reading content of disk to file\r
+  PatchType   : PatchTypeFloppy, PatchTypeIde, PatchTypeUsb\r
+  ProcessMbr  : TRUE is to process MBR, otherwise, processing boot sector\r
+\r
+Return:\r
+  ErrorSuccess\r
+  ErrorFileCreate\r
+  ErrorFileReadWrite\r
+  ErrorNoMbr\r
+  ErrorFatType\r
+--*/\r
+{\r
+  BYTE    DiskPartition[0x200];\r
+  BYTE    DiskPartitionBackup[0x200];\r
+  HANDLE  DiskHandle;\r
+  HANDLE  FileHandle;\r
+  DWORD   BytesReturn;\r
+  DWORD   DbrOffset;\r
+  INT     DrvNumOffset;\r
+\r
+  DiskHandle = CreateFile (\r
+                 DiskName, \r
+                 GENERIC_READ | GENERIC_WRITE, \r
+                 FILE_SHARE_READ, \r
+                 NULL, \r
+                 OPEN_EXISTING, \r
+                 FILE_ATTRIBUTE_NORMAL, \r
+                 NULL\r
+                 );\r
+  if (DiskHandle == INVALID_HANDLE_VALUE) {\r
+    return ErrorFileCreate;\r
+  }\r
+\r
+  FileHandle = CreateFile (\r
+                 FileName,\r
+                 GENERIC_READ | GENERIC_WRITE,\r
+                 0,\r
+                 NULL,\r
+                 OPEN_ALWAYS,\r
+                 FILE_ATTRIBUTE_NORMAL,\r
+                 NULL\r
+                 );\r
+  if (FileHandle == INVALID_HANDLE_VALUE) {\r
+    return ErrorFileCreate;\r
+  }\r
+\r
+  DbrOffset = 0;\r
+  //\r
+  // Skip potential MBR for Ide & USB disk\r
+  //\r
+  if ((PatchType == PatchTypeIde) || (PatchType == PatchTypeUsb)) {\r
+    //\r
+    // Even user just wants to process MBR, we get offset of boot sector here to validate the disk\r
+    //  if disk have MBR, DbrOffset should be greater than 0\r
+    //\r
+    DbrOffset = GetBootSectorOffset (DiskHandle, WriteToDisk, PatchType);\r
+\r
+    if (!ProcessMbr) {\r
+      //\r
+      // 1. Process boot sector, set file pointer to the beginning of boot sector\r
+      //\r
+      SetFilePointer (DiskHandle, DbrOffset * 0x200, NULL, FILE_BEGIN);\r
+    } else if(DbrOffset == 0) {\r
+      //\r
+      // If user want to process Mbr, but no Mbr exists, simply return FALSE\r
+      //\r
+      return ErrorNoMbr;\r
+    } else {\r
+      //\r
+      // 2. Process MBR, set file pointer to 0\r
+      //\r
+      SetFilePointer (DiskHandle, 0, NULL, FILE_BEGIN);\r
+    }\r
+  }\r
+\r
+  //\r
+  // [File Pointer is pointed to beginning of Mbr or Dbr]\r
+  //\r
+  if (WriteToDisk) {\r
+    //\r
+    // Write\r
+    //\r
+    if (!ReadFile (FileHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
+      return ErrorFileReadWrite;\r
+    }\r
+    if (ProcessMbr) {\r
+      //\r
+      // Use original partition table\r
+      //\r
+      if (!ReadFile (DiskHandle, DiskPartitionBackup, 0x200, &BytesReturn, NULL)) {\r
+        return ErrorFileReadWrite;\r
+      }\r
+      memcpy (DiskPartition + 0x1BE, DiskPartitionBackup + 0x1BE, 0x40);\r
+      SetFilePointer (DiskHandle, 0, NULL, FILE_BEGIN);\r
+    }\r
+\r
+    if (!WriteFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
+      return ErrorFileReadWrite;\r
+    }\r
+\r
+  } else {\r
+    //\r
+    // Read\r
+    //\r
+    if (!ReadFile (DiskHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
+      return ErrorFileReadWrite;\r
+    }\r
+\r
+    if (PatchType == PatchTypeUsb) {\r
+      // 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
+      // offset of BS_DrvNum is 0x24 for FAT12/16\r
+      //                        0x40 for FAT32\r
+      //\r
+      DrvNumOffset = GetDrvNumOffset (DiskPartition);\r
+      if (DrvNumOffset == -1) {\r
+        return ErrorFatType;\r
+      }\r
+      //\r
+      // Some legacy BIOS require 0x80 discarding MBR.\r
+      // Question left here: is it needed to check Mbr before set 0x80?\r
+      //\r
+      DiskPartition[DrvNumOffset] = ((DbrOffset > 0) ? 0x80 : 0);\r
+  }\r
+\r
+\r
+    if (PatchType == PatchTypeIde) {\r
+      //\r
+      // Patch LBAOffsetForBootSector\r
+      //\r
+      *(DWORD *)&DiskPartition [BOOT_SECTOR_LBA_OFFSET] = DbrOffset;\r
+    }\r
+    if (!WriteFile (FileHandle, DiskPartition, 0x200, &BytesReturn, NULL)) {\r
+      return ErrorFileReadWrite;\r
+    }\r
+  }\r
+  CloseHandle (FileHandle);\r
+  CloseHandle (DiskHandle);\r
+  return ErrorSuccess;\r
+}\r
+\r
+VOID\r
+PrintUsage (\r
+  CHAR* AppName\r
+  )\r
+{\r
+  fprintf (\r
+    stdout,\r
+    "Usage: %s [OPTIONS]...\n"\r
+    "Copy file content from/to bootsector.\n"\r
+    "\n"\r
+    "  -l        list disks\n"\r
+    "  -if=FILE  specified an input, can be files or disks\n"\r
+    "  -of=FILE  specified an output, can be files or disks\n"\r
+    "  -mbr      process MBR also\n"\r
+    "  -h        print this message\n"\r
+    "\n"\r
+    "FILE providing a volume plus a colon (X:), indicates a disk\n"\r
+    "FILE providing other format, indicates a file\n",\r
+    AppName\r
+    );\r
+}\r
\r
+INT\r
+main (\r
+  INT  argc,\r
+  CHAR *argv[]\r
+  )\r
+{\r
+  CHAR          *AppName;\r
+  INT           Index;\r
+  BOOL          ProcessMbr;\r
+  CHAR          VolumeLetter;\r
+  CHAR          *FilePath;\r
+  BOOL          WriteToDisk;\r
+  DRIVE_INFO    DriveInfo;\r
+  PATCH_TYPE    PatchType;\r
+  ERROR_STATUS  Status;\r
+\r
+  CHAR        FloppyPathTemplate[] = "\\\\.\\%c:";\r
+  CHAR        DiskPathTemplate[]   = "\\\\.\\PHYSICALDRIVE%u";\r
+  CHAR        DiskPath[MAX_PATH];\r
+\r
+  AppName = *argv;\r
+  argv ++;\r
+  argc --;\r
+  \r
+  ProcessMbr    = FALSE;\r
+  WriteToDisk   = TRUE;\r
+  FilePath      = NULL;\r
+  VolumeLetter  = 0;\r
+\r
+  //\r
+  // Parse command line\r
+  //\r
+  for (Index = 0; Index < argc; Index ++) {\r
+    if (_stricmp (argv[Index], "-l") == 0) {\r
+      ListDrive ();\r
+      return 0;\r
+    }\r
+    else if (_stricmp (argv[Index], "-mbr") == 0) {\r
+      ProcessMbr = TRUE;\r
+    }\r
+    else if ((_strnicmp (argv[Index], "-if=", 4) == 0) ||\r
+             (_strnicmp (argv[Index], "-of=", 4) == 0)\r
+             ) {\r
+      if (argv[Index][6] == '\0' && argv[Index][5] == ':' && IsLetter (argv[Index][4])) {\r
+        VolumeLetter = argv[Index][4];\r
+        if (_strnicmp (argv[Index], "-if=", 4) == 0) {\r
+          WriteToDisk = FALSE;\r
+        }\r
+      }\r
+      else {\r
+        FilePath = &argv[Index][4];\r
+      }\r
+    }\r
+    else {\r
+      PrintUsage (AppName);\r
+      return 1;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check parameter\r
+  //\r
+  if (VolumeLetter == 0) {\r
+    fprintf (stderr, "ERROR: Volume isn't provided!\n");\r
+    PrintUsage (AppName);\r
+    return 1;\r
+  }\r
+  \r
+  if (FilePath == NULL) {\r
+    fprintf (stderr, "ERROR: File isn't pvovided!\n");\r
+    PrintUsage (AppName);\r
+    return 1;\r
+  }\r
+    \r
+  PatchType = PatchTypeUnknown;\r
+\r
+  if ((VolumeLetter == 'A') || (VolumeLetter == 'a') || \r
+      (VolumeLetter == 'B') || (VolumeLetter == 'b') \r
+      ) {\r
+    //\r
+    // Floppy\r
+    //\r
+    sprintf (DiskPath, FloppyPathTemplate, VolumeLetter);\r
+    PatchType = PatchTypeFloppy;\r
+  }\r
+  else {\r
+    //\r
+    // Hard/USB disk\r
+    //\r
+    if (!GetDriveInfo (VolumeLetter, &DriveInfo)) {\r
+      fprintf (stderr, "ERROR: GetDriveInfo - 0x%x\n", GetLastError ());\r
+      return 1;\r
+    }\r
+\r
+    //\r
+    // Shouldn't patch my own hard disk, but can read it.\r
+    // very safe then:)\r
+    //\r
+    if (DriveInfo.DriveType->Type == DRIVE_FIXED && WriteToDisk) {\r
+      fprintf (stderr, "ERROR: Write to local harddisk - permission denied!\n");\r
+      return 1;\r
+    }\r
+    \r
+    sprintf (DiskPath, DiskPathTemplate, DriveInfo.DiskNumber);\r
+    if (DriveInfo.DriveType->Type == DRIVE_REMOVABLE) {\r
+      PatchType = PatchTypeUsb;\r
+    }\r
+    else if (DriveInfo.DriveType->Type == DRIVE_FIXED) {\r
+      PatchType = PatchTypeIde;\r
+    }\r
+  }\r
+\r
+  if (PatchType == PatchTypeUnknown) {\r
+    fprintf (stderr, "ERROR: PatchType unknown!\n");\r
+    return 1;\r
+  }\r
+\r
+  //\r
+  // Process DBR (Patch or Read)\r
+  //\r
+  Status = ProcessBsOrMbr (DiskPath, FilePath, WriteToDisk, PatchType, ProcessMbr);\r
+  if (Status == ErrorSuccess) {\r
+    fprintf (\r
+      stdout, \r
+      "%s %s: successfully!\n", \r
+      WriteToDisk ? "Write" : "Read", \r
+      ProcessMbr ? "MBR" : "DBR"\r
+      );\r
+    return 0;\r
+  } else {\r
+    fprintf (\r
+      stderr, \r
+      "%s: %s %s: failed - %s (LastError: 0x%x)!\n",\r
+      (Status == ErrorNoMbr) ? "WARNING" : "ERROR",\r
+      WriteToDisk ? "Write" : "Read", \r
+      ProcessMbr ? "MBR" : "DBR", \r
+      ErrorStatusDesc[Status],\r
+      GetLastError ()\r
+      );\r
+    return 1;\r
+  }\r
+}\r