├── LICENSE ├── MODULE_LICENSE_GPL ├── fuzzer ├── corpus │ └── typical.bin ├── Android.bp └── libgptf_fuzzer.cc ├── OWNERS ├── METADATA ├── crc32.h ├── uninstall-fixparts ├── uninstall-gdisk ├── sgdisk.h ├── attributes.h ├── mbr.h ├── Makefile.mingw ├── Makefile.mingw64 ├── Makefile.freebsd ├── Makefile ├── guid.h ├── crc32.cc ├── Makefile.mac ├── gptcl.h ├── popt.h ├── diskio-heap.cc ├── parttypes.h ├── gdisk.cc ├── diskio.cc ├── diskio.h ├── support.h ├── cgdisk.cc ├── gpttext.h ├── current.spec ├── Android.bp ├── bsd.h ├── fixparts.cc ├── android_popt.cc ├── gptpart.h ├── mbrpart.h ├── sgdisk.cc ├── gptcurses.h ├── basicmbr.h ├── README-efi.txt ├── mbr.cc ├── README.Windows ├── guid.cc ├── attributes.cc ├── gpt.h ├── gdisk_test.sh ├── fixparts.8 ├── diskio-windows.cc ├── bsd.cc ├── mbrpart.cc ├── support.cc └── README /LICENSE: -------------------------------------------------------------------------------- 1 | COPYING -------------------------------------------------------------------------------- /MODULE_LICENSE_GPL: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fuzzer/corpus/typical.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ArrowOS/android_external_gptfdisk/arrow-13.1/fuzzer/corpus/typical.bin -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # Default code reviewers picked from top 3 or more developers. 2 | # Please update this list if you find better candidates. 3 | bohu@google.com 4 | adelva@google.com 5 | -------------------------------------------------------------------------------- /METADATA: -------------------------------------------------------------------------------- 1 | name: "gptfdisk" 2 | description: "This package includes the source code for four related disk partitioning programs." 3 | third_party { 4 | url { 5 | type: HOMEPAGE 6 | value: "https://sourceforge.net/projects/gptfdisk/" 7 | } 8 | url { 9 | type: GIT 10 | value: "https://git.code.sf.net/p/gptfdisk/code" 11 | } 12 | version: "d292ff36a3b350115835c62462911c3d8721704f" 13 | license_type: RESTRICTED 14 | last_upgrade_date { 15 | year: 2020 16 | month: 2 17 | day: 10 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /crc32.h: -------------------------------------------------------------------------------- 1 | /* 2 | * efone - Distributed internet phone system. 3 | * 4 | * (c) 1999,2000 Krzysztof Dabrowski 5 | * (c) 1999,2000 ElysiuM deeZine 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 10 | * 2 of the License, or (at your option) any later version. 11 | * 12 | */ 13 | 14 | /* based on implementation by Finn Yannick Jacobs. */ 15 | 16 | #include 17 | 18 | void chksum_crc32gentab (); 19 | uint32_t chksum_crc32 (unsigned char *block, unsigned int length); 20 | extern unsigned int crc_tab[256]; 21 | -------------------------------------------------------------------------------- /uninstall-fixparts: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to uninstall FixParts from OS X 4 | 5 | OSName=`uname -s` 6 | if [[ $OSName != 'Darwin' ]] ; then 7 | echo "This script is useful only under OS X! Exiting!" 8 | exit 1 9 | fi 10 | 11 | # Remove from pre-1.0.1 locations 12 | rm -f /usr/sbin/fixparts 13 | rm -rf /usr/share/doc/fixparts 14 | rm -f /usr/share/man/man8/fixparts.8 15 | 16 | # Remove from 1.0.1 (and later) locations 17 | rm -f /usr/local/bin/fixparts 18 | rm -rf /usr/local/doc/fixparts 19 | rm -f /usr/local/man/man8/fixparts.8 20 | 21 | echo "All FixParts program files successfully removed!" 22 | 23 | # And finally, erase this script itself.... 24 | rm -f /usr/local/bin/uninstall-fixparts 25 | -------------------------------------------------------------------------------- /uninstall-gdisk: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Script to uninstall GPT fdisk from OS X 4 | 5 | OSName=`uname -s` 6 | if [[ $OSName != 'Darwin' ]] ; then 7 | echo "This script is useful only under OS X! Exiting!" 8 | exit 1 9 | fi 10 | 11 | # Remove from pre-1.0.1 locations 12 | rm -f /usr/sbin/gdisk 13 | rm -f /usr/sbin/sgdisk 14 | rm -f /usr/sbin/cgdisk 15 | rm -rf /usr/share/doc/gdisk/ 16 | rm -f /usr/share/man/man8/gdisk.8 17 | rm -f /usr/share/man/man8/sgdisk.8 18 | rm -f /usr/share/man/man8/cgdisk.8 19 | 20 | # Remove from 1.0.1 (and later) locations 21 | rm -f /usr/local/bin/gdisk 22 | rm -f /usr/local/bin/sgdisk 23 | rm -f /usr/local/bin/cgdisk 24 | rm -rf /usr/local/doc/gdisk 25 | rm -f /usr/local/man/man8/gdisk.8 26 | rm -f /usr/local/man/man8/sgdisk.8 27 | rm -f /usr/local/man/man8/cgdisk.8 28 | 29 | echo "All GPT fdisk program files successfully removed!" 30 | 31 | # And finally, erase this script itself.... 32 | rm -f /usr/local/bin/uninstall-gdisk 33 | -------------------------------------------------------------------------------- /fuzzer/Android.bp: -------------------------------------------------------------------------------- 1 | package { 2 | // See: http://go/android-license-faq 3 | // A large-scale-change added 'default_applicable_licenses' to import 4 | // all of the 'license_kinds' from "external_gptfdisk_license" 5 | // to get the below license kinds: 6 | // SPDX-license-identifier-GPL-2.0 7 | default_applicable_licenses: ["external_gptfdisk_license"], 8 | } 9 | 10 | cc_fuzz { 11 | name: "libgptf_fuzzer", 12 | srcs: ["libgptf_fuzzer.cc"], 13 | cflags: ["-DENABLE_HEAP_DISKIO"], 14 | host_supported: true, 15 | corpus: ["corpus/*"], 16 | static_libs: ["libgmock"], 17 | target: { 18 | android: { 19 | static_libs: [ 20 | "libgptf_fuzzer_lib", 21 | "libext2_uuid", 22 | ], 23 | }, 24 | host: { 25 | static_libs: [ 26 | "libgptf_fuzzer_lib", 27 | "libext2_uuid", 28 | ], 29 | }, 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /sgdisk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Lineage Android Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef __SGDISK 18 | #define __SGDISK 19 | 20 | #include 21 | #include 22 | 23 | enum ptbl_type { 24 | MBR, 25 | GPT 26 | }; 27 | 28 | struct sgdisk_partition_table { 29 | ptbl_type type; 30 | std::string guid; 31 | }; 32 | 33 | struct sgdisk_partition { 34 | int num; 35 | std::string type; 36 | std::string guid; 37 | std::string name; 38 | }; 39 | 40 | int sgdisk_read(const char* device, sgdisk_partition_table& ptbl, 41 | std::vector& partitions); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /attributes.h: -------------------------------------------------------------------------------- 1 | /* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed 2 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 3 | 4 | #include 5 | #include 6 | 7 | #ifndef __GPT_ATTRIBUTES 8 | #define __GPT_ATTRIBUTES 9 | 10 | #define NUM_ATR 64 /* # of attributes -- 64, since it's a 64-bit field */ 11 | #define ATR_NAME_SIZE 25 /* maximum size of attribute names */ 12 | 13 | using namespace std; 14 | 15 | class Attributes { 16 | protected: 17 | static string atNames[NUM_ATR]; 18 | static int numAttrs; 19 | void Setup(void); 20 | uint64_t attributes; 21 | 22 | public: 23 | Attributes(void); 24 | Attributes(const uint64_t a); 25 | ~Attributes(void); 26 | void operator=(uint64_t a) {attributes = a;} 27 | 28 | uint64_t GetAttributes(void) const {return attributes;} 29 | void DisplayAttributes(void); 30 | void ShowAttributes(const uint32_t partNum); 31 | 32 | void ChangeAttributes(void); 33 | bool OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits); 34 | 35 | static const string& GetAttributeName(const uint32_t bitNum) {return atNames [bitNum];} 36 | static void ListAttributes(void); 37 | }; // class Attributes 38 | 39 | ostream & operator<<(ostream & os, const Attributes & data); 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /fuzzer/libgptf_fuzzer.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * This software is licensed under the terms of the GNU General Public 5 | * License version 2, as published by the Free Software Foundation, and 6 | * may be copied, distributed, and modified under those terms. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #include 15 | #include 16 | 17 | #include "diskio.h" 18 | #include "mbr.h" 19 | #include "gpt.h" 20 | 21 | #include 22 | 23 | std::ofstream silence("/dev/null"); 24 | 25 | extern "C" int LLVMFuzzerInitialize(int *, char ***) { 26 | std::cout.rdbuf(silence.rdbuf()); 27 | std::cerr.rdbuf(silence.rdbuf()); 28 | return 0; 29 | } 30 | 31 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { 32 | DiskIO disk; 33 | disk.OpenForRead(static_cast(data), size); 34 | 35 | BasicMBRData mbrData; 36 | mbrData.ReadMBRData(&disk); 37 | 38 | GPTData gptData; 39 | gptData.SetDisk(disk); 40 | gptData.LoadPartitions("/dev/does_not_exist"); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /mbr.h: -------------------------------------------------------------------------------- 1 | /* mbr.h -- MBR data structure definitions, types, and functions */ 2 | 3 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 4 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 5 | 6 | #include 7 | #include 8 | #include "gptpart.h" 9 | //#include "partnotes.h" 10 | #include "diskio.h" 11 | #include "basicmbr.h" 12 | 13 | #ifndef __MBRSTRUCTS 14 | #define __MBRSTRUCTS 15 | 16 | using namespace std; 17 | 18 | /**************************************** 19 | * * 20 | * MBRData class and related structures * 21 | * * 22 | ****************************************/ 23 | 24 | // Full data in tweaked MBR format 25 | class MBRData : public BasicMBRData { 26 | protected: 27 | public: 28 | MBRData(void) {} 29 | MBRData(string deviceFilename) : BasicMBRData(deviceFilename) {} 30 | MBRData & operator=(const BasicMBRData & orig); 31 | ~MBRData(void); 32 | 33 | // Functions to create, delete, or change partitions 34 | // Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact 35 | void MakeProtectiveMBR(int clearBoot = 0); 36 | void OptimizeEESize(void); 37 | int DeleteByLocation(uint64_t start64, uint64_t length64); 38 | 39 | // Functions to extract data on specific partitions.... 40 | GPTPart AsGPT(int i); 41 | }; // struct MBRData 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /Makefile.mingw: -------------------------------------------------------------------------------- 1 | CC=/usr/bin/i686-w64-mingw32-gcc 2 | CXX=/usr/bin/i686-w64-mingw32-g++ 3 | STRIP=/usr/bin/i686-w64-mingw32-strip 4 | CFLAGS=-O2 -Wall -static -static-libgcc -static-libstdc++ -D_FILE_OFFSET_BITS=64 -g 5 | CXXFLAGS=-O2 -Wall -static -static-libgcc -static-libstdc++ -D_FILE_OFFSET_BITS=64 -g 6 | #CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g 7 | LIB_NAMES=guid gptpart bsd parttypes attributes crc32 mbrpart basicmbr mbr gpt support diskio diskio-windows 8 | MBR_LIBS=support diskio diskio-windows basicmbr mbrpart 9 | LIB_SRCS=$(NAMES:=.cc) 10 | LIB_OBJS=$(LIB_NAMES:=.o) 11 | MBR_LIB_OBJS=$(MBR_LIBS:=.o) 12 | LIB_HEADERS=$(LIB_NAMES:=.h) 13 | DEPEND= makedepend $(CFLAGS) 14 | 15 | all: gdisk fixparts 16 | 17 | gdisk: $(LIB_OBJS) gdisk.o gpttext.o 18 | $(CXX) $(CXXFLAGS) $(LIB_OBJS) gdisk.o gpttext.o -lrpcrt4 -static-libgcc -o gdisk32.exe 19 | 20 | sgdisk: $(LIB_OBJS) sgdisk.o 21 | $(CXX) $(CXXFLAGS) $(LIB_OBJS) sgdisk.o -lpopt -static-libgcc -o sgdisk32.exe 22 | 23 | fixparts: $(MBR_LIB_OBJS) fixparts.o 24 | $(CXX) $(CXXFLAGS) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -static-libgcc -o fixparts32.exe 25 | 26 | lint: #no pre-reqs 27 | lint $(SRCS) 28 | 29 | clean: #no pre-reqs 30 | rm -f core *.o *~ gdisk.exe sgdisk.exe 31 | 32 | strip: #no pre-reqs 33 | $(STRIP) gdisk32.exe fixparts32.exe 34 | 35 | # what are the source dependencies 36 | depend: $(SRCS) 37 | $(DEPEND) $(SRCS) 38 | 39 | $(OBJS): 40 | 41 | # DO NOT DELETE 42 | -------------------------------------------------------------------------------- /Makefile.mingw64: -------------------------------------------------------------------------------- 1 | CC=/usr/bin/x86_64-w64-mingw32-gcc 2 | CXX=/usr/bin/x86_64-w64-mingw32-g++ 3 | STRIP=/usr/bin/x86_64-w64-mingw32-strip 4 | CFLAGS=-O2 -Wall -static -static-libgcc -static-libstdc++ -D_FILE_OFFSET_BITS=64 -g 5 | CXXFLAGS=-O2 -Wall -static -static-libgcc -static-libstdc++ -D_FILE_OFFSET_BITS=64 -g 6 | #CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g 7 | LIB_NAMES=guid gptpart bsd parttypes attributes crc32 mbrpart basicmbr mbr gpt support diskio diskio-windows 8 | MBR_LIBS=support diskio diskio-windows basicmbr mbrpart 9 | LIB_SRCS=$(NAMES:=.cc) 10 | LIB_OBJS=$(LIB_NAMES:=.o) 11 | MBR_LIB_OBJS=$(MBR_LIBS:=.o) 12 | LIB_HEADERS=$(LIB_NAMES:=.h) 13 | DEPEND= makedepend $(CFLAGS) 14 | 15 | all: gdisk fixparts 16 | 17 | gdisk: $(LIB_OBJS) gdisk.o gpttext.o 18 | $(CXX) $(CXXFLAGS) $(LIB_OBJS) gdisk.o gpttext.o -lrpcrt4 -static-libgcc -o gdisk64.exe 19 | 20 | sgdisk: $(LIB_OBJS) sgdisk.o 21 | $(CXX) $(CXXFLAGS) $(LIB_OBJS) sgdisk.o -lpopt -static-libgcc -o sgdisk64.exe 22 | 23 | fixparts: $(MBR_LIB_OBJS) fixparts.o 24 | $(CXX) $(CXXFLAGS) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -static-libgcc -o fixparts64.exe 25 | 26 | lint: #no pre-reqs 27 | lint $(SRCS) 28 | 29 | clean: #no pre-reqs 30 | rm -f core *.o *~ gdisk64.exe sgdisk64.exe 31 | 32 | strip: #no pre-reqs 33 | $(STRIP) gdisk64.exe fixparts64.exe 34 | 35 | # what are the source dependencies 36 | depend: $(SRCS) 37 | $(DEPEND) $(SRCS) 38 | 39 | $(OBJS): 40 | 41 | # DO NOT DELETE 42 | -------------------------------------------------------------------------------- /Makefile.freebsd: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=g++ 3 | CFLAGS+=-D_FILE_OFFSET_BITS=64 4 | #CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64 -D USE_UTF16 -I/usr/local/include 5 | CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include 6 | LDFLAGS+= 7 | LIB_NAMES=crc32 support guid gptpart mbrpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix 8 | MBR_LIBS=support diskio diskio-unix basicmbr mbrpart 9 | LIB_OBJS=$(LIB_NAMES:=.o) 10 | MBR_LIB_OBJS=$(MBR_LIBS:=.o) 11 | LIB_HEADERS=$(LIB_NAMES:=.h) 12 | DEPEND= makedepend $(CXXFLAGS) 13 | 14 | all: gdisk cgdisk sgdisk fixparts 15 | 16 | gdisk: $(LIB_OBJS) gdisk.o gpttext.o 17 | # $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -licuio -luuid -o gdisk 18 | $(CXX) $(LIB_OBJS) gdisk.o gpttext.o -L/usr/local/lib $(LDFLAGS) -luuid -o gdisk 19 | 20 | cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o 21 | # $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o -L/usr/local/lib $(LDFLAGS) -licuio -luuid -lncurses -o cgdisk 22 | $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o -L/usr/local/lib $(LDFLAGS) -luuid -lncurses -o cgdisk 23 | 24 | sgdisk: $(LIB_OBJS) sgdisk.o gptcl.o 25 | # $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o -L/usr/local/lib $(LDFLAGS) -luuid -licuio -lpopt -o sgdisk 26 | $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o -L/usr/local/lib $(LDFLAGS) -luuid -lpopt -o sgdisk 27 | 28 | fixparts: $(MBR_LIB_OBJS) fixparts.o 29 | $(CXX) $(MBR_LIB_OBJS) fixparts.o -L/usr/local/lib $(LDFLAGS) -o fixparts 30 | 31 | lint: #no pre-reqs 32 | lint $(SRCS) 33 | 34 | clean: #no pre-reqs 35 | rm -f core *.o *~ gdisk sgdisk 36 | 37 | # what are the source dependencies 38 | depend: $(SRCS) 39 | $(DEPEND) $(SRCS) 40 | 41 | $(OBJS): 42 | $(CRITICAL_CXX_FLAGS) 43 | 44 | # DO NOT DELETE 45 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS+=-D_FILE_OFFSET_BITS=64 2 | #CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64 -D USE_UTF16 3 | CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64 4 | LDFLAGS+= 5 | LIB_NAMES=crc32 support guid gptpart mbrpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix 6 | MBR_LIBS=support diskio diskio-unix basicmbr mbrpart 7 | LIB_OBJS=$(LIB_NAMES:=.o) 8 | MBR_LIB_OBJS=$(MBR_LIBS:=.o) 9 | LIB_HEADERS=$(LIB_NAMES:=.h) 10 | DEPEND= makedepend $(CXXFLAGS) 11 | 12 | all: cgdisk gdisk sgdisk fixparts 13 | 14 | gdisk: $(LIB_OBJS) gdisk.o gpttext.o 15 | $(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -luuid $(LDLIBS) -o gdisk 16 | # $(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -licuio -licuuc -luuid -o gdisk 17 | 18 | cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o 19 | $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -luuid -lncursesw $(LDLIBS) -o cgdisk 20 | # $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -licuio -licuuc -luuid -lncurses -o cgdisk 21 | 22 | sgdisk: $(LIB_OBJS) sgdisk.o gptcl.o 23 | $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o $(LDFLAGS) -luuid -lpopt $(LDLIBS) -o sgdisk 24 | # $(CXX) $(LIB_OBJS) sgdisk.o gptcl.o $(LDFLAGS) -licuio -licuuc -luuid -lpopt -o sgdisk 25 | 26 | fixparts: $(MBR_LIB_OBJS) fixparts.o 27 | $(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) $(LDLIBS) -o fixparts 28 | 29 | test: 30 | ./gdisk_test.sh 31 | 32 | lint: #no pre-reqs 33 | lint $(SRCS) 34 | 35 | clean: #no pre-reqs 36 | rm -f core *.o *~ gdisk sgdisk cgdisk fixparts 37 | 38 | # what are the source dependencies 39 | depend: $(SRCS) 40 | $(DEPEND) $(SRCS) 41 | 42 | $(OBJS): 43 | $(CRITICAL_CXX_FLAGS) 44 | 45 | # makedepend dependencies below -- type "makedepend *.cc" to regenerate.... 46 | # DO NOT DELETE 47 | -------------------------------------------------------------------------------- /guid.h: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Interface: GUIDData 3 | // 4 | // Description: GUIDData class header 5 | // Implements the GUIDData data structure and support methods 6 | // 7 | // 8 | // Author: Rod Smith , (C) 2010-2011 9 | // 10 | // Copyright: See COPYING file that comes with this distribution 11 | // 12 | // 13 | 14 | #ifndef __GUIDDATA_CLASS 15 | #define __GUIDDATA_CLASS 16 | 17 | #include 18 | #include 19 | 20 | // Have to play games with uuid_t since it's defined in incompatible ways 21 | // for Unix (libuuid) vs. Windows (in rpc.h) 22 | #ifdef _WIN32 23 | #include 24 | #ifdef _MSC_VER 25 | #pragma comment(lib, "Rpcrt4.lib") 26 | #endif 27 | typedef unsigned char my_uuid_t[16]; 28 | #else // Not Windows 29 | #include 30 | typedef uuid_t my_uuid_t; 31 | #endif 32 | 33 | using namespace std; 34 | 35 | // Note: This class's data size is critical. If data elements must be added, 36 | // it will be necessary to modify various GPT classes to compensate. 37 | class GUIDData { 38 | private: 39 | static bool firstInstance; 40 | protected: 41 | my_uuid_t uuidData; 42 | string DeleteSpaces(string s); 43 | public: 44 | GUIDData(void); 45 | GUIDData(const GUIDData & orig); 46 | GUIDData(const string & orig); 47 | GUIDData(const char * orig); 48 | ~GUIDData(void); 49 | 50 | // Data assignment operators.... 51 | GUIDData & operator=(const GUIDData & orig); 52 | GUIDData & operator=(const string & orig); 53 | GUIDData & operator=(const char * orig); 54 | void Zero(void); 55 | void Randomize(void); 56 | 57 | // Data tests.... 58 | int operator==(const GUIDData & orig) const; 59 | int operator!=(const GUIDData & orig) const; 60 | 61 | // Data retrieval.... 62 | string AsString(void) const; 63 | }; // class GUIDData 64 | 65 | ostream & operator<<(ostream & os, const GUIDData & data); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /crc32.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * efone - Distributed internet phone system. 3 | * 4 | * (c) 1999,2000 Krzysztof Dabrowski 5 | * (c) 1999,2000 ElysiuM deeZine 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 10 | * 2 of the License, or (at your option) any later version. 11 | * 12 | */ 13 | 14 | /* based on implementation by Finn Yannick Jacobs */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include "crc32.h" 20 | 21 | /* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab(). 22 | * so make sure, you call it before using the other 23 | * functions! 24 | */ 25 | uint32_t crc_tab[256]; 26 | 27 | /* chksum_crc() -- to a given block, this one calculates the 28 | * crc32-checksum until the length is 29 | * reached. the crc32-checksum will be 30 | * the result. 31 | */ 32 | uint32_t chksum_crc32 (unsigned char *block, unsigned int length) 33 | { 34 | unsigned long crc; 35 | unsigned long i; 36 | 37 | crc = 0xFFFFFFFF; 38 | for (i = 0; i < length; i++) 39 | { 40 | crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF]; 41 | } 42 | return (crc ^ 0xFFFFFFFF); 43 | } 44 | 45 | /* chksum_crc32gentab() -- to a global crc_tab[256], this one will 46 | * calculate the crcTable for crc32-checksums. 47 | * it is generated to the polynom [..] 48 | */ 49 | 50 | void chksum_crc32gentab () 51 | { 52 | unsigned long crc, poly; 53 | int i, j; 54 | 55 | poly = 0xEDB88320L; 56 | for (i = 0; i < 256; i++) 57 | { 58 | crc = i; 59 | for (j = 8; j > 0; j--) 60 | { 61 | if (crc & 1) 62 | { 63 | crc = (crc >> 1) ^ poly; 64 | } 65 | else 66 | { 67 | crc >>= 1; 68 | } 69 | } 70 | crc_tab[i] = crc; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Makefile.mac: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | CXX=clang++ 3 | FATBINFLAGS=-arch x86_64 -arch i386 -mmacosx-version-min=10.4 4 | THINBINFLAGS=-arch x86_64 -mmacosx-version-min=10.4 5 | CFLAGS=$(FATBINFLAGS) -O2 -D_FILE_OFFSET_BITS=64 -g 6 | #CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -D USE_UTF16 -I/opt/local/include -I/usr/local/include -I/opt/local/include -g 7 | CXXFLAGS=$(FATBINFLAGS) -O2 -Wall -D_FILE_OFFSET_BITS=64 -I/opt/local/include -I /usr/local/include -I/opt/local/include -g 8 | LIB_NAMES=crc32 support guid gptpart mbrpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix 9 | MBR_LIBS=support diskio diskio-unix basicmbr mbrpart 10 | #LIB_SRCS=$(NAMES:=.cc) 11 | LIB_OBJS=$(LIB_NAMES:=.o) 12 | MBR_LIB_OBJS=$(MBR_LIBS:=.o) 13 | LIB_HEADERS=$(LIB_NAMES:=.h) 14 | DEPEND= makedepend $(CFLAGS) 15 | 16 | all: gdisk sgdisk cgdisk fixparts 17 | 18 | gdisk: $(LIB_OBJS) gpttext.o gdisk.o 19 | $(CXX) $(LIB_OBJS) gpttext.o gdisk.o $(FATBINFLAGS) -o gdisk 20 | # $(CXX) $(LIB_OBJS) -L/usr/lib -licucore gpttext.o gdisk.o -o gdisk 21 | 22 | cgdisk: $(LIB_OBJS) cgdisk.o gptcurses.o 23 | $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o /usr/lib/libncurses.dylib $(LDFLAGS) $(FATBINFLAGS) -o cgdisk 24 | # $(CXX) $(LIB_OBJS) cgdisk.o gptcurses.o $(LDFLAGS) -licucore -lncurses -o cgdisk 25 | 26 | sgdisk: $(LIB_OBJS) gptcl.o sgdisk.o 27 | # $(CXX) $(LIB_OBJS) gptcl.o sgdisk.o /opt/local/lib/libiconv.a /opt/local/lib/libintl.a /opt/local/lib/libpopt.a $(FATBINFLAGS) -o sgdisk 28 | $(CXX) $(LIB_OBJS) gptcl.o sgdisk.o -L/usr/local/lib -lpopt $(THINBINFLAGS) -o sgdisk 29 | # $(CXX) $(LIB_OBJS) gptcl.o sgdisk.o -L/sw/lib -licucore -lpopt -o sgdisk 30 | 31 | fixparts: $(MBR_LIB_OBJS) fixparts.o 32 | $(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) $(FATBINFLAGS) -o fixparts 33 | 34 | testguid: $(LIB_OBJS) testguid.o 35 | $(CXX) $(LIB_OBJS) testguid.o -o testguid 36 | 37 | lint: #no pre-reqs 38 | lint $(SRCS) 39 | 40 | clean: #no pre-reqs 41 | rm -f core *.o *~ gdisk sgdisk cgdisk fixparts 42 | 43 | # what are the source dependencies 44 | depend: $(SRCS) 45 | $(DEPEND) $(SRCS) 46 | 47 | $(OBJS): 48 | 49 | # DO NOT DELETE 50 | -------------------------------------------------------------------------------- /gptcl.h: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation of GPTData class derivative with popt-based command 3 | line processing 4 | Copyright (C) 2010-2013 Roderick W. Smith 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation; either version 2 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | */ 21 | 22 | #ifndef __GPTCL_H 23 | #define __GPTCL_H 24 | 25 | #include "gpt.h" 26 | #include 27 | #include 28 | 29 | using namespace std; 30 | 31 | class GPTDataCL : public GPTData { 32 | protected: 33 | // Following are variables associated with popt parameters.... 34 | char *attributeOperation, *backupFile, *partName, *hybrids; 35 | char *newPartInfo, *mbrParts, *twoParts, *outDevice, *typeCode; 36 | char *partGUID, *diskGUID; 37 | int alignment, deletePartNum, infoPartNum, largestPartNum, bsdPartNum; 38 | uint32_t tableSize; 39 | poptContext poptCon; 40 | std::map typeRaw; 41 | 42 | int BuildMBR(char* argument, int isHybrid); 43 | public: 44 | GPTDataCL(void); 45 | GPTDataCL(string filename); 46 | ~GPTDataCL(void); 47 | void LoadBackupFile(string backupFile, int &saveData, int &neverSaveData); 48 | int DoOptions(int argc, char* argv[]); 49 | }; // class GPTDataCL 50 | 51 | int CountColons(char* argument); 52 | uint64_t GetInt(const string & argument, int itemNum); 53 | string GetString(string argument, int itemNum); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /popt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * This software is licensed under the terms of the GNU General Public 5 | * License version 2, as published by the Free Software Foundation, and 6 | * may be copied, distributed, and modified under those terms. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #ifndef ANDROID_POPT_H 15 | #define ANDROID_POPT_H 16 | 17 | /* 18 | * popt has been deprecated for some time, and is replaced by GNOME's glib 19 | * option parser. Instead of pulling in either of those dependencies, this 20 | * stub implements just enough of popt to get things working. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #define POPT_ARG_NONE 0U 29 | #define POPT_ARG_STRING 1U 30 | #define POPT_ARG_INT 2U 31 | 32 | #define POPT_AUTOHELP 33 | 34 | #pragma pack(push) 35 | #pragma pack(0) 36 | 37 | struct poptOption { 38 | const char *longName; 39 | char shortName; 40 | unsigned int argInfo; 41 | void *arg; 42 | int val; 43 | const char *descrip; 44 | const char *argDescrip; 45 | }; 46 | 47 | struct _poptContext { 48 | int argc; 49 | const char **argv; 50 | const struct poptOption *options; 51 | struct option *long_options; 52 | const char *otherHelp; 53 | }; 54 | 55 | typedef struct _poptContext *poptContext; 56 | 57 | #pragma pack(pop) 58 | 59 | poptContext poptGetContext(const char *name, int argc, const char **argv, 60 | const struct poptOption *options, unsigned int flags); 61 | poptContext poptFreeContext(poptContext con); 62 | void poptResetContext(poptContext con); 63 | 64 | void poptSetOtherOptionHelp(poptContext con, const char *text); 65 | void poptPrintUsage(poptContext con, FILE *fp, int flags); 66 | 67 | int poptGetNextOpt(poptContext con); 68 | const char *poptGetArg(poptContext con); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /diskio-heap.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * This software is licensed under the terms of the GNU General Public 5 | * License version 2, as published by the Free Software Foundation, and 6 | * may be copied, distributed, and modified under those terms. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #include 15 | 16 | #include "diskio.h" 17 | 18 | using namespace std; 19 | 20 | int DiskIO::OpenForRead(const unsigned char* data, size_t size) { 21 | this->data = data; 22 | this->size = size; 23 | this->off = 0; 24 | this->isOpen = 1; 25 | this->openForWrite = 0; 26 | return 1; 27 | } 28 | 29 | void DiskIO::MakeRealName(void) { 30 | realFilename = userFilename; 31 | } 32 | 33 | int DiskIO::OpenForRead(void) { 34 | return 1; 35 | } 36 | 37 | int DiskIO::OpenForWrite(void) { 38 | return 1; 39 | } 40 | 41 | void DiskIO::Close(void) { 42 | } 43 | 44 | int DiskIO::GetBlockSize(void) { 45 | return 512; 46 | } 47 | 48 | int DiskIO::GetPhysBlockSize(void) { 49 | return 512; 50 | } 51 | 52 | uint32_t DiskIO::GetNumHeads(void) { 53 | return 255; 54 | } 55 | 56 | uint32_t DiskIO::GetNumSecsPerTrack(void) { 57 | return 63; 58 | } 59 | 60 | int DiskIO::DiskSync(void) { 61 | return 1; 62 | } 63 | 64 | int DiskIO::Seek(uint64_t sector) { 65 | off_t off = sector * GetBlockSize(); 66 | if (off >= this->size) { 67 | return 0; 68 | } else { 69 | this->off = off; 70 | return 1; 71 | } 72 | } 73 | 74 | int DiskIO::Read(void* buffer, int numBytes) { 75 | int actualBytes = std::min(static_cast(this->size - this->off), numBytes); 76 | memcpy(buffer, this->data + this->off, actualBytes); 77 | return actualBytes; 78 | } 79 | 80 | int DiskIO::Write(void*, int) { 81 | return 0; 82 | } 83 | 84 | uint64_t DiskIO::DiskSize(int *) { 85 | return this->size / GetBlockSize(); 86 | } 87 | -------------------------------------------------------------------------------- /parttypes.h: -------------------------------------------------------------------------------- 1 | /* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed 2 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 3 | 4 | #include 5 | #include 6 | #ifdef USE_UTF16 7 | #include 8 | #else 9 | #define UnicodeString string 10 | #endif 11 | #include 12 | #include "support.h" 13 | #include "guid.h" 14 | 15 | #ifndef __PARTITION_TYPES 16 | #define __PARTITION_TYPES 17 | 18 | using namespace std; 19 | 20 | // A partition type 21 | struct AType { 22 | // I'm using a custom 16-bit extension of the original MBR 8-bit 23 | // type codes, so as to permit disambiguation and use of new 24 | // codes required by GPT 25 | uint16_t MBRType; 26 | GUIDData GUIDType; 27 | string name; 28 | int display; // 1 to show to users as available type, 0 not to 29 | AType* next; 30 | }; // struct AType 31 | 32 | class PartType : public GUIDData { 33 | protected: 34 | static int numInstances; 35 | static AType* allTypes; // Linked list holding all the data 36 | static AType* lastType; // Pointer to last entry in the list 37 | void AddAllTypes(void); 38 | public: 39 | PartType(void); 40 | PartType(const PartType & orig); 41 | PartType(const GUIDData & orig); 42 | ~PartType(void); 43 | 44 | // Set up type information 45 | int AddType(uint16_t mbrType, const char * guidData, const char * name, int toDisplay = 1); 46 | 47 | // New assignment operators.... 48 | PartType & operator=(const string & orig); 49 | PartType & operator=(const char * orig); 50 | 51 | // Assignment operators based on base class.... 52 | GUIDData & operator=(const GUIDData & orig) {return GUIDData::operator=(orig);} 53 | 54 | // New data assignment 55 | PartType & operator=(uint16_t ID); // Use MBR type code times 0x0100 to assign GUID 56 | 57 | // Retrieve transformed GUID data based on type code matches 58 | string TypeName(void) const; 59 | UnicodeString UTypeName(void) const; 60 | uint16_t GetHexType() const; 61 | 62 | // Information relating to all type data 63 | void ShowAllTypes(int maxLines = 21) const; 64 | int Valid(uint16_t code) const; 65 | }; 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /gdisk.cc: -------------------------------------------------------------------------------- 1 | // gdisk.cc 2 | // Program modelled after Linux fdisk, but it manipulates GPT partitions 3 | // rather than MBR partitions. 4 | // 5 | // by Rod Smith, project began February 2009 6 | 7 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 8 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 9 | 10 | #include 11 | #include 12 | #include "gpttext.h" 13 | 14 | int main(int argc, char* argv[]) { 15 | GPTDataTextUI theGPT; 16 | string device = ""; 17 | UnicodeString uString; 18 | int isError = 0; 19 | 20 | #ifndef EFI 21 | cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n"; 22 | #endif /*EFI*/ 23 | 24 | if (!SizesOK()) 25 | exit(1); 26 | 27 | switch (argc) { 28 | case 1: 29 | cout << "Type device filename, or press to exit: "; 30 | device = ReadString(); 31 | if (device.length() == 0) 32 | exit(0); 33 | else if (theGPT.LoadPartitions(device)) { 34 | if (theGPT.GetState() != use_gpt) 35 | WinWarning(); 36 | theGPT.MainMenu(device); 37 | } // if/elseif 38 | break; 39 | case 2: // basic usage 40 | if (theGPT.LoadPartitions(argv[1])) { 41 | if (theGPT.GetState() != use_gpt) 42 | WinWarning(); 43 | theGPT.MainMenu(argv[1]); 44 | } // if 45 | break; 46 | case 3: // usage with "-l" option 47 | if (strcmp(argv[1], "-l") == 0) { 48 | device = (string) argv[2]; 49 | } else if (strcmp(argv[2], "-l") == 0) { 50 | device = (string) argv[1]; 51 | } else { // 3 arguments, but none is "-l" 52 | cerr << "Usage: " << argv[0] << " [-l] device_file\n"; 53 | isError = 1; 54 | } // if/elseif/else 55 | if (device != "") { 56 | theGPT.JustLooking(); 57 | if (theGPT.LoadPartitions(device)) 58 | theGPT.DisplayGPTData(); 59 | else 60 | isError = 1; 61 | } // if 62 | break; 63 | default: 64 | cerr << "Usage: " << argv[0] << " [-l] device_file\n"; 65 | isError = 1; 66 | break; 67 | } // switch 68 | return (isError); 69 | } // main 70 | -------------------------------------------------------------------------------- /diskio.cc: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Interface: diskio (platform-independent components) 3 | // 4 | // Description: Class to handle low-level disk I/O for GPT fdisk 5 | // 6 | // 7 | // Author: Rod Smith , (C) 2009 8 | // 9 | // Copyright: See COPYING file that comes with this distribution 10 | // 11 | // 12 | // This program is copyright (c) 2009 by Roderick W. Smith. It is distributed 13 | // under the terms of the GNU GPL version 2, as detailed in the COPYING file. 14 | 15 | #define __STDC_LIMIT_MACROS 16 | #ifndef __STDC_CONSTANT_MACROS 17 | #define __STDC_CONSTANT_MACROS 18 | #endif 19 | 20 | #ifdef _WIN32 21 | #include 22 | #include 23 | #define fstat64 fstat 24 | #define stat64 stat 25 | #define S_IRGRP 0 26 | #define S_IROTH 0 27 | #else 28 | #include 29 | #endif 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include "support.h" 38 | #include "diskio.h" 39 | //#include "gpt.h" 40 | 41 | using namespace std; 42 | 43 | DiskIO::DiskIO(void) { 44 | userFilename = ""; 45 | realFilename = ""; 46 | modelName = ""; 47 | isOpen = 0; 48 | openForWrite = 0; 49 | } // constructor 50 | 51 | DiskIO::~DiskIO(void) { 52 | Close(); 53 | } // destructor 54 | 55 | // Open a disk device for reading. Returns 1 on success, 0 on failure. 56 | int DiskIO::OpenForRead(const string & filename) { 57 | int shouldOpen = 1; 58 | 59 | if (isOpen) { // file is already open 60 | if (((realFilename != filename) && (userFilename != filename)) || (openForWrite)) { 61 | Close(); 62 | } else { 63 | shouldOpen = 0; 64 | } // if/else 65 | } // if 66 | 67 | if (shouldOpen) { 68 | userFilename = filename; 69 | MakeRealName(); 70 | OpenForRead(); 71 | } // if 72 | 73 | return isOpen; 74 | } // DiskIO::OpenForRead(string filename) 75 | 76 | // Open a disk for reading and writing by filename. 77 | // Returns 1 on success, 0 on failure. 78 | int DiskIO::OpenForWrite(const string & filename) { 79 | int retval = 0; 80 | 81 | if ((isOpen) && (openForWrite) && ((filename == realFilename) || (filename == userFilename))) { 82 | retval = 1; 83 | } else { 84 | userFilename = filename; 85 | MakeRealName(); 86 | retval = OpenForWrite(); 87 | if (retval == 0) { 88 | realFilename = userFilename = ""; 89 | } // if 90 | } // if/else 91 | return retval; 92 | } // DiskIO::OpenForWrite(string filename) 93 | -------------------------------------------------------------------------------- /diskio.h: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Interface: diskio 3 | // 4 | // Description: Class to handle low-level disk I/O for GPT fdisk 5 | // 6 | // 7 | // Author: Rod Smith , (C) 2009 8 | // 9 | // Copyright: See COPYING file that comes with this distribution 10 | // 11 | // 12 | // This program is copyright (c) 2009 by Roderick W. Smith. It is distributed 13 | // under the terms of the GNU GPL version 2, as detailed in the COPYING file. 14 | 15 | #ifndef __DISKIO_H 16 | #define __DISKIO_H 17 | 18 | #include 19 | #include 20 | #include 21 | #ifdef _WIN32 22 | #include 23 | #include 24 | #else 25 | #include 26 | #endif 27 | 28 | #ifdef __sun__ 29 | #include 30 | #endif 31 | 32 | #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) 33 | #define fstat64 fstat 34 | #define stat64 stat 35 | #endif 36 | 37 | #include "support.h" 38 | //#include "parttypes.h" 39 | 40 | using namespace std; 41 | 42 | /*************************************** 43 | * * 44 | * DiskIO class and related structures * 45 | * * 46 | ***************************************/ 47 | 48 | class DiskIO { 49 | protected: 50 | string userFilename; 51 | string realFilename; 52 | string modelName; 53 | int isOpen; 54 | int openForWrite; 55 | #ifdef _WIN32 56 | HANDLE fd; 57 | #else 58 | int fd; 59 | #endif 60 | #ifdef ENABLE_HEAP_DISKIO 61 | const unsigned char* data; 62 | size_t size; 63 | off_t off; 64 | #endif 65 | public: 66 | DiskIO(void); 67 | ~DiskIO(void); 68 | 69 | void MakeRealName(void); 70 | #ifdef ENABLE_HEAP_DISKIO 71 | int OpenForRead(const unsigned char* data, size_t size); 72 | #endif 73 | int OpenForRead(const string & filename); 74 | int OpenForRead(void); 75 | int OpenForWrite(const string & filename); 76 | int OpenForWrite(void); 77 | void Close(); 78 | int Seek(uint64_t sector); 79 | int Read(void* buffer, int numBytes); 80 | int Write(void* buffer, int numBytes); 81 | int DiskSync(void); // resync disk caches to use new partitions 82 | int GetBlockSize(void); 83 | int GetPhysBlockSize(void); 84 | string GetModel(void) {return modelName;} 85 | uint32_t GetNumHeads(void); 86 | uint32_t GetNumSecsPerTrack(void); 87 | int IsOpen(void) {return isOpen;} 88 | int IsOpenForWrite(void) {return openForWrite;} 89 | string GetName(void) const {return realFilename;} 90 | 91 | uint64_t DiskSize(int* err); 92 | }; // class DiskIO 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /support.h: -------------------------------------------------------------------------------- 1 | /* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed 2 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifndef __GPTSUPPORT 9 | #define __GPTSUPPORT 10 | 11 | #define GPTFDISK_VERSION "1.0.4" 12 | 13 | #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__) 14 | // Darwin (Mac OS) & FreeBSD: disk IOCTLs are different, and there is no lseek64 15 | #include 16 | #define lseek64 lseek 17 | #endif 18 | 19 | #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) 20 | #define DEFAULT_GPT_TYPE 0xA503 21 | #endif 22 | 23 | #ifdef __APPLE__ 24 | #define DEFAULT_GPT_TYPE 0xAF00 25 | #endif 26 | 27 | #ifdef _WIN32 28 | #define DEFAULT_GPT_TYPE 0x0700 29 | #endif 30 | 31 | #ifdef __sun__ 32 | #define DEFAULT_GPT_TYPE 0xbf01 33 | #endif 34 | 35 | // Microsoft Visual C++ only 36 | #if defined (_MSC_VER) 37 | #define sscanf sscanf_s 38 | #define strcpy strcpy_s 39 | #define sprintf sprintf_s 40 | #endif 41 | 42 | // Linux only.... 43 | #ifdef __linux__ 44 | #include 45 | #define DEFAULT_GPT_TYPE 0x8300 46 | #endif 47 | 48 | #ifndef DEFAULT_GPT_TYPE 49 | #define DEFAULT_GPT_TYPE 0x8300 50 | #endif 51 | 52 | // Set this as a default 53 | #define SECTOR_SIZE UINT32_C(512) 54 | 55 | // Signatures for Apple (APM) disks, multiplied by 0x100000000 56 | #define APM_SIGNATURE1 UINT64_C(0x00004D5000000000) 57 | #define APM_SIGNATURE2 UINT64_C(0x0000535400000000) 58 | 59 | /************************** 60 | * Some GPT constants.... * 61 | **************************/ 62 | 63 | #define GPT_SIGNATURE UINT64_C(0x5452415020494645) 64 | 65 | // Number and size of GPT entries... 66 | #define NUM_GPT_ENTRIES 128 67 | #define GPT_SIZE 128 68 | #define HEADER_SIZE UINT32_C(92) 69 | #define GPT_RESERVED 420 70 | #define NAME_SIZE 36 // GPT allows 36 UTF-16LE code units for a name in a 128 byte partition entry 71 | 72 | using namespace std; 73 | 74 | string ReadString(void); 75 | uint64_t GetNumber(uint64_t low, uint64_t high, uint64_t def, const string & prompt); 76 | char GetYN(void); 77 | uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt); 78 | uint64_t IeeeToInt(string IeeeValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def = 0); 79 | string BytesToIeee(uint64_t size, uint32_t sectorSize); 80 | unsigned char StrToHex(const string & input, unsigned int position); 81 | int IsHex(string input); // Returns 1 if input can be hexadecimal number.... 82 | int IsLittleEndian(void); // Returns 1 if CPU is little-endian, 0 if it's big-endian 83 | void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theValue 84 | void WinWarning(void); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /cgdisk.cc: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2011 3 | 4 | This program is free software; you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation; either version 2 of the License, or 7 | (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | 18 | */ 19 | 20 | /* This class implements an interactive curses-based interface atop the 21 | GPTData class */ 22 | 23 | #include 24 | #include "gptcurses.h" 25 | 26 | using namespace std; 27 | 28 | #define MAX_OPTIONS 50 29 | 30 | int main(int argc, char *argv[]) { 31 | string device = ""; 32 | int displayType = USE_CURSES; 33 | 34 | if (!SizesOK()) 35 | exit(1); 36 | 37 | switch (argc) { 38 | case 1: 39 | cout << "Type device filename, or press to exit: "; 40 | device = ReadString(); 41 | if (device.length() == 0) 42 | exit(0); 43 | break; 44 | case 2: // basic usage 45 | device = (string) argv[1]; 46 | break; 47 | case 3: // "-a" usage or illegal 48 | if (strcmp(argv[1], "-a") == 0) { 49 | device = (string) argv[2]; 50 | } else if (strcmp(argv[2], "-a") == 0) { 51 | device = (string) argv[1]; 52 | } else { 53 | cerr << "Usage: " << argv[0] << " [-a] device_file\n"; 54 | exit(1); 55 | } // if/elseif/else 56 | displayType = USE_ARROW; 57 | break; 58 | default: 59 | cerr << "Usage: " << argv[0] << " [-a] device_file\n"; 60 | exit(1); 61 | break; 62 | } // switch 63 | 64 | GPTDataCurses theGPT; 65 | 66 | theGPT.SetDisplayType(displayType); 67 | if (theGPT.LoadPartitions(device)) { 68 | if (theGPT.GetState() != use_gpt) { 69 | Report("Warning! Non-GPT or damaged disk detected! This program will attempt to\n" 70 | "convert to GPT form or repair damage to GPT data structures, but may not\n" 71 | "succeed. Use gdisk or another disk repair tool if you have a damaged GPT\n" 72 | "disk."); 73 | } // if 74 | theGPT.MainMenu(); 75 | } else { 76 | Report("Could not load partitions from '" + device + "'! Aborting!"); 77 | } // if/else 78 | return 0; 79 | } // main 80 | -------------------------------------------------------------------------------- /gpttext.h: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation of GPTData class derivative with basic text-mode interaction 3 | Copyright (C) 2010-2018 Roderick W. Smith 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | */ 20 | 21 | #ifndef __GPTDATATEXT_H 22 | #define __GPTDATATEXT_H 23 | 24 | #include "gpt.h" 25 | 26 | using namespace std; 27 | 28 | class GPTDataTextUI : public GPTData { 29 | protected: 30 | public: 31 | GPTDataTextUI(void); 32 | GPTDataTextUI(string filename); 33 | ~GPTDataTextUI(void); 34 | 35 | // This one needs to be explicitly defined, even though it does nothing new.... 36 | // const GPTPart & operator[](uint32_t partNum) {return GPTData::operator[](partNum);} 37 | 38 | // Extended (interactive) versions of some base-class functions 39 | WhichToUse UseWhichPartitions(void); 40 | int XFormDisklabel(void); 41 | 42 | // Request information from the user (& possibly do something with it) 43 | uint32_t GetPartNum(void); 44 | void ResizePartitionTable(void); 45 | void MoveMainTable(void); 46 | void CreatePartition(void); 47 | void DeletePartition(void); 48 | void ChangePartType(void); 49 | void ChangeUniqueGuid(void); 50 | void SetAttributes(uint32_t partNum); 51 | int SetName(uint32_t partNum); 52 | int SwapPartitions(void); 53 | int DestroyGPTwPrompt(void); // Returns 1 if user proceeds 54 | void ShowDetails(void); 55 | void MakeHybrid(void); 56 | int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful 57 | 58 | // An informational function.... 59 | void WarnAboutIffyMBRPart(int partNum); 60 | 61 | // Main menu functions 62 | void MainMenu(string filename); 63 | void ShowCommands(void); 64 | void ExpertsMenu(string filename); 65 | void ShowExpertCommands(void); 66 | void RecoveryMenu(string filename); 67 | void ShowRecoveryCommands(void); 68 | }; // class GPTDataTextUI 69 | 70 | int GetMBRTypeCode(int defType); 71 | UnicodeString ReadUString(void); 72 | 73 | #endif // __GPTDATATEXT_H 74 | -------------------------------------------------------------------------------- /current.spec: -------------------------------------------------------------------------------- 1 | Summary: GPT partitioning and MBR repair software 2 | Name: gptfdisk 3 | Version: 1.0.4 4 | 5 | Release: 1%{?dist} 6 | License: GPLv2 7 | URL: http://www.rodsbooks.com/gdisk 8 | Group: Applications/System 9 | Source: http://www.rodsbooks.com/gdisk/gptfdisk-1.0.4.tar.gz 10 | BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 11 | 12 | %description 13 | 14 | Partitioning software for GPT disks and to repair MBR disks. The gdisk, 15 | cgdisk, and sgdisk utilities (in the gdisk package) are GPT-enabled 16 | partitioning tools; the fixparts utility (in the fixparts package) fixes 17 | some problems with MBR disks that can be created by buggy partitioning 18 | software. 19 | 20 | %package -n gdisk 21 | 22 | Group: Applications/System 23 | 24 | Summary: An fdisk-like partitioning tool for GPT disks 25 | 26 | %description -n gdisk 27 | An fdisk-like partitioning tool for GPT disks. GPT 28 | fdisk features a command-line interface, fairly direct 29 | manipulation of partition table structures, recovery 30 | tools to help you deal with corrupt partition tables, 31 | and the ability to convert MBR disks to GPT format. 32 | 33 | %prep 34 | %setup -q 35 | 36 | %build 37 | CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_CXX_FLAGS" make 38 | 39 | %install 40 | rm -rf $RPM_BUILD_ROOT 41 | mkdir -p $RPM_BUILD_ROOT/usr/sbin 42 | install -Dp -m0755 gdisk $RPM_BUILD_ROOT/usr/sbin 43 | install -Dp -m0755 sgdisk $RPM_BUILD_ROOT/usr/sbin 44 | install -Dp -m0755 cgdisk $RPM_BUILD_ROOT/usr/sbin 45 | install -Dp -m0755 fixparts $RPM_BUILD_ROOT/usr/sbin 46 | install -Dp -m0644 gdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/gdisk.8 47 | install -Dp -m0644 sgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/sgdisk.8 48 | install -Dp -m0644 cgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/cgdisk.8 49 | install -Dp -m0644 fixparts.8 $RPM_BUILD_ROOT/%{_mandir}/man8/fixparts.8 50 | 51 | %clean 52 | rm -rf $RPM_BUILD_ROOT 53 | 54 | %files -n gdisk 55 | %defattr(-,root,root -) 56 | %doc NEWS COPYING README 57 | /usr/sbin/gdisk 58 | /usr/sbin/sgdisk 59 | /usr/sbin/cgdisk 60 | %doc %{_mandir}/man8/gdisk.8* 61 | %doc %{_mandir}/man8/sgdisk.8* 62 | %doc %{_mandir}/man8/cgdisk.8* 63 | 64 | %package -n fixparts 65 | 66 | Group: Applications/System 67 | 68 | Summary: A tool for repairing certain types of damage to MBR disks 69 | 70 | %description -n fixparts 71 | A program that corrects errors that can creep into MBR-partitioned 72 | disks. Removes stray GPT data, fixes mis-sized extended partitions, 73 | and enables changing primary vs. logical partition status. Also 74 | provides a few additional partition manipulation features. 75 | 76 | %files -n fixparts 77 | %defattr(-,root,root -) 78 | %doc NEWS COPYING README 79 | /usr/sbin/fixparts 80 | %doc %{_mandir}/man8/fixparts.8* 81 | 82 | 83 | %changelog 84 | * Thu Jul 5 2018 R Smith - 1.0.4 85 | - Created spec file for 1.0.4 release 86 | -------------------------------------------------------------------------------- /Android.bp: -------------------------------------------------------------------------------- 1 | package { 2 | default_applicable_licenses: ["external_gptfdisk_license"], 3 | } 4 | 5 | // Added automatically by a large-scale-change that took the approach of 6 | // 'apply every license found to every target'. While this makes sure we respect 7 | // every license restriction, it may not be entirely correct. 8 | // 9 | // e.g. GPL in an MIT project might only apply to the contrib/ directory. 10 | // 11 | // Please consider splitting the single license below into multiple licenses, 12 | // taking care not to lose any license_kind information, and overriding the 13 | // default license using the 'licenses: [...]' property on targets as needed. 14 | // 15 | // For unused files, consider creating a 'fileGroup' with "//visibility:private" 16 | // to attach the license to, and including a comment whether the files may be 17 | // used in the current project. 18 | // See: http://go/android-license-faq 19 | license { 20 | name: "external_gptfdisk_license", 21 | visibility: [":__subpackages__"], 22 | license_kinds: [ 23 | "SPDX-license-identifier-GPL", 24 | "SPDX-license-identifier-GPL-2.0", 25 | "SPDX-license-identifier-LGPL", 26 | ], 27 | license_text: [ 28 | "COPYING", 29 | ], 30 | } 31 | 32 | cc_defaults { 33 | name: "gptfdisk_default_flags", 34 | cflags: [ 35 | "-Wno-unused-parameter", 36 | "-Wno-pragma-pack", 37 | "-Werror", 38 | "-fPIC", 39 | ], 40 | target: { 41 | darwin: { 42 | cflags: [ 43 | "-D_FILE_OFFSET_BITS=64", 44 | "-Doff64_t=off_t", 45 | ], 46 | }, 47 | }, 48 | } 49 | 50 | cc_binary { 51 | name: "sgdisk", 52 | defaults: ["gptfdisk_default_flags"], 53 | host_supported: true, 54 | 55 | srcs: [ 56 | "sgdisk.cc", 57 | ], 58 | 59 | shared_libs: ["libext2_uuid"], 60 | static_libs: ["libgptf"], 61 | } 62 | 63 | lib_common_srcs = [ 64 | "gptcl.cc", 65 | "crc32.cc", 66 | "support.cc", 67 | "guid.cc", 68 | "gptpart.cc", 69 | "mbrpart.cc", 70 | "basicmbr.cc", 71 | "mbr.cc", 72 | "gpt.cc", 73 | "bsd.cc", 74 | "parttypes.cc", 75 | "attributes.cc", 76 | "diskio.cc", 77 | "android_popt.cc", 78 | ] 79 | 80 | cc_library_static { 81 | name: "libgptf", 82 | defaults: ["gptfdisk_default_flags"], 83 | host_supported: true, 84 | recovery_available: true, 85 | 86 | export_include_dirs: ["."], 87 | srcs: lib_common_srcs + ["diskio-unix.cc"], 88 | 89 | shared_libs: ["libext2_uuid"], 90 | } 91 | 92 | cc_library_static { 93 | name: "libgptf_fuzzer_lib", 94 | defaults: ["gptfdisk_default_flags"], 95 | host_supported: true, 96 | 97 | export_include_dirs: ["."], 98 | srcs: lib_common_srcs + ["diskio-heap.cc"], 99 | cflags: ["-DENABLE_HEAP_DISKIO"], 100 | 101 | shared_libs: ["libext2_uuid"], 102 | } 103 | 104 | cc_library { 105 | name: "libsgdisk", 106 | recovery_available: true, 107 | 108 | defaults: ["gptfdisk_default_flags"], 109 | 110 | srcs: [ 111 | "sgdisk.cc", 112 | ], 113 | cflags: [ 114 | "-Dmain=sgdisk_main", 115 | ], 116 | 117 | shared_libs: ["libext2_uuid"], 118 | static_libs: ["libgptf"], 119 | } 120 | -------------------------------------------------------------------------------- /bsd.h: -------------------------------------------------------------------------------- 1 | /* bsd.h -- BSD disklabel data structure definitions, types, and functions */ 2 | 3 | /* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed 4 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 5 | 6 | #include 7 | #include 8 | #include "gptpart.h" 9 | #include "diskio.h" 10 | 11 | #ifndef __BSD_STRUCTS 12 | #define __BSD_STRUCTS 13 | 14 | #define BSD_SIGNATURE UINT32_C(0x82564557) /* BSD disklabel signature ("magic") */ 15 | 16 | // BSD disklabels can start at offsets of 64 or the sector size -- at least, 17 | // I *THINK* that's what's going on. I've seen them at 64 or 512 on disks 18 | // with 512-byte blocks and at 2048 on disks with 2048-byte blocks. The 19 | // LABEL_OFFSET2 value will be replaced by the block size in the 20 | // ReadBSDData() function.... 21 | #define LABEL_OFFSET1 64 22 | #define LABEL_OFFSET2 512 23 | #define NUM_OFFSETS 2 24 | 25 | // FreeBSD documents a maximum # of partitions of 8, but I saw 16 on a NetBSD 26 | // disk. I'm quadrupling that for further safety. Note that BSDReadData() 27 | // uses a 4096-byte I/O buffer. In combination with LABEL_OFFSET3 and the 28 | // additional 148-byte offset to the actual partition data, that gives a 29 | // theoretical maximum of 118.75 partitions that the program can handle before 30 | // memory errors will occur. 31 | #define MAX_BSD_PARTS 64 32 | 33 | 34 | using namespace std; 35 | 36 | /**************************************** 37 | * * 38 | * BSDData class and related structures * 39 | * * 40 | ****************************************/ 41 | 42 | // Possible states of the MBR 43 | enum BSDValidity {unknown, bsd_invalid, bsd}; 44 | 45 | // Data for a single BSD partition record 46 | // Create entries for all fields, although we only use lengthLBA, firstLBA, 47 | // and fsType, to simplify loading the data from disk.... 48 | struct BSDRecord { // the partition table 49 | uint32_t lengthLBA; // number of sectors in partition 50 | uint32_t firstLBA; // starting sector 51 | uint32_t fragSize; // filesystem basic fragment size 52 | uint8_t fsType; // filesystem type, see below 53 | uint8_t frag; // filesystem fragments per block 54 | uint16_t pcpg; // filesystem cylinders per group 55 | }; 56 | 57 | // Full data in tweaked BSD format 58 | // For some reason this has to be packed or MS Visual C++'s debugger complains 59 | // about memory errors whenever a BSDData variable is destroyed. 60 | #pragma pack(push) 61 | #pragma pack (8) 62 | class BSDData { 63 | protected: 64 | // We only need a few items from the main BSD disklabel data structure.... 65 | uint32_t signature; // the magic number 66 | uint32_t sectorSize; // # of bytes per sector 67 | uint32_t signature2; // the magic number (again) 68 | uint16_t numParts; // number of partitions in table 69 | struct BSDRecord* partitions; // partition array 70 | 71 | // Above are basic BSD disklabel data; now add more stuff.... 72 | uint64_t labelFirstLBA; // first sector of BSD disklabel (partition or disk) 73 | uint64_t labelLastLBA; // final sector of BSD disklabel 74 | uint64_t labelStart; // BSD disklabel start point in bytes from labelFirstLBA 75 | BSDValidity state; 76 | public: 77 | BSDData(void); 78 | ~BSDData(void); 79 | int ReadBSDData(const string & deviceFilename, uint64_t startSector, uint64_t endSector); 80 | int ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector); 81 | void ReverseMetaBytes(void); 82 | void DisplayBSDData(void); 83 | int ShowState(void); // returns 1 if BSD disklabel detected 84 | int IsDisklabel(void); 85 | 86 | // Functions to extract data on specific partitions.... 87 | uint8_t GetType(int i); 88 | uint64_t GetFirstSector(int i); 89 | uint64_t GetLength(int i); 90 | int GetNumParts(void); 91 | GPTPart AsGPT(int i); // Return BSD part. as GPT part. 92 | }; // struct MBRData 93 | #pragma pack () 94 | 95 | #pragma pack(pop) 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /fixparts.cc: -------------------------------------------------------------------------------- 1 | // fixparts 2 | // Program to fix certain types of damaged Master Boot Record (MBR) partition 3 | // tables 4 | // 5 | // Copyright 2011 by Roderick W. Smith 6 | // 7 | // This program is distributed under the terms of the GNU GPL, as described 8 | // in the COPYING file. 9 | // 10 | // Based on C++ classes originally created for GPT fdisk (gdisk and sgdisk) 11 | // programs 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "basicmbr.h" 19 | #include "support.h" 20 | 21 | using namespace std; 22 | 23 | void DoMBR(BasicMBRData & mbrTable); 24 | 25 | int main(int argc, char* argv[]) { 26 | BasicMBRData mbrTable; 27 | string device; 28 | 29 | cout << "FixParts " << GPTFDISK_VERSION << "\n"; 30 | 31 | switch (argc) { 32 | case 1: 33 | cout << "Type device filename, or press to exit: "; 34 | device = ReadString(); 35 | if (device.length() == 0) 36 | exit(0); 37 | break; 38 | case 2: 39 | device = argv[1]; 40 | break; 41 | default: 42 | cerr << "Usage: " << argv[0] << " device_filename\n"; 43 | exit(1); 44 | } // switch 45 | 46 | cout << "\nLoading MBR data from " << device << "\n"; 47 | if (!mbrTable.ReadMBRData(device)) { 48 | cerr << "\nUnable to read MBR data from '" << device << "'! Exiting!\n\n"; 49 | exit(1); 50 | } // if 51 | 52 | // This switch() statement weeds out disks with GPT signatures and non-MBR 53 | // disks so we don't accidentally damage them.... 54 | switch(mbrTable.GetValidity()) { 55 | case hybrid: case gpt: 56 | cerr << "\nThis disk appears to be a GPT disk. Use GNU Parted or GPT fdisk on it!\n"; 57 | cerr << "Exiting!\n\n"; 58 | exit(1); 59 | break; 60 | case invalid: 61 | cerr << "\nCannot find valid MBR data on '" << device << "'! Exiting!\n\n"; 62 | exit(1); 63 | break; 64 | case mbr: 65 | DoMBR(mbrTable); 66 | break; 67 | default: 68 | cerr << "\nCannot determine the validity of the disk on '" << device 69 | << "'! Exiting!\n\n"; 70 | exit(1); 71 | break; 72 | } // switch() 73 | return 0; 74 | } // main() 75 | 76 | // Do the bulk of the processing on actual MBR disks. First checks for old 77 | // GPT data (note this is different from the earlier check; this one only 78 | // looks for the GPT signatures in the main and backup GPT area, not for 79 | // a protective partition in the MBR, which we know is NOT present, since 80 | // if it were, this function would NOT be called!) and offers to destroy 81 | // it, if found; then makes sure the partitions are in a consistent and 82 | // legal state; then presents the MBR menu and, if it returns a "1" value 83 | // (meaning the user opted to write changes), writes the table to disk. 84 | void DoMBR(BasicMBRData & mbrTable) { 85 | int doItAgain; 86 | 87 | if (mbrTable.CheckForGPT() > 0) { 88 | cout << "\nNOTICE: GPT signatures detected on the disk, but no 0xEE protective " 89 | << "partition!\nThe GPT signatures are probably left over from a previous " 90 | << "partition table.\nDo you want to delete them (if you answer 'Y', this " 91 | << "will happen\nimmediately)? "; 92 | if (GetYN() == 'Y') { 93 | cout << "Erasing GPT data!\n"; 94 | if (mbrTable.BlankGPTData() != 1) 95 | cerr << "GPT signature erasure failed!\n"; 96 | } // if 97 | } // if 98 | 99 | mbrTable.MakeItLegal(); 100 | do { 101 | doItAgain = 0; 102 | if (mbrTable.DoMenu() > 0) { 103 | cout << "\nFinal checks complete. About to write MBR data. THIS WILL OVERWRITE " 104 | << "EXISTING\nPARTITIONS!!\n\nDo you want to proceed? "; 105 | if (GetYN() == 'Y') { 106 | mbrTable.WriteMBRData(); 107 | mbrTable.DiskSync(); 108 | doItAgain = 0; 109 | } else { 110 | doItAgain = 1; 111 | } // else 112 | } // if 113 | } while (doItAgain); 114 | } // DoMBR() 115 | -------------------------------------------------------------------------------- /android_popt.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 The Android Open Source Project 3 | * 4 | * This software is licensed under the terms of the GNU General Public 5 | * License version 2, as published by the Free Software Foundation, and 6 | * may be copied, distributed, and modified under those terms. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | */ 13 | 14 | #include 15 | 16 | // #define LOCAL_DEBUG 17 | 18 | /* 19 | * popt has been deprecated for some time, and is replaced by GNOME's glib 20 | * option parser. Instead of pulling in either of those dependencies, this 21 | * stub implements just enough of popt to get things working. 22 | */ 23 | 24 | poptContext poptGetContext(const char *name, int argc, const char **argv, 25 | const struct poptOption *options, unsigned int flags) { 26 | // Convert into getopt format, sanity checking our limited 27 | // capabilities along the way 28 | int count = 0; 29 | for (; options[count].longName; count++) { 30 | } 31 | 32 | // getopt_long expects the last element to be null 33 | // so allocate count + 1 34 | struct option *long_options = (struct option *) 35 | calloc(count + 1, sizeof(struct option)); 36 | for (int i = 0; options[i].longName; i++) { 37 | long_options[i].name = options[i].longName; 38 | long_options[i].flag = 0; 39 | 40 | if (!options[i].val) { 41 | fprintf(stderr, __FILE__ ": val required\n"); 42 | abort(); 43 | } 44 | long_options[i].val = options[i].val; 45 | 46 | switch (options[i].argInfo) { 47 | case POPT_ARG_NONE: 48 | long_options[i].has_arg = no_argument; 49 | break; 50 | case POPT_ARG_STRING: 51 | case POPT_ARG_INT: 52 | if (!options[i].arg) { 53 | fprintf(stderr, __FILE__ ": arg required\n"); 54 | abort(); 55 | } 56 | long_options[i].has_arg = required_argument; 57 | break; 58 | default: 59 | fprintf(stderr, __FILE__ ": unsupported argInfo\n"); 60 | abort(); 61 | } 62 | } 63 | 64 | poptContext con = (poptContext) calloc(1, sizeof(struct _poptContext)); 65 | con->argc = argc; 66 | con->argv = argv; 67 | con->options = options; 68 | con->long_options = long_options; 69 | return con; 70 | } 71 | 72 | poptContext poptFreeContext(poptContext con) { 73 | free(con->long_options); 74 | free(con); 75 | return 0; 76 | } 77 | 78 | void poptResetContext(poptContext con) { 79 | optind = 1; 80 | } 81 | 82 | void poptSetOtherOptionHelp(poptContext con, const char *text) { 83 | con->otherHelp = text; 84 | } 85 | 86 | void poptPrintUsage(poptContext con, FILE *fp, int flags) { 87 | fprintf(fp, "USAGE: %s %s\n", con->argv[0], con->otherHelp); 88 | int i = 0; 89 | for (; con->options[i].longName; i++) { 90 | fprintf(fp, "\t--%s\t%s\n", con->options[i].longName, 91 | con->options[i].descrip); 92 | } 93 | fprintf(fp, "\n"); 94 | } 95 | 96 | int poptGetNextOpt(poptContext con) { 97 | int i = -1; 98 | int res = getopt_long(con->argc, (char *const *) con->argv, "", 99 | con->long_options, &i); 100 | #ifdef LOCAL_DEBUG 101 | fprintf(stderr, "getopt_long()=%c\n", res); 102 | #endif 103 | if (res <= 0 || res == '?' || i == -1) { 104 | return -1; 105 | } 106 | 107 | // Copy over found argument value 108 | switch (con->options[i].argInfo) { 109 | case POPT_ARG_STRING: 110 | *((char**) con->options[i].arg) = strdup(optarg); 111 | break; 112 | case POPT_ARG_INT: 113 | *((int*) con->options[i].arg) = atoi(optarg); 114 | break; 115 | } 116 | 117 | return res; 118 | } 119 | 120 | const char *poptGetArg(poptContext con) { 121 | const char *res = con->argv[optind++]; 122 | #ifdef LOCAL_DEBUG 123 | fprintf(stderr, "poptGetArg()=%s\n", res); 124 | #endif 125 | return res; 126 | } 127 | -------------------------------------------------------------------------------- /gptpart.h: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Interface: gptpart 3 | // 4 | // Description: Class to implement a single GPT partition 5 | // 6 | // 7 | // Author: Rod Smith , (C) 2009 8 | // 9 | // Copyright: See COPYING file that comes with this distribution 10 | // 11 | // 12 | // This program is copyright (c) 2009 by Roderick W. Smith. It is distributed 13 | // under the terms of the GNU GPL version 2, as detailed in the COPYING file. 14 | 15 | #ifndef __GPTPART_H 16 | #define __GPTPART_H 17 | 18 | #include 19 | #include 20 | #include 21 | #include "support.h" 22 | #include "parttypes.h" 23 | #include "guid.h" 24 | #include "attributes.h" 25 | 26 | using namespace std; 27 | 28 | // Values returned by GPTPart::IsSizedForMBR() 29 | #define MBR_SIZED_GOOD 0 /* Whole partition under 2^32 sectors */ 30 | #define MBR_SIZED_IFFY 1 /* Partition starts under 2^32 & is less than 2^32, but ends over 2^32 */ 31 | #define MBR_SIZED_BAD 2 /* Partition starts over 2^32, is bigger than 2^32, or otherwise bad */ 32 | 33 | /**************************************** 34 | * * 35 | * GPTPart class and related structures * 36 | * * 37 | ****************************************/ 38 | 39 | class GPTPart { 40 | protected: 41 | // Caution: The non-static data in GPTPart is precisely the right size 42 | // to enable easy loading of the data directly from disk. If any 43 | // non-static variables are added to the below, the data size will 44 | // change and the program will stop working. This can be corrected by 45 | // adjusting the data-load operation in GPTData::LoadMainTable() and 46 | // GPTData::LoadSecondTableAsMain() and then removing the GPTPart 47 | // size check in SizesOK() (in gpt.cc file). 48 | PartType partitionType; 49 | GUIDData uniqueGUID; 50 | uint64_t firstLBA; 51 | uint64_t lastLBA; 52 | Attributes attributes; 53 | uint16_t name[NAME_SIZE]; 54 | public: 55 | GPTPart(void); 56 | GPTPart(const GPTPart &); 57 | ~GPTPart(void); 58 | 59 | // Simple data retrieval: 60 | PartType & GetType(void) {return partitionType;} 61 | uint16_t GetHexType(void) const; 62 | string GetTypeName(void); 63 | UnicodeString GetUTypeName(void); 64 | const GUIDData GetUniqueGUID(void) const {return uniqueGUID;} 65 | uint64_t GetFirstLBA(void) const {return firstLBA;} 66 | uint64_t GetLastLBA(void) const {return lastLBA;} 67 | uint64_t GetLengthLBA(void) const; 68 | Attributes GetAttributes(void) {return attributes;} 69 | void ShowAttributes(uint32_t partNum) {attributes.ShowAttributes(partNum);} 70 | UnicodeString GetDescription(void); 71 | int IsUsed(void); 72 | int IsSizedForMBR(void); 73 | 74 | // Simple data assignment: 75 | void SetType(PartType t); 76 | void SetType(uint16_t hex) {partitionType = hex;} 77 | void SetUniqueGUID(GUIDData u) {uniqueGUID = u;} 78 | void RandomizeUniqueGUID(void) {uniqueGUID.Randomize();} 79 | void SetFirstLBA(uint64_t f) {firstLBA = f;} 80 | void SetLastLBA(uint64_t l) {lastLBA = l;} 81 | void SetAttributes(uint64_t a) {attributes = a;} 82 | void SetAttributes(void) {attributes.ChangeAttributes();} 83 | void SetName(const string & theName); 84 | #ifdef USE_UTF16 85 | void SetName(const UnicodeString & theName); 86 | #endif 87 | void SetDefaultDescription(void); 88 | 89 | // Additional functions 90 | GPTPart & operator=(const GPTPart & orig); 91 | bool operator<(const GPTPart &other) const; 92 | void ShowSummary(int partNum, uint32_t blockSize); // display summary information (1-line) 93 | void ShowDetails(uint32_t blockSize); // display detailed information (multi-line) 94 | void BlankPartition(void); // empty partition of data 95 | int DoTheyOverlap(const GPTPart & other); // returns 1 if there's overlap 96 | void ReversePartBytes(void); // reverse byte order of all integer fields 97 | 98 | // Functions requiring user interaction 99 | void ChangeType(void); // Change the type code 100 | }; // struct GPTPart 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /mbrpart.h: -------------------------------------------------------------------------------- 1 | /* 2 | MBRPart class, part of GPT fdisk program family. 3 | Copyright (C) 2011 Roderick W. Smith 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef MBRPART_H 21 | #define MBRPART_H 22 | 23 | #include 24 | 25 | #define MAX_HEADS 255 /* numbered 0 - 254 */ 26 | #define MAX_SECSPERTRACK 63 /* numbered 1 - 63 */ 27 | #define MAX_CYLINDERS 1024 /* numbered 0 - 1023 */ 28 | 29 | #define NONE 0 /* don't include partition when writing */ 30 | #define PRIMARY 1 /* write partition as primary */ 31 | #define LOGICAL 2 /* write partition as logical */ 32 | #define EBR 4 /* sector is used as an EBR or MBR */ 33 | #define INVALID 8 /* sector number is too large for disk */ 34 | 35 | using namespace std; 36 | 37 | // Data for a single MBR partition record 38 | // Note that firstSector and lastSector are in CHS addressing, which 39 | // splits the bits up in a weird way. 40 | // On read or write of MBR entries, firstLBA is an absolute disk sector. 41 | // On read of logical entries, it's relative to the EBR record for that 42 | // partition. When writing EBR records, it's relative to the extended 43 | // partition's start. 44 | #pragma pack(push) 45 | #pragma pack(1) 46 | struct MBRRecord { 47 | uint8_t status; 48 | uint8_t firstSector[3]; 49 | uint8_t partitionType; 50 | uint8_t lastSector[3]; 51 | uint32_t firstLBA; // see above 52 | uint32_t lengthLBA; 53 | }; // struct MBRRecord 54 | #pragma pack () 55 | 56 | class MBRPart { 57 | protected: 58 | uint8_t status; 59 | uint8_t firstSector[3]; 60 | uint8_t partitionType; 61 | uint8_t lastSector[3]; 62 | uint32_t firstLBA; // see above 63 | uint32_t lengthLBA; 64 | int includeAs; // PRIMARY, LOGICAL, or NONE 65 | int canBeLogical; 66 | int canBePrimary; 67 | static uint32_t numHeads; 68 | static uint32_t numSecspTrack; 69 | static uint64_t diskSize; 70 | static uint32_t blockSize; 71 | static int numInstances; 72 | 73 | public: 74 | MBRPart(); 75 | MBRPart(const MBRPart& other); 76 | virtual ~MBRPart(); 77 | virtual MBRPart& operator=(const MBRPart& orig); 78 | virtual MBRPart& operator=(const struct MBRRecord& orig); 79 | bool operator<(const MBRPart &other) const; 80 | 81 | // Set information on partitions or disks... 82 | void SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs); 83 | void Empty(void); 84 | void SetStartLBA(uint64_t s); 85 | void SetLengthLBA(uint64_t l); 86 | void SetLocation(uint64_t start, uint64_t length); 87 | int SetType(uint8_t typeCode, int isExtended = 0); 88 | void SetStatus(uint8_t s) {status = s;} 89 | void SetInclusion(int status = PRIMARY) {includeAs = status;} 90 | void SetCanBeLogical(int c) {canBeLogical = c;} 91 | void SetCanBePrimary(int c) {canBePrimary = c;} 92 | void StoreInStruct(struct MBRRecord *theStruct); 93 | 94 | // Get information on partitions or disk.... 95 | uint8_t GetType(void) {return partitionType;} 96 | uint8_t GetStatus(void) {return status;} 97 | uint64_t GetStartLBA(void) {return firstLBA;} 98 | uint64_t GetLengthLBA(void) {return lengthLBA;} 99 | uint64_t GetLastLBA(void) const; 100 | uint8_t GetInclusion(void) {return includeAs;} 101 | int CanBeLogical(void) {return canBeLogical;} 102 | int CanBePrimary(void) {return canBePrimary;} 103 | int DoTheyOverlap (const MBRPart& other); 104 | 105 | // Adjust information on partitions or disks... 106 | int RecomputeCHS(void); 107 | int LBAtoCHS(uint32_t lba, uint8_t * chs); 108 | void ReverseByteOrder(void); 109 | 110 | // User I/O... 111 | void ShowData(int isGpt); 112 | }; // MBRPart 113 | 114 | #pragma pack(pop) 115 | 116 | #endif // MBRPART_H 117 | -------------------------------------------------------------------------------- /sgdisk.cc: -------------------------------------------------------------------------------- 1 | // sgdisk.cc 2 | // Command-line-based version of gdisk. This program is named after sfdisk, 3 | // and it can serve a similar role (easily scripted, etc.), but it's used 4 | // strictly via command-line arguments, and it doesn't bear much resemblance 5 | // to sfdisk in actual use. 6 | // 7 | // by Rod Smith, project began February 2009; sgdisk begun January 2010. 8 | 9 | /* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed 10 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "sgdisk.h" 23 | #include "gptcl.h" 24 | 25 | using namespace std; 26 | 27 | #define MAX_OPTIONS 50 28 | 29 | int sgdisk_read(const char* device, sgdisk_partition_table& ptbl, 30 | vector& partitions) { 31 | BasicMBRData mbrData; 32 | GPTData gptData; 33 | GPTPart partData; 34 | int numParts = 0; 35 | 36 | /* Silence noisy underlying library */ 37 | int stdout_fd = dup(STDOUT_FILENO); 38 | int stderr_fd = dup(STDERR_FILENO); 39 | int silence = open("/dev/null", 0); 40 | dup2(silence, STDOUT_FILENO); 41 | dup2(silence, STDERR_FILENO); 42 | 43 | if (!mbrData.ReadMBRData((string) device)) { 44 | cerr << "Failed to read MBR" << endl; 45 | return 8; 46 | } 47 | 48 | switch (mbrData.GetValidity()) { 49 | case mbr: 50 | ptbl.type = MBR; 51 | ptbl.guid.clear(); 52 | for (size_t i = 0; i < MAX_MBR_PARTS; i++) { 53 | if (mbrData.GetLength(i) > 0) { 54 | char typebuf[2+8+1]; 55 | sprintf(typebuf, "%x", (unsigned int)mbrData.GetType(i)); 56 | sgdisk_partition part; 57 | part.num = i + 1; 58 | part.type = typebuf; 59 | partitions.push_back(part); 60 | } 61 | } 62 | break; 63 | case gpt: 64 | gptData.JustLooking(); 65 | if (!gptData.LoadPartitions((string) device)) { 66 | cerr << "Failed to read GPT" << endl; 67 | return 9; 68 | } 69 | 70 | ptbl.type = GPT; 71 | ptbl.guid = gptData.GetDiskGUID().AsString(); 72 | for (size_t i = 0; i < gptData.GetNumParts(); i++) { 73 | partData = gptData[i]; 74 | if (partData.GetFirstLBA() > 0) { 75 | sgdisk_partition part; 76 | part.num = i + 1; 77 | part.type = partData.GetType().AsString(); 78 | part.guid = partData.GetUniqueGUID().AsString(); 79 | part.name = partData.GetDescription(); 80 | partitions.push_back(part); 81 | } 82 | } 83 | break; 84 | default: 85 | cerr << "Unknown partition table" << endl; 86 | return 10; 87 | } 88 | 89 | fflush(stdout); 90 | fflush(stderr); 91 | dup2(stdout_fd, STDOUT_FILENO); 92 | dup2(stderr_fd, STDERR_FILENO); 93 | close(silence); 94 | 95 | return 0; 96 | } 97 | 98 | /* 99 | * Dump partition details in a machine readable format: 100 | * 101 | * DISK [mbr|gpt] [guid] 102 | * PART [n] [type] [guid] 103 | */ 104 | static int android_dump(const char* device) { 105 | sgdisk_partition_table ptbl; 106 | vector partitions; 107 | int rc = sgdisk_read(device, ptbl, partitions); 108 | if (rc == 0) { 109 | stringstream res; 110 | switch (ptbl.type) { 111 | case MBR: 112 | res << "DISK mbr" << endl; 113 | for (auto& part : partitions) { 114 | res << "PART " << part.num << " " << part.type << endl; 115 | } 116 | break; 117 | case GPT: 118 | res << "DISK gpt " << ptbl.guid << endl; 119 | for (auto& part : partitions) { 120 | res << "PART " << part.num << " " << part.type << " " 121 | << part.guid << " " << part.name << endl; 122 | } 123 | break; 124 | default: 125 | return 10; 126 | } 127 | string partStr = res.str(); 128 | write(STDOUT_FILENO, partStr.c_str(), partStr.length()); 129 | } 130 | return rc; 131 | } 132 | 133 | extern "C" int main(int argc, char *argv[]) { 134 | for (int i = 0; i < argc; i++) { 135 | if (!strcmp("--android-dump", argv[i])) { 136 | return android_dump(argv[i + 1]); 137 | } 138 | } 139 | 140 | GPTDataCL theGPT; 141 | return theGPT.DoOptions(argc, argv); 142 | } 143 | -------------------------------------------------------------------------------- /gptcurses.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Implementation of GPTData class derivative with curses-based text-mode 3 | * interaction 4 | * Copyright (C) 2011-2018 Roderick W. Smith 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | * 20 | */ 21 | 22 | #include 23 | #include 24 | #include "gptpart.h" 25 | #include "gpt.h" 26 | 27 | #ifndef __GPT_CURSES 28 | #define __GPT_CURSES 29 | 30 | using namespace std; 31 | 32 | struct MenuItem { 33 | int key; // Keyboard shortcut 34 | string name; // Item name; 8 characters 35 | string desc; // Description 36 | }; 37 | 38 | static struct MenuItem menuMain[] = { 39 | { 'a', "Align ", "Set partition alignment policy" }, 40 | { 'b', "Backup", "Back up the partition table" }, 41 | { 'd', "Delete", "Delete the current partition" }, 42 | { 'h', " Help ", "Print help screen" }, 43 | { 'i', " Info ", "Display information about the partition" }, 44 | { 'l', " Load ", "Load partition table backup from file" }, 45 | { 'm', " naMe ", "Change the partition's name" }, 46 | { 'n', " New ", "Create new partition from free space" }, 47 | { 'q', " Quit ", "Quit program without writing partition table" }, 48 | { 't', " Type ", "Change the filesystem type code GUID" }, 49 | { 'v', "Verify", "Verify the integrity of the disk's data structures" }, 50 | { 'w', "Write ", "Write partition table to disk (this might destroy data)" }, 51 | { 0, "", "" } 52 | }; 53 | 54 | #define EMPTY_SPACE_OPTIONS "abhlnqvw" 55 | #define PARTITION_OPTIONS "abdhilmqtvw" 56 | 57 | // Constants for how to highlight a selected menu item 58 | #define USE_CURSES 1 59 | #define USE_ARROW 2 60 | 61 | // A "Space" is a partition or an unallocated chunk of disk space, maintained 62 | // in a doubly-linked-list data structure to facilitate creating displays of 63 | // partitions and unallocated chunks of space on the disk in the main 64 | // cgdisk partition list. This list MUST be correctly maintained and in order, 65 | // and the numSpaces variable in the main GPTDataCurses class must specify 66 | // how many Spaces are in the main linked list of Spaces. 67 | struct Space { 68 | uint64_t firstLBA; 69 | uint64_t lastLBA; 70 | GPTPart *origPart; 71 | int partNum; 72 | Space *nextSpace; 73 | Space *prevSpace; 74 | }; 75 | 76 | class GPTDataCurses : public GPTData { 77 | protected: 78 | static int numInstances; 79 | GPTPart emptySpace; 80 | Space *firstSpace; 81 | Space *lastSpace; 82 | Space *currentSpace; 83 | int currentSpaceNum; 84 | string whichOptions; 85 | char currentKey; 86 | int numSpaces; 87 | int displayType; 88 | 89 | // Functions relating to Spaces data structures 90 | void EmptySpaces(void); 91 | int MakeSpacesFromParts(void); 92 | void AddEmptySpace(uint64_t firstLBA, uint64_t lastLBA); 93 | int AddEmptySpaces(void); 94 | void UnlinkSpace(Space *theSpace); 95 | void LinkToEnd(Space *theSpace); 96 | void SortSpaces(void); 97 | void IdentifySpaces(void); 98 | 99 | // Data display functions 100 | Space* ShowSpace(int spaceNum, int lineNum); 101 | int DisplayParts(int selected); 102 | public: 103 | GPTDataCurses(void); 104 | ~GPTDataCurses(void); 105 | // Functions corresponding to main menu items 106 | void DeletePartition(int partNum); 107 | void ShowInfo(int partNum); 108 | void ChangeName(int partNum); 109 | void ChangeType(int partNum); 110 | void SetAlignment(void); 111 | void Verify(void); 112 | void MakeNewPart(void); 113 | void SaveData(void); 114 | void Backup(void); 115 | void LoadBackup(void); 116 | void ShowHelp(void); 117 | // User input and menuing functions 118 | void SetDisplayType(int dt) {displayType = dt;} 119 | void ChangeSpaceSelection(int delta); 120 | void MoveSelection(int delta); 121 | void DisplayOptions(char selectedKey); 122 | void AcceptInput(); 123 | int Dispatch(char operation); 124 | void DrawMenu(void); 125 | int MainMenu(void); 126 | }; // class GPTDataCurses 127 | 128 | // Non-class support functions (mostly to do simple curses stuff).... 129 | 130 | void ClearLine(int lineNum); 131 | void ClearBottom(void); 132 | void PromptToContinue(void); 133 | void Report(string theText); 134 | void ShowTypes(void); 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /basicmbr.h: -------------------------------------------------------------------------------- 1 | /* basicmbr.h -- MBR data structure definitions, types, and functions */ 2 | 3 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 4 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 5 | 6 | #include 7 | #include 8 | #include "diskio.h" 9 | #include "mbrpart.h" 10 | 11 | #ifndef __BASICMBRSTRUCTS 12 | #define __BASICMBRSTRUCTS 13 | 14 | #define MBR_SIGNATURE UINT16_C(0xAA55) 15 | 16 | // Maximum number of MBR partitions 17 | #define MAX_MBR_PARTS 128 18 | 19 | using namespace std; 20 | 21 | /**************************************** 22 | * * 23 | * MBRData class and related structures * 24 | * * 25 | ****************************************/ 26 | 27 | // A 512-byte data structure into which the MBR can be loaded in one 28 | // go. Also used when loading logical partitions. 29 | #pragma pack(push) 30 | #pragma pack(1) 31 | struct TempMBR { 32 | uint8_t code[440]; 33 | uint32_t diskSignature; 34 | uint16_t nulls; 35 | struct MBRRecord partitions[4]; 36 | uint16_t MBRSignature; 37 | }; // struct TempMBR 38 | #pragma pack () 39 | 40 | // Possible states of the MBR 41 | enum MBRValidity {invalid, gpt, hybrid, mbr}; 42 | 43 | // Full data in tweaked MBR format 44 | class BasicMBRData { 45 | protected: 46 | uint8_t code[440]; 47 | uint32_t diskSignature; 48 | uint16_t nulls; 49 | // MAX_MBR_PARTS defaults to 128. This array holds both the primary and 50 | // the logical partitions, to simplify data retrieval for GPT conversions. 51 | MBRPart partitions[MAX_MBR_PARTS]; 52 | uint16_t MBRSignature; 53 | 54 | // Above are basic MBR data; now add more stuff.... 55 | uint32_t blockSize; // block size (usually 512) 56 | uint64_t diskSize; // size in blocks 57 | uint32_t numHeads; // number of heads, in CHS scheme 58 | uint32_t numSecspTrack; // number of sectors per track, in CHS scheme 59 | DiskIO* myDisk; 60 | int canDeleteMyDisk; 61 | string device; 62 | MBRValidity state; 63 | MBRPart* GetPartition(int i); // Return primary or logical partition 64 | public: 65 | BasicMBRData(void); 66 | BasicMBRData(string deviceFilename); 67 | BasicMBRData(const BasicMBRData &); 68 | ~BasicMBRData(void); 69 | BasicMBRData & operator=(const BasicMBRData & orig); 70 | 71 | // File I/O functions... 72 | int ReadMBRData(const string & deviceFilename); 73 | int ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1); 74 | int ReadLogicalParts(uint64_t extendedStart, int partNum); 75 | int WriteMBRData(void); 76 | int WriteMBRData(DiskIO *theDisk); 77 | int WriteMBRData(const string & deviceFilename); 78 | int WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t sector); 79 | void DiskSync(void) {myDisk->DiskSync();} 80 | void SetDisk(DiskIO *theDisk); 81 | 82 | // Display data for user... 83 | void DisplayMBRData(void); 84 | void ShowState(void); 85 | 86 | // GPT checks and fixes... 87 | int CheckForGPT(void); 88 | int BlankGPTData(void); 89 | 90 | // Functions that set or get disk metadata (size, CHS geometry, etc.) 91 | void SetDiskSize(uint64_t ds) {diskSize = ds;} 92 | void SetBlockSize(uint32_t bs) {blockSize = bs;} 93 | MBRValidity GetValidity(void) {return state;} 94 | void SetHybrid(void) {state = hybrid;} // Set hybrid flag 95 | void ReadCHSGeom(void); 96 | int GetPartRange(uint32_t* low, uint32_t* high); 97 | int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS 98 | int FindOverlaps(void); 99 | int NumPrimaries(void); 100 | int NumLogicals(void); 101 | int CountParts(void); 102 | void UpdateCanBeLogical(void); 103 | uint64_t FirstLogicalLBA(void); 104 | uint64_t LastLogicalLBA(void); 105 | int AreLogicalsContiguous(void); 106 | int DoTheyFit(void); 107 | int SpaceBeforeAllLogicals(void); 108 | int IsLegal(void); 109 | int IsEEActive(void); 110 | int FindNextInUse(int start); 111 | 112 | // Functions to create, delete, or change partitions 113 | // Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact 114 | void EmptyMBR(int clearBootloader = 1); 115 | void EmptyBootloader(void); 116 | void AddPart(int num, const MBRPart& newPart); 117 | void MakePart(int num, uint64_t startLBA, uint64_t lengthLBA, int type = 0x07, 118 | int bootable = 0); 119 | int SetPartType(int num, int type); 120 | int SetPartBootable(int num, int bootable = 1); 121 | int MakeBiggestPart(int i, int type); // Make partition filling most space 122 | void DeletePartition(int i); 123 | int SetInclusionwChecks(int num, int inclStatus); 124 | void RecomputeCHS(int partNum); 125 | void SortMBR(int start = 0); 126 | int DeleteOversizedParts(); 127 | int DeleteExtendedParts(); 128 | void OmitOverlaps(void); 129 | void MaximizeLogicals(); 130 | void MaximizePrimaries(); 131 | void TrimPrimaries(); 132 | void MakeLogicalsContiguous(void); 133 | void MakeItLegal(void); 134 | int RemoveLogicalsFromFirstFour(void); 135 | int MovePrimariesToFirstFour(void); 136 | int CreateExtended(void); 137 | 138 | // Functions to find information on free space.... 139 | uint64_t FindFirstAvailable(uint64_t start = 1); 140 | uint64_t FindLastInFree(uint64_t start); 141 | uint64_t FindFirstInFree(uint64_t start); 142 | int SectorUsedAs(uint64_t sector, int topPartNum = MAX_MBR_PARTS); 143 | 144 | // Functions to extract data on specific partitions.... 145 | uint8_t GetStatus(int i); 146 | uint8_t GetType(int i); 147 | uint64_t GetFirstSector(int i); 148 | uint64_t GetLength(int i); 149 | 150 | // User interaction functions.... 151 | int DoMenu(const string& prompt = "\nMBR command (? for help): "); 152 | void ShowCommands(void); 153 | }; // class BasicMBRData 154 | 155 | #pragma pack(pop) 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /README-efi.txt: -------------------------------------------------------------------------------- 1 | README for EFI version of GPT fdisk 2 | =================================== 3 | 4 | GPT fdisk for EFI is a binary build of gdisk to run as a pre-boot EFI 5 | application. It's OS-independent and may be used to check or recover 6 | partition tables before installing or booting an OS. It may be used to 7 | overcome boot problems caused by partition table damage or to prepare a 8 | partition table prior to installing an OS. 9 | 10 | Installing GPT fdisk for EFI 11 | ---------------------------- 12 | 13 | The contents of this archive are: 14 | 15 | - COPYING -- The GNU GPL 16 | - gdisk.html -- The gdisk man page, in HTML form 17 | - gdisk_x64.efi -- The gdisk binary, built for EFI (x86-64 CPU) 18 | - NEWS -- The GPT fdisk changelog 19 | - README-efi.txt -- This file 20 | - refind.cer -- The rEFInd public key, .cer (DER) form 21 | - refind.crt -- The rEFInd public key, .crt form 22 | 23 | The gdisk_x64.efi binary included here is built using the UEFI GPT fdisk 24 | library (https://sourceforge.net/p/uefigptfdisk/), which is a beta-level 25 | partial C++ library for UEFI. To use it, you must copy it to your EFI 26 | System Partition (ESP) or some other EFI-accessible location. Under Linux, 27 | the ESP is usually one of the first two or three partitions on /dev/sda. 28 | Under OS X, it's usually the first partition on /dev/disk0 (that is, 29 | /dev/disk0s1). Under Windows, you can mount it to S: by typing "mountvol S: 30 | /S" in an Administrator command prompt. In any of these cases, the 31 | recommended location for gdisk_x64.efi is the EFI/tools directory on the 32 | ESP. In that location, my rEFInd boot manager will detect the gdisk binary 33 | and create a menu option to launch it. If you don't use rEFInd, you can 34 | launch the program using an EFI shell, register it as a boot program with 35 | your firmware, or configure your boot manager (GRUB, gummiboot, etc.) to 36 | launch it. Note that boot LOADERS, such as SYSLINUX and ELILO, can't launch 37 | gdisk. 38 | 39 | Alternatively, you can create a USB flash drive that will launch gdisk when 40 | you boot from it. To do so, create a FAT filesystem on a partition on a USB 41 | flash drive and copy gdisk_x64.efi to it as EFI/BOOT/bootx64.efi. (You'll 42 | need to create the EFI/BOOT directory.) Some systems may require the FAT 43 | filesystem to be flagged as an ESP (with a type code of EF00 in gdisk). You 44 | can use your firmware's built-in boot manager to boot from the USB flash 45 | drive. Some such boot managers present two options for booting USB flash 46 | drives. If yours does this, select the option that includes the string 47 | "UEFI" in the description. 48 | 49 | The gdisk_x64.efi binary is signed with the rEFInd Secure Boot key. Thus, 50 | if you're launching a rEFInd that I've compiled and distributed myself, 51 | gdisk should launch, too. If you're *NOT* running rEFInd but ARE using 52 | Shim, you'll need to add the refind.cer file to your MOK list by using the 53 | MokManager utility. If you're using Secure Boot and you've signed rEFInd 54 | yourself, you'll need to sign gdisk_x64.efi yourself, too. Note that the 55 | rEFInd PPA distributes unsigned binaries and signs them with a local key 56 | stored in /etc/refind/keys. To copy and sign the gdisk_x64.efi binary, you 57 | should type (as root or using sudo): 58 | 59 | sbsign --key /etc/refind.d/keys/refind_local.key \ 60 | --cert /etc/refind.d/keys/refind.crt \ 61 | --output /boot/efi/EFI/tooks/gdisk_x64.efi ./gdisk_x64.efi 62 | 63 | This command assumes you have local rEFInd keys stored in the locations 64 | created by the rEFInd installation script. Substitute your own keys if 65 | you've built them in some other way. Some distributions don't provide the 66 | sbsign binary, so you may need to build it yourself. See the following page 67 | for details: 68 | 69 | https://git.kernel.org/cgit/linux/kernel/git/jejb/sbsigntools.git/ 70 | 71 | Note that you do *NOT* need to sign gdisk if your computer doesn't use 72 | Secure Boot or if you've disabled this feature. 73 | 74 | Using gdisk for EFI 75 | ------------------- 76 | 77 | The EFI version of gdisk is basically the same as using the Linux, OS X, or 78 | other OS versions. One exception is that you do not specify a disk device 79 | on the command line; gdisk for EFI instead displays a list of devices when 80 | you launch and enables you to select one, as in: 81 | 82 | List of hard disks found: 83 | 1: Disk EFI_HANDLE(3EB5DD98): 108423424 sectors, 51.7 GiB 84 | Acpi(PNP0A03,0)/Pci(1|1)/Ata(Primary,Master) 85 | 2: Disk EFI_HANDLE(3EB58289): 105456768 sectors, 50.3 GiB 86 | Acpi(PNP0A03,0)/Pci(D|0)? 87 | 88 | Disk number (1-2): 2 89 | 90 | Once you've selected your disk, it should operate in much the same way as 91 | any other version of gdisk. (See the next section, though!) Some programs, 92 | including my rEFInd boot manager, complain about the changed partition 93 | table, even if you've made no changes. If you run into problems using other 94 | programs or launching an OS immediately after running gdisk, reboot; that 95 | should cause the firmware to re-load its partition table. 96 | 97 | Caveats 98 | ------- 99 | 100 | I've tested gdisk_x64.efi on several systems. It's worked fine for me on 4 101 | of 6 computers (5 of 7, counting VirtualBox). Two systems gave me problems, 102 | though: 103 | 104 | * gdisk presented a never-ending list of options (as if receiving a 105 | never-ending string of "?" or other unrecognized command characters) on a 106 | 2014 MacBook Air. 107 | * A computer based on an Intel DG43NB motherboard rebooted as soon as I 108 | launched gdisk. 109 | 110 | Both computers have relatively old EFIs. (Despite its newness, the Mac has 111 | a 1.10 EFI, as do all Macs, to the best of my knowledge.) Most of the 112 | computers that worked had 2.31 EFIs, although one had a 2.10 EFI. 113 | 114 | The bottom line is that I can't guarantee that this binary will work on all 115 | computers. It's conceivable that recompiling gdisk with the latest version 116 | of the UEFI GPT fdisk library will help. Also, I haven't compiled a 32-bit 117 | version, so if you have a 32-bit EFI, you'll have to compile it yourself or 118 | do without. 119 | 120 | References 121 | ---------- 122 | 123 | The following sites have useful additional information: 124 | 125 | UEFI GPT fdisk: 126 | https://sourceforge.net/projects/uefigptfdisk/ 127 | 128 | sbsigntools git repository: 129 | https://git.kernel.org/cgit/linux/kernel/git/jejb/sbsigntools.git/ 130 | 131 | rEFInd: 132 | http://www.rodsbooks.com/refind/ 133 | -------------------------------------------------------------------------------- /mbr.cc: -------------------------------------------------------------------------------- 1 | /* mbr.cc -- Functions for loading, saving, and manipulating legacy MBR partition 2 | data. */ 3 | 4 | /* Initial coding by Rod Smith, January to February, 2009 */ 5 | 6 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 7 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 | 9 | #define __STDC_LIMIT_MACROS 10 | #ifndef __STDC_CONSTANT_MACROS 11 | #define __STDC_CONSTANT_MACROS 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "mbr.h" 24 | 25 | using namespace std; 26 | 27 | /**************************************** 28 | * * 29 | * MBRData class and related structures * 30 | * * 31 | ****************************************/ 32 | 33 | MBRData::~MBRData(void) { 34 | } // MBRData destructor 35 | 36 | // Assignment operator -- copy entire set of MBR data. 37 | MBRData & MBRData::operator=(const BasicMBRData & orig) { 38 | BasicMBRData::operator=(orig); 39 | return *this; 40 | } // MBRData::operator=() 41 | 42 | /***************************************************** 43 | * * 44 | * Functions to create, delete, or change partitions * 45 | * * 46 | *****************************************************/ 47 | 48 | // Create a protective MBR. Clears the boot loader area if clearBoot > 0. 49 | void MBRData::MakeProtectiveMBR(int clearBoot) { 50 | 51 | EmptyMBR(clearBoot); 52 | 53 | // Initialize variables 54 | nulls = 0; 55 | MBRSignature = MBR_SIGNATURE; 56 | diskSignature = UINT32_C(0); 57 | 58 | partitions[0].SetStatus(0); // Flag the protective part. as unbootable 59 | 60 | partitions[0].SetType(UINT8_C(0xEE)); 61 | if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 62 | partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1)); 63 | } else { // disk is too big to represent, so fake it... 64 | partitions[0].SetLocation(UINT32_C(1), UINT32_MAX); 65 | } // if/else 66 | partitions[0].SetInclusion(PRIMARY); 67 | 68 | state = gpt; 69 | } // MBRData::MakeProtectiveMBR() 70 | 71 | // Optimizes the size of the 0xEE (EFI GPT) partition 72 | void MBRData::OptimizeEESize(void) { 73 | int i, typeFlag = 0; 74 | uint64_t after; 75 | 76 | for (i = 0; i < 4; i++) { 77 | // Check for non-empty and non-0xEE partitions 78 | if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00)) 79 | typeFlag++; 80 | if (partitions[i].GetType() == 0xEE) { 81 | // Blank space before this partition; fill it.... 82 | if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) { 83 | partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1)); 84 | } // if 85 | // Blank space after this partition; fill it.... 86 | after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA(); 87 | if (SectorUsedAs(after, 4) == NONE) { 88 | partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1); 89 | } // if free space after 90 | if (after > diskSize) { 91 | if (diskSize < UINT32_MAX) { // If the disk is under 2TiB 92 | partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA()); 93 | } else { // disk is too big to represent, so fake it... 94 | partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA()); 95 | } // if/else 96 | } // if protective partition is too big 97 | RecomputeCHS(i); 98 | } // if partition is 0xEE 99 | } // for partition loop 100 | if (typeFlag == 0) { // No non-hybrid partitions found 101 | MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR. 102 | } // if 103 | } // MBRData::OptimizeEESize() 104 | 105 | // Delete a partition if one exists at the specified location. 106 | // Returns 1 if a partition was deleted, 0 otherwise.... 107 | // Used to help keep GPT & hybrid MBR partitions in sync.... 108 | int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) { 109 | uint32_t start32, length32; 110 | int i, deleted = 0; 111 | 112 | if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) { 113 | start32 = (uint32_t) start64; 114 | length32 = (uint32_t) length64; 115 | for (i = 0; i < MAX_MBR_PARTS; i++) { 116 | if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32) 117 | && (partitions[i].GetLengthLBA() == length32)) { 118 | DeletePartition(i); 119 | if (state == hybrid) 120 | OptimizeEESize(); 121 | deleted = 1; 122 | } // if (match found) 123 | } // for i (partition scan) 124 | } // if (hybrid & GPT partition < 2TiB) 125 | return deleted; 126 | } // MBRData::DeleteByLocation() 127 | 128 | /****************************************************** 129 | * * 130 | * Functions that extract data on specific partitions * 131 | * * 132 | ******************************************************/ 133 | 134 | // Return the MBR data as a GPT partition.... 135 | GPTPart MBRData::AsGPT(int i) { 136 | MBRPart* origPart; 137 | GPTPart newPart; 138 | uint8_t origType; 139 | uint64_t firstSector, lastSector; 140 | 141 | newPart.BlankPartition(); 142 | origPart = GetPartition(i); 143 | if (origPart != NULL) { 144 | origType = origPart->GetType(); 145 | 146 | // don't convert extended, hybrid protective, or null (non-existent) 147 | // partitions (Note similar protection is in GPTData::XFormPartitions(), 148 | // but I want it here too in case I call this function in another 149 | // context in the future....) 150 | if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) && 151 | (origType != 0x00) && (origType != 0xEE)) { 152 | firstSector = (uint64_t) origPart->GetStartLBA(); 153 | newPart.SetFirstLBA(firstSector); 154 | lastSector = (uint64_t) origPart->GetLastLBA(); 155 | newPart.SetLastLBA(lastSector); 156 | newPart.SetType(((uint16_t) origType) * 0x0100); 157 | newPart.RandomizeUniqueGUID(); 158 | newPart.SetAttributes(0); 159 | newPart.SetName(newPart.GetTypeName()); 160 | } // if not extended, protective, or non-existent 161 | } // if (origPart != NULL) 162 | return newPart; 163 | } // MBRData::AsGPT() 164 | 165 | -------------------------------------------------------------------------------- /README.Windows: -------------------------------------------------------------------------------- 1 | GPT fdisk (aka gdisk) and FixParts 2 | 3 | by Roderick W. Smith, rodsmith@rodsbooks.com 4 | 5 | ******************************** IMPORTANT ******************************** 6 | Most versions of Windows cannot boot from a GPT disk on BIOS-based 7 | computers, and most varieties prior to Vista cannot read GPT disks. GPT 8 | fdisk is a partition editor for GPT disks, and it will *AUTOMATICALLY 9 | CONVERT* MBR disks to GPT form. Therefore, you should **NOT** use GPT fdisk 10 | on a Windows system unless you fully understand what you're doing or are 11 | certain that your computer boots in EFI/UEFI mode! If you accidentally use 12 | GPT fdisk on a BIOS-mode boot disk, or perhaps even on a data disk, you may 13 | find recovery to be very difficult! Pre-installed Windows 8 and later 14 | systems almost always use GPT disks and boot in EFI/UEFI mode, but 15 | self-installed Windows 8 systems sometimes use BIOS mode. This caveat does 16 | not apply to FixParts, though; that tool works only on MBR disks. 17 | *************************************************************************** 18 | 19 | Read the main README file for general information on the program, and read 20 | the gdisk.html or fixparts.html documents (the Linux man pages converted to 21 | HTML format) for detailed use information. My GPT fdisk Web page, 22 | http://www.rodsbooks.com/gdisk/, provides a more tutorial introduction to 23 | the software. I originally wrote GPT fdisk on Linux, and some Linux- and 24 | Unix-centric language remains in the documentation. 25 | 26 | Windows Use Notes 27 | ----------------- 28 | 29 | The Windows version of GPT fdisk was added with version 0.6.2 of the 30 | package. The Windows binary package includes the gdisk.exe interactive 31 | text-mode program file but no equivalent to the sgdisk program that's 32 | available with Linux, FreeBSD, and OS X builds. In theory, an sgdisk.exe 33 | for Windows could be built if the popt library were installed. I've not 34 | attempted to do this myself, though. If you care to try, check 35 | http://gnuwin32.sourceforge.net/packages/popt.htm for information on popt 36 | for Windows. 37 | 38 | Beginning with version 0.8.10, I'm distributing both 32-bit and 64-bit 39 | binaries, which include the strings "32" or "64" in their names. The 32-bit 40 | binaries work fine on most versions of Windows, but some 64-bit 41 | installations of Windows 8 lack 32-bit support libraries and so may need 42 | the 64-bit binaries. 43 | 44 | The FixParts program (fixparts32.exe and fixparts64.exe) is new with GPT 45 | fdisk 0.7.0. As described in the main README file, this program fixes 46 | certain partition table problems that can be created by buggy partitioning 47 | software. Windows seems to be unfazed by most such problems, but I've not 48 | done an extensive survey of Windows partitioning tools on this score. 49 | 50 | To install the programs, copy the gdisk32.exe and fixparts32.exe (or 51 | gdisk64.exe and fixparts64.exe) program files to any directory on your 52 | path, such as C:\Windows. Alternatively, you can change to the program's 53 | directory or type its complete path whenever you use it. 54 | 55 | To use the programs, first launch a Command Prompt as the Administrator. To 56 | do this, locate the Command Prompt program icon, right-click it, and select 57 | "Run as Administrator." If you use a non-Administrator Command Prompt, you 58 | won't be able to edit hard disk partition tables, although you will be able 59 | to edit raw disk image files. 60 | 61 | The program requires a hard disk identifier as an option. You can specify 62 | this in either of two forms. The first way is as a number followed by a 63 | colon, as in: 64 | 65 | gdisk 0: 66 | 67 | Disks are numbered starting from 0, so the preceding command launches gdisk 68 | on the first disk. The second way to specify a disk device is via a 69 | harder-to-remember name: 70 | 71 | gdisk32 \\.\physicaldrive0 72 | 73 | This command is equivalent to the earlier one -- it edits the partition 74 | table on the first physical disk. Change the number at the end of the 75 | device name to change the disk edited. 76 | 77 | If you pass the "-l" option to gdisk.exe in addition to the disk 78 | identifier, the program displays the current partition table information 79 | and then exits. This use entails no risk to MBR disks, since the program 80 | never writes data back to the disk when used in this way. 81 | 82 | As noted above, editing the first disk with GPT fdisk is usually a Bad 83 | Idea. An exception would be if your system uses an Extensible Firmware 84 | Interface (EFI) and already boots from a GPT disk. It's safer to edit 85 | non-boot disks, which usually have numbers of 1 and above, but only if you 86 | run a version of Windows with GPT support. For more information on Windows' 87 | support of GPT, see Microsoft's Web page on the topic: 88 | 89 | http://www.microsoft.com/whdc/device/storage/GPT_FAQ.mspx 90 | 91 | The Windows binaries I've compiled do not support Unicode UTF-16LE GPT 92 | partition names. This feature was added to version 0.7.1 of the software 93 | for Linux, FreeBSD, and OS X, and with changes to some #ifndef lines in the 94 | source files, it can be compiled for Windows; however, it seems to do 95 | little good in Windows because of Command Prompt window and/or ICU library 96 | limitations. Thus, I've omitted this support in the interests of 97 | simplifying the binary distribution, since including it would mean 98 | distributing the ICU libraries. 99 | 100 | Source Code and Compilation Issues 101 | ---------------------------------- 102 | 103 | I have successfully compiled GPT fdisk using three different Windows 104 | compilers: 105 | 106 | - MinGW (http://www.mingw.org), and in particular its Linux-hosted 107 | cross-compiler -- Under Ubuntu Linux, the Makefile.mingw and 108 | Makefile.mingw64 files enable compilation of the software via MinGW. 109 | (Type "make -f Makefile.mingw" to compile 32-bit binaries, and "make -f 110 | Makefile.mingw64" to compile 64-bit binaries.) If you try to compile 111 | using another compiler or even using MinGW under Windows or another Linux 112 | variety, you may need to adjust the Makefile.mingw options. 113 | 114 | - Microsoft Visual C++ 2008 Express 115 | (http://www.microsoft.com/express/Windows/) -- This compiler requires a 116 | third-party stdint.h file (I used the one from 117 | http://msinttypes.googlecode.com/svn/trunk/stdint.h), but it otherwise 118 | works fine. A project is easily created by adding all the *.h files and 119 | all the *.cc files except diskio-unix.cc, sgdisk.cc, and whichever 120 | program file you intend to NOT build (gdisk.cc or fixparts.cc). 121 | 122 | - Microsoft Visual C++ 2010 Express -- This compiler works much like the 123 | 2008 version, although I didn't need to add a third-party stdint.h file. 124 | 125 | The MinGW compiler produces much larger executables than do the MS 126 | compilers. The resulting binaries seem to work equally well, but my testing 127 | has been minimal. 128 | 129 | I've also attempted to compile the code with OpenWatcom 1.8, but this 130 | attempt failed, mostly because the compiler can't yet handle iostream 131 | output on standard C++ strings. OpenWatcom also seems to have incorrectly 132 | set the value of UINT32_MAX as if uint32_t values were 64-bit integers. 133 | This alone won't cause the compile to fail, but it would create bugs. 134 | 135 | If you modify GPT fdisk to get it to compile under another compiler, I 136 | welcome submission of patches. 137 | -------------------------------------------------------------------------------- /guid.cc: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Implementation: GUIDData 3 | // 4 | // Description: GUIDData class header 5 | // Implements the GUIDData data structure and support methods 6 | // 7 | // 8 | // Author: Rod Smith , (C) 2010-2011 9 | // 10 | // Copyright: See COPYING file that comes with this distribution 11 | // 12 | // 13 | 14 | #define __STDC_LIMIT_MACROS 15 | #ifndef __STDC_CONSTANT_MACROS 16 | #define __STDC_CONSTANT_MACROS 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "guid.h" 25 | #include "support.h" 26 | 27 | using namespace std; 28 | 29 | bool GUIDData::firstInstance = 1; 30 | 31 | GUIDData::GUIDData(void) { 32 | if (firstInstance) { 33 | srand((unsigned int) time(0)); 34 | firstInstance = 0; 35 | } // if 36 | Zero(); 37 | } // constructor 38 | 39 | GUIDData::GUIDData(const GUIDData & orig) { 40 | memcpy(uuidData, orig.uuidData, sizeof(uuidData)); 41 | } // copy constructor 42 | 43 | GUIDData::GUIDData(const string & orig) { 44 | operator=(orig); 45 | } // copy (from string) constructor 46 | 47 | GUIDData::GUIDData(const char * orig) { 48 | operator=(orig); 49 | } // copy (from char*) constructor 50 | 51 | GUIDData::~GUIDData(void) { 52 | } // destructor 53 | 54 | GUIDData & GUIDData::operator=(const GUIDData & orig) { 55 | memcpy(uuidData, orig.uuidData, sizeof(uuidData)); 56 | return *this; 57 | } // GUIDData::operator=(const GUIDData & orig) 58 | 59 | // Assign the GUID from a string input value. A GUID is normally formatted 60 | // with four dashes as element separators, for a total length of 36 61 | // characters. If the input string is this long or longer, this function 62 | // assumes standard separator positioning; if the input string is less 63 | // than 36 characters long, this function assumes the input GUID has 64 | // been compressed by removal of separators. In either event, there's 65 | // little in the way of sanity checking, so garbage in = garbage out! 66 | // One special case: If the first character is 'r' or 'R', a random 67 | // GUID is assigned. 68 | GUIDData & GUIDData::operator=(const string & orig) { 69 | string copy, fragment; 70 | size_t len; 71 | // Break points for segments, either with or without characters separating the segments.... 72 | size_t longSegs[6] = {0, 9, 14, 19, 24, 36}; 73 | size_t shortSegs[6] = {0, 8, 12, 16, 20, 32}; 74 | size_t *segStart = longSegs; // Assume there are separators between segments 75 | 76 | // If first character is an 'R' or 'r', set a random GUID; otherwise, 77 | // try to parse it as a real GUID 78 | if ((orig[0] == 'R') || (orig[0] == 'r')) { 79 | Randomize(); 80 | } else { 81 | Zero(); 82 | 83 | // Delete stray spaces.... 84 | copy = DeleteSpaces(orig); 85 | 86 | // If length is too short, assume there are no separators between segments 87 | len = copy.length(); 88 | if (len < 36) { 89 | segStart = shortSegs; 90 | }; 91 | 92 | // Extract data fragments at fixed locations and convert to 93 | // integral types.... 94 | if (len >= segStart[1]) { 95 | uuidData[3] = StrToHex(copy, 0); 96 | uuidData[2] = StrToHex(copy, 2); 97 | uuidData[1] = StrToHex(copy, 4); 98 | uuidData[0] = StrToHex(copy, 6); 99 | } // if 100 | if (len >= segStart[2]) { 101 | uuidData[5] = StrToHex(copy, (unsigned int) segStart[1]); 102 | uuidData[4] = StrToHex(copy, (unsigned int) segStart[1] + 2); 103 | } // if 104 | if (len >= segStart[3]) { 105 | uuidData[7] = StrToHex(copy, (unsigned int) segStart[2]); 106 | uuidData[6] = StrToHex(copy, (unsigned int) segStart[2] + 2); 107 | } // if 108 | if (len >= segStart[4]) { 109 | uuidData[8] = StrToHex(copy, (unsigned int) segStart[3]); 110 | uuidData[9] = StrToHex(copy, (unsigned int) segStart[3] + 2); 111 | } // if 112 | if (len >= segStart[5]) { 113 | uuidData[10] = StrToHex(copy, (unsigned int) segStart[4]); 114 | uuidData[11] = StrToHex(copy, (unsigned int) segStart[4] + 2); 115 | uuidData[12] = StrToHex(copy, (unsigned int) segStart[4] + 4); 116 | uuidData[13] = StrToHex(copy, (unsigned int) segStart[4] + 6); 117 | uuidData[14] = StrToHex(copy, (unsigned int) segStart[4] + 8); 118 | uuidData[15] = StrToHex(copy, (unsigned int) segStart[4] + 10); 119 | } // if 120 | } // if/else randomize/set value 121 | 122 | return *this; 123 | } // GUIDData::operator=(const string & orig) 124 | 125 | // Assignment from C-style string; rely on C++ casting.... 126 | GUIDData & GUIDData::operator=(const char * orig) { 127 | return operator=((string) orig); 128 | } // GUIDData::operator=(const char * orig) 129 | 130 | // Erase the contents of the GUID 131 | void GUIDData::Zero(void) { 132 | memset(uuidData, 0, sizeof(uuidData)); 133 | } // GUIDData::Zero() 134 | 135 | // Set a completely random GUID value.... 136 | // The uuid_generate() function returns a value that needs to have its 137 | // first three fields byte-reversed to conform to Intel's GUID layout. 138 | // The Windows UuidCreate() function doesn't need this adjustment. If 139 | // neither function is defined, or if UuidCreate() fails, set a completely 140 | // random GUID -- not completely kosher, but it works on most platforms 141 | // (immediately after creating the UUID on Windows 7 being an important 142 | // exception). 143 | void GUIDData::Randomize(void) { 144 | int i, uuidGenerated = 0; 145 | 146 | #ifdef _UUID_UUID_H 147 | uuid_generate(uuidData); 148 | ReverseBytes(&uuidData[0], 4); 149 | ReverseBytes(&uuidData[4], 2); 150 | ReverseBytes(&uuidData[6], 2); 151 | uuidGenerated = 1; 152 | #endif 153 | #if defined (_RPC_H) || defined (__RPC_H__) 154 | UUID MsUuid; 155 | if (UuidCreate(&MsUuid) == RPC_S_OK) { 156 | memcpy(uuidData, &MsUuid, 16); 157 | uuidGenerated = 1; 158 | } // if 159 | #endif 160 | 161 | if (!uuidGenerated) { 162 | cerr << "Warning! Unable to generate a proper UUID! Creating an improper one as a last\n" 163 | << "resort! Windows 7 may crash if you save this partition table!\a\n"; 164 | for (i = 0; i < 16; i++) 165 | uuidData[i] = (unsigned char) (256.0 * (rand() / (RAND_MAX + 1.0))); 166 | } // if 167 | } // GUIDData::Randomize 168 | 169 | // Equality operator; returns 1 if the GUIDs are equal, 0 if they're unequal 170 | int GUIDData::operator==(const GUIDData & orig) const { 171 | return !memcmp(uuidData, orig.uuidData, sizeof(uuidData)); 172 | } // GUIDData::operator== 173 | 174 | // Inequality operator; returns 1 if the GUIDs are unequal, 0 if they're equal 175 | int GUIDData::operator!=(const GUIDData & orig) const { 176 | return !operator==(orig); 177 | } // GUIDData::operator!= 178 | 179 | // Return the GUID as a string, suitable for display to the user. 180 | string GUIDData::AsString(void) const { 181 | char theString[40]; 182 | 183 | sprintf(theString, 184 | "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 185 | uuidData[3], uuidData[2], uuidData[1], uuidData[0], uuidData[5], 186 | uuidData[4], uuidData[7], uuidData[6], uuidData[8], uuidData[9], 187 | uuidData[10], uuidData[11], uuidData[12], uuidData[13], uuidData[14], 188 | uuidData[15]); 189 | return theString; 190 | } // GUIDData::AsString(void) 191 | 192 | // Delete spaces or braces (which often enclose GUIDs) from the orig string, 193 | // returning modified string. 194 | string GUIDData::DeleteSpaces(string s) { 195 | size_t position; 196 | 197 | if (s.length() > 0) { 198 | for (position = s.length(); position > 0; position--) { 199 | if ((s[position - 1] == ' ') || (s[position - 1] == '{') || (s[position - 1] == '}')) { 200 | s.erase(position - 1, 1); 201 | } // if 202 | } // for 203 | } // if 204 | return s; 205 | } // GUIDData::DeleteSpaces() 206 | 207 | /******************************* 208 | * * 209 | * Non-class support functions * 210 | * * 211 | *******************************/ 212 | 213 | // Display a GUID as a string.... 214 | ostream & operator<<(ostream & os, const GUIDData & data) { 215 | // string asString; 216 | 217 | os << data.AsString(); 218 | return os; 219 | } // GUIDData::operator<<() 220 | -------------------------------------------------------------------------------- /attributes.cc: -------------------------------------------------------------------------------- 1 | // attributes.cc 2 | // Class to manage partition attribute codes. These are binary bit fields, 3 | // of which only four are currently (2/2011) documented on Wikipedia, and 4 | // two others found from other sources. 5 | 6 | /* This program is copyright (c) 2009-2013 by Roderick W. Smith. It is distributed 7 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 | 9 | #define __STDC_LIMIT_MACROS 10 | #ifndef __STDC_CONSTANT_MACROS 11 | #define __STDC_CONSTANT_MACROS 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "attributes.h" 20 | #include "support.h" 21 | 22 | using namespace std; 23 | 24 | string Attributes::atNames[NUM_ATR]; 25 | int Attributes::numAttrs = 0; 26 | //Attributes::staticInit Attributes::staticInitializer; 27 | 28 | // Default constructor 29 | Attributes::Attributes(void) { 30 | numAttrs++; 31 | if (numAttrs == 1) 32 | Setup(); 33 | attributes = 0; 34 | } // constructor 35 | 36 | // Alternate constructor 37 | Attributes::Attributes(const uint64_t a) { 38 | numAttrs++; 39 | if (numAttrs == 1) 40 | Setup(); 41 | attributes = a; 42 | } // alternate constructor 43 | 44 | // Destructor. 45 | Attributes::~Attributes(void) { 46 | numAttrs--; 47 | } // Attributes destructor 48 | 49 | void Attributes::Setup(void) { 50 | ostringstream temp; 51 | 52 | // Most bits are undefined, so start by giving them an 53 | // appropriate name 54 | for (int i = 0; i < NUM_ATR; i++) { 55 | temp.str(""); 56 | temp << "Undefined bit #" << i; 57 | Attributes::atNames[i] = temp.str(); 58 | } // for 59 | 60 | // Now reset those names that are defined.... 61 | atNames[0] = "system partition"; // required for computer to operate 62 | atNames[1] = "hide from EFI"; 63 | atNames[2] = "legacy BIOS bootable"; 64 | atNames[60] = "read-only"; 65 | atNames[62] = "hidden"; 66 | atNames[63] = "do not automount"; 67 | } // Attributes::Setup() 68 | 69 | // Display current attributes to user 70 | void Attributes::DisplayAttributes(void) { 71 | uint32_t i; 72 | int numSet = 0; 73 | 74 | cout << "Attribute value is "; 75 | cout.setf(ios::uppercase); 76 | cout.fill('0'); 77 | cout.width(16); 78 | cout << hex << attributes << dec << ". Set fields are:\n"; 79 | for (i = 0; i < NUM_ATR; i++) { 80 | if ((UINT64_C(1) << i) & attributes) { 81 | cout << i << " (" << GetAttributeName(i) << ")" << "\n"; 82 | numSet++; 83 | } // if 84 | } // for 85 | cout.fill(' '); 86 | if (numSet == 0) 87 | cout << " No fields set\n"; 88 | cout << "\n"; 89 | } // Attributes::DisplayAttributes() 90 | 91 | // Display attributes for a partition. Note that partNum is just passed for 92 | // immediate display; it's not used to access a particular partition. 93 | void Attributes::ShowAttributes(const uint32_t partNum) { 94 | uint32_t bitNum; 95 | bool bitset; 96 | 97 | for (bitNum = 0; bitNum < 64; bitNum++) { 98 | bitset = (UINT64_C(1) << bitNum) & attributes; 99 | if (bitset) { 100 | cout << partNum+1 << ":" << bitNum << ":" << bitset 101 | << " (" << GetAttributeName(bitNum) << ")" << endl; 102 | } // if 103 | } // for 104 | } // Attributes::ShowAttributes 105 | 106 | // Prompt user for attribute changes 107 | void Attributes::ChangeAttributes(void) { 108 | int response; 109 | uint64_t bitValue; 110 | 111 | cout << "Known attributes are:\n"; 112 | ListAttributes(); 113 | cout << "\n"; 114 | 115 | do { 116 | DisplayAttributes(); 117 | response = GetNumber(0, NUM_ATR, 64, 118 | "Toggle which attribute field (0-63, 64 or to exit): "); 119 | if (response != 64) { 120 | bitValue = UINT64_C(1) << response; // Find the integer value of the bit 121 | if (bitValue & attributes) { // bit is set 122 | attributes &= ~bitValue; // so unset it 123 | cout << "Have disabled the '" << atNames[response] << "' attribute.\n"; 124 | } else { // bit is not set 125 | attributes |= bitValue; // so set it 126 | cout << "Have enabled the '" << atNames[response] << "' attribute.\n"; 127 | } // if/else 128 | } // if 129 | } while (response != 64); 130 | } // Attributes::ChangeAttributes() 131 | 132 | // Display all defined attributes on the screen (omits undefined bits). 133 | void Attributes::ListAttributes(void) { 134 | uint32_t bitNum; 135 | string tempAttr; 136 | 137 | for (bitNum = 0; bitNum < NUM_ATR; bitNum++) { 138 | tempAttr = GetAttributeName(bitNum); 139 | if (tempAttr.substr(0, 15) != "Undefined bit #" ) 140 | cout << bitNum << ": " << Attributes::GetAttributeName(bitNum) << "\n"; 141 | } // for 142 | } // Attributes::ListAttributes 143 | 144 | // multifaceted attributes access 145 | // returns true upon success, false upon failure 146 | bool Attributes::OperateOnAttributes(const uint32_t partNum, const string& attributeOperator, const string& attributeBits) { 147 | 148 | // attribute access opcode 149 | typedef enum { 150 | ao_or, ao_nand, ao_xor, ao_assignall, // operate on all attributes (bitmask) 151 | ao_unknown, // must be after bitmask operators and before bitnum operators 152 | ao_set, ao_clear, ao_toggle, ao_get // operate on a single attribute (bitnum) 153 | } attribute_opcode_t; // typedef enum 154 | 155 | // translate attribute operator into an attribute opcode 156 | attribute_opcode_t attributeOpcode = ao_unknown; { // opcode is not known yet 157 | if (attributeOperator == "or") attributeOpcode = ao_or; 158 | else if (attributeOperator == "nand") attributeOpcode = ao_nand; 159 | else if (attributeOperator == "xor") attributeOpcode = ao_xor; 160 | else if (attributeOperator == "=") attributeOpcode = ao_assignall; 161 | else if (attributeOperator == "set") attributeOpcode = ao_set; 162 | else if (attributeOperator == "clear") attributeOpcode = ao_clear; 163 | else if (attributeOperator == "toggle") attributeOpcode = ao_toggle; 164 | else if (attributeOperator == "get") attributeOpcode = ao_get; 165 | else { 166 | cerr << "Unknown attributes operator: " << attributeOperator << endl; 167 | return false; 168 | } // else 169 | } // attributeOpcode 170 | 171 | // get bit mask if operating on entire attribute set 172 | uint64_t attributeBitMask; { if (attributeOpcode < ao_unknown) { 173 | if (1 != sscanf (attributeBits.c_str(), "%qx", (long long unsigned int*) &attributeBitMask)) { 174 | cerr << "Could not convert hex attribute mask" << endl; 175 | return false; 176 | } // if 177 | }} // attributeBitMask, if 178 | 179 | // get bit number and calculate bit mask if operating on a single attribute 180 | int bitNum; { if (attributeOpcode > ao_unknown) { 181 | if (1 != sscanf (attributeBits.c_str(), "%d", &bitNum)) { 182 | cerr << "Could not convert bit number" << endl; 183 | return false; 184 | } // if 185 | const uint64_t one = 1; 186 | attributeBitMask = one << bitNum; 187 | }} // bitNum, if 188 | 189 | switch (attributeOpcode) { 190 | // assign all attributes at once 191 | case ao_assignall: attributes = attributeBitMask; break; 192 | 193 | // set individual attribute(s) 194 | case ao_set: 195 | case ao_or: attributes |= attributeBitMask; break; 196 | 197 | // clear individual attribute(s) 198 | case ao_clear: 199 | case ao_nand: attributes &= ~attributeBitMask; break; 200 | 201 | // toggle individual attribute(s) 202 | case ao_toggle: 203 | case ao_xor: attributes ^= attributeBitMask; break; 204 | 205 | // display a single attribute 206 | case ao_get: { 207 | cout << partNum+1 << ":" << bitNum << ":" 208 | << bool (attributeBitMask & attributes) << endl; 209 | break; 210 | } // case ao_get 211 | 212 | default: break; // will never get here 213 | } // switch 214 | 215 | return true; 216 | } // Attributes::OperateOnAttributes() 217 | 218 | /******************************* 219 | * * 220 | * Non-class support functions * 221 | * * 222 | *******************************/ 223 | 224 | // Display attributes 225 | ostream & operator<<(ostream & os, const Attributes & data) { 226 | os << data.GetAttributes(); 227 | return os; 228 | } // operator<<() 229 | -------------------------------------------------------------------------------- /gpt.h: -------------------------------------------------------------------------------- 1 | /* gpt.h -- GPT and data structure definitions, types, and 2 | functions */ 3 | 4 | /* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed 5 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 6 | 7 | #include 8 | #include 9 | #include "gptpart.h" 10 | #include "support.h" 11 | #include "mbr.h" 12 | #include "bsd.h" 13 | #include "gptpart.h" 14 | 15 | #ifndef __GPTSTRUCTS 16 | #define __GPTSTRUCTS 17 | 18 | // Default values for sector alignment 19 | #define DEFAULT_ALIGNMENT 2048 20 | #define MAX_ALIGNMENT 65536 21 | #define MIN_AF_ALIGNMENT 8 22 | 23 | // Below constant corresponds to a ~279GiB (300GB) disk, since the 24 | // smallest Advanced Format drive I know of is 320GB in size 25 | #define SMALLEST_ADVANCED_FORMAT UINT64_C(585937500) 26 | 27 | using namespace std; 28 | 29 | /**************************************** 30 | * * 31 | * GPTData class and related structures * 32 | * * 33 | ****************************************/ 34 | 35 | // Validity state of GPT data 36 | enum GPTValidity {gpt_valid, gpt_corrupt, gpt_invalid}; 37 | 38 | // Which set of partition data to use 39 | enum WhichToUse {use_gpt, use_mbr, use_bsd, use_new, use_abort}; 40 | 41 | // Header (first 512 bytes) of GPT table 42 | #pragma pack(push) 43 | #pragma pack(1) 44 | struct GPTHeader { 45 | uint64_t signature; 46 | uint32_t revision; 47 | uint32_t headerSize; 48 | uint32_t headerCRC; 49 | uint32_t reserved; 50 | uint64_t currentLBA; 51 | uint64_t backupLBA; 52 | uint64_t firstUsableLBA; 53 | uint64_t lastUsableLBA; 54 | GUIDData diskGUID; 55 | uint64_t partitionEntriesLBA; 56 | uint32_t numParts; 57 | uint32_t sizeOfPartitionEntries; 58 | uint32_t partitionEntriesCRC; 59 | unsigned char reserved2[GPT_RESERVED]; 60 | }; // struct GPTHeader 61 | #pragma pack () 62 | 63 | // Data in GPT format 64 | class GPTData { 65 | protected: 66 | struct GPTHeader mainHeader; 67 | GPTPart *partitions; 68 | uint32_t numParts; // # of partitions the table can hold 69 | struct GPTHeader secondHeader; 70 | MBRData protectiveMBR; 71 | string device; // device filename 72 | DiskIO myDisk; 73 | uint32_t blockSize; // device logical block size 74 | uint32_t physBlockSize; // device physical block size (or 0 if it can't be determined) 75 | uint64_t diskSize; // size of device, in logical blocks 76 | GPTValidity state; // is GPT valid? 77 | int justLooking; // Set to 1 if program launched with "-l" or if read-only 78 | int mainCrcOk; 79 | int secondCrcOk; 80 | int mainPartsCrcOk; 81 | int secondPartsCrcOk; 82 | int apmFound; // set to 1 if APM detected 83 | int bsdFound; // set to 1 if BSD disklabel detected in MBR 84 | uint32_t sectorAlignment; // Start partitions at multiples of sectorAlignment 85 | int beQuiet; 86 | WhichToUse whichWasUsed; 87 | 88 | int LoadHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector, int *crcOk); 89 | int LoadPartitionTable(const struct GPTHeader & header, DiskIO & disk, uint64_t sector = 0); 90 | int CheckTable(struct GPTHeader *header); 91 | int SaveHeader(struct GPTHeader *header, DiskIO & disk, uint64_t sector); 92 | int SavePartitionTable(DiskIO & disk, uint64_t sector); 93 | public: 94 | // Basic necessary functions.... 95 | GPTData(void); 96 | GPTData(const GPTData &); 97 | GPTData(string deviceFilename); 98 | virtual ~GPTData(void); 99 | GPTData & operator=(const GPTData & orig); 100 | 101 | // Verify (or update) data integrity 102 | int Verify(void); 103 | int CheckGPTSize(void); 104 | int CheckHeaderValidity(void); 105 | int CheckHeaderCRC(struct GPTHeader* header, int warn = 0); 106 | void RecomputeCRCs(void); 107 | void RebuildMainHeader(void); 108 | void RebuildSecondHeader(void); 109 | int VerifyMBR(void) {return protectiveMBR.FindOverlaps();} 110 | int FindHybridMismatches(void); 111 | int FindOverlaps(void); 112 | int FindInsanePartitions(void); 113 | 114 | // Load or save data from/to disk 115 | int SetDisk(const string & deviceFilename); 116 | int SetDisk(const DiskIO & disk); 117 | DiskIO* GetDisk(void) {return &myDisk;} 118 | int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);} 119 | int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);} 120 | void PartitionScan(void); 121 | int LoadPartitions(const string & deviceFilename); 122 | int ForceLoadGPTData(void); 123 | int LoadMainTable(void); 124 | int LoadSecondTableAsMain(void); 125 | int SaveGPTData(int quiet = 0); 126 | int SaveGPTBackup(const string & filename); 127 | int LoadGPTBackup(const string & filename); 128 | int SaveMBR(void); 129 | int DestroyGPT(void); 130 | int DestroyMBR(void); 131 | 132 | // Display data.... 133 | void ShowAPMState(void); 134 | void ShowGPTState(void); 135 | void DisplayGPTData(void); 136 | void DisplayMBRData(void) {protectiveMBR.DisplayMBRData();} 137 | void ShowPartDetails(uint32_t partNum); 138 | 139 | // Convert between GPT and other formats 140 | virtual WhichToUse UseWhichPartitions(void); 141 | void XFormPartitions(void); 142 | int XFormDisklabel(uint32_t partNum); 143 | int XFormDisklabel(BSDData* disklabel); 144 | int OnePartToMBR(uint32_t gptPart, int mbrPart); // add one partition to MBR. Returns 1 if successful 145 | 146 | // Adjust GPT structures WITHOUT user interaction... 147 | int SetGPTSize(uint32_t numEntries, int fillGPTSectors = 1); 148 | int MoveMainTable(uint64_t pteSector); 149 | void BlankPartitions(void); 150 | int DeletePartition(uint32_t partNum); 151 | uint32_t CreatePartition(uint32_t partNum, uint64_t startSector, uint64_t endSector); 152 | void SortGPT(void); 153 | int SwapPartitions(uint32_t partNum1, uint32_t partNum2); 154 | int ClearGPTData(void); 155 | void MoveSecondHeaderToEnd(); 156 | int SetName(uint32_t partNum, const UnicodeString & theName); 157 | void SetDiskGUID(GUIDData newGUID); 158 | int SetPartitionGUID(uint32_t pn, GUIDData theGUID); 159 | void RandomizeGUIDs(void); 160 | int ChangePartType(uint32_t pn, PartType theGUID); 161 | void MakeProtectiveMBR(void) {protectiveMBR.MakeProtectiveMBR();} 162 | void RecomputeCHS(void); 163 | int Align(uint64_t* sector); 164 | void SetProtectiveMBR(BasicMBRData & newMBR) {protectiveMBR = newMBR;} 165 | 166 | // Return data about the GPT structures.... 167 | WhichToUse GetState(void) {return whichWasUsed;} 168 | int GetPartRange(uint32_t* low, uint32_t* high); 169 | int FindFirstFreePart(void); 170 | uint32_t GetNumParts(void) {return mainHeader.numParts;} 171 | uint64_t GetTableSizeInSectors(void) {return (((numParts * GPT_SIZE) / blockSize) + 172 | (((numParts * GPT_SIZE) % blockSize) != 0)); } 173 | uint64_t GetMainHeaderLBA(void) {return mainHeader.currentLBA;} 174 | uint64_t GetSecondHeaderLBA(void) {return secondHeader.currentLBA;} 175 | uint64_t GetMainPartsLBA(void) {return mainHeader.partitionEntriesLBA;} 176 | uint64_t GetSecondPartsLBA(void) {return secondHeader.partitionEntriesLBA;} 177 | uint64_t GetFirstUsableLBA(void) {return mainHeader.firstUsableLBA;} 178 | uint64_t GetLastUsableLBA(void) {return mainHeader.lastUsableLBA;} 179 | uint32_t CountParts(void); 180 | bool ValidPartNum (const uint32_t partNum); 181 | const GPTPart & operator[](uint32_t partNum) const; 182 | const GUIDData & GetDiskGUID(void) const; 183 | uint32_t GetBlockSize(void) {return blockSize;} 184 | 185 | // Find information about free space 186 | uint64_t FindFirstAvailable(uint64_t start = 0); 187 | uint64_t FindFirstUsedLBA(void); 188 | uint64_t FindFirstInLargest(void); 189 | uint64_t FindLastAvailable(); 190 | uint64_t FindLastInFree(uint64_t start); 191 | uint64_t FindFreeBlocks(uint32_t *numSegments, uint64_t *largestSegment); 192 | int IsFree(uint64_t sector, uint32_t *partNum = NULL); 193 | int IsFreePartNum(uint32_t partNum); 194 | int IsUsedPartNum(uint32_t partNum); 195 | 196 | // Change how functions work, or return information on same 197 | void SetAlignment(uint32_t n); 198 | uint32_t ComputeAlignment(void); // Set alignment based on current partitions 199 | uint32_t GetAlignment(void) {return sectorAlignment;} 200 | void JustLooking(int i = 1) {justLooking = i;} 201 | void BeQuiet(int i = 1) {beQuiet = i;} 202 | WhichToUse WhichWasUsed(void) {return whichWasUsed;} 203 | 204 | // Endianness functions 205 | void ReverseHeaderBytes(struct GPTHeader* header); 206 | void ReversePartitionBytes(); // for endianness 207 | 208 | // Attributes functions 209 | int ManageAttributes(int partNum, const string & command, const string & bits); 210 | void ShowAttributes(const uint32_t partNum); 211 | void GetAttribute(const uint32_t partNum, const string& attributeBits); 212 | 213 | }; // class GPTData 214 | 215 | // Function prototypes.... 216 | int SizesOK(void); 217 | 218 | #pragma pack(pop) 219 | 220 | #endif 221 | -------------------------------------------------------------------------------- /gdisk_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # test gdisk and sgdisk by creating a dd file 3 | # Copyright (C) 2011 Guillaume Delacour 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along 16 | # with this program; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # 19 | # 20 | # Requires: coreutils (mktemp, dd) and 64M of disk space in /tmp (temp dd disk) 21 | # 22 | # This script test gdisk commands through the following scenario: 23 | # - Initialize a new GPT table 24 | # - Create a single Linux partition 25 | # - Change name of partition 26 | # - Change type of partition 27 | # - Backup to file the GPT table 28 | # - Delete the single partition 29 | # - Restore from backup file the GPT table 30 | # - Wipe the GPT table 31 | 32 | # TODO 33 | # Try to generate a wrong GPT table to detect problems (test --verify) 34 | # Create MBR partition table with fdisk and migrate it with gdisk 35 | 36 | GDISK_BIN=./gdisk 37 | SGDISK_BIN=./sgdisk 38 | 39 | OPT_CLEAR="o" 40 | OPT_NEW="n" 41 | OPT_CHANGE_NAME="c" 42 | OPT_CHANGE_TYPE="t" 43 | OPT_BACKUP="b" 44 | OPT_DELETE="d" 45 | OPT_ZAP="z" 46 | 47 | # temp disk for testing gdisk 48 | TEMP_DISK=$(mktemp) 49 | # 64 MiB 50 | TEMP_DISK_SIZE=65536 51 | 52 | # the test partition to create 53 | TEST_PART_TYPE="8300" 54 | TEST_PART_DEFAULT_NAME="Linux filesystem" 55 | 56 | # newname for the partition 57 | TEST_PART_NEWNAME=$(tr -dc "[:alpha:]" < /dev/urandom | head -c 8) 58 | # and new type (swap for example) 59 | TEST_PART_NEWTYPE="8200" 60 | 61 | # GPT data backup to filename 62 | GPT_BACKUP_FILENAME=$(mktemp) 63 | 64 | # Pretty print string (Red if FAILED or green if SUCCESS) 65 | # $1: string to pretty print 66 | pretty_print() { 67 | if [ "$1" = "SUCCESS" ] 68 | then 69 | # green 70 | color="32" 71 | else 72 | # red 73 | color="31" 74 | fi 75 | 76 | printf "\033[0;${color}m**$1**\033[m $2\n" 77 | } 78 | 79 | # Verify that the partition exist and has the given type/name 80 | # $1: Partition type to verify (ex.: 8300) 81 | # $2: Partition name to verify (ex.: Linux filesystem) 82 | # $3: Text to print 83 | verify_part() { 84 | partition=$($GDISK_BIN -l $TEMP_DISK | tail -n 1) 85 | echo $partition | grep -q "$1[[:space:]]$2$" 86 | 87 | if [ $? -eq 0 ] 88 | then 89 | pretty_print "SUCCESS" "$3" 90 | else 91 | pretty_print "FAILED" "$3" 92 | exit 1 93 | fi 94 | } 95 | 96 | 97 | ##################################### 98 | # Get GUID of disk 99 | ##################################### 100 | get_diskguid() { 101 | DISK_GUID=$($GDISK_BIN -l $TEMP_DISK | grep "^Disk identifier (GUID):" | awk '{print $4}') 102 | return $DISK_GUID 103 | } 104 | 105 | 106 | ##################################### 107 | # Create a new empty table 108 | ##################################### 109 | create_table() { 110 | case $1 in 111 | gdisk) 112 | $GDISK_BIN $TEMP_DISK << EOF 113 | $OPT_CLEAR 114 | Y 115 | w 116 | Y 117 | EOF 118 | 119 | ret=$? 120 | if [ $ret -ne 0 ] 121 | then 122 | pretty_print "FAILED" "gdisk return $ret when creating partition table" 123 | exit 1 124 | fi 125 | ;; 126 | sgdisk) 127 | $SGDISK_BIN $TEMP_DISK -${OPT_CLEAR} 128 | 129 | ret=$? 130 | if [ $ret -ne 0 ] 131 | then 132 | pretty_print "FAILED" "sgdisk return $ret when creating partition table" 133 | exit 1 134 | fi 135 | ;; 136 | esac 137 | 138 | # verify that the table is empty 139 | # only the columns should appear in the table 140 | verify_part "Code" "Name" "Create new empty GPT table" 141 | echo "" 142 | } 143 | 144 | 145 | 146 | ##################################### 147 | # First create a new partition 148 | ##################################### 149 | create_partition() { 150 | case $1 in 151 | gdisk) 152 | $GDISK_BIN $TEMP_DISK << EOF 153 | $OPT_NEW 154 | 1 155 | 156 | 157 | $TEST_PART_TYPE 158 | w 159 | Y 160 | EOF 161 | ;; 162 | 163 | sgdisk) 164 | $SGDISK_BIN $TEMP_DISK -${OPT_NEW} 1 -${OPT_CHANGE_NAME} 1:"${TEST_PART_DEFAULT_NAME}" -${OPT_CHANGE_TYPE} 1:$TEST_PART_TYPE 165 | ;; 166 | esac 167 | 168 | verify_part "$TEST_PART_TYPE" "$TEST_PART_DEFAULT_NAME" "Create new partition" 169 | echo "" 170 | } 171 | 172 | 173 | ##################################### 174 | # Change name of partition 175 | ##################################### 176 | change_partition_name() { 177 | case $1 in 178 | gdisk) 179 | $GDISK_BIN $TEMP_DISK << EOF 180 | $OPT_CHANGE_NAME 181 | $TEST_PART_NEWNAME 182 | w 183 | Y 184 | EOF 185 | ;; 186 | 187 | sgdisk) 188 | $SGDISK_BIN $TEMP_DISK -${OPT_CHANGE_NAME} 1:${TEST_PART_NEWNAME} 189 | ;; 190 | esac 191 | 192 | verify_part "$TEST_PART_TYPE" "$TEST_PART_NEWNAME" "Change partition 1 name ($TEST_PART_DEFAULT_NAME -> $TEST_PART_NEWNAME)" 193 | echo "" 194 | } 195 | 196 | 197 | change_partition_type() { 198 | ##################################### 199 | # Change type of partition 200 | ##################################### 201 | case $1 in 202 | gdisk) 203 | $GDISK_BIN $TEMP_DISK << EOF 204 | $OPT_CHANGE_TYPE 205 | $TEST_PART_NEWTYPE 206 | w 207 | Y 208 | EOF 209 | ;; 210 | 211 | sgdisk) 212 | $SGDISK_BIN $TEMP_DISK -${OPT_CHANGE_TYPE} 1:${TEST_PART_NEWTYPE} 213 | ;; 214 | esac 215 | 216 | verify_part "$TEST_PART_NEWTYPE" "$TEST_PART_NEWNAME" "Change partition 1 type ($TEST_PART_TYPE -> $TEST_PART_NEWTYPE)" 217 | echo "" 218 | } 219 | 220 | 221 | ##################################### 222 | # Backup GPT data to file 223 | ##################################### 224 | backup_table() { 225 | case $1 in 226 | gdisk) 227 | $GDISK_BIN $TEMP_DISK << EOF 228 | $OPT_BACKUP 229 | $GPT_BACKUP_FILENAME 230 | q 231 | EOF 232 | echo "" 233 | ;; 234 | 235 | sgdisk) 236 | $SGDISK_BIN $TEMP_DISK -${OPT_BACKUP} ${GPT_BACKUP_FILENAME} 237 | ;; 238 | esac 239 | 240 | # if exist and not empty; we will test it after 241 | if [ -s $GPT_BACKUP_FILENAME ] 242 | then 243 | pretty_print "SUCCESS" "GPT data backuped sucessfully" 244 | else 245 | pretty_print "FAILED" "Unable to create GPT backup file !" 246 | exit 1 247 | fi 248 | } 249 | 250 | 251 | ##################################### 252 | # Now, we can delete the partition 253 | ##################################### 254 | delete_partition() { 255 | case $1 in 256 | gdisk) 257 | $GDISK_BIN $TEMP_DISK << EOF 258 | $OPT_DELETE 259 | w 260 | Y 261 | EOF 262 | ;; 263 | 264 | sgdisk) 265 | $SGDISK_BIN $TEMP_DISK -${OPT_DELETE} 1 266 | ;; 267 | esac 268 | 269 | # verify that the table is empty (just one partition): 270 | # only the columns should appear in the table 271 | verify_part "Code" "Name" "Delete partition 1" 272 | echo "" 273 | } 274 | 275 | 276 | ##################################### 277 | # Restore GPT table 278 | ##################################### 279 | restore_table() { 280 | $GDISK_BIN $TEMP_DISK << EOF 281 | r 282 | r 283 | l 284 | $GPT_BACKUP_FILENAME 285 | w 286 | Y 287 | EOF 288 | 289 | verify_part "$TEST_PART_NEWTYPE" "$TEST_PART_NEWNAME" "Restore the GPT backup" 290 | echo "" 291 | } 292 | 293 | 294 | ##################################### 295 | # Change UID of disk 296 | ##################################### 297 | change_disk_uid() { 298 | 299 | # get UID of disk before changing it 300 | GUID=get_diskguid 301 | 302 | 303 | case $1 in 304 | gdisk) 305 | $GDISK_BIN $TEMP_DISK << EOF 306 | x 307 | g 308 | R 309 | w 310 | Y 311 | EOF 312 | ;; 313 | 314 | sgdisk) 315 | $SGDISK_BIN $TEMP_DISK -U=R 316 | ;; 317 | esac 318 | 319 | # get GUID after change 320 | NEW_DISK_GUID=get_diskguid 321 | 322 | # compare them 323 | if [ "$DISK_GUID" != "$NEW_DISK_GUID" ] 324 | then 325 | pretty_print "SUCCESS" "GUID of disk has been sucessfully changed" 326 | else 327 | pretty_print "FAILED" "GUID of disk is the same as the previous one" 328 | exit 1 329 | fi 330 | } 331 | 332 | ##################################### 333 | # Wipe GPT table 334 | ##################################### 335 | wipe_table() { 336 | case $1 in 337 | gdisk) 338 | $GDISK_BIN $TEMP_DISK << EOF 339 | x 340 | $OPT_ZAP 341 | Y 342 | Y 343 | EOF 344 | ;; 345 | 346 | sgdisk) 347 | $SGDISK_BIN $TEMP_DISK -${OPT_ZAP} 348 | esac 349 | 350 | # verify that the table is empty (just one partition): 351 | # only the columns should appear in the table 352 | verify_part "Code" "Name" "Wipe GPT table" 353 | echo "" 354 | } 355 | 356 | ##################################### 357 | # Test stdin EOF 358 | ##################################### 359 | eof_stdin() { 360 | $SGDISK_BIN $TEMP_DISK << EOF 361 | ^D 362 | EOF 363 | pretty_print "SUCCESS" "EOF successfully exit gdisk" 364 | } 365 | 366 | ################################### 367 | # Main 368 | ################################### 369 | 370 | # create a file to simulate a real device 371 | dd if=/dev/zero of=$TEMP_DISK bs=1024 count=$TEMP_DISK_SIZE > /dev/null 2>&1 372 | 373 | if [ -s $TEMP_DISK ] 374 | then 375 | pretty_print "SUCCESS" "Temp disk sucessfully created" 376 | else 377 | pretty_print "FAILED" "Unable to create temp disk !" 378 | exit 1 379 | fi 380 | 381 | # test gdisk and sgdisk 382 | for binary in gdisk sgdisk 383 | do 384 | echo "" 385 | printf "\033[0;34m**Testing $binary binary**\033[m\n" 386 | echo "" 387 | create_table "$binary" 388 | create_partition "$binary" 389 | change_partition_name "$binary" 390 | change_partition_type "$binary" 391 | backup_table "$binary" 392 | delete_partition "$binary" 393 | restore_table # only with gdisk 394 | change_disk_uid "$binary" 395 | wipe_table "$binary" 396 | eof_stdin # only with gdisk 397 | done 398 | 399 | # remove temp files 400 | rm -f $TEMP_DISK $GPT_BACKUP_FILENAME 401 | 402 | exit 0 403 | -------------------------------------------------------------------------------- /fixparts.8: -------------------------------------------------------------------------------- 1 | .\" Copyright 2011-2018 Roderick W. Smith (rodsmith@rodsbooks.com) 2 | .\" May be distributed under the GNU General Public License 3 | .TH "FIXPARTS" "8" "1.0.4" "Roderick W. Smith" "FixParts Manual" 4 | .SH "NAME" 5 | fixparts \- MBR partition table repair utility 6 | .SH "SYNOPSIS" 7 | .BI "fixparts " 8 | .I device 9 | 10 | .SH "DESCRIPTION" 11 | 12 | FixParts (aka \fBfixparts\fR) is a text\-mode menu\-driven program for 13 | repairing certain types of problems with Master Boot Record (MBR) partition 14 | tables. The program has three design goals, although a few additional 15 | features are supported, as well: 16 | 17 | .TP 18 | .B * 19 | It can remove stray GUID Partition Table (GPT) data, which can be left 20 | behind on a disk that was once used as a GPT disk but then incompletely 21 | converted to the more common (as of 2011) MBR form. 22 | 23 | .TP 24 | .B * 25 | It can repair mis-sized extended partitions \-\- either partitions that 26 | extend beyond the physical end of the disk or that overlap with nearby 27 | primary partitions. FixParts is designed in such a way that this type of 28 | repair occurs automatically, so if it's the only problem with your disk, 29 | you can launch the program and then immediately save the partition table, 30 | making no manual changes, and the program will fix the problem. 31 | 32 | .TP 33 | .B * 34 | You can change primary partitions into logical partitions or vice\-versa, 35 | within constraints imposed by the MBR data structures. 36 | 37 | .PP 38 | 39 | Additional features include the ability to change partition type codes or 40 | boot/active flags, to delete partitions, and to recompute CHS values. With 41 | the possible exception of recomputing CHS values, these secondary features 42 | are better performed with \fBfdisk\fR, because \fBfixparts\fR' design means 43 | that it's likely to alter partition numbering even when such changes are 44 | not requested. 45 | 46 | The \fBfixparts\fR program employs a user interface similar to that of 47 | Linux's \fBfdisk\fR, but \fBfixparts\fR is much more specialized. Most 48 | importantly, you can't create new partitions with \fBfixparts\fR, although 49 | you can change primary/logical assignment. 50 | 51 | In the MBR scheme, partitions come in three varieties: 52 | 53 | .TP 54 | .B primary 55 | These partitions are defined in the first sector of the hard disk and 56 | are limited in number to four. Some OSes, such as Windows and FreeBSD, must 57 | boot from a primary partition. 58 | 59 | .TP 60 | .B extended 61 | Extended partitions are specialized primary partitions. They serve as 62 | holding areas for logical partitions. 63 | 64 | .TP 65 | .B logical 66 | A disk can contain an arbitrary number of logical partitions 67 | (\fBfixparts\fR, however, imposes a limit of 124 logical partitions). All 68 | the logical partitions reside inside a single extended partition, and are 69 | defined using a linked-list data structure. This fact means that every 70 | logical partition must be preceded by at least one sector of unallocated space 71 | to hold its defining data structure (an Extended Boot Record, or EBR). 72 | 73 | .PP 74 | 75 | These distinctions mean that primary and logical partitions cannot be 76 | arbitrarily interspersed. A disk can contain one to three primary 77 | partitions, a block of one or more logical partitions, and one to three 78 | more primary partitions (for a total of three primary partitions, not 79 | counting the extended partition). Primary partitions may not be sandwiched 80 | between logical partitions, since this would mean placing a primary 81 | partition within an extended partition (which is just a specific type of 82 | primary partition). 83 | 84 | Unlike most disk utilities, \fBfixparts\fR' user interface ignores extended 85 | partitions. Internally, the program discards the information on the 86 | original extended partition and, when you tell it to save its changes, it 87 | generates a new extended partition to contain the then-defined logical 88 | partitions. This is done because most of the repairs and manipulations the 89 | tool performs require generating a fresh extended partition, so keeping the 90 | original in the user interface would only be a complication. 91 | 92 | Another unusual feature of \fBfixparts\fR' user interface is that partition 93 | numbers do not necessarily correlate with primary/logical status. In most 94 | utilities, partitions 1\-4 correspond to primary partitions, whereas 95 | partitions 5 and up are logical partitions. In \fBfixparts\fR, any partition 96 | number may be assigned primary or logical status, so long as the rules for 97 | layout described earlier are obeyed. When the partition table is saved, 98 | partitions will be assigned appropriately and then tools such as the Linux 99 | kernel and \fBfdisk\fR will give them conventional numbers. 100 | 101 | When it first starts, \fBfixparts\fR performs a scan for GPT data. If the 102 | disk looks like a conventional GPT disk, \fBfixparts\fR refuses to run. If 103 | the disk appears to be a conventional MBR disk but GPT signatures are 104 | present in the GPT primary or secondary header areas, \fBfixparts\fR 105 | offers to delete this extraneous data. If you tell it to do so, the program 106 | immediately wipes the GPT header or headers. (If only one header was found, 107 | only that one header will be erased, to minimize the risk of damaging a 108 | boot loader or other data that might have overwritten just one of the GPT 109 | headers.) 110 | 111 | With the exception of optionally erasing leftover GPT data when it first 112 | starts, \fBfixparts\fR keeps all changes in memory until the user writes 113 | changes with the \fBw\fR command. Thus, you can adjust your partitions in 114 | the user interface and abort those changes by typing \fBq\fR to quit 115 | without saving changes. 116 | 117 | .SH "OPTIONS" 118 | 119 | The \fBfixparts\fR utility supports no command\-line options, except for 120 | specification of the target device. 121 | 122 | Most interactions with \fBfixparts\fR occur with its interactive text\-mode 123 | menu. Specific functions are: 124 | 125 | .TP 126 | .B a 127 | Toggle the active/boot flag. This flag is required by some boot loaders and 128 | OSes. 129 | 130 | 131 | .TP 132 | .B c 133 | Recompute the cylinder/head/sector (CHS) values for all partitions. CHS 134 | addressing mode is largely obsolete, but some OSes and utilities complain 135 | if they don't like the CHS values. Note that \fBfixparts\fR' CHS values are 136 | likely to be incorrect on disks smaller than about 8 GiB except on Linux. 137 | 138 | .TP 139 | .B l 140 | Change a partition's status to logical. This option will only work if the 141 | current partition layout supports such a change. Note that if changing a 142 | partition's status in this way is not currently possible, making some other 143 | change may make it possible. For instance, omitting a partition that 144 | precedes the target partition may enable converting a partition to logical 145 | form if there had been no free sectors between the two partitions. 146 | 147 | .TP 148 | .B o 149 | Omit a partition. Once omitted, the partition will still appear in the 150 | \fBfixparts\fR partition list, but it will be flagged as omitted. You can 151 | subsequently convert it to primary or logical form with the \fBr\fR or 152 | \fBl\fR commands, respectively. When you save your changes with \fBw\fR, 153 | though, the partition will be lost. 154 | 155 | .TP 156 | .B p 157 | Display basic partition summary data. This includes partition's number, the 158 | boot/active flag's status, starting and ending sector numbers, 159 | primary/logical/omitted status, whether or not the partition may be 160 | converted to logical form, and the partition's MBR types code. 161 | 162 | .TP 163 | .B q 164 | Quit from the program \fIwithout saving your changes\fR. 165 | Use this option if you just wanted to view information or if you make a 166 | mistake and want to back out of all your changes. 167 | 168 | .TP 169 | .B r 170 | Change a partition's status to primary. This option will only work if the 171 | current partition layout supports such a change. Note that every partition 172 | can theoretically become a primary partition, although in some 173 | configurations, making this change will require omitting some partitions. 174 | If \fBfixparts\fR refuses to allow changing a partition to primary, you may 175 | need to convert other partitions to logical form or omit them entirely. 176 | 177 | .TP 178 | .B s 179 | Sort partition entries. This option orders partitions in the display to 180 | match their on-disk positions, which can make understanding the disk layout 181 | easier in some cases. This option has no effect on the ultimate ordering of 182 | logical partitions, which are sorted before being saved. The order of 183 | primary partitions in the final saved partition table may be affected by 184 | this option. In both cases, as already noted, the partition numbers 185 | displayed by \fBfixparts\fR may not be the same as those used by the kernel 186 | or displayed by other partitioning tools. 187 | 188 | .TP 189 | .B t 190 | Change a partition's type code. You enter the type code using a one\-byte 191 | hexadecimal number. 192 | 193 | .TP 194 | .B w 195 | Write data. Use this command to save your changes and exit from the program. 196 | 197 | .TP 198 | .B ? 199 | Print the menu. Type this command (or any other unrecognized command) to 200 | see a summary of available options. 201 | 202 | .PP 203 | 204 | .SH "BUGS" 205 | Known bugs and limitations include: 206 | 207 | .TP 208 | .B * 209 | The program compiles correctly only on Linux, FreeBSD, Mac OS X, and Windows. 210 | Linux versions for x86\-64 (64\-bit), x86 (32\-bit), and PowerPC (32\-bit) have been 211 | tested, with the x86\-64 version having seen the most testing. Under FreeBSD, 212 | 32\-bit (x86) and 64\-bit (x86\-64) versions have been tested. Only 32\-bit 213 | versions for Mac OS X and Windows have been tested. 214 | 215 | .TP 216 | .B * 217 | The FreeBSD version of the program can't write changes to the partition 218 | table to a disk when existing partitions on that disk are mounted. (The 219 | same problem exists with many other FreeBSD utilities, such as 220 | \fBgpt\fR, \fBfdisk\fR, and \fBdd\fR.) This limitation can be overcome 221 | by typing \fBsysctl kern.geom.debugflags=16\fR at a shell prompt. 222 | 223 | .TP 224 | .B * 225 | The program can load only up to 128 partitions (4 primary partitions and 226 | 124 logical partitions). This limit can be raised by changing the 227 | \fI#define MAX_MBR_PARTS\fR line in the \fIbasicmbr.h\fR source code file 228 | and recompiling. 229 | 230 | .TP 231 | .B * 232 | The program can read partitions only if the disk has correct LBA partition 233 | descriptors. These descriptors should be present on any disk over 8 GiB in 234 | size or on smaller disks partitioned with any but very ancient software. 235 | 236 | .TP 237 | .B * 238 | The program makes no effort to preserve partition numbers. This can have 239 | consequences for boot loaders and for mounting filesystems via 240 | \fB/etc/fstab\fR. It may be necessary to edit configuration files or even 241 | to re-install your boot loader. 242 | 243 | .TP 244 | .B * 245 | 246 | The program may change the order of partitions in the partition table. 247 | 248 | .PP 249 | 250 | .SH "AUTHORS" 251 | Primary author: Roderick W. Smith (rodsmith@rodsbooks.com) 252 | 253 | Contributors: 254 | 255 | * Yves Blusseau (1otnwmz02@sneakemail.com) 256 | 257 | * David Hubbard (david.c.hubbard@gmail.com) 258 | 259 | * Justin Maggard (justin.maggard@netgear.com) 260 | 261 | * Dwight Schauer (dschauer@gmail.com) 262 | 263 | * Florian Zumbiehl (florz@florz.de) 264 | 265 | 266 | .SH "SEE ALSO" 267 | .BR cfdisk (8), 268 | .BR cgdisk (8), 269 | .BR fdisk (8), 270 | .BR mkfs (8), 271 | .BR parted (8), 272 | .BR sfdisk (8), 273 | .BR gdisk (8), 274 | .BR sgdisk (8). 275 | 276 | \fIhttp://en.wikipedia.org/wiki/Master_boot_record\fR 277 | 278 | \fIhttp://www.rodsbooks.com/fixparts/\fR 279 | 280 | .SH "AVAILABILITY" 281 | The \fBfixparts\fR command is part of the \fIGPT fdisk\fR package and is 282 | available from Rod Smith. 283 | -------------------------------------------------------------------------------- /diskio-windows.cc: -------------------------------------------------------------------------------- 1 | // 2 | // C++ Interface: diskio (Windows-specific components) 3 | // 4 | // Description: Class to handle low-level disk I/O for GPT fdisk 5 | // 6 | // 7 | // Author: Rod Smith , (C) 2009 8 | // 9 | // Copyright: See COPYING file that comes with this distribution 10 | // 11 | // 12 | // This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed 13 | // under the terms of the GNU GPL version 2, as detailed in the COPYING file. 14 | 15 | #define __STDC_LIMIT_MACROS 16 | #define __STDC_CONSTANT_MACROS 17 | 18 | #include 19 | #include 20 | #define fstat64 fstat 21 | #define stat64 stat 22 | #define S_IRGRP 0 23 | #define S_IROTH 0 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "support.h" 33 | #include "diskio.h" 34 | 35 | using namespace std; 36 | 37 | // Returns the official Windows name for a shortened version of same. 38 | void DiskIO::MakeRealName(void) { 39 | size_t colonPos; 40 | 41 | colonPos = userFilename.find(':', 0); 42 | if ((colonPos != string::npos) && (colonPos <= 3)) { 43 | realFilename = "\\\\.\\physicaldrive"; 44 | realFilename += userFilename.substr(0, colonPos); 45 | } else { 46 | realFilename = userFilename; 47 | } // if/else 48 | } // DiskIO::MakeRealName() 49 | 50 | // Open the currently on-record file for reading 51 | int DiskIO::OpenForRead(void) { 52 | int shouldOpen = 1; 53 | 54 | if (isOpen) { // file is already open 55 | if (openForWrite) { 56 | Close(); 57 | } else { 58 | shouldOpen = 0; 59 | } // if/else 60 | } // if 61 | 62 | if (shouldOpen) { 63 | fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 64 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 65 | if (fd == INVALID_HANDLE_VALUE) { 66 | CloseHandle(fd); 67 | cerr << "Problem opening " << realFilename << " for reading!\n"; 68 | realFilename = ""; 69 | userFilename = ""; 70 | isOpen = 0; 71 | openForWrite = 0; 72 | } else { 73 | isOpen = 1; 74 | openForWrite = 0; 75 | } // if/else 76 | } // if 77 | 78 | return isOpen; 79 | } // DiskIO::OpenForRead(void) 80 | 81 | // An extended file-open function. This includes some system-specific checks. 82 | // Returns 1 if the file is open, 0 otherwise.... 83 | int DiskIO::OpenForWrite(void) { 84 | if ((isOpen) && (openForWrite)) 85 | return 1; 86 | 87 | // Close the disk, in case it's already open for reading only.... 88 | Close(); 89 | 90 | // try to open the device; may fail.... 91 | fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE, 92 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 93 | FILE_ATTRIBUTE_NORMAL, NULL); 94 | // Preceding call can fail when creating backup files; if so, try 95 | // again with different option... 96 | if (fd == INVALID_HANDLE_VALUE) { 97 | CloseHandle(fd); 98 | fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE, 99 | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 100 | FILE_ATTRIBUTE_NORMAL, NULL); 101 | } // if 102 | if (fd == INVALID_HANDLE_VALUE) { 103 | CloseHandle(fd); 104 | isOpen = 0; 105 | openForWrite = 0; 106 | errno = GetLastError(); 107 | } else { 108 | isOpen = 1; 109 | openForWrite = 1; 110 | } // if/else 111 | return isOpen; 112 | } // DiskIO::OpenForWrite(void) 113 | 114 | // Close the disk device. Note that this does NOT erase the stored filenames, 115 | // so the file can be re-opened without specifying the filename. 116 | void DiskIO::Close(void) { 117 | if (isOpen) 118 | CloseHandle(fd); 119 | isOpen = 0; 120 | openForWrite = 0; 121 | } // DiskIO::Close() 122 | 123 | // Returns block size of device pointed to by fd file descriptor. If the ioctl 124 | // returns an error condition, assume it's a disk file and return a value of 125 | // SECTOR_SIZE (512). If the disk can't be opened at all, return a value of 0. 126 | int DiskIO::GetBlockSize(void) { 127 | DWORD blockSize = 0, retBytes; 128 | DISK_GEOMETRY_EX geom; 129 | 130 | // If disk isn't open, try to open it.... 131 | if (!isOpen) { 132 | OpenForRead(); 133 | } // if 134 | 135 | if (isOpen) { 136 | if (DeviceIoControl(fd, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, 137 | &geom, sizeof(geom), &retBytes, NULL)) { 138 | blockSize = geom.Geometry.BytesPerSector; 139 | } else { // was probably an ordinary file; set default value.... 140 | blockSize = SECTOR_SIZE; 141 | } // if/else 142 | } // if (isOpen) 143 | 144 | return (blockSize); 145 | } // DiskIO::GetBlockSize() 146 | 147 | // In theory, returns the physical block size. In practice, this is only 148 | // supported in Linux, as of yet. 149 | // TODO: Get this working in Windows. 150 | int DiskIO::GetPhysBlockSize(void) { 151 | return 0; 152 | } // DiskIO::GetPhysBlockSize() 153 | 154 | // Returns the number of heads, according to the kernel, or 255 if the 155 | // correct value can't be determined. 156 | uint32_t DiskIO::GetNumHeads(void) { 157 | return UINT32_C(255); 158 | } // DiskIO::GetNumHeads(); 159 | 160 | // Returns the number of sectors per track, according to the kernel, or 63 161 | // if the correct value can't be determined. 162 | uint32_t DiskIO::GetNumSecsPerTrack(void) { 163 | return UINT32_C(63); 164 | } // DiskIO::GetNumSecsPerTrack() 165 | 166 | // Resync disk caches so the OS uses the new partition table. This code varies 167 | // a lot from one OS to another. 168 | // Returns 1 on success, 0 if the kernel continues to use the old partition table. 169 | int DiskIO::DiskSync(void) { 170 | DWORD i; 171 | GET_LENGTH_INFORMATION buf; 172 | int retval = 0; 173 | 174 | // If disk isn't open, try to open it.... 175 | if (!openForWrite) { 176 | OpenForWrite(); 177 | } // if 178 | 179 | if (isOpen) { 180 | if (DeviceIoControl(fd, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, &buf, sizeof(buf), &i, NULL) == 0) { 181 | cout << "Disk synchronization failed! The computer may use the old partition table\n" 182 | << "until you reboot or remove and re-insert the disk!\n"; 183 | } else { 184 | cout << "Disk synchronization succeeded! The computer should now use the new\n" 185 | << "partition table.\n"; 186 | retval = 1; 187 | } // if/else 188 | } else { 189 | cout << "Unable to open the disk for synchronization operation! The computer will\n" 190 | << "continue to use the old partition table until you reboot or remove and\n" 191 | << "re-insert the disk!\n"; 192 | } // if (isOpen) 193 | return retval; 194 | } // DiskIO::DiskSync() 195 | 196 | // Seek to the specified sector. Returns 1 on success, 0 on failure. 197 | int DiskIO::Seek(uint64_t sector) { 198 | int retval = 1; 199 | LARGE_INTEGER seekTo; 200 | 201 | // If disk isn't open, try to open it.... 202 | if (!isOpen) { 203 | retval = OpenForRead(); 204 | } // if 205 | 206 | if (isOpen) { 207 | seekTo.QuadPart = sector * (uint64_t) GetBlockSize(); 208 | retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN); 209 | if (retval == 0) { 210 | errno = GetLastError(); 211 | cerr << "Error when seeking to " << seekTo.QuadPart << "! Error is " << errno << "\n"; 212 | retval = 0; 213 | } // if 214 | } // if 215 | return retval; 216 | } // DiskIO::Seek() 217 | 218 | // A variant on the standard read() function. Done to work around 219 | // limitations in FreeBSD concerning the matching of the sector 220 | // size with the number of bytes read. 221 | // Returns the number of bytes read into buffer. 222 | int DiskIO::Read(void* buffer, int numBytes) { 223 | int blockSize = 512, i, numBlocks; 224 | char* tempSpace; 225 | DWORD retval = 0; 226 | 227 | // If disk isn't open, try to open it.... 228 | if (!isOpen) { 229 | OpenForRead(); 230 | } // if 231 | 232 | if (isOpen) { 233 | // Compute required space and allocate memory 234 | blockSize = GetBlockSize(); 235 | if (numBytes <= blockSize) { 236 | numBlocks = 1; 237 | tempSpace = new char [blockSize]; 238 | } else { 239 | numBlocks = numBytes / blockSize; 240 | if ((numBytes % blockSize) != 0) 241 | numBlocks++; 242 | tempSpace = new char [numBlocks * blockSize]; 243 | } // if/else 244 | if (tempSpace == NULL) { 245 | cerr << "Unable to allocate memory in DiskIO::Read()! Terminating!\n"; 246 | exit(1); 247 | } // if 248 | 249 | // Read the data into temporary space, then copy it to buffer 250 | ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL); 251 | for (i = 0; i < numBytes; i++) { 252 | ((char*) buffer)[i] = tempSpace[i]; 253 | } // for 254 | 255 | // Adjust the return value, if necessary.... 256 | if (((numBlocks * blockSize) != numBytes) && (retval > 0)) 257 | retval = numBytes; 258 | 259 | delete[] tempSpace; 260 | } // if (isOpen) 261 | return retval; 262 | } // DiskIO::Read() 263 | 264 | // A variant on the standard write() function. 265 | // Returns the number of bytes written. 266 | int DiskIO::Write(void* buffer, int numBytes) { 267 | int blockSize = 512, i, numBlocks, retval = 0; 268 | char* tempSpace; 269 | DWORD numWritten; 270 | 271 | // If disk isn't open, try to open it.... 272 | if ((!isOpen) || (!openForWrite)) { 273 | OpenForWrite(); 274 | } // if 275 | 276 | if (isOpen) { 277 | // Compute required space and allocate memory 278 | blockSize = GetBlockSize(); 279 | if (numBytes <= blockSize) { 280 | numBlocks = 1; 281 | tempSpace = new char [blockSize]; 282 | } else { 283 | numBlocks = numBytes / blockSize; 284 | if ((numBytes % blockSize) != 0) numBlocks++; 285 | tempSpace = new char [numBlocks * blockSize]; 286 | } // if/else 287 | if (tempSpace == NULL) { 288 | cerr << "Unable to allocate memory in DiskIO::Write()! Terminating!\n"; 289 | exit(1); 290 | } // if 291 | 292 | // Copy the data to my own buffer, then write it 293 | for (i = 0; i < numBytes; i++) { 294 | tempSpace[i] = ((char*) buffer)[i]; 295 | } // for 296 | for (i = numBytes; i < numBlocks * blockSize; i++) { 297 | tempSpace[i] = 0; 298 | } // for 299 | WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL); 300 | retval = (int) numWritten; 301 | 302 | // Adjust the return value, if necessary.... 303 | if (((numBlocks * blockSize) != numBytes) && (retval > 0)) 304 | retval = numBytes; 305 | 306 | delete[] tempSpace; 307 | } // if (isOpen) 308 | return retval; 309 | } // DiskIO:Write() 310 | 311 | // Returns the size of the disk in blocks. 312 | uint64_t DiskIO::DiskSize(int *err) { 313 | uint64_t sectors = 0; // size in sectors 314 | DWORD bytes, moreBytes; // low- and high-order bytes of file size 315 | GET_LENGTH_INFORMATION buf; 316 | DWORD i; 317 | 318 | // If disk isn't open, try to open it.... 319 | if (!isOpen) { 320 | OpenForRead(); 321 | } // if 322 | 323 | if (isOpen) { 324 | // Note to self: I recall testing a simplified version of 325 | // this code, similar to what's in the __APPLE__ block, 326 | // on Linux, but I had some problems. IIRC, it ran OK on 32-bit 327 | // systems but not on 64-bit. Keep this in mind in case of 328 | // 32/64-bit issues on MacOS.... 329 | if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) { 330 | sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize(); 331 | *err = 0; 332 | } else { // doesn't seem to be a disk device; assume it's an image file.... 333 | bytes = GetFileSize(fd, &moreBytes); 334 | sectors = ((uint64_t) bytes + ((uint64_t) moreBytes) * UINT32_MAX) / GetBlockSize(); 335 | *err = 0; 336 | } // if 337 | } else { 338 | *err = -1; 339 | sectors = 0; 340 | } // if/else (isOpen) 341 | 342 | return sectors; 343 | } // DiskIO::DiskSize() 344 | -------------------------------------------------------------------------------- /bsd.cc: -------------------------------------------------------------------------------- 1 | /* bsd.cc -- Functions for loading and manipulating legacy BSD disklabel 2 | data. */ 3 | 4 | /* By Rod Smith, initial coding August, 2009 */ 5 | 6 | /* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed 7 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 | 9 | #define __STDC_LIMIT_MACROS 10 | #ifndef __STDC_CONSTANT_MACROS 11 | #define __STDC_CONSTANT_MACROS 12 | #endif 13 | 14 | #include 15 | //#include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "support.h" 24 | #include "bsd.h" 25 | 26 | using namespace std; 27 | 28 | 29 | BSDData::BSDData(void) { 30 | state = unknown; 31 | signature = UINT32_C(0); 32 | signature2 = UINT32_C(0); 33 | sectorSize = 512; 34 | numParts = 0; 35 | labelFirstLBA = 0; 36 | labelLastLBA = 0; 37 | labelStart = LABEL_OFFSET1; // assume raw disk format 38 | partitions = NULL; 39 | } // default constructor 40 | 41 | BSDData::~BSDData(void) { 42 | delete[] partitions; 43 | } // destructor 44 | 45 | // Read BSD disklabel data from the specified device filename. This function 46 | // just opens the device file and then calls an overloaded function to do 47 | // the bulk of the work. Returns 1 on success, 0 on failure. 48 | int BSDData::ReadBSDData(const string & device, uint64_t startSector, uint64_t endSector) { 49 | int allOK = 1; 50 | DiskIO myDisk; 51 | 52 | if (device != "") { 53 | if (myDisk.OpenForRead(device)) { 54 | allOK = ReadBSDData(&myDisk, startSector, endSector); 55 | } else { 56 | allOK = 0; 57 | } // if/else 58 | 59 | myDisk.Close(); 60 | } else { 61 | allOK = 0; 62 | } // if/else 63 | return allOK; 64 | } // BSDData::ReadBSDData() (device filename version) 65 | 66 | // Load the BSD disklabel data from an already-opened disk 67 | // file, starting with the specified sector number. 68 | int BSDData::ReadBSDData(DiskIO *theDisk, uint64_t startSector, uint64_t endSector) { 69 | int allOK = 1; 70 | int i, foundSig = 0, bigEnd = 0; 71 | int relative = 0; // assume absolute partition sector numbering 72 | uint8_t buffer[4096]; // I/O buffer 73 | uint32_t realSig; 74 | uint32_t* temp32; 75 | uint16_t* temp16; 76 | BSDRecord* tempRecords; 77 | int offset[NUM_OFFSETS] = { LABEL_OFFSET1, LABEL_OFFSET2 }; 78 | 79 | labelFirstLBA = startSector; 80 | labelLastLBA = endSector; 81 | offset[1] = theDisk->GetBlockSize(); 82 | 83 | // Read 4096 bytes (eight 512-byte sectors or equivalent) 84 | // into memory; we'll extract data from this buffer. 85 | // (Done to work around FreeBSD limitation on size of reads 86 | // from block devices.) 87 | allOK = theDisk->Seek(startSector); 88 | if (allOK) allOK = theDisk->Read(buffer, 4096); 89 | 90 | // Do some strangeness to support big-endian architectures... 91 | bigEnd = (IsLittleEndian() == 0); 92 | realSig = BSD_SIGNATURE; 93 | if (bigEnd && allOK) 94 | ReverseBytes(&realSig, 4); 95 | 96 | // Look for the signature at any of two locations. 97 | // Note that the signature is repeated at both the original 98 | // offset and 132 bytes later, so we need two checks.... 99 | if (allOK) { 100 | i = 0; 101 | do { 102 | temp32 = (uint32_t*) &buffer[offset[i]]; 103 | signature = *temp32; 104 | if (signature == realSig) { // found first, look for second 105 | temp32 = (uint32_t*) &buffer[offset[i] + 132]; 106 | signature2 = *temp32; 107 | if (signature2 == realSig) { 108 | foundSig = 1; 109 | labelStart = offset[i]; 110 | } // if found signature 111 | } // if/else 112 | i++; 113 | } while ((!foundSig) && (i < NUM_OFFSETS)); 114 | allOK = foundSig; 115 | } // if 116 | 117 | // Load partition metadata from the buffer.... 118 | if (allOK) { 119 | temp32 = (uint32_t*) &buffer[labelStart + 40]; 120 | sectorSize = *temp32; 121 | temp16 = (uint16_t*) &buffer[labelStart + 138]; 122 | numParts = *temp16; 123 | } // if 124 | 125 | // Make it big-endian-aware.... 126 | if ((IsLittleEndian() == 0) && allOK) 127 | ReverseMetaBytes(); 128 | 129 | // Check validity of the data and flag it appropriately.... 130 | if (foundSig && (numParts <= MAX_BSD_PARTS) && allOK) { 131 | state = bsd; 132 | } else { 133 | state = bsd_invalid; 134 | } // if/else 135 | 136 | // If the state is good, go ahead and load the main partition data.... 137 | if (state == bsd) { 138 | partitions = new struct BSDRecord[numParts * sizeof(struct BSDRecord)]; 139 | if (partitions == NULL) { 140 | cerr << "Unable to allocate memory in BSDData::ReadBSDData()! Terminating!\n"; 141 | exit(1); 142 | } // if 143 | for (i = 0; i < numParts; i++) { 144 | // Once again, we use the buffer, but index it using a BSDRecord 145 | // pointer (dangerous, but effective).... 146 | tempRecords = (BSDRecord*) &buffer[labelStart + 148]; 147 | partitions[i].lengthLBA = tempRecords[i].lengthLBA; 148 | partitions[i].firstLBA = tempRecords[i].firstLBA; 149 | partitions[i].fsType = tempRecords[i].fsType; 150 | if (bigEnd) { // reverse data (fsType is a single byte) 151 | ReverseBytes(&partitions[i].lengthLBA, 4); 152 | ReverseBytes(&partitions[i].firstLBA, 4); 153 | } // if big-endian 154 | // Check for signs of relative sector numbering: A "0" first sector 155 | // number on a partition with a non-zero length -- but ONLY if the 156 | // length is less than the disk size, since NetBSD has a habit of 157 | // creating a disk-sized partition within a carrier MBR partition 158 | // that's too small to house it, and this throws off everything.... 159 | if ((partitions[i].firstLBA == 0) && (partitions[i].lengthLBA > 0) 160 | && (partitions[i].lengthLBA < labelLastLBA)) 161 | relative = 1; 162 | } // for 163 | // Some disklabels use sector numbers relative to the enclosing partition's 164 | // start, others use absolute sector numbers. If relative numbering was 165 | // detected above, apply a correction to all partition start sectors.... 166 | if (relative) { 167 | for (i = 0; i < numParts; i++) { 168 | partitions[i].firstLBA += (uint32_t) startSector; 169 | } // for 170 | } // if 171 | } // if signatures OK 172 | // DisplayBSDData(); 173 | return allOK; 174 | } // BSDData::ReadBSDData(DiskIO* theDisk, uint64_t startSector) 175 | 176 | // Reverse metadata's byte order; called only on big-endian systems 177 | void BSDData::ReverseMetaBytes(void) { 178 | ReverseBytes(&signature, 4); 179 | ReverseBytes(§orSize, 4); 180 | ReverseBytes(&signature2, 4); 181 | ReverseBytes(&numParts, 2); 182 | } // BSDData::ReverseMetaByteOrder() 183 | 184 | // Display basic BSD partition data. Used for debugging. 185 | void BSDData::DisplayBSDData(void) { 186 | int i; 187 | 188 | if (state == bsd) { 189 | cout << "BSD partitions:\n"; 190 | for (i = 0; i < numParts; i++) { 191 | cout.width(4); 192 | cout << i + 1 << "\t"; 193 | cout.width(13); 194 | cout << partitions[i].firstLBA << "\t"; 195 | cout.width(15); 196 | cout << partitions[i].lengthLBA << " \t0x"; 197 | cout.width(2); 198 | cout.fill('0'); 199 | cout.setf(ios::uppercase); 200 | cout << hex << (int) partitions[i].fsType << "\n" << dec; 201 | cout.fill(' '); 202 | } // for 203 | } // if 204 | } // BSDData::DisplayBSDData() 205 | 206 | // Displays the BSD disklabel state. Called during program launch to inform 207 | // the user about the partition table(s) status 208 | int BSDData::ShowState(void) { 209 | int retval = 0; 210 | 211 | switch (state) { 212 | case bsd_invalid: 213 | cout << " BSD: not present\n"; 214 | break; 215 | case bsd: 216 | cout << " BSD: present\n"; 217 | retval = 1; 218 | break; 219 | default: 220 | cout << "\a BSD: unknown -- bug!\n"; 221 | break; 222 | } // switch 223 | return retval; 224 | } // BSDData::ShowState() 225 | 226 | // Weirdly, this function has stopped working when defined inline, 227 | // but it's OK here.... 228 | int BSDData::IsDisklabel(void) { 229 | return (state == bsd); 230 | } // BSDData::IsDiskLabel() 231 | 232 | // Returns the BSD table's partition type code 233 | uint8_t BSDData::GetType(int i) { 234 | uint8_t retval = 0; // 0 = "unused" 235 | 236 | if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) 237 | retval = partitions[i].fsType; 238 | 239 | return(retval); 240 | } // BSDData::GetType() 241 | 242 | // Returns the number of the first sector of the specified partition 243 | uint64_t BSDData::GetFirstSector(int i) { 244 | uint64_t retval = UINT64_C(0); 245 | 246 | if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) 247 | retval = (uint64_t) partitions[i].firstLBA; 248 | 249 | return retval; 250 | } // BSDData::GetFirstSector 251 | 252 | // Returns the length (in sectors) of the specified partition 253 | uint64_t BSDData::GetLength(int i) { 254 | uint64_t retval = UINT64_C(0); 255 | 256 | if ((i < numParts) && (i >= 0) && (state == bsd) && (partitions != 0)) 257 | retval = (uint64_t) partitions[i].lengthLBA; 258 | 259 | return retval; 260 | } // BSDData::GetLength() 261 | 262 | // Returns the number of partitions defined in the current table 263 | int BSDData::GetNumParts(void) { 264 | return numParts; 265 | } // BSDData::GetNumParts() 266 | 267 | // Returns the specified partition as a GPT partition. Used in BSD-to-GPT 268 | // conversion process 269 | GPTPart BSDData::AsGPT(int i) { 270 | GPTPart guid; // dump data in here, then return it 271 | uint64_t sectorOne, sectorEnd; // first & last sectors of partition 272 | int passItOn = 1; // Set to 0 if partition is empty or invalid 273 | 274 | guid.BlankPartition(); 275 | sectorOne = (uint64_t) partitions[i].firstLBA; 276 | sectorEnd = sectorOne + (uint64_t) partitions[i].lengthLBA; 277 | if (sectorEnd > 0) sectorEnd--; 278 | // Note on above: BSD partitions sometimes have a length of 0 and a start 279 | // sector of 0. With unsigned ints, the usual way (start + length - 1) to 280 | // find the end will result in a huge number, which will be confusing. 281 | // Thus, apply the "-1" part only if it's reasonable to do so. 282 | 283 | // Do a few sanity checks on the partition before we pass it on.... 284 | // First, check that it falls within the bounds of its container 285 | // and that it starts before it ends.... 286 | if ((sectorOne < labelFirstLBA) || (sectorEnd > labelLastLBA) || (sectorOne > sectorEnd)) 287 | passItOn = 0; 288 | // Some disklabels include a pseudo-partition that's the size of the entire 289 | // disk or containing partition. Don't return it. 290 | if ((sectorOne <= labelFirstLBA) && (sectorEnd >= labelLastLBA) && 291 | (GetType(i) == 0)) 292 | passItOn = 0; 293 | // If the end point is 0, it's not a valid partition. 294 | if ((sectorEnd == 0) || (sectorEnd == labelFirstLBA)) 295 | passItOn = 0; 296 | 297 | if (passItOn) { 298 | guid.SetFirstLBA(sectorOne); 299 | guid.SetLastLBA(sectorEnd); 300 | // Now set a random unique GUID for the partition.... 301 | guid.RandomizeUniqueGUID(); 302 | // ... zero out the attributes and name fields.... 303 | guid.SetAttributes(UINT64_C(0)); 304 | // Most BSD disklabel type codes seem to be archaic or rare. 305 | // They're also ambiguous; a FreeBSD filesystem is impossible 306 | // to distinguish from a NetBSD one. Thus, these code assignment 307 | // are going to be rough to begin with. For a list of meanings, 308 | // see http://fxr.watson.org/fxr/source/sys/dtype.h?v=DFBSD, 309 | // or Google it. 310 | switch (GetType(i)) { 311 | case 1: // BSD swap 312 | guid.SetType(0xa502); break; 313 | case 7: // BSD FFS 314 | guid.SetType(0xa503); break; 315 | case 8: case 11: // MS-DOS or HPFS 316 | guid.SetType(0x0700); break; 317 | case 9: // log-structured fs 318 | guid.SetType(0xa903); break; 319 | case 13: // bootstrap 320 | guid.SetType(0xa501); break; 321 | case 14: // vinum 322 | guid.SetType(0xa505); break; 323 | case 15: // RAID 324 | guid.SetType(0xa903); break; 325 | case 27: // FreeBSD ZFS 326 | guid.SetType(0xa504); break; 327 | default: 328 | guid.SetType(0xa503); break; 329 | } // switch 330 | // Set the partition name to the name of the type code.... 331 | guid.SetName(guid.GetTypeName()); 332 | } // if 333 | return guid; 334 | } // BSDData::AsGPT() 335 | -------------------------------------------------------------------------------- /mbrpart.cc: -------------------------------------------------------------------------------- 1 | /* 2 | MBRPart class, part of GPT fdisk program family. 3 | Copyright (C) 2011 Roderick W. Smith 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #define __STDC_LIMIT_MACROS 21 | #ifndef __STDC_CONSTANT_MACROS 22 | #define __STDC_CONSTANT_MACROS 23 | #endif 24 | 25 | #include 26 | #include 27 | #include 28 | #include "support.h" 29 | #include "mbrpart.h" 30 | 31 | using namespace std; 32 | 33 | uint32_t MBRPart::numHeads = MAX_HEADS; 34 | uint32_t MBRPart::numSecspTrack = MAX_SECSPERTRACK; 35 | uint64_t MBRPart::diskSize = 0; 36 | uint32_t MBRPart::blockSize = 512; 37 | int MBRPart::numInstances = 0; 38 | 39 | MBRPart::MBRPart() { 40 | int i; 41 | 42 | status = 0; 43 | for (i = 0; i < 3; i++) { 44 | firstSector[i] = 0; 45 | lastSector[i] = 0; 46 | } // for 47 | partitionType = 0x00; 48 | firstLBA = 0; 49 | lengthLBA = 0; 50 | includeAs = NONE; 51 | canBePrimary = 0; 52 | canBeLogical = 0; 53 | if (numInstances == 0) { 54 | numHeads = MAX_HEADS; 55 | numSecspTrack = MAX_SECSPERTRACK; 56 | diskSize = 0; 57 | blockSize = 512; 58 | } // if 59 | numInstances++; 60 | } 61 | 62 | MBRPart::MBRPart(const MBRPart& orig) { 63 | numInstances++; 64 | operator=(orig); 65 | } 66 | 67 | MBRPart::~MBRPart() { 68 | numInstances--; 69 | } 70 | 71 | MBRPart& MBRPart::operator=(const MBRPart& orig) { 72 | int i; 73 | 74 | status = orig.status; 75 | for (i = 0; i < 3; i++) { 76 | firstSector[i] = orig.firstSector[i]; 77 | lastSector[i] = orig.lastSector[i]; 78 | } // for 79 | partitionType = orig.partitionType; 80 | firstLBA = orig.firstLBA; 81 | lengthLBA = orig.lengthLBA; 82 | includeAs = orig.includeAs; 83 | canBePrimary = orig.canBePrimary; 84 | canBeLogical = orig.canBeLogical; 85 | return *this; 86 | } // MBRPart::operator=(const MBRPart& orig) 87 | 88 | // Set partition data from packed MBRRecord structure. 89 | MBRPart& MBRPart::operator=(const struct MBRRecord& orig) { 90 | int i; 91 | 92 | status = orig.status; 93 | for (i = 0; i < 3; i++) { 94 | firstSector[i] = orig.firstSector[i]; 95 | lastSector[i] = orig.lastSector[i]; 96 | } // for 97 | partitionType = orig.partitionType; 98 | firstLBA = orig.firstLBA; 99 | lengthLBA = orig.lengthLBA; 100 | if (lengthLBA > 0) 101 | includeAs = PRIMARY; 102 | else 103 | includeAs = NONE; 104 | return *this; 105 | } // MBRPart::operator=(const struct MBRRecord& orig) 106 | 107 | // Compare the values, and return a bool result. 108 | // Because this is intended for sorting and a lengthLBA value of 0 denotes 109 | // a partition that's not in use and so that should be sorted upwards, 110 | // we return the opposite of the usual arithmetic result when either 111 | // lengthLBA value is 0. 112 | bool MBRPart::operator<(const MBRPart &other) const { 113 | if (lengthLBA && other.lengthLBA) 114 | return (firstLBA < other.firstLBA); 115 | else 116 | return (other.firstLBA < firstLBA); 117 | } // operator<() 118 | 119 | /************************************************** 120 | * * 121 | * Set information on partitions or disks without * 122 | * interacting with the user.... * 123 | * * 124 | **************************************************/ 125 | 126 | void MBRPart::SetGeometry(uint32_t heads, uint32_t sectors, uint64_t ds, uint32_t bs) { 127 | numHeads = heads; 128 | numSecspTrack = sectors; 129 | diskSize = ds; 130 | blockSize = bs; 131 | } // MBRPart::SetGeometry 132 | 133 | // Empty the partition (zero out all values). 134 | void MBRPart::Empty(void) { 135 | status = UINT8_C(0); 136 | firstSector[0] = UINT8_C(0); 137 | firstSector[1] = UINT8_C(0); 138 | firstSector[2] = UINT8_C(0); 139 | partitionType = UINT8_C(0); 140 | lastSector[0] = UINT8_C(0); 141 | lastSector[1] = UINT8_C(0); 142 | lastSector[2] = UINT8_C(0); 143 | firstLBA = UINT32_C(0); 144 | lengthLBA = UINT32_C(0); 145 | includeAs = NONE; 146 | } // MBRPart::Empty() 147 | 148 | // Sets the type code, but silently refuses to change it to an extended type 149 | // code. 150 | // Returns 1 on success, 0 on failure (extended type code) 151 | int MBRPart::SetType(uint8_t typeCode, int isExtended) { 152 | int allOK = 0; 153 | 154 | if ((isExtended == 1) || ((typeCode != 0x05) && (typeCode != 0x0f) && (typeCode != 0x85))) { 155 | partitionType = typeCode; 156 | allOK = 1; 157 | } // if 158 | return allOK; 159 | } // MBRPart::SetType() 160 | 161 | void MBRPart::SetStartLBA(uint64_t start) { 162 | if (start > UINT32_MAX) 163 | cerr << "Partition start out of range! Continuing, but problems now likely!\n"; 164 | firstLBA = (uint32_t) start; 165 | RecomputeCHS(); 166 | } // MBRPart::SetStartLBA() 167 | 168 | void MBRPart::SetLengthLBA(uint64_t length) { 169 | if (length > UINT32_MAX) 170 | cerr << "Partition length out of range! Continuing, but problems now likely!\n"; 171 | lengthLBA = (uint32_t) length; 172 | RecomputeCHS(); 173 | } // MBRPart::SetLengthLBA() 174 | 175 | // Set the start point and length of the partition. This function takes LBA 176 | // values, sets them directly, and sets the CHS values based on the LBA 177 | // values and the current geometry settings. 178 | void MBRPart::SetLocation(uint64_t start, uint64_t length) { 179 | int validCHS; 180 | 181 | if ((start > UINT32_MAX) || (length > UINT32_MAX)) { 182 | cerr << "Partition values out of range in MBRPart::SetLocation()!\n" 183 | << "Continuing, but strange problems are now likely!\n"; 184 | } // if 185 | firstLBA = (uint32_t) start; 186 | lengthLBA = (uint32_t) length; 187 | validCHS = RecomputeCHS(); 188 | 189 | // If this is a complete 0xEE protective MBR partition, max out its 190 | // CHS last sector value, as per the GPT spec. (Set to 0xffffff, 191 | // although the maximum legal MBR value is 0xfeffff, which is 192 | // actually what GNU Parted and Apple's Disk Utility use, in 193 | // violation of the GPT spec.) 194 | if ((partitionType == 0xEE) && (!validCHS) && (firstLBA == 1) && 195 | ((lengthLBA == diskSize - 1) || (lengthLBA == UINT32_MAX))) { 196 | lastSector[0] = lastSector[1] = lastSector[2] = 0xFF; 197 | } // if 198 | } // MBRPart::SetLocation() 199 | 200 | // Store the MBR data in the packed structure used for disk I/O... 201 | void MBRPart::StoreInStruct(MBRRecord* theStruct) { 202 | int i; 203 | 204 | theStruct->firstLBA = firstLBA; 205 | theStruct->lengthLBA = lengthLBA; 206 | theStruct->partitionType = partitionType; 207 | theStruct->status = status; 208 | for (i = 0; i < 3; i++) { 209 | theStruct->firstSector[i] = firstSector[i]; 210 | theStruct->lastSector[i] = lastSector[i]; 211 | } // for 212 | } // MBRPart::StoreInStruct() 213 | 214 | /********************************************** 215 | * * 216 | * Get information on partitions or disks.... * 217 | * * 218 | **********************************************/ 219 | 220 | // Returns the last LBA value. Note that this can theoretically be a 33-bit 221 | // value, so we return a 64-bit value. If lengthLBA == 0, returns 0, even if 222 | // firstLBA is non-0. 223 | uint64_t MBRPart::GetLastLBA(void) const { 224 | if (lengthLBA > 0) 225 | return (uint64_t) firstLBA + (uint64_t) lengthLBA - UINT64_C(1); 226 | else 227 | return 0; 228 | } // MBRPart::GetLastLBA() 229 | 230 | // Returns 1 if other overlaps with the current partition, 0 if they don't 231 | // overlap 232 | int MBRPart::DoTheyOverlap (const MBRPart& other) { 233 | return lengthLBA && other.lengthLBA && 234 | (firstLBA <= other.GetLastLBA()) != (GetLastLBA() < other.firstLBA); 235 | } // MBRPart::DoTheyOverlap() 236 | 237 | /************************************************* 238 | * * 239 | * Adjust information on partitions or disks.... * 240 | * * 241 | *************************************************/ 242 | 243 | // Recompute the CHS values for the start and end points. 244 | // Returns 1 if both computed values are within the range 245 | // that can be expressed by that CHS, 0 otherwise. 246 | int MBRPart::RecomputeCHS(void) { 247 | int retval = 1; 248 | 249 | if (lengthLBA > 0) { 250 | retval = LBAtoCHS(firstLBA, firstSector); 251 | retval *= LBAtoCHS(firstLBA + lengthLBA - 1, lastSector); 252 | } // if 253 | return retval; 254 | } // MBRPart::RecomputeCHS() 255 | 256 | // Converts 32-bit LBA value to MBR-style CHS value. Returns 1 if conversion 257 | // was within the range that can be expressed by CHS (including 0, for an 258 | // empty partition), 0 if the value is outside that range, and -1 if chs is 259 | // invalid. 260 | int MBRPart::LBAtoCHS(uint32_t lba, uint8_t * chs) { 261 | uint64_t cylinder, head, sector; // all numbered from 0 262 | uint64_t remainder; 263 | int retval = 1; 264 | int done = 0; 265 | 266 | if (chs != NULL) { 267 | // Special case: In case of 0 LBA value, zero out CHS values.... 268 | if (lba == 0) { 269 | chs[0] = chs[1] = chs[2] = UINT8_C(0); 270 | done = 1; 271 | } // if 272 | // If LBA value is too large for CHS, max out CHS values.... 273 | if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) { 274 | chs[0] = 254; 275 | chs[1] = chs[2] = 255; 276 | done = 1; 277 | retval = 0; 278 | } // if 279 | // If neither of the above applies, compute CHS values.... 280 | if (!done) { 281 | cylinder = lba / (numHeads * numSecspTrack); 282 | remainder = lba - (cylinder * numHeads * numSecspTrack); 283 | head = remainder / numSecspTrack; 284 | remainder -= head * numSecspTrack; 285 | sector = remainder; 286 | if (head < numHeads) 287 | chs[0] = (uint8_t) head; 288 | else 289 | retval = 0; 290 | if (sector < numSecspTrack) { 291 | chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64); 292 | chs[2] = (uint8_t) (cylinder & UINT32_C(0xFF)); 293 | } else { 294 | retval = 0; 295 | } // if/else 296 | } // if value is expressible and non-0 297 | } else { // Invalid (NULL) chs pointer 298 | retval = -1; 299 | } // if CHS pointer valid 300 | return (retval); 301 | } // MBRPart::LBAtoCHS() 302 | 303 | // Reverses the byte order, but only if we're on a big-endian platform. 304 | // Note that most data come in 8-bit structures, so don't need reversing; 305 | // only the LBA data needs to be reversed.... 306 | void MBRPart::ReverseByteOrder(void) { 307 | if (IsLittleEndian() == 0) { 308 | ReverseBytes(&firstLBA, 4); 309 | ReverseBytes(&lengthLBA, 4); 310 | } // if 311 | } // MBRPart::ReverseByteOrder() 312 | 313 | /************************** 314 | * * 315 | * User I/O functions.... * 316 | * * 317 | **************************/ 318 | 319 | // Show MBR data. Should update canBeLogical flags before calling. 320 | // If isGpt == 1, omits the "can be logical" and "can be primary" columns. 321 | void MBRPart::ShowData(int isGpt) { 322 | char bootCode = ' '; 323 | 324 | if (status & 0x80) // it's bootable 325 | bootCode = '*'; 326 | cout.fill(' '); 327 | cout << bootCode << " "; 328 | cout.width(13); 329 | cout << firstLBA; 330 | cout.width(13); 331 | cout << GetLastLBA() << " "; 332 | switch (includeAs) { 333 | case PRIMARY: 334 | cout << "primary"; 335 | break; 336 | case LOGICAL: 337 | cout << "logical"; 338 | break; 339 | case NONE: 340 | cout << "omitted"; 341 | break; 342 | default: 343 | cout << "error "; 344 | break; 345 | } // switch 346 | cout.width(7); 347 | if (!isGpt) { 348 | if (canBeLogical) 349 | cout << " Y "; 350 | else 351 | cout << " "; 352 | if (canBePrimary) 353 | cout << " Y "; 354 | else 355 | cout << " "; 356 | } // if 357 | cout << "0x"; 358 | cout.width(2); 359 | cout.fill('0'); 360 | cout << hex << (int) partitionType << dec << "\n"; 361 | } // MBRPart::ShowData() 362 | -------------------------------------------------------------------------------- /support.cc: -------------------------------------------------------------------------------- 1 | // support.cc 2 | // Non-class support functions for gdisk program. 3 | // Primarily by Rod Smith, February 2009, but with a few functions 4 | // copied from other sources (see attributions below). 5 | 6 | /* This program is copyright (c) 2009-2018 by Roderick W. Smith. It is distributed 7 | under the terms of the GNU GPL version 2, as detailed in the COPYING file. */ 8 | 9 | #define __STDC_LIMIT_MACROS 10 | #ifndef __STDC_CONSTANT_MACROS 11 | #define __STDC_CONSTANT_MACROS 12 | #endif 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "support.h" 25 | 26 | #include 27 | 28 | // As of 1/2010, BLKPBSZGET is very new, so I'm explicitly defining it if 29 | // it's not already defined. This should become unnecessary in the future. 30 | // Note that this is a Linux-only ioctl.... 31 | #ifndef BLKPBSZGET 32 | #define BLKPBSZGET _IO(0x12,123) 33 | #endif 34 | 35 | using namespace std; 36 | 37 | // Reads a string from stdin, returning it as a C++-style string. 38 | // Note that the returned string will NOT include the carriage return 39 | // entered by the user. 40 | #ifdef EFI 41 | extern int __sscanf( const char * str , const char * format , ... ) ; 42 | string ReadString(void) { 43 | string inString; 44 | char efiString[256]; 45 | int stringLength; 46 | 47 | if (fgets(efiString, 255, stdin) != NULL) { 48 | stringLength = strlen(efiString); 49 | if ((stringLength > 0) && (efiString[stringLength - 1] == '\n')) 50 | efiString[stringLength - 1] = '\0'; 51 | inString = efiString; 52 | } else { 53 | inString = ""; 54 | } 55 | return inString; 56 | } // ReadString() 57 | #else 58 | string ReadString(void) { 59 | string inString; 60 | 61 | cout << flush; 62 | getline(cin, inString); 63 | if (!cin.good()) 64 | exit(5); 65 | return inString; 66 | } // ReadString() 67 | #endif 68 | 69 | // Get a numeric value from the user, between low and high (inclusive). 70 | // Keeps looping until the user enters a value within that range. 71 | // If user provides no input, def (default value) is returned. 72 | // (If def is outside of the low-high range, an explicit response 73 | // is required.) 74 | uint64_t GetNumber(uint64_t low, uint64_t high, uint64_t def, const string & prompt) { 75 | uint64_t response, num; 76 | char line[255]; 77 | 78 | if (low != high) { // bother only if low and high differ... 79 | do { 80 | cout << prompt << flush; 81 | cin.getline(line, 255); 82 | if (!cin.good()) 83 | exit(5); 84 | num = sscanf(line, "%" SCNu64, &response); 85 | if (num == 1) { // user provided a response 86 | if ((response < low) || (response > high)) 87 | cout << "Value out of range\n"; 88 | } else { // user hit enter; return default 89 | response = def; 90 | } // if/else 91 | } while ((response < low) || (response > high)); 92 | } else { // low == high, so return this value 93 | cout << "Using " << low << "\n"; 94 | response = low; 95 | } // else 96 | return (response); 97 | } // GetNumber() 98 | 99 | // Gets a Y/N response (and converts lowercase to uppercase) 100 | char GetYN(void) { 101 | char response; 102 | string line; 103 | bool again = 0 ; 104 | 105 | do { 106 | if ( again ) { cout << "Your option? " ; } 107 | again = 1 ; 108 | cout << "(Y/N): " << flush; 109 | line = ReadString(); 110 | response = toupper(line[0]); 111 | } while ((response != 'Y') && (response != 'N')); 112 | return response; 113 | } // GetYN(void) 114 | 115 | // Obtains a sector number, between low and high, from the 116 | // user, accepting values prefixed by "+" to add sectors to low, 117 | // or the same with "K", "M", "G", "T", or "P" as suffixes to add 118 | // kilobytes, megabytes, gigabytes, terabytes, or petabytes, 119 | // respectively. If a "-" prefix is used, use the high value minus 120 | // the user-specified number of sectors (or KiB, MiB, etc.). Use the 121 | // def value as the default if the user just hits Enter. The sSize is 122 | // the sector size of the device. 123 | uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, 124 | const string & prompt) { 125 | uint64_t response; 126 | char line[255]; 127 | 128 | do { 129 | cout << prompt; 130 | cin.getline(line, 255); 131 | if (!cin.good()) 132 | exit(5); 133 | response = IeeeToInt(line, sSize, low, high, def); 134 | } while ((response < low) || (response > high)); 135 | return response; 136 | } // GetSectorNum() 137 | 138 | // Convert an IEEE-1541-2002 value (K, M, G, T, P, or E) to its equivalent in 139 | // number of sectors. If no units are appended, interprets as the number 140 | // of sectors; otherwise, interprets as number of specified units and 141 | // converts to sectors. For instance, with 512-byte sectors, "1K" converts 142 | // to 2. If value includes a "+", adds low and subtracts 1; if SIValue 143 | // inclues a "-", subtracts from high. If IeeeValue is empty, returns def. 144 | // Returns final sector value. In case inValue is invalid, returns 0 (a 145 | // sector value that's always in use on GPT and therefore invalid); and if 146 | // inValue works out to something outside the range low-high, returns the 147 | // computed value; the calling function is responsible for checking the 148 | // validity of this value. 149 | // NOTE: There's a difference in how GCC and VC++ treat oversized values 150 | // (say, "999999999999999999999") read via the ">>" operator; GCC turns 151 | // them into the maximum value for the type, whereas VC++ turns them into 152 | // 0 values. The result is that IeeeToInt() returns UINT64_MAX when 153 | // compiled with GCC (and so the value is rejected), whereas when VC++ 154 | // is used, the default value is returned. 155 | uint64_t IeeeToInt(string inValue, uint64_t sSize, uint64_t low, uint64_t high, uint64_t def) { 156 | uint64_t response = def, bytesPerUnit = 1, mult = 1, divide = 1; 157 | size_t foundAt = 0; 158 | char suffix = ' ', plusFlag = ' '; 159 | string suffixes = "KMGTPE"; 160 | int badInput = 0; // flag bad input; once this goes to 1, other values are irrelevant 161 | 162 | if (sSize == 0) { 163 | sSize = SECTOR_SIZE; 164 | cerr << "Bug: Sector size invalid in IeeeToInt()!\n"; 165 | } // if 166 | 167 | // Remove leading spaces, if present 168 | while (inValue[0] == ' ') 169 | inValue.erase(0, 1); 170 | 171 | // If present, flag and remove leading plus or minus sign 172 | if ((inValue[0] == '+') || (inValue[0] == '-')) { 173 | plusFlag = inValue[0]; 174 | inValue.erase(0, 1); 175 | } // if 176 | 177 | // Extract numeric response and, if present, suffix 178 | istringstream inString(inValue); 179 | if (((inString.peek() < '0') || (inString.peek() > '9')) && (inString.peek() != -1)) 180 | badInput = 1; 181 | inString >> response >> suffix; 182 | suffix = toupper(suffix); 183 | 184 | // If no response, or if response == 0, use default (def) 185 | if ((inValue.length() == 0) || (response == 0)) { 186 | response = def; 187 | suffix = ' '; 188 | plusFlag = ' '; 189 | } // if 190 | 191 | // Find multiplication and division factors for the suffix 192 | foundAt = suffixes.find(suffix); 193 | if (foundAt != string::npos) { 194 | bytesPerUnit = UINT64_C(1) << (10 * (foundAt + 1)); 195 | mult = bytesPerUnit / sSize; 196 | divide = sSize / bytesPerUnit; 197 | } // if 198 | 199 | // Adjust response based on multiplier and plus flag, if present 200 | if (mult > 1) { 201 | if (response > (UINT64_MAX / mult)) 202 | badInput = 1; 203 | else 204 | response *= mult; 205 | } else if (divide > 1) { 206 | response /= divide; 207 | } // if/elseif 208 | 209 | if (plusFlag == '+') { 210 | // Recompute response based on low part of range (if default == high 211 | // value, which should be the case when prompting for the end of a 212 | // range) or the defaut value (if default != high, which should be 213 | // the case for the first sector of a partition). 214 | if (def == high) { 215 | if (response > 0) 216 | response--; 217 | if (response > (UINT64_MAX - low)) 218 | badInput = 1; 219 | else 220 | response = response + low; 221 | } else { 222 | if (response > (UINT64_MAX - def)) 223 | badInput = 1; 224 | else 225 | response = response + def; 226 | } // if/else 227 | } else if (plusFlag == '-') { 228 | if (response > high) 229 | badInput = 1; 230 | else 231 | response = high - response; 232 | } // if 233 | 234 | if (badInput) 235 | response = UINT64_C(0); 236 | 237 | return response; 238 | } // IeeeToInt() 239 | 240 | // Takes a size and converts this to a size in IEEE-1541-2002 units (KiB, MiB, 241 | // GiB, TiB, PiB, or EiB), returned in C++ string form. The size is either in 242 | // units of the sector size or, if that parameter is omitted, in bytes. 243 | // (sectorSize defaults to 1). Note that this function uses peculiar 244 | // manual computation of decimal value rather than simply setting 245 | // theValue.precision() because this isn't possible using the available 246 | // EFI library. 247 | string BytesToIeee(uint64_t size, uint32_t sectorSize) { 248 | uint64_t sizeInIeee; 249 | uint64_t previousIeee; 250 | float decimalIeee; 251 | uint64_t index = 0; 252 | string units, prefixes = " KMGTPEZ"; 253 | ostringstream theValue; 254 | 255 | sizeInIeee = previousIeee = size * (uint64_t) sectorSize; 256 | while ((sizeInIeee > 1024) && (index < (prefixes.length() - 1))) { 257 | index++; 258 | previousIeee = sizeInIeee; 259 | sizeInIeee /= 1024; 260 | } // while 261 | if (prefixes[index] == ' ') { 262 | theValue << sizeInIeee << " bytes"; 263 | } else { 264 | units = " iB"; 265 | units[1] = prefixes[index]; 266 | decimalIeee = ((float) previousIeee - 267 | ((float) sizeInIeee * 1024.0) + 51.2) / 102.4; 268 | if (decimalIeee >= 10.0) { 269 | decimalIeee = 0.0; 270 | sizeInIeee++; 271 | } 272 | theValue << sizeInIeee << "." << (uint32_t) decimalIeee << units; 273 | } // if/else 274 | return theValue.str(); 275 | } // BytesToIeee() 276 | 277 | // Converts two consecutive characters in the input string into a 278 | // number, interpreting the string as a hexadecimal number, starting 279 | // at the specified position. 280 | unsigned char StrToHex(const string & input, unsigned int position) { 281 | unsigned char retval = 0x00; 282 | unsigned int temp; 283 | 284 | if (input.length() > position) { 285 | sscanf(input.substr(position, 2).c_str(), "%x", &temp); 286 | retval = (unsigned char) temp; 287 | } // if 288 | return retval; 289 | } // StrToHex() 290 | 291 | // Returns 1 if input can be interpreted as a hexadecimal number -- 292 | // all characters must be spaces, digits, or letters A-F (upper- or 293 | // lower-case), with at least one valid hexadecimal digit; with the 294 | // exception of the first two characters, which may be "0x"; otherwise 295 | // returns 0. 296 | int IsHex(string input) { 297 | int isHex = 1, foundHex = 0, i; 298 | 299 | if (input.substr(0, 2) == "0x") 300 | input.erase(0, 2); 301 | for (i = 0; i < (int) input.length(); i++) { 302 | if ((input[i] < '0') || (input[i] > '9')) { 303 | if ((input[i] < 'A') || (input[i] > 'F')) { 304 | if ((input[i] < 'a') || (input[i] > 'f')) { 305 | if ((input[i] != ' ') && (input[i] != '\n')) { 306 | isHex = 0; 307 | } 308 | } else foundHex = 1; 309 | } else foundHex = 1; 310 | } else foundHex = 1; 311 | } // for 312 | if (!foundHex) 313 | isHex = 0; 314 | return isHex; 315 | } // IsHex() 316 | 317 | // Return 1 if the CPU architecture is little endian, 0 if it's big endian.... 318 | int IsLittleEndian(void) { 319 | int littleE = 1; // assume little-endian (Intel-style) 320 | union { 321 | uint32_t num; 322 | unsigned char uc[sizeof(uint32_t)]; 323 | } endian; 324 | 325 | endian.num = 1; 326 | if (endian.uc[0] != (unsigned char) 1) { 327 | littleE = 0; 328 | } // if 329 | return (littleE); 330 | } // IsLittleEndian() 331 | 332 | // Reverse the byte order of theValue; numBytes is number of bytes 333 | void ReverseBytes(void* theValue, int numBytes) { 334 | char* tempValue = NULL; 335 | int i; 336 | 337 | tempValue = new char [numBytes]; 338 | if (tempValue != NULL) { 339 | memcpy(tempValue, theValue, numBytes); 340 | for (i = 0; i < numBytes; i++) 341 | ((char*) theValue)[i] = tempValue[numBytes - i - 1]; 342 | delete[] tempValue; 343 | } else { 344 | cerr << "Could not allocate memory in ReverseBytes()! Terminating\n"; 345 | exit(1); 346 | } // if/else 347 | } // ReverseBytes() 348 | 349 | // On Windows, display a warning and ask whether to continue. If the user elects 350 | // not to continue, exit immediately. 351 | void WinWarning(void) { 352 | #ifdef _WIN32 353 | cout << "\a************************************************************************\n" 354 | << "Most versions of Windows cannot boot from a GPT disk except on a UEFI-based\n" 355 | << "computer, and most varieties prior to Vista cannot read GPT disks. Therefore,\n" 356 | << "you should exit now unless you understand the implications of converting MBR\n" 357 | << "to GPT or creating a new GPT disk layout!\n" 358 | << "************************************************************************\n\n"; 359 | cout << "Are you SURE you want to continue? "; 360 | if (GetYN() != 'Y') 361 | exit(0); 362 | #endif 363 | } // WinWarning() 364 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | GPT fdisk (aka gdisk, cgdisk, and sgdisk) and FixParts 2 | by Roderick W. Smith, rodsmith@rodsbooks.com 3 | 4 | Introduction 5 | ------------ 6 | 7 | This package includes the source code for four related disk partitioning 8 | programs: 9 | 10 | - gdisk -- This program is modeled after Linux fdisk, but it operates on 11 | GUID Partition Table (GPT) disks rather than the Master Boot Record (MBR) 12 | disks that fdisk modifies. As such, gdisk is an interactive text-mode 13 | tool for manipulating partitions, but it does nothing to the contents of 14 | those partitions (usually filesystems, but sometimes swap space or other 15 | data). 16 | 17 | - cgdisk -- This program is modeled after Linux cfdisk, but it operates on 18 | GPT disks rather than the MBR disks that cfdisk modifies. As such, cgdisk 19 | is a curses-based text-mode tool for manipulating partitions, which is to 20 | say that it uses an interface that relies on arrow keys and a dynamic 21 | display rather than the command letters and a scrolling display like 22 | gdisk uses. 23 | 24 | - sgdisk -- This program is conceptually similar to the Linux sfdisk and 25 | FreeBSD gpt programs, but its operational details differ. It enables 26 | manipulation of GPT disks using command-line options, so it's suitable 27 | for use in scripts or by experts to perform specific tasks that might 28 | take several commands in gdisk to accomplish. 29 | 30 | - fixparts -- This program, unlike the preceding three, operates on MBR 31 | disks. It's intended to fix certain problems that can be created by 32 | various utilities. Specifically, it can fix mis-sized extended partitions 33 | and primary partitions located in the middle of extended partitions. It 34 | also enables changing primary vs. logical partition status (within limits 35 | of what's legal in the MBR scheme) and making a few other minor changes. 36 | It does NOT support creating new partitions; for that, you should use 37 | fdisk, parted, or some other tool. 38 | 39 | More details about the abilities of these tools follows. 40 | 41 | All four programs rely on the same set of underlying code base; they differ 42 | only in their control interfaces (defined in gdisk.cc, cgdisk.cc, 43 | sgdisk.cc, and fixparts.cc, respectively) and in which support code they 44 | use. 45 | 46 | GPT fdisk (gdisk, cgdisk, and sgdisk) Details 47 | --------------------------------------------- 48 | 49 | The gdisk program is intended as a (somewhat) fdisk-workalike program for 50 | GPT-partitioned disks, cgdisk is similarly a workalike for fdisk, and 51 | sgdisk provides most of gdisk's functionality in a more script-friendly 52 | program. Although libparted and programs that use it (GNU Parted, gparted, 53 | etc.) provide the ability to handle GPT disks, they have certain 54 | limitations that gdisk overcomes. Specific advantages of gdisk, cgdisk, and 55 | sgdisk include: 56 | 57 | * The ability to convert MBR-partitioned disks in-place to GPT format, 58 | without losing data 59 | 60 | * The ability to convert BSD disklabels in-place to create GPT 61 | partitions, without losing data 62 | 63 | * The ability to convert from GPT format to MBR format without data loss 64 | (gdisk and sgdisk only) 65 | 66 | * More flexible specification of filesystem type code GUIDs, which 67 | GNU Parted tends to corrupt 68 | 69 | * Clear identification of the number of unallocated sectors on a 70 | disk 71 | 72 | * A user interface that's familiar to long-time users of Linux 73 | fdisk and cfdisk (gdisk and cgdisk only) 74 | 75 | * The MBR boot loader code is left alone 76 | 77 | * The ability to create a hybrid MBR, which permits GPT-unaware OSes to 78 | access up to three GPT partitions on the disk (gdisk and sgdisk only) 79 | 80 | Of course, GPT fdisk isn't without its limitations. Most notably, it lacks 81 | the filesystem awareness and filesystem-related features of GParted. You 82 | can't resize a partition's filesystem or create a partition with a 83 | filesystem already in place with gdisk, for instance. There's no GUI 84 | version of gdisk. 85 | 86 | The GPT fdisk package provides three program files: the interactive 87 | text-mode gdisk, the curses-based interactive cgdisk, and the 88 | command-line-driven sgdisk. The first two are intended for use in manually 89 | partitioning disks or changing partitioning details; sgdisk is intended for 90 | use in scripts to help automate tasks such as disk cloning or preparing 91 | multiple disks for Linux installation. 92 | 93 | FixParts Details 94 | ---------------- 95 | 96 | This program's creation was motivated by cries for help I've seen in online 97 | forums from users who have found their partition tables to be corrupted by 98 | various buggy partitioning tools. Although most OSes can handle the 99 | afflicted disks fine, libparted-based tools (GParted, parted, most Linux 100 | installers, etc.) tend to flake out when presented with these disks. 101 | Typically, the symptom is a disk that appears to hold no partitions; 102 | however, sometimes the libparted tool presents partitions other than those 103 | that the OS sees. 104 | 105 | I've observed four causes of these symptoms, three of which FixParts can 106 | correct: 107 | 108 | * Old GPT data -- If a disk is used as a GPT disk and then re-used as an 109 | MBR disk, the GPT data may be incompletely erased. This happens if the 110 | disk is repartitioned with fdisk or the Microsoft Windows installer, for 111 | instance. (Tools based on libparted correctly remove the old GPT data 112 | when converting from GPT to MBR format.) FixParts checks for this problem 113 | when it starts and offers to correct it. If you opt to erase the GPT 114 | data, this erasure occurs immediately, unlike other changes the program 115 | makes. 116 | 117 | * Mis-sized extended partitions -- Some tools create an extended partition 118 | that's too large, typically ending after the last sector of the disk. 119 | FixParts automatically corrects this problem (if you use the 'w' option 120 | to save the partition table). 121 | 122 | * Primary partitions inside an extended partition -- Some utilities create 123 | or move primary partitions to within the range covered by the extended 124 | partition. FixParts can usually correct this problem by turning the 125 | primary partition into a logical partition or by changing one or more 126 | other logical partitions into primaries. Such corrections aren't always 127 | possible, though, at least not without deleting or resizing other 128 | partitions. 129 | 130 | * Leftover RAID data -- If a disk is used in a RAID array and then re-used 131 | as a non-RAID disk, some utilities can become confused and fail to see 132 | the disk. FixParts can NOT correct this problem. You must destroy the old 133 | RAID data, or possibly remove the dmraid package from the system, to fix 134 | this problem. 135 | 136 | When run, FixParts presents an fdisk-like interface, enabling you to adjust 137 | partition types (primary, logical, or omitted), change type codes, change 138 | the bootable flag, and so on. Although you can delete a partition (by 139 | omitting it), you can't create new partitions with the program. If you're 140 | used to partitioning disks, particularly with Linux fdisk, two unusual 141 | features of FixParts require elaboration: 142 | 143 | * No extended partitions -- Internally, FixParts reads the partition table 144 | and discards data on any extended partition(s) it finds. When you save 145 | the partition table, the program generates a new extended partition. This 146 | design means that the program automatically corrects many problems 147 | related to the extended partition. It also means that you'll see no 148 | evidence of extended partitions in the FixParts user interface, although 149 | it keeps track of the requirements and prevents you from creating illegal 150 | layouts, such as a primary between two logicals. 151 | 152 | * Partition numbering -- In most Linux tools, partitions 1-4 are primaries 153 | and partitions 5 and up are logicals. Although a legal partition table 154 | loaded into FixParts will initially conform to this convention, some 155 | types of damaged table might not, and various changes you make can also 156 | cause deviations. When FixParts writes the partition table, its numbering 157 | will be altered to conform to the standard MBR conventions, but you 158 | should use the explicit labeling of partitions as primary or logical 159 | rather than the partition numbers to determine a partition's status. 160 | 161 | Installing 162 | ---------- 163 | 164 | To compile GPT fdisk, you must have appropriate development tools 165 | installed, most notably the GNU Compiler Collection (GCC) and its g++ 166 | compiler for C++. I've also tested compilation with Clang, which seems to 167 | work; however, I've not done extensive testing of the resulting binaries, 168 | beyond checking a few basics. Under Windows, Microsoft Visual C++ 2008 can 169 | be used instead. In addition, note these requirements: 170 | 171 | * On Linux, FreeBSD, OS X, and Solaris, libuuid must be installed. This is 172 | the standard for Linux and OS X, although you may need to install a 173 | package called uuid-dev or something similar to get the headers. On 174 | FreeBSD, the e2fsprogs-libuuid port must be installed. 175 | 176 | * The ICU library (http://site.icu-project.org), which provides support for 177 | Unicode partition names, is optional on all platforms except Windows, on 178 | which it's not supported. Using this library was required to get proper 179 | UTF-16 partition name support in GPT fdisk versions prior to 0.8.9, but 180 | as of that version it should not longer be required. Nonetheless, you can 181 | use it if you're having problems with the new UTF-16 support. This 182 | library is normally installed in Linux and OS X, but you may need to 183 | install the development headers (libicu-dev or something similar in 184 | Linux; or the libicu36-dev Fink package in OS X). To compile with ICU 185 | support, you must modify the Makefile: Look for commented-out lines that 186 | refer to USE_UTF16, -licuuc, -licudata, or -licucore. Uncomment them and 187 | comment out the equivalents that lack these lines. 188 | 189 | * The cgdisk program requires the ncurses library and its development files 190 | (headers). Most Linux distributions install ncurses by default, but you 191 | may need to install a package called libncurses5-dev, ncurses-devel, or 192 | something similar to obtain the header files. These files were installed 193 | already on my Mac OS X development system; however, they may have been 194 | installed as dependencies of other programs I've installed. If you're 195 | having problems installing ncurses, you can compile gdisk and/or sgdisk 196 | without cgdisk by specifying only the targets you want to compile to 197 | make. 198 | 199 | * The sgdisk program requires the popt library and its development files 200 | (headers). Most Linux distributions install popt by default, but you may 201 | need to install a package called popt-dev, popt-devel, or something 202 | similar to obtain the header files. Mac OS users can find a version of 203 | popt for Mac OS from Darwin Ports (http://popt.darwinports.com), MacPorts 204 | (https://trac.macports.org/browser/trunk/dports/devel/popt/Portfile), Fink 205 | (http://www.finkproject.org), or brew (http://macappstore.org/popt/); 206 | however, you'll first need to install the relevant environment 207 | (instructions exist on the relevant projects' pages). Alternatively, you 208 | can compile gdisk and/or cgdisk alone, without sgdisk; gdisk doesn't 209 | require popt. 210 | 211 | When all the necessary development tools and libraries are installed, you 212 | can uncompress the package and type "make" at the command prompt in the 213 | resulting directory. (You may need to type "make -f Makefile.mac" on Mac OS 214 | X, "make -f Makefile.freebsd" on FreeBSD, "make -f Makefile.solaris" on 215 | Solaris, or "make -f Makefile.mingw" to compile using MinGW for Windows.) 216 | You may also need to add header (include) directories or library 217 | directories by setting the CXXFLAGS environment variable or by editing the 218 | Makefile. The result should be program files called gdisk, cgdisk, sgdisk, 219 | and fixparts. Typing "make gdisk", "make cgdisk", "make sgdisk", or "make 220 | fixparts" will compile only the requested programs. You can use these 221 | programs in place or copy the files to a suitable directory, such as 222 | /usr/local/sbin. You can copy the man pages (gdisk.8, cgdisk.8, sgdisk.8, 223 | and fixparts.8) to /usr/local/man/man8 to make them available. 224 | 225 | Caveats 226 | ------- 227 | 228 | THIS SOFTWARE IS BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR EATS YOUR 229 | CAT, DON'T BLAME ME! To date, I've tested the software on several USB flash 230 | drives, physical hard disks, and virtual disks in the QEMU and VirtualBox 231 | environments. Many others have now used the software on their computers, as 232 | well. I believe all data-corruption bugs to be squashed, but I know full well 233 | that the odds of my missing something are high. This is particularly true for 234 | large (over-2TiB) drives; my only direct testing with such disks is with 235 | virtual QEMU and VirtualBox disks. I've received user reports of success with 236 | RAID arrays over 2TiB in size, though. 237 | 238 | My main development platform is a system running the 64-bit version of 239 | Ubuntu Linux. I've also tested on several other 32- and 64-bit Linux 240 | distributions, Intel-based Mac OS X 10.6 and several later versions, 64-bit 241 | FreeBSD 7.1, and Windows 7 and 10. 242 | 243 | Redistribution 244 | -------------- 245 | 246 | This program is licensed under terms of the GNU GPL (see the file COPYING). 247 | 248 | Acknowledgements 249 | ---------------- 250 | 251 | This code is mostly my own; however, I've used three functions from two 252 | other GPLed programs: 253 | 254 | - The code used to generate CRCs is taken from the efone program by 255 | Krzysztof Dabrowski and ElysiuM deeZine. (See the crc32.h and 256 | crc32.cc source code files.) 257 | 258 | - A function to find the disk size is taken from Linux fdisk by A. V. Le 259 | Blanc. This code has subsequently been heavily modified. 260 | 261 | Additional code contributors include: 262 | 263 | - Yves Blusseau (1otnwmz02@sneakemail.com) 264 | 265 | - David Hubbard (david.c.hubbard@gmail.com) 266 | 267 | - Justin Maggard (justin.maggard@netgear.com) 268 | 269 | - Dwight Schauer (dschauer@ti.com) 270 | 271 | - Florian Zumbiehl (florz@florz.de) 272 | 273 | - Guillaume Delacour (contributed the gdisk_test.sh script) 274 | --------------------------------------------------------------------------------