From a7c0c3ce10b4a6a9a481ea486da625eac6ae3d58 Mon Sep 17 00:00:00 2001 From: jncronin Date: Mon, 14 Jul 2014 21:05:41 +0000 Subject: git-svn-id: https://www.tysos.org/svn/branches/tysila3/tload/mkgpt@549 21779fe5-bacf-4c11-b3ef-82bd0e1f58e8 --- Makefile.am | 12 ++ configure.ac | 32 ++++ crc32.c | 328 +++++++++++++++++++++++++++++++++ fstypes.c | 64 +++++++ fstypes.h | 35 ++++ guid.c | 203 +++++++++++++++++++++ guid.h | 44 +++++ mkgpt.c | 568 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ mkgpt.vcxproj | 78 ++++++++ part.h | 44 +++++ 10 files changed, 1408 insertions(+) create mode 100644 Makefile.am create mode 100644 configure.ac create mode 100644 crc32.c create mode 100644 fstypes.c create mode 100644 fstypes.h create mode 100644 guid.c create mode 100644 guid.h create mode 100644 mkgpt.c create mode 100644 mkgpt.vcxproj create mode 100644 part.h diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..04f820f --- /dev/null +++ b/Makefile.am @@ -0,0 +1,12 @@ +AUTOMAKE_OPTIONS = foreign subdir-objects + +CXXFLAGS = @CXXFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CFLAGS = @CFLAGS@ -Wall -Wextra -pedantic -Werror -std=gnu99 +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +bin_PROGRAMS = mkgpt +mkgpt_SOURCES = mkgpt.c crc32.c fstypes.c guid.c +noinst_HEADERS = fstypes.h guid.h part.h mkgpt.vcxproj + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..2e3c0b3 --- /dev/null +++ b/configure.ac @@ -0,0 +1,32 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. +AC_PREREQ([2.68]) +AC_INIT([mkgpt], [0.1]) +AM_INIT_AUTOMAKE +AC_CONFIG_SRCDIR([mkgpt.c]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([stdint.h stdlib.h string.h stddef.h time.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T + +# Checks for library functions. +AC_FUNC_MALLOC +AC_CHECK_FUNCS([memset]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/crc32.c b/crc32.c new file mode 100644 index 0000000..4d9eb02 --- /dev/null +++ b/crc32.c @@ -0,0 +1,328 @@ +/*++ + +Copyright (c) 2004, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + + crc32.c + +Abstract: + + CalcuateCrc32 routine. + + Modified to avoid EFI dependencies for mkgpt + +--*/ + +#include +#include + +uint32_t mCrcTable[256] = { + 0x00000000, + 0x77073096, + 0xEE0E612C, + 0x990951BA, + 0x076DC419, + 0x706AF48F, + 0xE963A535, + 0x9E6495A3, + 0x0EDB8832, + 0x79DCB8A4, + 0xE0D5E91E, + 0x97D2D988, + 0x09B64C2B, + 0x7EB17CBD, + 0xE7B82D07, + 0x90BF1D91, + 0x1DB71064, + 0x6AB020F2, + 0xF3B97148, + 0x84BE41DE, + 0x1ADAD47D, + 0x6DDDE4EB, + 0xF4D4B551, + 0x83D385C7, + 0x136C9856, + 0x646BA8C0, + 0xFD62F97A, + 0x8A65C9EC, + 0x14015C4F, + 0x63066CD9, + 0xFA0F3D63, + 0x8D080DF5, + 0x3B6E20C8, + 0x4C69105E, + 0xD56041E4, + 0xA2677172, + 0x3C03E4D1, + 0x4B04D447, + 0xD20D85FD, + 0xA50AB56B, + 0x35B5A8FA, + 0x42B2986C, + 0xDBBBC9D6, + 0xACBCF940, + 0x32D86CE3, + 0x45DF5C75, + 0xDCD60DCF, + 0xABD13D59, + 0x26D930AC, + 0x51DE003A, + 0xC8D75180, + 0xBFD06116, + 0x21B4F4B5, + 0x56B3C423, + 0xCFBA9599, + 0xB8BDA50F, + 0x2802B89E, + 0x5F058808, + 0xC60CD9B2, + 0xB10BE924, + 0x2F6F7C87, + 0x58684C11, + 0xC1611DAB, + 0xB6662D3D, + 0x76DC4190, + 0x01DB7106, + 0x98D220BC, + 0xEFD5102A, + 0x71B18589, + 0x06B6B51F, + 0x9FBFE4A5, + 0xE8B8D433, + 0x7807C9A2, + 0x0F00F934, + 0x9609A88E, + 0xE10E9818, + 0x7F6A0DBB, + 0x086D3D2D, + 0x91646C97, + 0xE6635C01, + 0x6B6B51F4, + 0x1C6C6162, + 0x856530D8, + 0xF262004E, + 0x6C0695ED, + 0x1B01A57B, + 0x8208F4C1, + 0xF50FC457, + 0x65B0D9C6, + 0x12B7E950, + 0x8BBEB8EA, + 0xFCB9887C, + 0x62DD1DDF, + 0x15DA2D49, + 0x8CD37CF3, + 0xFBD44C65, + 0x4DB26158, + 0x3AB551CE, + 0xA3BC0074, + 0xD4BB30E2, + 0x4ADFA541, + 0x3DD895D7, + 0xA4D1C46D, + 0xD3D6F4FB, + 0x4369E96A, + 0x346ED9FC, + 0xAD678846, + 0xDA60B8D0, + 0x44042D73, + 0x33031DE5, + 0xAA0A4C5F, + 0xDD0D7CC9, + 0x5005713C, + 0x270241AA, + 0xBE0B1010, + 0xC90C2086, + 0x5768B525, + 0x206F85B3, + 0xB966D409, + 0xCE61E49F, + 0x5EDEF90E, + 0x29D9C998, + 0xB0D09822, + 0xC7D7A8B4, + 0x59B33D17, + 0x2EB40D81, + 0xB7BD5C3B, + 0xC0BA6CAD, + 0xEDB88320, + 0x9ABFB3B6, + 0x03B6E20C, + 0x74B1D29A, + 0xEAD54739, + 0x9DD277AF, + 0x04DB2615, + 0x73DC1683, + 0xE3630B12, + 0x94643B84, + 0x0D6D6A3E, + 0x7A6A5AA8, + 0xE40ECF0B, + 0x9309FF9D, + 0x0A00AE27, + 0x7D079EB1, + 0xF00F9344, + 0x8708A3D2, + 0x1E01F268, + 0x6906C2FE, + 0xF762575D, + 0x806567CB, + 0x196C3671, + 0x6E6B06E7, + 0xFED41B76, + 0x89D32BE0, + 0x10DA7A5A, + 0x67DD4ACC, + 0xF9B9DF6F, + 0x8EBEEFF9, + 0x17B7BE43, + 0x60B08ED5, + 0xD6D6A3E8, + 0xA1D1937E, + 0x38D8C2C4, + 0x4FDFF252, + 0xD1BB67F1, + 0xA6BC5767, + 0x3FB506DD, + 0x48B2364B, + 0xD80D2BDA, + 0xAF0A1B4C, + 0x36034AF6, + 0x41047A60, + 0xDF60EFC3, + 0xA867DF55, + 0x316E8EEF, + 0x4669BE79, + 0xCB61B38C, + 0xBC66831A, + 0x256FD2A0, + 0x5268E236, + 0xCC0C7795, + 0xBB0B4703, + 0x220216B9, + 0x5505262F, + 0xC5BA3BBE, + 0xB2BD0B28, + 0x2BB45A92, + 0x5CB36A04, + 0xC2D7FFA7, + 0xB5D0CF31, + 0x2CD99E8B, + 0x5BDEAE1D, + 0x9B64C2B0, + 0xEC63F226, + 0x756AA39C, + 0x026D930A, + 0x9C0906A9, + 0xEB0E363F, + 0x72076785, + 0x05005713, + 0x95BF4A82, + 0xE2B87A14, + 0x7BB12BAE, + 0x0CB61B38, + 0x92D28E9B, + 0xE5D5BE0D, + 0x7CDCEFB7, + 0x0BDBDF21, + 0x86D3D2D4, + 0xF1D4E242, + 0x68DDB3F8, + 0x1FDA836E, + 0x81BE16CD, + 0xF6B9265B, + 0x6FB077E1, + 0x18B74777, + 0x88085AE6, + 0xFF0F6A70, + 0x66063BCA, + 0x11010B5C, + 0x8F659EFF, + 0xF862AE69, + 0x616BFFD3, + 0x166CCF45, + 0xA00AE278, + 0xD70DD2EE, + 0x4E048354, + 0x3903B3C2, + 0xA7672661, + 0xD06016F7, + 0x4969474D, + 0x3E6E77DB, + 0xAED16A4A, + 0xD9D65ADC, + 0x40DF0B66, + 0x37D83BF0, + 0xA9BCAE53, + 0xDEBB9EC5, + 0x47B2CF7F, + 0x30B5FFE9, + 0xBDBDF21C, + 0xCABAC28A, + 0x53B39330, + 0x24B4A3A6, + 0xBAD03605, + 0xCDD70693, + 0x54DE5729, + 0x23D967BF, + 0xB3667A2E, + 0xC4614AB8, + 0x5D681B02, + 0x2A6F2B94, + 0xB40BBE37, + 0xC30C8EA1, + 0x5A05DF1B, + 0x2D02EF8D +}; + +int +CalculateCrc32 ( + uint8_t *Data, + size_t DataSize, + uint32_t *CrcOut + ) +/*++ + +Routine Description: + + The CalculateCrc32 routine. + +Arguments: + + Data - The buffer contaning the data to be processed + DataSize - The size of data to be processed + CrcOut - A pointer to the caller allocated UINT32 that on + contains the CRC32 checksum of Data + +Returns: + + EFI_SUCCESS - Calculation is successful. + EFI_INVALID_PARAMETER - Data / CrcOut = NULL, or DataSize = 0 + +--*/ +{ + uint32_t Crc; + size_t Index; + uint8_t *Ptr; + + if ((DataSize == 0) || (Data == NULL) || (CrcOut == NULL)) { + return -1; + } + + Crc = 0xffffffff; + for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) { + Crc = (Crc >> 8) ^ mCrcTable[(uint8_t) Crc ^ *Ptr]; + } + + *CrcOut = Crc ^ 0xffffffff; + + return 0; +} diff --git a/fstypes.c b/fstypes.c new file mode 100644 index 0000000..4dc44e3 --- /dev/null +++ b/fstypes.c @@ -0,0 +1,64 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "guid.h" +#include + +GUID fstypes[512]; +char *fsnames[512]; + +#include "fstypes.h" + +void init_fstypes() +{ + int i; + + for(i = 0; i < 512; i++) + { + string_to_guid(&fstypes[i], "00000000-0000-0000-0000-000000000000"); + fsnames[i] = NULL; + } + + string_to_guid(&fstypes[FSTYPE_EFI_SYSTEM], "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"); + fsnames[FSTYPE_EFI_SYSTEM] = "system"; + string_to_guid(&fstypes[FSTYPE_BIOS_BOOT], "21686148-6449-6E6F-744E-656564454649"); + fsnames[FSTYPE_BIOS_BOOT] = "bios"; + string_to_guid(&fstypes[0x01], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x01] = "fat12"; + string_to_guid(&fstypes[0x04], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x04] = "fat16"; + string_to_guid(&fstypes[0x06], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x06] = "fat16b"; + string_to_guid(&fstypes[0x07], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x07] = "ntfs"; + string_to_guid(&fstypes[0x0b], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x0b] = "fat32"; + string_to_guid(&fstypes[0x0c], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x0c] = "fat32x"; + string_to_guid(&fstypes[0x0e], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x0e] = "fat16x"; + string_to_guid(&fstypes[0x28], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x28] = "fat16+"; + string_to_guid(&fstypes[0x29], "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7"); + fsnames[0x29] = "fat32+"; + string_to_guid(&fstypes[0x83], "0FC63DAF-8483-4772-8E79-3D69D8477DE4"); + fsnames[0x83] = "linux"; +} diff --git a/fstypes.h b/fstypes.h new file mode 100644 index 0000000..6267701 --- /dev/null +++ b/fstypes.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef FSTYPES_H +#define FSTYPES_H + +#include "guid.h" + +extern GUID fstypes[512]; +extern char *fsnames[512]; + +#define FSTYPE_EFI_SYSTEM 256 +#define FSTYPE_BIOS_BOOT 257 + +void init_fstypes(); + +#endif diff --git a/guid.c b/guid.c new file mode 100644 index 0000000..8a71b7e --- /dev/null +++ b/guid.c @@ -0,0 +1,203 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include +#include + +#ifdef WINDOWS +#include +#include +#endif + +#include "guid.h" + +#define GUID_FMT "%08X-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX" + +static int rnd_init = 0; + +int guid_to_string(char *str, GUID *guid) +{ + if(guid == NULL) + { + fprintf(stderr, "guid_to_string: guid is null\n"); + return -1; + } + if(str == NULL) + { + fprintf(stderr, "guid_to_string: str is null\n"); + return -1; + } + + sprintf(str, GUID_FMT, guid->data1, guid->data2, guid->data3, guid->data4[0], guid->data4[1], + guid->data4[2], guid->data4[3], guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); + + return 0; +} + +int string_to_guid(GUID *guid, char *str) +{ + if(guid == NULL) + { + fprintf(stderr, "string_to_guid: guid is null\n"); + return -1; + } + if(str == NULL) + { + fprintf(stderr, "string_to_guid: str is null\n"); + return -1; + } + + sscanf(str, GUID_FMT, &guid->data1, &guid->data2, &guid->data3, &guid->data4[0], &guid->data4[1], + &guid->data4[2], &guid->data4[3], &guid->data4[4], &guid->data4[5], &guid->data4[6], &guid->data4[7]); + + return 0; +} + +int guid_to_bytestring(uint8_t *bytes, GUID *guid) +{ + int i; + + if(guid == NULL) + { + fprintf(stderr, "guid_to_bytestring: guid is null\n"); + return -1; + } + if(bytes == NULL) + { + fprintf(stderr, "guid_to_bytestring: bytes is null\n"); + return -1; + } + + *(uint32_t *)&bytes[0] = guid->data1; + *(uint16_t *)&bytes[4] = guid->data2; + *(uint16_t *)&bytes[6] = guid->data3; + for(i = 0; i < 8; i++) + bytes[8 + i] = guid->data4[i]; + + return 0; +} + +int guid_is_zero(GUID *guid) +{ + int i; + + if(guid->data1 != 0) + return 0; + if(guid->data2 != 0) + return 0; + if(guid->data3 != 0) + return 0; + for(i = 0; i < 8; i++) + { + if(guid->data4[i] != 0) + return 0; + } + return 1; +} + +void init_rnd() +{ + /* Attempt to initialise the random number generator */ + FILE *rnd = fopen("/dev/random", "r"); + if(rnd != NULL) + { + unsigned int seed; + if(fread(&seed, 1, sizeof(unsigned int), rnd) == sizeof(unsigned int)) + { + srand(seed); + fclose(rnd); + rnd_init = 1; + return; + } + + fclose(rnd); + } + +#ifdef WINDOWS + { + HCRYPTPROV prov = 0; + if(!CryptAcquireContext(&prov, NULL, NULL, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT)) + { + if(!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + prov = 0; + } + + if(prov != 0) + { + unsigned int seed; + CryptGenRandom(prov, sizeof(unsigned int), (BYTE *)&seed); + srand(seed); + rnd_init = 1; + return; + } + } +#endif + + { + time_t t = time(NULL); + struct tm *tmptr = gmtime(&t); + int seed = tmptr->tm_hour; + seed <<= 3; + seed ^= tmptr->tm_isdst; + seed <<= 3; + seed ^= tmptr->tm_mday; + seed <<= 3; + seed ^= tmptr->tm_min; + seed <<= 3; + seed ^= tmptr->tm_mon; + seed <<= 3; + seed ^= tmptr->tm_sec; + seed <<= 3; + seed ^= tmptr->tm_wday; + seed <<= 3; + seed ^= tmptr->tm_yday; + seed <<= 3; + seed ^= tmptr->tm_year; + + srand((unsigned int)seed); + rnd_init = 1; + return; + } +} + +uint8_t rnd_byte() +{ + if(rnd_init == 0) + init_rnd(); + + return (uint8_t)(rand() & 0xff); +} + +int random_guid(GUID *guid) +{ + int i; + + guid->data1 = (uint32_t)rnd_byte() | (((uint32_t)rnd_byte()) << 8) | + (((uint32_t)rnd_byte()) << 16) | (((uint32_t)rnd_byte()) << 24); + guid->data2 = (uint16_t)rnd_byte() | (((uint16_t)rnd_byte()) << 8); + guid->data3 = (uint16_t)rnd_byte() | (((uint16_t)((rnd_byte() & 0x0f) | 0x40)) << 8); + for(i = 0; i < 8; i++) + guid->data4[i] = rnd_byte(); + + return 0; +} diff --git a/guid.h b/guid.h new file mode 100644 index 0000000..95a5e37 --- /dev/null +++ b/guid.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef GUID_H +#define GUID_H + +#include + +typedef struct _guid +{ + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} GUID; + +#define GUID_STRING_LENGTH 36 +#define GUID_BYTESTRING_LENGTH 16 + +int guid_to_string(char *str, GUID *guid); +int string_to_guid(GUID *guid, char *str); +int guid_to_bytestring(uint8_t *bytes, GUID *guid); +int random_guid(GUID *guid); +int guid_is_zero(GUID *guid); + +#endif diff --git a/mkgpt.c b/mkgpt.c new file mode 100644 index 0000000..6ca6423 --- /dev/null +++ b/mkgpt.c @@ -0,0 +1,568 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "guid.h" +#include "part.h" +#include "fstypes.h" +#include +#include +#include +#include +#include +#include +#include + +void dump_help(char *fname); +int check_parts(); +int parse_opts(int argc, char **argv); +int parse_guid(char *str, GUID *guid); +void write_output(); + +int CalculateCrc32 (uint8_t *Data, size_t DataSize, uint32_t *CrcOut); + +size_t sect_size = 512; +long image_sects = 0; +PART *first_part = NULL; +PART *last_part = NULL; +FILE *output = NULL; +GUID disk_guid; +int part_count; +int header_sectors; +int first_usable_sector; +int secondary_headers_sect; +int secondary_gpt_sect; + +int main(int argc, char **argv) +{ + init_fstypes(); + random_guid(&disk_guid); + + if(parse_opts(argc, argv) != 0) + return -1; + + if(output == NULL) + { + fprintf(stderr, "no output file specifed\n"); + dump_help(argv[0]); + return -1; + } + if(first_part == NULL) + { + fprintf(stderr, "no partitions specified\n"); + dump_help(argv[0]); + return -1; + } + + if(check_parts() != 0) + return -1; + + write_output(); + fclose(output); + + return 0; +} + +int parse_opts(int argc, char **argv) +{ + int i = 1; + int cur_part_id = 0; + PART *cur_part = NULL; + + /* First, parse global options */ + while(i < argc) + { + if(!strcmp(argv[i], "--output") || !strcmp(argv[i], "-o")) + { + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "no output file specified\n"); + return -1; + } + + output = fopen(argv[i], "w+"); + if(output == NULL) + { + fprintf(stderr, "unable to open %s for writing (%s)\n", argv[i], + strerror(errno)); + return -1; + } + i++; + } + else if(!strcmp(argv[i], "--disk-guid")) + { + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "no disk guid file specified\n"); + return -1; + } + + if(parse_guid(argv[i], &disk_guid) != 0) + { + fprintf(stderr, "invalid disk uuid (%s)\n", argv[i]); + return -1; + } + + i++; + } + else if(!strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) + { + dump_help(argv[0]); + return -1; + } + else if(!strcmp(argv[i], "--sector-size")) + { + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "sector size not specified\n"); + return -1; + } + + sect_size = atoi(argv[i]); + + if(sect_size < 512 || sect_size > 4096 || sect_size % 512) + { + fprintf(stderr, "invalid sector size (%zu) - must be >= 512 and <= 4096 and " + "a multiple of 512", sect_size); + return -1; + } + i++; + } + else if(!strcmp(argv[i], "--image-size")) + { + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "image size not specified\n"); + return -1; + } + + image_sects = atoi(argv[i]); + + i++; + } + else if(!strcmp(argv[i], "--part") || !strcmp(argv[i], "-p")) + break; + else + { + fprintf(stderr, "unknown argument - %s\n", argv[i]); + dump_help(argv[0]); + return i; + } + } + + /* Now parse partitions */ + while(i < argc) + { + if(!strcmp(argv[i], "--part") || !strcmp(argv[i], "-p")) + { + /* Store the current partition data if there is one */ + if(cur_part != NULL) + { + if(last_part == NULL) + { + first_part = last_part = cur_part; + cur_part->next = NULL; + } + else + { + last_part->next = cur_part; + last_part = cur_part; + cur_part->next = NULL; + } + } + + /* Allocate a new partition structure */ + cur_part = (PART *)malloc(sizeof(PART)); + if(cur_part == NULL) + { + fprintf(stderr, "out of memory allocating partition structure\n"); + return -1; + } + memset(cur_part, 0, sizeof(PART)); + cur_part_id++; + cur_part->id = cur_part_id; + + /* Get the filename of the partition image */ + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "no partition image specified for partition %i\n", cur_part_id); + return -1; + } + cur_part->src = fopen(argv[i], "r"); + if(cur_part->src == NULL) + { + fprintf(stderr, "unable to open partition image (%s) for partition (%i) - %s\n", argv[i], + cur_part_id, strerror(errno)); + return -1; + } + + i++; + } + else if(!strcmp(argv[i], "--name") || !strcmp(argv[i], "-n")) + { + if(cur_part == NULL) + { + fprintf(stderr, "--part must be specified before --name argument\n"); + return -1; + } + + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "partition name not specified %i\n", cur_part_id); + return -1; + } + + cur_part->name = argv[i]; + + i++; + } + else if(!strcmp(argv[i], "--type") || (!strcmp(argv[i], "-t"))) + { + if(cur_part == NULL) + { + fprintf(stderr, "--part must be specifed before --type argument\n"); + return -1; + } + + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "partition type not specified %i\n", cur_part_id); + return -1; + } + + if(parse_guid(argv[i], &cur_part->type) != 0) + { + fprintf(stderr, "invalid partition type (%s) for partition %i\n", argv[i], cur_part_id); + return -1; + } + + i++; + } + else if(!strcmp(argv[i], "--uuid") || (!strcmp(argv[i], "-u"))) + { + if(cur_part == NULL) + { + fprintf(stderr, "--part must be specifed before --uuid argument\n"); + return -1; + } + + i++; + if(i == argc || argv[i][0] == '-') + { + fprintf(stderr, "partition uuid not specified %i\n", cur_part_id); + return -1; + } + + if(parse_guid(argv[i], &cur_part->uuid) != 0) + { + fprintf(stderr, "invalid partition uuid (%s) for partition %i\n", argv[i], cur_part_id); + return -1; + } + + i++; + } + else + { + fprintf(stderr, "unknown argument - %s\n", argv[i]); + dump_help(argv[0]); + return i; + } + } + + if(cur_part != NULL) + { + if(last_part == NULL) + { + first_part = last_part = cur_part; + cur_part->next = NULL; + } + else + { + last_part->next = cur_part; + last_part = cur_part; + cur_part->next = NULL; + } + } + + return 0; +} + +void dump_help(char *fname) +{ + printf("Usage: %s -o [-h] [--sector-size sect_size] [partition def 0] [part def 1] ... [part def n]\n", + fname); + +} + +int parse_guid(char *str, GUID *guid) +{ + long mbr_id = -1; + int i; + + /* detect request for random uuid */ + if(!strcmp(str, "random") || !strcmp(str, "rnd")) + return random_guid(guid); + + /* detect mbr partition id by number */ + mbr_id = strtol(str, NULL, 0); + if(mbr_id == LONG_MIN || mbr_id == LONG_MAX) + mbr_id = -1; + + /* detect by name */ + for(i = 0; i < 512; i++) + { + if(fsnames[i] == NULL) + continue; + if(!strcmp(fsnames[i], str)) + { + mbr_id = i; + break; + } + } + + if(mbr_id >= 0 && mbr_id <= 511) + { + if(guid_is_zero(&fstypes[mbr_id])) + return -1; + memcpy(guid, &fstypes[mbr_id], sizeof(GUID)); + return 0; + } + + /* try and parse as guid */ + return string_to_guid(guid, str); +} + +int check_parts() +{ + /* Iterate through the partitions, checking validity */ + int cur_part_id = 0; + int cur_sect; + PART *cur_part; + int header_length; + int needed_file_length; + + /* Count partitions */ + cur_part = first_part; + part_count = 0; + while(cur_part) + { + part_count++; + cur_part = cur_part->next; + } + + /* Determine the sectors needed for MBR, GPT header and partition entries */ + cur_sect = 2; /* MBR + GPT header */ + header_length = part_count * 128; + header_sectors = header_length / sect_size; + if(header_length % sect_size) + header_sectors++; + cur_sect += header_sectors; + first_usable_sector = cur_sect; + + cur_part = first_part; + while(cur_part) + { + long cur_part_file_len; + + cur_part_id++; + + if(guid_is_zero(&cur_part->type)) + { + fprintf(stderr, "partition type not specified for partition %i\n", cur_part_id); + return -1; + } + + if(guid_is_zero(&cur_part->uuid)) + random_guid(&cur_part->uuid); + + if(cur_part->sect_start == 0) + cur_part->sect_start = cur_sect; + else if(cur_part->sect_start < cur_sect) + { + fprintf(stderr, "unable to start partition %i at sector %i (would conflict with other data)\n", + cur_part_id, cur_part->sect_start); + return -1; + } + + if(cur_part->name == NULL) + { + cur_part->name = (char *)malloc(128); + sprintf(cur_part->name, "part%i", cur_part_id); + } + + fseek(cur_part->src, 0, SEEK_END); + cur_part_file_len = ftell(cur_part->src); + fseek(cur_part->src, 0, SEEK_SET); + + if(cur_part->sect_length == 0) + { + cur_part->sect_length = cur_part_file_len / sect_size; + if(cur_part_file_len % sect_size) + cur_part->sect_length++; + } + cur_sect = cur_part->sect_start + cur_part->sect_length; + + cur_part = cur_part->next; + } + + /* Add space for the secondary GPT */ + needed_file_length = cur_sect + 1 + header_sectors; + + if(image_sects == 0) + image_sects = needed_file_length; + else if(image_sects < needed_file_length) + { + fprintf(stderr, "requested image size (%lu) is too small to hold the partitions\n", image_sects * sect_size); + return -1; + } + + secondary_headers_sect = image_sects - 1 - header_sectors; + secondary_gpt_sect = image_sects - 1; + + return 0; +} + +void write_output() +{ + int i; + uint8_t *mbr, *gpt, *gpt2, *parts, *image_buf; + PART *cur_part; + + /* Write MBR */ + mbr = (uint8_t *)malloc(sect_size); + memset(mbr, 0, sect_size); + + *(uint32_t *)&mbr[446] = 0x00020000; /* boot indicator = 0, start CHS = 0x000200 */ + mbr[446 + 4] = 0xee; /* OSType = GPT Protective */ + mbr[446 + 5] = 0xff; + mbr[446 + 6] = 0xff; + mbr[446 + 7] = 0xff; /* EndingCHS = 0xffffff */ + *(uint32_t *)&mbr[446 + 8] = 0x1; /* StartingLBA = 1 */ + + if(image_sects > 0xffffffff) + *(uint32_t *)&mbr[446 + 12] = 0xffffffff; + else + *(uint32_t *)&mbr[446 + 12] = (uint32_t)image_sects - 1; + + mbr[510] = 0x55; mbr[511] = 0xaa; /* Signature */ + + assert(fwrite(mbr, 1, sect_size, output) == sect_size); + + /* Define GPT headers */ + gpt = (uint8_t *)malloc(sect_size); + assert(gpt); + gpt2 = (uint8_t *)malloc(sect_size); + assert(gpt2); + + memset(gpt, 0, sect_size); + memset(gpt2, 0, sect_size); + + *(uint64_t *)&gpt[0] = 0x5452415020494645ULL; /* Signature */ + *(uint32_t *)&gpt[8] = 0x00010000UL; /* Revision */ + *(uint32_t *)&gpt[12] = 96; /* HeaderSize */ + *(uint32_t *)&gpt[16] = 0; /* HeaderCRC32 */ + *(uint32_t *)&gpt[20] = 0; /* Reserved */ + *(uint64_t *)&gpt[24] = 0x1; /* MyLBA */ + *(uint64_t *)&gpt[32] = secondary_gpt_sect; /* AlternateLBA */ + *(uint64_t *)&gpt[40] = first_usable_sector; /* FirstUsableLBA */ + *(uint64_t *)&gpt[48] = secondary_headers_sect - 1; /* LastUsableLBA */ + guid_to_bytestring(&gpt[56], &disk_guid); /* DiskGUID */ + *(uint64_t *)&gpt[72] = 0x2; /* PartitionEntryLBA */ + *(uint32_t *)&gpt[80] = part_count; /* NumberOfPartitionEntries */ + *(uint32_t *)&gpt[84] = 128; /* SizeOfPartitionEntry */ + *(uint32_t *)&gpt[88] = 0; /* PartitionEntryArrayCRC32 */ + + /* Define GPT partition entries */ + parts = (uint8_t *)malloc(header_sectors * sect_size); + assert(parts); + memset(parts, 0, header_sectors * sect_size); + + cur_part = first_part; + i = 0; + while(cur_part) + { + int char_id; + + guid_to_bytestring(&parts[i * 128], &cur_part->type); /* PartitionTypeGUID */ + guid_to_bytestring(&parts[i * 128 + 16], &cur_part->uuid); /* UniquePartitionGUID */ + *(uint64_t *)&parts[i * 128 + 32] = cur_part->sect_start; /* StartingLBA */ + *(uint64_t *)&parts[i * 128 + 40] = cur_part->sect_start + cur_part->sect_length - 1; /* EndingLBA */ + *(uint64_t *)&parts[i * 128 + 48] = cur_part->attrs; /* Attributes */ + + for(char_id = 0; char_id < (int)strlen(cur_part->name) && char_id < 35; char_id++) + *(uint16_t *)&parts[i * 128 + 56 + char_id * 2] = (uint16_t)cur_part->name[char_id]; + + i++; + cur_part = cur_part->next; + } + + /* Do CRC calculations on the partition table entries and GPT headers */ + CalculateCrc32(parts, part_count * 128, (uint32_t *)&gpt[88]); + CalculateCrc32(gpt, 96, (uint32_t *)&gpt[16]); + + memcpy(gpt2, gpt, 96); + *(uint32_t *)&gpt2[16] = 0; /* HeaderCRC32 */ + *(uint64_t *)&gpt2[24] = secondary_gpt_sect; /* MyLBA */ + *(uint64_t *)&gpt2[32] = 0x1; /* AlternateLBA */ + *(uint64_t *)&gpt2[72] = secondary_headers_sect; /* PartitionEntryLBA */ + CalculateCrc32(gpt2, 96, (uint32_t *)&gpt2[16]); + + /* Write primary GPT and headers */ + assert(fwrite(gpt, 1, sect_size, output) == sect_size); + assert(fwrite(parts, 1, header_sectors * sect_size, output) == header_sectors * sect_size); + + /* Write partitions */ + cur_part = first_part; + image_buf = (uint8_t *)malloc(sect_size); + while(cur_part) + { + size_t bytes_read; + size_t bytes_written = 0; + + fseek(output, cur_part->sect_start * sect_size, SEEK_SET); + while((bytes_read = fread(image_buf, 1, sect_size, cur_part->src)) > 0) + { + size_t bytes_to_write = bytes_read; + + /* Determine how much to write */ + if((bytes_written + bytes_to_write) > (size_t)(cur_part->sect_length * sect_size)) + bytes_to_write = cur_part->sect_length * sect_size - bytes_written; + + assert(fwrite(image_buf, 1, bytes_to_write, output) == bytes_to_write); + + bytes_written += bytes_to_write; + } + + cur_part = cur_part->next; + } + + /* Write secondary GPT partition headers and header */ + fseek(output, secondary_headers_sect * sect_size, SEEK_SET); + assert(fwrite(parts, 1, header_sectors * sect_size, output) == header_sectors * sect_size); + fseek(output, secondary_gpt_sect * sect_size, SEEK_SET); + assert(fwrite(gpt2, 1, sect_size, output) == sect_size); +} diff --git a/mkgpt.vcxproj b/mkgpt.vcxproj new file mode 100644 index 0000000..c9d7e97 --- /dev/null +++ b/mkgpt.vcxproj @@ -0,0 +1,78 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {40443019-486A-4245-8816-9F1FEEB9FE9D} + mkgpt + + + + Application + true + v110 + MultiByte + + + Application + false + v110 + true + MultiByte + + + + + + + + + + + + + + + Level3 + Disabled + + + true + + + + + Level3 + MaxSpeed + true + true + + + true + true + true + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/part.h b/part.h new file mode 100644 index 0000000..19d43c8 --- /dev/null +++ b/part.h @@ -0,0 +1,44 @@ +/* Copyright (C) 2014 by John Cronin + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef PART_H +#define PART_H + +#include +#include +#include "guid.h" + +typedef struct _part +{ + GUID type; + GUID uuid; + int id; + uint64_t attrs; + int sect_start; + int sect_length; + long src_length; + char *name; + FILE *src; + + struct _part *next; +} PART; + +#endif -- cgit 1.4.1-2-gfad0