summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsrs5694 <srs5694@users.sourceforge.net>2011-03-12 01:23:12 -0500
committersrs5694 <srs5694@users.sourceforge.net>2011-03-12 01:23:12 -0500
commitbf8950cad0285ee6ab8a896e8d0a30c5fb62c7af (patch)
treeca6eaedd03128249d84544d6ad077f1498d66e41
parent96312236d7f0c857efc95871a31857e24ecdc81b (diff)
downloadsgdisk-bf8950cad0285ee6ab8a896e8d0a30c5fb62c7af.tar.gz
Version 0.7.0
-rw-r--r--Makefile364
-rw-r--r--Makefile.mac11
-rw-r--r--Makefile.mingw13
-rw-r--r--NEWS24
-rw-r--r--README158
-rw-r--r--README.Windows63
-rw-r--r--basicmbr.cc1258
-rw-r--r--basicmbr.h95
-rw-r--r--current.spec53
-rw-r--r--diskio-unix.cc41
-rw-r--r--diskio-windows.cc12
-rw-r--r--diskio.cc2
-rw-r--r--diskio.h4
-rw-r--r--gdisk.89
-rw-r--r--gdisk.cc72
-rw-r--r--gpt.cc62
-rw-r--r--gpt.h15
-rw-r--r--gptpart.cc15
-rw-r--r--gptpart.h4
-rw-r--r--gpttext.cc192
-rw-r--r--gpttext.h1
-rw-r--r--mbr.cc55
-rw-r--r--mbr.h4
-rw-r--r--sgdisk.89
-rw-r--r--sgdisk.cc51
-rw-r--r--support.cc15
-rw-r--r--support.h12
27 files changed, 1526 insertions, 1088 deletions
diff --git a/Makefile b/Makefile
index 3865013..f1146ef 100644
--- a/Makefile
+++ b/Makefile
@@ -3,13 +3,15 @@ CXX=g++
CFLAGS+=-D_FILE_OFFSET_BITS=64
CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64
LDFLAGS+=
-LIB_NAMES=crc32 support guid partnotes gptpartnotes gptpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
-LIB_SRCS=$(NAMES:=.cc)
+LIB_NAMES=crc32 support guid gptpart mbrpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
+MBR_LIBS=support diskio diskio-unix basicmbr mbrpart
+#LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
+MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CXXFLAGS)
-all: gdisk sgdisk
+all: gdisk sgdisk fixparts
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o $(LDFLAGS) -luuid -o gdisk
@@ -17,11 +19,14 @@ gdisk: $(LIB_OBJS) gdisk.o gpttext.o
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o $(LDFLAGS) -luuid -lpopt -o sgdisk
+fixparts: $(MBR_LIB_OBJS) fixparts.o
+ $(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
+
lint: #no pre-reqs
lint $(SRCS)
clean: #no pre-reqs
- rm -f core *.o *~ gdisk sgdisk
+ rm -f core *.o *~ gdisk sgdisk fixparts
# what are the source dependencies
depend: $(SRCS)
@@ -32,354 +37,3 @@ $(OBJS):
# DO NOT DELETE
-attributes.o: /usr/include/stdint.h /usr/include/features.h
-attributes.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-attributes.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-attributes.o: /usr/include/bits/wchar.h /usr/include/stdio.h
-attributes.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-attributes.o: /usr/include/libio.h /usr/include/_G_config.h
-attributes.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-attributes.o: /usr/include/bits/sys_errlist.h attributes.h support.h
-attributes.o: /usr/include/stdlib.h /usr/include/sys/types.h
-attributes.o: /usr/include/time.h /usr/include/endian.h
-attributes.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-attributes.o: /usr/include/sys/select.h /usr/include/bits/select.h
-attributes.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-attributes.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-attributes.o: /usr/include/alloca.h
-bsd.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
-bsd.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
-bsd.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
-bsd.o: /usr/include/bits/typesizes.h /usr/include/libio.h
-bsd.o: /usr/include/_G_config.h /usr/include/wchar.h
-bsd.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-bsd.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
-bsd.o: /usr/include/endian.h /usr/include/bits/endian.h
-bsd.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-bsd.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-bsd.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-bsd.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-bsd.o: /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/fcntl.h
-bsd.o: /usr/include/bits/fcntl.h /usr/include/sys/stat.h
-bsd.o: /usr/include/bits/stat.h /usr/include/errno.h
-bsd.o: /usr/include/bits/errno.h /usr/include/linux/errno.h
-bsd.o: /usr/include/asm/errno.h /usr/include/asm-generic/errno.h
-bsd.o: /usr/include/asm-generic/errno-base.h support.h bsd.h gptpart.h
-bsd.o: parttypes.h guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h
-bsd.o: attributes.h diskio.h /usr/include/sys/ioctl.h
-bsd.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-bsd.o: /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h
-bsd.o: /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h
-bsd.o: /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h
-crc32.o: /usr/include/stdio.h /usr/include/features.h
-crc32.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-crc32.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-crc32.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-crc32.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
-crc32.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-crc32.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
-crc32.o: /usr/include/endian.h /usr/include/bits/endian.h
-crc32.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-crc32.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-crc32.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-crc32.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h crc32.h
-crc32.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-diskio.o: /usr/include/sys/ioctl.h /usr/include/features.h
-diskio.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-diskio.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-diskio.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-diskio.o: /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h
-diskio.o: /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h
-diskio.o: /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h
-diskio.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-diskio.o: /usr/include/errno.h /usr/include/bits/errno.h
-diskio.o: /usr/include/linux/errno.h /usr/include/asm/errno.h
-diskio.o: /usr/include/asm-generic/errno.h
-diskio.o: /usr/include/asm-generic/errno-base.h /usr/include/fcntl.h
-diskio.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
-diskio.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-diskio.o: /usr/include/time.h /usr/include/endian.h
-diskio.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-diskio.o: /usr/include/sys/select.h /usr/include/bits/select.h
-diskio.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-diskio.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-diskio.o: /usr/include/sys/stat.h /usr/include/bits/stat.h support.h
-diskio.o: /usr/include/stdlib.h /usr/include/alloca.h diskio.h parttypes.h
-diskio.o: guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h gpt.h
-diskio.o: gptpart.h attributes.h mbr.h partnotes.h bsd.h
-diskio-unix.o: /usr/include/sys/ioctl.h /usr/include/features.h
-diskio-unix.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-diskio-unix.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-diskio-unix.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-diskio-unix.o: /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h
-diskio-unix.o: /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h
-diskio-unix.o: /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h
-diskio-unix.o: /usr/include/string.h /usr/include/xlocale.h
-diskio-unix.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-diskio-unix.o: /usr/include/errno.h /usr/include/bits/errno.h
-diskio-unix.o: /usr/include/linux/errno.h /usr/include/asm/errno.h
-diskio-unix.o: /usr/include/asm-generic/errno.h
-diskio-unix.o: /usr/include/asm-generic/errno-base.h /usr/include/fcntl.h
-diskio-unix.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
-diskio-unix.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-diskio-unix.o: /usr/include/time.h /usr/include/endian.h
-diskio-unix.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-diskio-unix.o: /usr/include/sys/select.h /usr/include/bits/select.h
-diskio-unix.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-diskio-unix.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-diskio-unix.o: /usr/include/sys/stat.h /usr/include/bits/stat.h diskio.h
-diskio-unix.o: support.h /usr/include/stdlib.h /usr/include/alloca.h
-diskio-unix.o: parttypes.h guid.h /usr/include/uuid/uuid.h
-diskio-unix.o: /usr/include/sys/time.h
-diskio-windows.o: /usr/include/stdio.h /usr/include/features.h
-diskio-windows.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-diskio-windows.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-diskio-windows.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-diskio-windows.o: /usr/include/libio.h /usr/include/_G_config.h
-diskio-windows.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-diskio-windows.o: /usr/include/bits/sys_errlist.h /usr/include/stdint.h
-diskio-windows.o: /usr/include/bits/wchar.h /usr/include/errno.h
-diskio-windows.o: /usr/include/bits/errno.h /usr/include/linux/errno.h
-diskio-windows.o: /usr/include/asm/errno.h /usr/include/asm-generic/errno.h
-diskio-windows.o: /usr/include/asm-generic/errno-base.h /usr/include/fcntl.h
-diskio-windows.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
-diskio-windows.o: /usr/include/time.h /usr/include/endian.h
-diskio-windows.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-diskio-windows.o: /usr/include/sys/select.h /usr/include/bits/select.h
-diskio-windows.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-diskio-windows.o: /usr/include/sys/sysmacros.h
-diskio-windows.o: /usr/include/bits/pthreadtypes.h /usr/include/sys/stat.h
-diskio-windows.o: /usr/include/bits/stat.h support.h /usr/include/stdlib.h
-diskio-windows.o: /usr/include/alloca.h diskio.h /usr/include/sys/ioctl.h
-diskio-windows.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-diskio-windows.o: /usr/include/asm-generic/ioctls.h
-diskio-windows.o: /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h
-diskio-windows.o: /usr/include/asm-generic/ioctl.h
-diskio-windows.o: /usr/include/bits/ioctl-types.h
-diskio-windows.o: /usr/include/sys/ttydefaults.h parttypes.h guid.h
-diskio-windows.o: /usr/include/uuid/uuid.h /usr/include/sys/time.h
-gdisk.o: /usr/include/stdio.h /usr/include/features.h
-gdisk.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-gdisk.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-gdisk.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-gdisk.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
-gdisk.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-gdisk.o: /usr/include/string.h /usr/include/xlocale.h mbr.h
-gdisk.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-gdisk.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
-gdisk.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-gdisk.o: /usr/include/sys/select.h /usr/include/bits/select.h
-gdisk.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-gdisk.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-gdisk.o: gptpart.h support.h /usr/include/stdlib.h /usr/include/alloca.h
-gdisk.o: parttypes.h guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h
-gdisk.o: attributes.h partnotes.h gpt.h bsd.h diskio.h
-gdisk.o: /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h
-gdisk.o: /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h
-gdisk.o: /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h
-gdisk.o: /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h
-gdisk.o: /usr/include/sys/ttydefaults.h gpttext.h
-gpt.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
-gpt.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
-gpt.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
-gpt.o: /usr/include/bits/typesizes.h /usr/include/libio.h
-gpt.o: /usr/include/_G_config.h /usr/include/wchar.h
-gpt.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-gpt.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
-gpt.o: /usr/include/endian.h /usr/include/bits/endian.h
-gpt.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-gpt.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-gpt.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-gpt.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-gpt.o: /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/fcntl.h
-gpt.o: /usr/include/bits/fcntl.h /usr/include/string.h /usr/include/xlocale.h
-gpt.o: /usr/include/math.h /usr/include/bits/huge_val.h
-gpt.o: /usr/include/bits/huge_valf.h /usr/include/bits/huge_vall.h
-gpt.o: /usr/include/bits/inf.h /usr/include/bits/nan.h
-gpt.o: /usr/include/bits/mathdef.h /usr/include/bits/mathcalls.h
-gpt.o: /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/errno.h
-gpt.o: /usr/include/bits/errno.h /usr/include/linux/errno.h
-gpt.o: /usr/include/asm/errno.h /usr/include/asm-generic/errno.h
-gpt.o: /usr/include/asm-generic/errno-base.h crc32.h gpt.h gptpart.h
-gpt.o: support.h parttypes.h guid.h /usr/include/uuid/uuid.h
-gpt.o: /usr/include/sys/time.h attributes.h mbr.h partnotes.h diskio.h
-gpt.o: /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h
-gpt.o: /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h
-gpt.o: /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h
-gpt.o: /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h
-gpt.o: /usr/include/sys/ttydefaults.h bsd.h
-gptpart.o: /usr/include/string.h /usr/include/features.h
-gptpart.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-gptpart.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-gptpart.o: /usr/include/xlocale.h /usr/include/stdio.h
-gptpart.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-gptpart.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
-gptpart.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-gptpart.o: gptpart.h /usr/include/stdint.h /usr/include/bits/wchar.h
-gptpart.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/endian.h
-gptpart.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-gptpart.o: /usr/include/sys/select.h /usr/include/bits/select.h
-gptpart.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-gptpart.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-gptpart.o: support.h /usr/include/stdlib.h /usr/include/alloca.h parttypes.h
-gptpart.o: guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h
-gptpart.o: attributes.h
-gpttext.o: /usr/include/string.h /usr/include/features.h
-gpttext.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-gpttext.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-gpttext.o: /usr/include/xlocale.h /usr/include/errno.h
-gpttext.o: /usr/include/bits/errno.h /usr/include/linux/errno.h
-gpttext.o: /usr/include/asm/errno.h /usr/include/asm-generic/errno.h
-gpttext.o: /usr/include/asm-generic/errno-base.h /usr/include/stdint.h
-gpttext.o: /usr/include/bits/wchar.h /usr/include/limits.h
-gpttext.o: /usr/include/bits/posix1_lim.h /usr/include/bits/local_lim.h
-gpttext.o: /usr/include/linux/limits.h /usr/include/bits/posix2_lim.h
-gpttext.o: attributes.h gpttext.h gpt.h /usr/include/sys/types.h
-gpttext.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-gpttext.o: /usr/include/time.h /usr/include/endian.h
-gpttext.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-gpttext.o: /usr/include/sys/select.h /usr/include/bits/select.h
-gpttext.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-gpttext.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-gpttext.o: gptpart.h support.h /usr/include/stdlib.h /usr/include/alloca.h
-gpttext.o: parttypes.h guid.h /usr/include/uuid/uuid.h
-gpttext.o: /usr/include/sys/time.h mbr.h partnotes.h diskio.h
-gpttext.o: /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h
-gpttext.o: /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h
-gpttext.o: /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h
-gpttext.o: /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h
-gpttext.o: /usr/include/sys/ttydefaults.h bsd.h
-guid.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
-guid.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
-guid.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
-guid.o: /usr/include/bits/typesizes.h /usr/include/libio.h
-guid.o: /usr/include/_G_config.h /usr/include/wchar.h
-guid.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-guid.o: /usr/include/time.h guid.h /usr/include/stdint.h
-guid.o: /usr/include/bits/wchar.h /usr/include/uuid/uuid.h
-guid.o: /usr/include/sys/types.h /usr/include/endian.h
-guid.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-guid.o: /usr/include/sys/select.h /usr/include/bits/select.h
-guid.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-guid.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-guid.o: /usr/include/sys/time.h support.h /usr/include/stdlib.h
-guid.o: /usr/include/alloca.h
-mbr.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
-mbr.o: /usr/include/bits/wordsize.h /usr/include/gnu/stubs.h
-mbr.o: /usr/include/gnu/stubs-64.h /usr/include/bits/types.h
-mbr.o: /usr/include/bits/typesizes.h /usr/include/libio.h
-mbr.o: /usr/include/_G_config.h /usr/include/wchar.h
-mbr.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-mbr.o: /usr/include/stdlib.h /usr/include/sys/types.h /usr/include/time.h
-mbr.o: /usr/include/endian.h /usr/include/bits/endian.h
-mbr.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-mbr.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-mbr.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-mbr.o: /usr/include/bits/pthreadtypes.h /usr/include/alloca.h
-mbr.o: /usr/include/stdint.h /usr/include/bits/wchar.h /usr/include/fcntl.h
-mbr.o: /usr/include/bits/fcntl.h /usr/include/string.h /usr/include/xlocale.h
-mbr.o: /usr/include/sys/stat.h /usr/include/bits/stat.h /usr/include/errno.h
-mbr.o: /usr/include/bits/errno.h /usr/include/linux/errno.h
-mbr.o: /usr/include/asm/errno.h /usr/include/asm-generic/errno.h
-mbr.o: /usr/include/asm-generic/errno-base.h mbr.h gptpart.h support.h
-mbr.o: parttypes.h guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h
-mbr.o: attributes.h partnotes.h gpt.h bsd.h diskio.h /usr/include/sys/ioctl.h
-mbr.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-mbr.o: /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h
-mbr.o: /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h
-mbr.o: /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h
-partnotes.o: /usr/include/stdio.h /usr/include/features.h
-partnotes.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-partnotes.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-partnotes.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-partnotes.o: /usr/include/libio.h /usr/include/_G_config.h
-partnotes.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-partnotes.o: /usr/include/bits/sys_errlist.h partnotes.h gpt.h
-partnotes.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-partnotes.o: /usr/include/sys/types.h /usr/include/time.h
-partnotes.o: /usr/include/endian.h /usr/include/bits/endian.h
-partnotes.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-partnotes.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-partnotes.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-partnotes.o: /usr/include/bits/pthreadtypes.h gptpart.h support.h
-partnotes.o: /usr/include/stdlib.h /usr/include/alloca.h parttypes.h guid.h
-partnotes.o: /usr/include/uuid/uuid.h /usr/include/sys/time.h attributes.h
-partnotes.o: mbr.h diskio.h /usr/include/sys/ioctl.h
-partnotes.o: /usr/include/bits/ioctls.h /usr/include/asm/ioctls.h
-partnotes.o: /usr/include/asm-generic/ioctls.h /usr/include/linux/ioctl.h
-partnotes.o: /usr/include/asm/ioctl.h /usr/include/asm-generic/ioctl.h
-partnotes.o: /usr/include/bits/ioctl-types.h /usr/include/sys/ttydefaults.h
-partnotes.o: bsd.h
-parttypes.o: /usr/include/string.h /usr/include/features.h
-parttypes.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-parttypes.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-parttypes.o: /usr/include/xlocale.h /usr/include/stdint.h
-parttypes.o: /usr/include/bits/wchar.h /usr/include/stdio.h
-parttypes.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-parttypes.o: /usr/include/libio.h /usr/include/_G_config.h
-parttypes.o: /usr/include/wchar.h /usr/include/bits/stdio_lim.h
-parttypes.o: /usr/include/bits/sys_errlist.h parttypes.h
-parttypes.o: /usr/include/stdlib.h /usr/include/sys/types.h
-parttypes.o: /usr/include/time.h /usr/include/endian.h
-parttypes.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-parttypes.o: /usr/include/sys/select.h /usr/include/bits/select.h
-parttypes.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-parttypes.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-parttypes.o: /usr/include/alloca.h support.h guid.h /usr/include/uuid/uuid.h
-parttypes.o: /usr/include/sys/time.h
-sgdisk.o: /usr/include/stdio.h /usr/include/features.h
-sgdisk.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-sgdisk.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-sgdisk.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-sgdisk.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
-sgdisk.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-sgdisk.o: /usr/include/popt.h /usr/include/errno.h /usr/include/bits/errno.h
-sgdisk.o: /usr/include/linux/errno.h /usr/include/asm/errno.h
-sgdisk.o: /usr/include/asm-generic/errno.h
-sgdisk.o: /usr/include/asm-generic/errno-base.h /usr/include/stdint.h
-sgdisk.o: /usr/include/bits/wchar.h mbr.h /usr/include/sys/types.h
-sgdisk.o: /usr/include/time.h /usr/include/endian.h
-sgdisk.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-sgdisk.o: /usr/include/sys/select.h /usr/include/bits/select.h
-sgdisk.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-sgdisk.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-sgdisk.o: gptpart.h support.h /usr/include/stdlib.h /usr/include/alloca.h
-sgdisk.o: parttypes.h guid.h /usr/include/uuid/uuid.h /usr/include/sys/time.h
-sgdisk.o: attributes.h partnotes.h gpt.h bsd.h diskio.h
-sgdisk.o: /usr/include/sys/ioctl.h /usr/include/bits/ioctls.h
-sgdisk.o: /usr/include/asm/ioctls.h /usr/include/asm-generic/ioctls.h
-sgdisk.o: /usr/include/linux/ioctl.h /usr/include/asm/ioctl.h
-sgdisk.o: /usr/include/asm-generic/ioctl.h /usr/include/bits/ioctl-types.h
-sgdisk.o: /usr/include/sys/ttydefaults.h
-support.o: /usr/include/stdio.h /usr/include/features.h
-support.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-support.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-support.o: /usr/include/bits/types.h /usr/include/bits/typesizes.h
-support.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h
-support.o: /usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h
-support.o: /usr/include/stdint.h /usr/include/bits/wchar.h
-support.o: /usr/include/errno.h /usr/include/bits/errno.h
-support.o: /usr/include/linux/errno.h /usr/include/asm/errno.h
-support.o: /usr/include/asm-generic/errno.h
-support.o: /usr/include/asm-generic/errno-base.h /usr/include/fcntl.h
-support.o: /usr/include/bits/fcntl.h /usr/include/sys/types.h
-support.o: /usr/include/time.h /usr/include/endian.h
-support.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
-support.o: /usr/include/sys/select.h /usr/include/bits/select.h
-support.o: /usr/include/bits/sigset.h /usr/include/bits/time.h
-support.o: /usr/include/sys/sysmacros.h /usr/include/bits/pthreadtypes.h
-support.o: /usr/include/string.h /usr/include/xlocale.h
-support.o: /usr/include/sys/stat.h /usr/include/bits/stat.h support.h
-support.o: /usr/include/stdlib.h /usr/include/alloca.h
-testguid.o: guid.h /usr/include/stdint.h /usr/include/features.h
-testguid.o: /usr/include/sys/cdefs.h /usr/include/bits/wordsize.h
-testguid.o: /usr/include/gnu/stubs.h /usr/include/gnu/stubs-64.h
-testguid.o: /usr/include/bits/wchar.h /usr/include/uuid/uuid.h
-testguid.o: /usr/include/sys/types.h /usr/include/bits/types.h
-testguid.o: /usr/include/bits/typesizes.h /usr/include/time.h
-testguid.o: /usr/include/endian.h /usr/include/bits/endian.h
-testguid.o: /usr/include/bits/byteswap.h /usr/include/sys/select.h
-testguid.o: /usr/include/bits/select.h /usr/include/bits/sigset.h
-testguid.o: /usr/include/bits/time.h /usr/include/sys/sysmacros.h
-testguid.o: /usr/include/bits/pthreadtypes.h /usr/include/sys/time.h
-testguid.o: parttypes.h /usr/include/stdlib.h /usr/include/alloca.h support.h
diff --git a/Makefile.mac b/Makefile.mac
index 9c55308..c9fe488 100644
--- a/Makefile.mac
+++ b/Makefile.mac
@@ -2,13 +2,15 @@ CC=gcc
CXX=g++
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
-LIB_NAMES=crc32 support guid partnotes gptpartnotes gptpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
-LIB_SRCS=$(NAMES:=.cc)
+LIB_NAMES=crc32 support guid gptpart mbrpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
+MBR_LIBS=support diskio diskio-unix basicmbr mbrpart
+#LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
+MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CFLAGS)
-all: gdisk sgdisk
+all: gdisk sgdisk fixparts
gdisk: $(LIB_OBJS) gpttext.o gdisk.o
$(CXX) $(LIB_OBJS) gpttext.o gdisk.o -o gdisk
@@ -16,6 +18,9 @@ gdisk: $(LIB_OBJS) gpttext.o gdisk.o
sgdisk: $(LIB_OBJS) sgdisk.o
$(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -lpopt -o sgdisk
+fixparts: $(MBR_LIB_OBJS) fixparts.o
+ $(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -o fixparts
+
testguid: $(LIB_OBJS) testguid.o
$(CXX) $(LIB_OBJS) testguid.o -o testguid
diff --git a/Makefile.mingw b/Makefile.mingw
index 9f3a9a3..70c8eda 100644
--- a/Makefile.mingw
+++ b/Makefile.mingw
@@ -4,19 +4,24 @@ STRIP=/usr/bin/i686-pc-mingw32-strip
CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g
CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -g
#CXXFLAGS=-O2 -Wall -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g
-LIB_NAMES=guid gptpart bsd parttypes partnotes gptpartnotes attributes crc32 basicmbr mbr gpt support diskio diskio-windows
+LIB_NAMES=guid gptpart bsd parttypes attributes crc32 mbrpart basicmbr mbr gpt support diskio diskio-windows
+MBR_LIBS=support diskio diskio-windows basicmbr mbrpart
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
+MBR_LIB_OBJS=$(MBR_LIBS:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
DEPEND= makedepend $(CFLAGS)
-all: gdisk
+all: gdisk fixparts
gdisk: $(LIB_OBJS) gdisk.o gpttext.o
$(CXX) $(LIB_OBJS) gdisk.o gpttext.o -luuid -static-libgcc -o gdisk.exe
sgdisk: $(LIB_OBJS) sgdisk.o
- $(CXX) $(LIB_OBJS) sgdisk.o -lpopt -o sgdisk.exe
+ $(CXX) $(LIB_OBJS) sgdisk.o -lpopt -static-libgcc -o sgdisk.exe
+
+fixparts: $(MBR_LIB_OBJS) fixparts.o
+ $(CXX) $(MBR_LIB_OBJS) fixparts.o $(LDFLAGS) -static-libgcc -o fixparts.exe
lint: #no pre-reqs
lint $(SRCS)
@@ -25,7 +30,7 @@ clean: #no pre-reqs
rm -f core *.o *~ gdisk.exe sgdisk.exe
strip: #no pre-reqs
- $(STRIP) gdisk.exe
+ $(STRIP) gdisk.exe fixparts.exe
# what are the source dependencies
depend: $(SRCS)
diff --git a/NEWS b/NEWS
index e90d99b..e3a0499 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,23 @@
-0.6.15 (?/?/2011):
+0.7.0 (3/11/2011):
------------------
+- Fixed bug that caused some types of logical partitions to be misread.
+
+- Created FixParts program, to fix problems on MBR-partitioned disks.
+ Although this program is part of the GPT fdisk family, it is NOT used on
+ GPT disks.
+
+- Completely redid the GPT-to-MBR code, used both for converting to MBR
+ form and for creating hybrid MBRs.
+
+- Fixed a bug that caused gdisk to "forget" some partitions if there were
+ numbering gaps when a conversion to MBR was aborted.
+
+- Improved CHS value creation on small (<~8GB) disks for protective MBR
+ and when creating hybrid MBRs or converting to MBR format. Linux-only,
+ for the moment; other platforms still produce bad CHS values on sub-~8GB
+ disks (but few OSes care these days).
+
- Enhanced disk replication features ('u' on the experts' menu in gdisk; -R
or --replicate in sgdisk). It's now possible to replicate the partition
table from a larger to a smaller disk, so long as all the partitions fit
@@ -15,11 +32,10 @@
- Changed largest drive that's not given a minimum 4 KiB alignment even
when smaller alignment is detected on the disk to 300 GB.
-- Fixed bug that preventing a partition table backup ('u' on the
+- Fixed bug that prevented aborting a partition table backup ('u' on the
experts' menu) by hitting the Enter key for the device filename.
-- Implemented a number of code cleanups provided by an anonymous
- contributor.
+- Implemented a number of code cleanups provided by Florian Zumbiehl.
0.6.14 (1/8/2011):
------------------
diff --git a/README b/README
index bca2f0e..0cda714 100644
--- a/README
+++ b/README
@@ -1,14 +1,49 @@
-GPT fdisk (aka gdisk)
+GPT fdisk (aka gdisk and sgdisk) and FixParts
by Roderick W. Smith, rodsmith@rodsbooks.com
Introduction
------------
-This software is intended as a (somewhat) fdisk-workalike program for
-GPT-partitioned disks. Although libparted and programs that use it (GNU
-Parted, gparted, etc.) provide the ability to handle GPT disks, they have
-certain limitations that gdisk overcomes. Specific advantages of gdisk and
-sgdisk include:
+This binary archive includes the source code for three related disk
+partitioning programs:
+
+- gdisk -- This program is modeled after Linux fdisk, but it operates on
+ GUID Partition Table (GPT) disks rather than the Master Boot Record (MBR)
+ disks that fdisk modifies. As such, gdisk is an interactive text-mode
+ tool for manipulating partitions, but it does nothing to the contents of
+ those partitions (usually filesystems, but sometimes swap space or other
+ data).
+
+- sgdisk -- This program is conceptually similar to the Linux sfdisk and
+ FreeBSD gpt programs, but its operational details differ. It enables
+ manipulation of GPT disks using command-line options, so it's suitable
+ for use in scripts or by experts to perform specific tasks that might
+ take several commands in gdisk to accomplish.
+
+- fixparts -- This program, unlike the preceding two, operates on MBR
+ disks. It's intended to fix certain problems that can be created by
+ various utilities. Specifically, it can fix mis-sized extended partitions
+ and primary partitions located in the middle of extended partitions. It
+ also enables changing primary vs. logical partition status (within limits
+ of what's legal in the MBR scheme) and making a few other minor changes.
+ It does NOT support creating new partitions; for that, you should use
+ fdisk, parted, or some other tool.
+
+More details about the abilities of these tools follows.
+
+All three programs rely on the same set of underlying code base; they
+differ only in their control interfaces (defined in gdisk.cc, sgdisk.cc,
+and fixparts.cc, respectively) and in which support code they use.
+
+GPT fdisk (gdisk and sgdisk) Details
+------------------------------------
+
+The gdisk program is intended as a (somewhat) fdisk-workalike program for
+GPT-partitioned disks, and sgdisk provides most of gdisk's functionality in
+a more script-friendly program. Although libparted and programs that use it
+(GNU Parted, gparted, etc.) provide the ability to handle GPT disks, they
+have certain limitations that gdisk overcomes. Specific advantages of gdisk
+and sgdisk include:
* The ability to convert MBR-partitioned disks in-place to GPT format,
without losing data
@@ -16,10 +51,10 @@ sgdisk include:
* The ability to convert BSD disklabels in-place to create GPT
partitions, without losing data
-* The ability to specify sector-exact partition sizes
+* The ability to convert from GPT format to MBR format without data loss
* More flexible specification of filesystem type code GUIDs, which
- GNU Parted tends to corrupt (particularly for FAT partitions)
+ GNU Parted tends to corrupt
* Clear identification of the number of unallocated sectors on a
disk
@@ -45,12 +80,81 @@ manually partitioning disks or changing partitioning details; the latter is
intended for use in scripts to help automate tasks such as disk cloning or
preparing multiple disks for Linux installation.
+FixParts Details
+----------------
+
+This program's creation was motivated by cries for help I've seen in online
+forums from users who have found their partition tables to be corrupted by
+various buggy partitioning tools. Although most OSes can handle the
+afflicted disks fine, libparted-based tools (GParted, parted, most Linux
+installers, etc.) tend to flake out when presented with these disks.
+Typically, the symptom is a disk that appears to hold no partitions;
+however, sometimes the libparted tool presents partitions other than those
+that the OS sees.
+
+I've observed four causes of these symptoms, three of which FixParts can
+correct:
+
+- Old GPT data -- If a disk is used as a GPT disk and then re-used as an
+ MBR disk, the GPT data may be incompletely erased. This happens if the
+ disk is repartitioned with fdisk or the Microsoft Windows installer, for
+ instance. (Tools based on libparted correctly remove the old GPT data
+ when converting from GPT to MBR format.) FixParts checks for this problem
+ when it starts and offers to correct it. If you opt to erase the GPT
+ data, this erasure occurs immediately, unlike other changes the program
+ makes.
+
+- Mis-sized extended partitions -- Some tools create an extended partition
+ that's too large, typically ending after the last sector of the disk.
+ FixParts automatically corrects this problem (if you use the 'w' option
+ to save the partition table).
+
+- Primary partitions inside an extended partition -- Some utilities create
+ or move primary partitions to within the range covered by the extended
+ partition. FixParts can usually correct this problem by turning the
+ primary partition into a logical partition or by changing one or more
+ other logical partitions into primaries. Such corrections aren't always
+ possible, though, at least not without deleting or resizing other
+ partitions.
+
+- Leftover RAID data -- If a disk is used in a RAID array and then re-used
+ as a non-RAID disk, some utilities can become confused and fail to see
+ the disk. FixParts can NOT correct this problem. You must destroy the old
+ RAID data, or possibly remove the dmraid package from the system, to fix
+ this problem.
+
+When run, FixParts presents an fdisk-like interface, enabling you to adjust
+partition types (primary, logical, or omitted), change type codes, change
+the bootable flag, and so on. Although you can delete a partition (by
+omitting it), you can't create new partitions with the program. If you're
+used to partitioning disks, particularly with Linux fdisk, two unusual
+features of FixParts require elaboration:
+
+- No extended partitions -- Internally, FixParts reads the partition table
+ and discards data on any extended partition(s) it finds. When you save
+ the partition table, the program generates a new extended partition. This
+ design means that the program automatically corrects many problems
+ related to the extended partition. It also means that you'll see no
+ evidence of extended partitions in the FixParts user interface, although
+ it keeps track of the requirements and prevents you from creating illegal
+ layouts, such as a primary between two logicals.
+
+- Partition numbering -- In most Linux tools, partitions 1-4 are primaries
+ and partitions 5 and up are logicals. Although a legal partition table
+ loaded into FixParts will initially conform to this convention, some
+ types of damaged table might not, and various changes you make can also
+ cause deviations. When FixParts writes the partition table, its numbering
+ will be altered to conform to the standard MBR conventions, but you
+ should use the explicit labeling of partitions as primary or logical
+ rather than the partition numbers to determine a partition's status.
+
Installing
----------
To compile GPT fdisk, you must have appropriate development tools
installed, most notably the GNU Compiler Collection (GCC) and its g++
-compiler for C++. In addition, note these requirements:
+compiler for C++. (Under Windows, Microsoft Visual C++ 2008 can also be
+used.) In addition, note these requirements:
* On Linux, FreeBSD, and OS X, libuuid must be installed. This is the
standard for Linux and OS X, although you may need to install a package
@@ -73,11 +177,11 @@ X, "make -f Makefile.freebsd" on FreeBSD, or "make -f Makefile.mingw" to
compile using MinGW for Windows.) You may also need to add header (include)
directories or library directories by setting the CXXFLAGS environment
variable or by editing the Makefile. The result should be program files
-called gdisk and sgdisk. Typing "make gdisk" or "make sgdisk" will compile
-only the requested programs. You can use these programs in place or copy
-the files to a suitable directory, such as /usr/local/sbin. You can copy
-the man pages (gdisk.8 and sgdisk.8) to /usr/local/man/man8 to make them
-available.
+called gdisk, sgdisk, and fixparts. Typing "make gdisk", "make sgdisk", or
+"make fixparts" will compile only the requested programs. You can use these
+programs in place or copy the files to a suitable directory, such as
+/usr/local/sbin. You can copy the man pages (gdisk.8, sgdisk.8, and
+fixparts.8) to /usr/local/man/man8 to make them available.
Caveats
-------
@@ -85,19 +189,17 @@ Caveats
THIS SOFTWARE IS BETA SOFTWARE! IF IT WIPES OUT YOUR HARD DISK OR EATS YOUR
CAT, DON'T BLAME ME! To date, I've tested the software on several USB flash
drives, a handful of PATA and SATA hard disks, and several virtual disks in
-a QEMU environment. I believe all data-corruption bugs to be squashed, but
-I know full well that the odds of my missing something are high. This is
-particularly true for large drives; my only direct testing with such disks
-is with virtual QEMU disks. I've received user reports of success with
-RAID arrays over 2TiB in size, though.
+the QEMU and VirtualBox environments. Many others have now used the
+software on their computers, as well. I believe all data-corruption bugs to
+be squashed, but I know full well that the odds of my missing something are
+high. This is particularly true for large drives; my only direct testing
+with such disks is with virtual QEMU disks. I've received user reports of
+success with RAID arrays over 2TiB in size, though.
My main development platform is a system running the 64-bit version of
-Gentoo Linux (previously Ubuntu 8.04). I've also tested on 64-bit OpenSuSE,
-32-bit Fedora 10, 32-bit Fedora 11, 32-bit Ubuntu 6.10, 64-bit Ubunut 9.10,
-32-bit PowerPC Debian Linux, 32-bit Intel-based Mac OS X 10.5 and 10.6,
-64-bit FreeBSD 7.1, and Windows 7. Problems relating to 64-bit integers on
-the 32-bit Linux have been common during development and may crop up in the
-future.
+Gentoo Linux (previously Ubuntu 8.04). I've also tested on several other
+32- and 64-bit Linux distributions Intel-based Mac OS X 10.5 and 10.6,
+64-bit FreeBSD 7.1, and Windows 7.
Redistribution
--------------
@@ -122,3 +224,9 @@ Additional code contributors include:
- Yves Blusseau (1otnwmz02@sneakemail.com)
- David Hubbard (david.c.hubbard@gmail.com)
+
+- Justin Maggard (justin.maggard@netgear.com)
+
+- Dwight Schauer (dschauer@ti.com)
+
+- Florian Zumbiehl (florz@florz.de)
diff --git a/README.Windows b/README.Windows
index 4ff6011..fa57484 100644
--- a/README.Windows
+++ b/README.Windows
@@ -1,20 +1,21 @@
-GPT fdisk (aka gdisk)
+GPT fdisk (aka gdisk) and FixParts
by Roderick W. Smith, rodsmith@rodsbooks.com
******************************** IMPORTANT ********************************
-Most versions of Windows cannot boot from a GPT disk, and most varieties
-prior to Vista cannot read GPT disks. GPT fdisk is a partition editor for
-GPT disks, and it will *AUTOMATICALLY CONVERT* MBR disks to GPT form.
-Therefore, you should **NOT** use GPT fdisk on a Windows system unless you
-fully understand what you're doing! If you accidentally use GPT fdisk on
-your boot disk, or perhaps even on a data disk, you may find recovery to be
-very difficult!
+Most versions of Windows cannot boot from a GPT disk on BIOS-based
+computers, and most varieties prior to Vista cannot read GPT disks. GPT
+fdisk is a partition editor for GPT disks, and it will *AUTOMATICALLY
+CONVERT* MBR disks to GPT form. Therefore, you should **NOT** use GPT fdisk
+on a Windows system unless you fully understand what you're doing! If you
+accidentally use GPT fdisk on your boot disk, or perhaps even on a data
+disk, you may find recovery to be very difficult! This caveat does not
+apply to FixParts, though; that tool works only on MBR disks.
***************************************************************************
Read the main README file for general information on the program, and read
-the gdisk.html document (the Linux man page converted to HTML format) for
-detailed use information. My GPT fdisk Web page,
+the gdisk.html or fixparts.html documents (the Linux man pages converted to
+HTML format) for detailed use information. My GPT fdisk Web page,
http://www.rodsbooks.com/gdisk/, provides a more tutorial introduction to
the software. I originally wrote GPT fdisk on Linux, and some Linux- and
Unix-centric language remains in the documentation.
@@ -31,11 +32,18 @@ attempted to do this myself, though. If you care to try, check
http://gnuwin32.sourceforge.net/packages/popt.htm for information on popt
for Windows.
-To install the program, copy the gdisk.exe program file to any directory on
-your path, such as C:\Windows. Alternatively, you can change to the
-program's directory or type its complete path whenever you use it.
+The FixParts program (fixparts.txt) is new with GPT fdisk 0.7.0. As
+described in the main README file, this program fixes certain partition
+table problems that can be created by buggy partitioning software. Windows
+seems to be unfazed by most such problems, but I've not done an extensive
+survey of Windows partitioning tools on this score.
-To use the program, first launch a Command Prompt as the Administrator. To
+To install the programs, copy the gdisk.exe and fixparts.exe program files
+to any directory on your path, such as C:\Windows. Alternatively, you can
+change to the program's directory or type its complete path whenever you
+use it.
+
+To use the programs, first launch a Command Prompt as the Administrator. To
do this, locate the Command Prompt program icon, right-click it, and select
"Run as Administrator." If you use a non-Administrator Command Prompt, you
won't be able to edit hard disk partition tables, although you will be able
@@ -57,10 +65,10 @@ This command is equivalent to the earlier one -- it edits the partition
table on the first physical disk. Change the number at the end of the
device name to change the disk edited.
-If you pass the "-l" option in addition to the disk identifier, the program
-displays the current partition table information and then exits. This use
-entails no risk to MBR disks, since the program never writes data back to
-the disk when used in this way.
+If you pass the "-l" option to gdisk.exe in addition to the disk
+identifier, the program displays the current partition table information
+and then exits. This use entails no risk to MBR disks, since the program
+never writes data back to the disk when used in this way.
As noted above, editing the first disk with GPT fdisk is usually a Bad
Idea. An exception would be if your system uses an Extensible Firmware
@@ -71,14 +79,14 @@ support of GPT, see Microsoft's Web page on the topic:
http://www.microsoft.com/whdc/device/storage/GPT_FAQ.mspx
-The GUIDs generated by the program to uniquely identify disks and
-partitions aren't "proper" GUIDs; they're purely random numbers. In
-practice, this has caused me no problems; however, it's conceivable that
-some disk utility will complain. The Unix versions of GPT fdisk generate
-proper GUIDs, as of version 0.6.3. Note that this limitation applies ONLY
-to the unique GUIDs for disks and partitions, not to the GUIDs used to
-identify partition type codes; those are standardized and are handled
-correctly by all versions of GPT fdisk.
+The GUIDs generated by gdisk to uniquely identify disks and partitions
+aren't "proper" GUIDs; they're purely random numbers. In practice, this has
+caused me no problems; however, it's conceivable that some disk utility
+will complain. The Unix versions of GPT fdisk generate proper GUIDs, as of
+version 0.6.3. Note that this limitation applies ONLY to the unique GUIDs
+for disks and partitions, not to the GUIDs used to identify partition type
+codes; those are standardized and are handled correctly by all versions of
+GPT fdisk.
Source Code and Compilation Issues
----------------------------------
@@ -98,7 +106,8 @@ compilers:
third-party stdint.h file (I used the one from
http://msinttypes.googlecode.com/svn/trunk/stdint.h), but it otherwise
works fine. A project is easily created by adding all the *.h files and
- all the *.cc files except diskio-unix.cc and sgdisk.cc.
+ all the *.cc files except diskio-unix.cc, sgdisk.cc, and whichever
+ program file you intend to NOT build (gdisk.cc or fixparts.cc).
The MinGW compiler produces much larger executables than does the MS
compiler. The resulting binaries seem to work equally well, but my testing
diff --git a/basicmbr.cc b/basicmbr.cc
index 6a8d103..764daaf 100644
--- a/basicmbr.cc
+++ b/basicmbr.cc
@@ -3,7 +3,7 @@
/* Initial coding by Rod Smith, January to February, 2009 */
-/* This program is copyright (c) 2009 by Roderick W. Smith. It is distributed
+/* This program is copyright (c) 2009-2011 by Roderick W. Smith. It is distributed
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#define __STDC_LIMIT_MACROS
@@ -19,7 +19,6 @@
#include <errno.h>
#include <iostream>
#include "mbr.h"
-#include "partnotes.h"
#include "support.h"
using namespace std;
@@ -35,7 +34,6 @@ BasicMBRData::BasicMBRData(void) {
diskSize = 0;
device = "";
state = invalid;
- srand((unsigned int) time(NULL));
numHeads = MAX_HEADS;
numSecspTrack = MAX_SECSPERTRACK;
myDisk = NULL;
@@ -53,7 +51,6 @@ BasicMBRData::BasicMBRData(string filename) {
myDisk = NULL;
canDeleteMyDisk = 0;
- srand((unsigned int) time(NULL));
// Try to read the specified partition table, but if it fails....
if (!ReadMBRData(filename)) {
EmptyMBR();
@@ -73,8 +70,7 @@ BasicMBRData::~BasicMBRData(void) {
BasicMBRData & BasicMBRData::operator=(const BasicMBRData & orig) {
int i;
- for (i = 0; i < 440; i++)
- code[i] = orig.code[i];
+ memcpy(code, orig.code, 440);
diskSignature = orig.diskSignature;
nulls = orig.nulls;
MBRSignature = orig.MBRSignature;
@@ -87,7 +83,8 @@ BasicMBRData & BasicMBRData::operator=(const BasicMBRData & orig) {
state = orig.state;
myDisk = new DiskIO;
- myDisk->OpenForRead(orig.myDisk->GetName());
+ if (orig.myDisk != NULL)
+ myDisk->OpenForRead(orig.myDisk->GetName());
for (i = 0; i < MAX_MBR_PARTS; i++) {
partitions[i] = orig.partitions[i];
@@ -128,11 +125,11 @@ int BasicMBRData::ReadMBRData(const string & deviceFilename) {
// in the partitions[] array, along with their contained partitions; the
// extended container partition(s) should be ignored by other functions.
int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
- int allOK = 1, i, j, logicalNum;
+ int allOK = 1, i, logicalNum = 0;
int err = 1;
TempMBR tempMBR;
- if ((myDisk != NULL) && (canDeleteMyDisk)) {
+ if ((myDisk != NULL) && (myDisk != theDisk) && (canDeleteMyDisk)) {
delete myDisk;
canDeleteMyDisk = 0;
} // if
@@ -153,16 +150,12 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
diskSignature = tempMBR.diskSignature;
nulls = tempMBR.nulls;
for (i = 0; i < 4; i++) {
- partitions[i].status = tempMBR.partitions[i].status;
- partitions[i].partitionType = tempMBR.partitions[i].partitionType;
- partitions[i].firstLBA = tempMBR.partitions[i].firstLBA;
- partitions[i].lengthLBA = tempMBR.partitions[i].lengthLBA;
- for (j = 0; j < 3; j++) {
- partitions[i].firstSector[j] = tempMBR.partitions[i].firstSector[j];
- partitions[i].lastSector[j] = tempMBR.partitions[i].lastSector[j];
- } // for j... (reading parts of CHS geometry)
+ partitions[i] = tempMBR.partitions[i];
+ if (partitions[i].GetLengthLBA() > 0)
+ partitions[i].SetInclusion(PRIMARY);
} // for i... (reading all four partitions)
MBRSignature = tempMBR.MBRSignature;
+ ReadCHSGeom();
// Reverse the byte order, if necessary
if (IsLittleEndian() == 0) {
@@ -170,8 +163,7 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
ReverseBytes(&nulls, 2);
ReverseBytes(&MBRSignature, 2);
for (i = 0; i < 4; i++) {
- ReverseBytes(&partitions[i].firstLBA, 4);
- ReverseBytes(&partitions[i].lengthLBA, 4);
+ partitions[i].ReverseByteOrder();
} // for
} // if
@@ -191,14 +183,15 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
// Load logical partition data, if any is found....
if (allOK) {
for (i = 0; i < 4; i++) {
- if ((partitions[i].partitionType == 0x05) || (partitions[i].partitionType == 0x0f)
- || (partitions[i].partitionType == 0x85)) {
+ if ((partitions[i].GetType() == 0x05) || (partitions[i].GetType() == 0x0f)
+ || (partitions[i].GetType() == 0x85)) {
// Found it, so call a recursive algorithm to load everything from them....
- logicalNum = ReadLogicalPart(partitions[i].firstLBA, UINT32_C(0), 4);
+ logicalNum = ReadLogicalPart(partitions[i].GetStartLBA(), UINT32_C(0), 4);
if ((logicalNum < 0) || (logicalNum >= MAX_MBR_PARTS)) {
allOK = 0;
cerr << "Error reading logical partitions! List may be truncated!\n";
} // if maxLogicals valid
+ DeletePartition(i);
} // if primary partition is extended
} // for primary partition loop
if (allOK) { // Loaded logicals OK
@@ -211,7 +204,7 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
// Check to see if it's in GPT format....
if (allOK) {
for (i = 0; i < 4; i++) {
- if (partitions[i].partitionType == UINT8_C(0xEE)) {
+ if (partitions[i].GetType() == UINT8_C(0xEE)) {
state = gpt;
} // if
} // for
@@ -221,9 +214,12 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
// to flag as hybrid
if (state == gpt) {
for (i = 0 ; i < 4; i++) {
- if ((partitions[i].partitionType != UINT8_C(0xEE)) &&
- (partitions[i].partitionType != UINT8_C(0x00)))
+ if ((partitions[i].GetType() != UINT8_C(0xEE)) &&
+ (partitions[i].GetType() != UINT8_C(0x00)))
state = hybrid;
+ if (logicalNum > 0)
+ cerr << "Warning! MBR Logical partitions found on a hybrid MBR disk! This is an\n"
+ << "EXTREMELY dangerous configuration!\n\a";
} // for
} // if (hybrid detection code)
} // no initial error
@@ -238,13 +234,14 @@ int BasicMBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
// extendedStart = LBA of the start of the extended partition
// diskOffset = LBA offset WITHIN the extended partition of the one to be read
// partNum = location in partitions[] array to store retrieved data
-int BasicMBRData::ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset, int partNum) {
+int BasicMBRData::ReadLogicalPart(uint64_t extendedStart, uint64_t diskOffset, int partNum) {
struct TempMBR ebr;
+ uint8_t ebrType;
uint64_t offset;
// Check for a valid partition number. Note that partitions MAY be read into
// the area normally used by primary partitions, although the only calling
- // function as of GPT fdisk version 0.5.0 doesn't do so.
+ // functions as of GPT fdisk version 0.7.0 don't do so.
if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
offset = (uint64_t) (extendedStart + diskOffset);
if (myDisk->Seek(offset) == 0) { // seek to EBR record
@@ -275,20 +272,29 @@ int BasicMBRData::ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset, i
cerr.fill(' ');
} // if
- // Copy over the basic data....
- partitions[partNum].status = ebr.partitions[0].status;
- partitions[partNum].firstLBA = ebr.partitions[0].firstLBA + diskOffset + extendedStart;
- partitions[partNum].lengthLBA = ebr.partitions[0].lengthLBA;
- partitions[partNum].partitionType = ebr.partitions[0].partitionType;
-
- // Find the next partition (if there is one) and recurse....
- if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
- (partNum < (MAX_MBR_PARTS - 1))) {
- partNum = ReadLogicalPart(extendedStart, ebr.partitions[1].firstLBA,
- partNum + 1);
+ // Sometimes an EBR points directly to another EBR, rather than defining
+ // a logical partition and then pointing to another EBR. Thus, we recurse
+ // directly if this is detected, else extract partition data and then
+ // recurse on the second entry in the EBR...
+ ebrType = ebr.partitions[0].partitionType;
+ if ((ebrType == 0x05) || (ebrType == 0x0f) || (ebrType == 0x85)) {
+ partNum = ReadLogicalPart(extendedStart, ebr.partitions[0].firstLBA, partNum);
} else {
- partNum++;
- } // if another partition
+ // Copy over the basic data....
+ partitions[partNum] = ebr.partitions[0];
+ // Adjust the start LBA, since it's encoded strangely....
+ partitions[partNum].SetStartLBA(ebr.partitions[0].firstLBA + diskOffset + extendedStart);
+ partitions[partNum].SetInclusion(LOGICAL);
+
+ // Find the next partition (if there is one) and recurse....
+ if ((ebr.partitions[1].firstLBA != UINT32_C(0)) && (partNum >= 4) &&
+ (partNum < (MAX_MBR_PARTS - 1))) {
+ partNum = ReadLogicalPart(extendedStart, ebr.partitions[1].firstLBA,
+ partNum + 1);
+ } else {
+ partNum++;
+ } // if another partition
+ } // if/else
} // Not enough space for all the logicals (or previous error encountered)
return (partNum);
} // BasicMBRData::ReadLogicalPart()
@@ -302,6 +308,7 @@ int BasicMBRData::WriteMBRData(void) {
if (myDisk != NULL) {
if (myDisk->OpenForWrite() != 0) {
allOK = WriteMBRData(myDisk);
+ cout << "Done writing data!\n";
} else {
allOK = 0;
} // if/else
@@ -311,35 +318,29 @@ int BasicMBRData::WriteMBRData(void) {
} // BasicMBRData::WriteMBRData(void)
// Save the MBR data to a file. This writes both the
-// MBR itself and any defined logical partitions, provided there's an
-// MBR extended partition.
+// MBR itself and any defined logical partitions.
int BasicMBRData::WriteMBRData(DiskIO *theDisk) {
- int i, j, partNum, allOK, moreLogicals = 0;
- uint32_t extFirstLBA = 0;
+ int i, j, partNum, next, allOK = 1, moreLogicals = 0;
+ uint64_t extFirstLBA = 0;
uint64_t writeEbrTo; // 64-bit because we support extended in 2-4TiB range
TempMBR tempMBR;
- // First write the main MBR data structure....
- for (i = 0; i < 440; i++)
- tempMBR.code[i] = code[i];
- tempMBR.diskSignature = diskSignature;
- tempMBR.nulls = nulls;
- tempMBR.MBRSignature = MBRSignature;
- for (i = 0; i < 4; i++) {
- tempMBR.partitions[i].status = partitions[i].status;
- tempMBR.partitions[i].partitionType = partitions[i].partitionType;
- tempMBR.partitions[i].firstLBA = partitions[i].firstLBA;
- tempMBR.partitions[i].lengthLBA = partitions[i].lengthLBA;
- for (j = 0; j < 3; j++) {
- tempMBR.partitions[i].firstSector[j] = partitions[i].firstSector[j];
- tempMBR.partitions[i].lastSector[j] = partitions[i].lastSector[j];
- } // for j...
- if (partitions[i].partitionType == 0x0f) {
- extFirstLBA = partitions[i].firstLBA;
- moreLogicals = 1;
- } // if
- } // for i...
- allOK = WriteMBRData(tempMBR, theDisk, 0);
+ allOK = CreateExtended();
+ if (allOK) {
+ // First write the main MBR data structure....
+ memcpy(tempMBR.code, code, 440);
+ tempMBR.diskSignature = diskSignature;
+ tempMBR.nulls = nulls;
+ tempMBR.MBRSignature = MBRSignature;
+ for (i = 0; i < 4; i++) {
+ partitions[i].StoreInStruct(&tempMBR.partitions[i]);
+ if (partitions[i].GetType() == 0x0f) {
+ extFirstLBA = partitions[i].GetStartLBA();
+ moreLogicals = 1;
+ } // if
+ } // for i...
+ } // if
+ allOK = allOK && WriteMBRData(tempMBR, theDisk, 0);
// Set up tempMBR with some constant data for logical partitions...
tempMBR.diskSignature = 0;
@@ -352,17 +353,18 @@ int BasicMBRData::WriteMBRData(DiskIO *theDisk) {
} // for j
} // for i
- partNum = 4;
+ partNum = FindNextInUse(4);
writeEbrTo = (uint64_t) extFirstLBA;
- // If extended partition is present, write logicals...
+ // Write logicals...
while (allOK && moreLogicals && (partNum < MAX_MBR_PARTS)) {
- tempMBR.partitions[0] = partitions[partNum];
- tempMBR.partitions[0].firstLBA = 1; // partition starts on sector after EBR
+ partitions[partNum].StoreInStruct(&tempMBR.partitions[0]);
+ tempMBR.partitions[0].firstLBA = 1;
// tempMBR.partitions[1] points to next EBR or terminates EBR linked list...
- if ((partNum < MAX_MBR_PARTS - 1) && (partitions[partNum + 1].firstLBA > 0)) {
+ next = FindNextInUse(partNum + 1);
+ if ((next < MAX_MBR_PARTS) && (next > 0) && (partitions[next].GetStartLBA() > 0)) {
tempMBR.partitions[1].partitionType = 0x0f;
- tempMBR.partitions[1].firstLBA = partitions[partNum + 1].firstLBA - 1;
- tempMBR.partitions[1].lengthLBA = partitions[partNum + 1].lengthLBA + 1;
+ tempMBR.partitions[1].firstLBA = (uint32_t) (partitions[next].GetStartLBA() - extFirstLBA - 1);
+ tempMBR.partitions[1].lengthLBA = (uint32_t) (partitions[next].GetLengthLBA() + 1);
LBAtoCHS((uint64_t) tempMBR.partitions[1].firstLBA,
(uint8_t *) &tempMBR.partitions[1].firstSector);
LBAtoCHS(tempMBR.partitions[1].lengthLBA - extFirstLBA,
@@ -374,9 +376,10 @@ int BasicMBRData::WriteMBRData(DiskIO *theDisk) {
moreLogicals = 0;
} // if/else
allOK = WriteMBRData(tempMBR, theDisk, writeEbrTo);
- partNum++;
writeEbrTo = (uint64_t) tempMBR.partitions[1].firstLBA + (uint64_t) extFirstLBA;
+ partNum = next;
} // while
+ DeleteExtendedParts();
return allOK;
} // BasicMBRData::WriteMBRData(DiskIO *theDisk)
@@ -429,6 +432,17 @@ int BasicMBRData::WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t s
return allOK;
} // BasicMBRData::WriteMBRData(uint64_t sector)
+// Set a new disk device; used in copying one disk's partition
+// table to another disk.
+void BasicMBRData::SetDisk(DiskIO *theDisk) {
+ int err;
+
+ myDisk = theDisk;
+ diskSize = theDisk->DiskSize(&err);
+ canDeleteMyDisk = 0;
+ ReadCHSGeom();
+} // BasicMBRData::SetDisk()
+
/********************************************
* *
* Functions that display data for the user *
@@ -437,40 +451,33 @@ int BasicMBRData::WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t s
// Show the MBR data to the user, up to the specified maximum number
// of partitions....
-void BasicMBRData::DisplayMBRData(int maxParts) {
+void BasicMBRData::DisplayMBRData(void) {
int i;
- char bootCode;
- if (maxParts > MAX_MBR_PARTS)
- maxParts = MAX_MBR_PARTS;
+ cout << "\nDisk size is " << diskSize << " sectors ("
+ << BytesToSI(diskSize, blockSize) << ")\n";
cout << "MBR disk identifier: 0x";
cout.width(8);
cout.fill('0');
cout.setf(ios::uppercase);
cout << hex << diskSignature << dec << "\n";
- cout << "MBR partitions:\n";
- cout << "Number\t Boot\t Start (sector)\t Length (sectors)\tType\n";
- for (i = 0; i < maxParts; i++) {
- if (partitions[i].lengthLBA != 0) {
- if (partitions[i].status && 0x80) // it's bootable
- bootCode = '*';
- else
- bootCode = ' ';
+ cout << "MBR partitions:\n\n";
+ if ((state == gpt) || (state == hybrid)) {
+ cout << "Number Boot Start Sector End Sector Status Code\n";
+ } else {
+ cout << " Can Be Can Be\n";
+ cout << "Number Boot Start Sector End Sector Status Logical Primary Code\n";
+ UpdateCanBeLogical();
+ } //
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if (partitions[i].GetLengthLBA() != 0) {
cout.fill(' ');
cout.width(4);
- cout << i + 1 << "\t " << bootCode << "\t";
- cout.width(13);
- cout << partitions[i].firstLBA << "\t";
- cout.width(15);
- cout << partitions[i].lengthLBA << " \t0x";
- cout.width(2);
- cout.fill('0');
- cout << hex << (int) partitions[i].partitionType << dec << "\n";
+ cout << i + 1 << " ";
+ partitions[i].ShowData((state == gpt) || (state == hybrid));
} // if
cout.fill(' ');
} // for
- cout << "\nDisk size is " << diskSize << " sectors ("
- << BytesToSI(diskSize, blockSize) << ")\n";
} // BasicMBRData::DisplayMBRData()
// Displays the state, as a word, on stdout. Used for debugging & to
@@ -495,6 +502,90 @@ void BasicMBRData::ShowState(void) {
} // switch
} // BasicMBRData::ShowState()
+/************************
+ * *
+ * GPT Checks and fixes *
+ * *
+ ************************/
+
+// Perform a very rudimentary check for GPT data on the disk; searches for
+// the GPT signature in the main and backup metadata areas.
+// Returns 0 if GPT data not found, 1 if main data only is found, 2 if
+// backup only is found, 3 if both main and backup data are found, and
+// -1 if a disk error occurred.
+int BasicMBRData::CheckForGPT(void) {
+ int retval = 0, err;
+ char signature1[9], signature2[9];
+
+ if (myDisk != NULL) {
+ if (myDisk->OpenForRead() != 0) {
+ if (myDisk->Seek(1)) {
+ myDisk->Read(signature1, 8);
+ signature1[8] = '\0';
+ } else retval = -1;
+ if (myDisk->Seek(myDisk->DiskSize(&err) - 1)) {
+ myDisk->Read(signature2, 8);
+ signature2[8] = '\0';
+ } else retval = -1;
+ if ((retval >= 0) && (strcmp(signature1, "EFI PART") == 0))
+ retval += 1;
+ if ((retval >= 0) && (strcmp(signature2, "EFI PART") == 0))
+ retval += 2;
+ } else {
+ retval = -1;
+ } // if/else
+ myDisk->Close();
+ } else retval = -1;
+ return retval;
+} // BasicMBRData::CheckForGPT()
+
+// Blanks the 2nd (sector #1, numbered from 0) and last sectors of the disk,
+// but only if GPT data are verified on the disk, and only for the sector(s)
+// with GPT signatures.
+// Returns 1 if operation completes successfully, 0 if not (returns 1 if
+// no GPT data are found on the disk).
+int BasicMBRData::BlankGPTData(void) {
+ int allOK = 1, err;
+ uint8_t blank[512];
+
+ memset(blank, 0, 512);
+ switch (CheckForGPT()) {
+ case -1:
+ allOK = 0;
+ break;
+ case 0:
+ break;
+ case 1:
+ if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
+ if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
+ allOK = 0;
+ myDisk->Close();
+ } else allOK = 0;
+ break;
+ case 2:
+ if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
+ if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
+ (myDisk->Write(blank, 512) == 512)))
+ allOK = 0;
+ myDisk->Close();
+ } else allOK = 0;
+ break;
+ case 3:
+ if ((myDisk != NULL) && (myDisk->OpenForWrite())) {
+ if (!((myDisk->Seek(1)) && (myDisk->Write(blank, 512) == 512)))
+ allOK = 0;
+ if (!((myDisk->Seek(myDisk->DiskSize(&err) - 1)) &&
+ (myDisk->Write(blank, 512) == 512)))
+ allOK = 0;
+ myDisk->Close();
+ } else allOK = 0;
+ break;
+ default:
+ break;
+ } // switch()
+ return allOK;
+} // BasicMBRData::BlankGPTData
+
/*********************************************************************
* *
* Functions that set or get disk metadata (CHS geometry, disk size, *
@@ -502,17 +593,43 @@ void BasicMBRData::ShowState(void) {
* *
*********************************************************************/
-// Sets the CHS geometry. CHS geometry is used by LBAtoCHS() function.
-// Note that this only sets the heads and sectors; the number of
-// cylinders is determined by these values and the disk size.
-void BasicMBRData::SetCHSGeom(uint32_t h, uint32_t s) {
- if ((h <= MAX_HEADS) && (s <= MAX_SECSPERTRACK)) {
- numHeads = h;
- numSecspTrack = s;
- } else {
- cout << "Warning! Attempt to set invalid CHS geometry!\n";
- } // if/else
-} // BasicMBRData::SetCHSGeom()
+// Read the CHS geometry using OS calls, or if that fails, set to
+// the most common value for big disks (255 heads, 63 sectors per
+// track, & however many cylinders that computes to).
+void BasicMBRData::ReadCHSGeom(void) {
+ numHeads = myDisk->GetNumHeads();
+ numSecspTrack = myDisk->GetNumSecsPerTrack();
+ partitions[0].SetGeometry(numHeads, numSecspTrack, diskSize, blockSize);
+} // BasicMBRData::ReadCHSGeom()
+
+// Find the low and high used partition numbers (numbered from 0).
+// Return value is the number of partitions found. Note that the
+// *low and *high values are both set to 0 when no partitions
+// are found, as well as when a single partition in the first
+// position exists. Thus, the return value is the only way to
+// tell when no partitions exist.
+int BasicMBRData::GetPartRange(uint32_t *low, uint32_t *high) {
+ uint32_t i;
+ int numFound = 0;
+
+ *low = MAX_MBR_PARTS + 1; // code for "not found"
+ *high = 0;
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if (partitions[i].GetStartLBA() != UINT32_C(0)) { // it exists
+ *high = i; // since we're counting up, set the high value
+ // Set the low value only if it's not yet found...
+ if (*low == (MAX_MBR_PARTS + 1))
+ *low = i;
+ numFound++;
+ } // if
+ } // for
+
+ // Above will leave *low pointing to its "not found" value if no partitions
+ // are defined, so reset to 0 if this is the case....
+ if (*low == (MAX_MBR_PARTS + 1))
+ *low = 0;
+ return numFound;
+} // GPTData::GetPartRange()
// Converts 64-bit LBA value to MBR-style CHS value. Returns 1 if conversion
// was within the range that can be expressed by CHS (including 0, for an
@@ -561,35 +678,25 @@ int BasicMBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
return (retval);
} // BasicMBRData::LBAtoCHS()
-// Look for problems -- overlapping partitions, etc.
-int BasicMBRData::Verify(void) {
- int i, j, theyOverlap, numProbs = 0, numEE = 0;
- uint32_t firstLBA1, firstLBA2, lastLBA1, lastLBA2;
+// Look for overlapping partitions.
+// Returns the number of problems found
+int BasicMBRData::FindOverlaps(void) {
+ int i, j, numProbs = 0, numEE = 0;
for (i = 0; i < MAX_MBR_PARTS; i++) {
for (j = i + 1; j < MAX_MBR_PARTS; j++) {
- theyOverlap = 0;
- firstLBA1 = partitions[i].firstLBA;
- firstLBA2 = partitions[j].firstLBA;
- if ((firstLBA1 != 0) && (firstLBA2 != 0)) {
- lastLBA1 = partitions[i].firstLBA + partitions[i].lengthLBA - 1;
- lastLBA2 = partitions[j].firstLBA + partitions[j].lengthLBA - 1;
- if ((firstLBA1 < lastLBA2) && (lastLBA1 >= firstLBA2))
- theyOverlap = 1;
- if ((firstLBA2 < lastLBA1) && (lastLBA2 >= firstLBA1))
- theyOverlap = 1;
- } // if
- if (theyOverlap) {
+ if ((partitions[i].GetInclusion() != NONE) &&
+ (partitions[i].DoTheyOverlap(partitions[j]))) {
numProbs++;
cout << "\nProblem: MBR partitions " << i + 1 << " and " << j + 1
<< " overlap!\n";
} // if
} // for (j...)
- if (partitions[i].partitionType == 0xEE) {
+ if (partitions[i].GetType() == 0xEE) {
numEE++;
- if (partitions[i].firstLBA != 1)
- cout << "\nWarning: 0xEE partition doesn't start on sector 1. This can cause problems\n"
- << "in some OSes.\n";
+ if (partitions[i].GetStartLBA() != 1)
+ cout << "\nWarning: 0xEE partition doesn't start on sector 1. This can cause "
+ << "problems\nin some OSes.\n";
} // if
} // for (i...)
if (numEE > 1)
@@ -597,7 +704,212 @@ int BasicMBRData::Verify(void) {
<< "in some OSes.\n";
return numProbs;
-} // BasicMBRData::Verify()
+} // BasicMBRData::FindOverlaps()
+
+// Returns the number of primary partitions, including the extended partition
+// required to hold any logical partitions found.
+int BasicMBRData::NumPrimaries(void) {
+ int i, numPrimaries = 0, logicalsFound = 0;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if (partitions[i].GetLengthLBA() > 0) {
+ if (partitions[i].GetInclusion() == PRIMARY)
+ numPrimaries++;
+ if (partitions[i].GetInclusion() == LOGICAL)
+ logicalsFound = 1;
+ } // if
+ } // for
+ return (numPrimaries + logicalsFound);
+} // BasicMBRData::NumPrimaries()
+
+// Returns the number of logical partitions.
+int BasicMBRData::NumLogicals(void) {
+ int i, numLogicals = 0;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if (partitions[i].GetInclusion() == LOGICAL)
+ numLogicals++;
+ } // for
+ return numLogicals;
+} // BasicMBRData::NumLogicals()
+
+// Returns the number of partitions (primaries plus logicals), NOT including
+// the extended partition required to house the logicals.
+int BasicMBRData::CountParts(void) {
+ int i, num = 0;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetInclusion() == LOGICAL) ||
+ (partitions[i].GetInclusion() == PRIMARY))
+ num++;
+ } // for
+ return num;
+} // BasicMBRData::CountParts()
+
+// Updates the canBeLogical and canBePrimary flags for all the partitions.
+void BasicMBRData::UpdateCanBeLogical(void) {
+ int i, j, sectorBefore, numPrimaries, numLogicals, usedAsEBR;
+ uint64_t firstLogical, lastLogical, lStart, pStart;
+
+ numPrimaries = NumPrimaries();
+ numLogicals = NumLogicals();
+ firstLogical = FirstLogicalLBA() - 1;
+ lastLogical = LastLogicalLBA();
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ usedAsEBR = (SectorUsedAs(partitions[i].GetLastLBA()) == EBR);
+ if (usedAsEBR) {
+ partitions[i].SetCanBeLogical(0);
+ partitions[i].SetCanBePrimary(0);
+ } else if (partitions[i].GetLengthLBA() > 0) {
+ // First determine if it can be logical....
+ sectorBefore = SectorUsedAs(partitions[i].GetStartLBA() - 1);
+ lStart = partitions[i].GetStartLBA(); // start of potential logical part.
+ if ((lastLogical > 0) &&
+ ((sectorBefore == EBR) || (sectorBefore == NONE))) {
+ // Assume it can be logical, then search for primaries that make it
+ // not work and, if found, flag appropriately.
+ partitions[i].SetCanBeLogical(1);
+ for (j = 0; j < MAX_MBR_PARTS; j++) {
+ if ((i != j) && (partitions[j].GetInclusion() == PRIMARY)) {
+ pStart = partitions[j].GetStartLBA();
+ if (((pStart < lStart) && (firstLogical < pStart)) ||
+ ((pStart > lStart) && (firstLogical > pStart))) {
+ partitions[i].SetCanBeLogical(0);
+ } // if/else
+ } // if
+ } // for
+ } else {
+ if ((sectorBefore != EBR) && (sectorBefore != NONE))
+ partitions[i].SetCanBeLogical(0);
+ else
+ partitions[i].SetCanBeLogical(lastLogical == 0); // can be logical only if no logicals already
+ } // if/else
+ // Now determine if it can be primary. Start by assuming it can be...
+ partitions[i].SetCanBePrimary(1);
+ if ((numPrimaries >= 4) && (partitions[i].GetInclusion() != PRIMARY)) {
+ partitions[i].SetCanBePrimary(0);
+ if ((partitions[i].GetInclusion() == LOGICAL) && (numLogicals == 1) &&
+ (numPrimaries == 4))
+ partitions[i].SetCanBePrimary(1);
+ } // if
+ if ((partitions[i].GetStartLBA() > (firstLogical + 1)) &&
+ (partitions[i].GetLastLBA() < lastLogical))
+ partitions[i].SetCanBePrimary(0);
+ } // else if
+ } // for
+} // BasicMBRData::UpdateCanBeLogical()
+
+// Returns the first sector occupied by any logical partition. Note that
+// this does NOT include the logical partition's EBR! Returns UINT32_MAX
+// if there are no logical partitions defined.
+uint64_t BasicMBRData::FirstLogicalLBA(void) {
+ int i;
+ uint64_t firstFound = UINT32_MAX;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetInclusion() == LOGICAL) &&
+ (partitions[i].GetStartLBA() < firstFound)) {
+ firstFound = partitions[i].GetStartLBA();
+ } // if
+ } // for
+ return firstFound;
+} // BasicMBRData::FirstLogicalLBA()
+
+// Returns the last sector occupied by any logical partition, or 0 if
+// there are no logical partitions defined.
+uint64_t BasicMBRData::LastLogicalLBA(void) {
+ int i;
+ uint64_t lastFound = 0;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetInclusion() == LOGICAL) &&
+ (partitions[i].GetLastLBA() > lastFound))
+ lastFound = partitions[i].GetLastLBA();
+ } // for
+ return lastFound;
+} // BasicMBRData::LastLogicalLBA()
+
+// Returns 1 if logical partitions are contiguous (have no primaries
+// in their midst), or 0 if one or more primaries exist between
+// logicals.
+int BasicMBRData::AreLogicalsContiguous(void) {
+ int allOK = 1, i = 0;
+ uint64_t firstLogical, lastLogical;
+
+ firstLogical = FirstLogicalLBA() - 1; // subtract 1 for EBR
+ lastLogical = LastLogicalLBA();
+ if (lastLogical > 0) {
+ do {
+ if ((partitions[i].GetInclusion() == PRIMARY) &&
+ (partitions[i].GetStartLBA() >= firstLogical) &&
+ (partitions[i].GetStartLBA() <= lastLogical)) {
+ allOK = 0;
+ } // if
+ i++;
+ } while ((i < MAX_MBR_PARTS) && allOK);
+ } // if
+ return allOK;
+} // BasicMBRData::AreLogicalsContiguous()
+
+// Returns 1 if all partitions fit on the disk, given its size; 0 if any
+// partition is too big.
+int BasicMBRData::DoTheyFit(void) {
+ int i, allOK = 1;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize)) {
+ allOK = 0;
+ } // if
+ } // for
+ return allOK;
+} // BasicMBRData::DoTheyFit(void)
+
+// Returns 1 if there's at least one free sector immediately preceding
+// all partitions flagged as logical; 0 if any logical partition lacks
+// this space.
+int BasicMBRData::SpaceBeforeAllLogicals(void) {
+ int i = 0, allOK = 1;
+
+ do {
+ if ((partitions[i].GetStartLBA() > 0) && (partitions[i].GetInclusion() == LOGICAL)) {
+ allOK = allOK && (SectorUsedAs(partitions[i].GetStartLBA() - 1) == EBR);
+// allOK = allOK && IsFree(partitions[i].GetStartLBA() - 1);
+ } // if
+ i++;
+ } while (allOK && (i < MAX_MBR_PARTS));
+ return allOK;
+} // BasicMBRData::SpaceBeforeAllLogicals()
+
+// Returns 1 if the partitions describe a legal layout -- all logicals
+// are contiguous and have at least one preceding empty partitions,
+// the number of primaries is under 4 (or under 3 if there are any
+// logicals), there are no overlapping partitions, etc.
+// Does NOT assume that primaries are numbered 1-4; uses the
+// IsItPrimary() function of the MBRPart class to determine
+// primary status. Also does NOT consider partition order; there
+// can be gaps and it will still be considered legal.
+int BasicMBRData::IsLegal(void) {
+ int allOK = 1;
+
+ allOK = (FindOverlaps() == 0);
+ allOK = (allOK && (NumPrimaries() <= 4));
+ allOK = (allOK && AreLogicalsContiguous());
+ allOK = (allOK && DoTheyFit());
+ allOK = (allOK && SpaceBeforeAllLogicals());
+ return allOK;
+} // BasicMBRData::IsLegal()
+
+// Finds the next in-use partition, starting with start (will return start
+// if it's in use). Returns -1 if no subsequent partition is in use.
+int BasicMBRData::FindNextInUse(int start) {
+ if (start >= MAX_MBR_PARTS)
+ start = -1;
+ while ((start < MAX_MBR_PARTS) && (start >= 0) && (partitions[start].GetInclusion() == NONE))
+ start++;
+ if ((start < 0) || (start >= MAX_MBR_PARTS))
+ start = -1;
+ return start;
+} // BasicMBRData::FindFirstLogical();
/*****************************************************
* *
@@ -619,18 +931,10 @@ void BasicMBRData::EmptyMBR(int clearBootloader) {
// Blank out the partitions
for (i = 0; i < MAX_MBR_PARTS; i++) {
- partitions[i].status = UINT8_C(0);
- partitions[i].firstSector[0] = UINT8_C(0);
- partitions[i].firstSector[1] = UINT8_C(0);
- partitions[i].firstSector[2] = UINT8_C(0);
- partitions[i].partitionType = UINT8_C(0);
- partitions[i].lastSector[0] = UINT8_C(0);
- partitions[i].lastSector[1] = UINT8_C(0);
- partitions[i].lastSector[2] = UINT8_C(0);
- partitions[i].firstLBA = UINT32_C(0);
- partitions[i].lengthLBA = UINT32_C(0);
+ partitions[i].Empty();
} // for
MBRSignature = MBR_SIGNATURE;
+ state = mbr;
} // BasicMBRData::EmptyMBR()
// Blank out the boot loader area. Done with the initial MBR-to-GPT
@@ -644,32 +948,37 @@ void BasicMBRData::EmptyBootloader(void) {
nulls = 0;
} // BasicMBRData::EmptyBootloader
+// Create a partition of the specified number based on the passed
+// partition. This function does *NO* error checking, so it's possible
+// to seriously screw up a partition table using this function!
+// Note: This function should NOT be used to create the 0xEE partition
+// in a conventional GPT configuration, since that partition has
+// specific size requirements that this function won't handle. It may
+// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
+// since those toss the rulebook away anyhow....
+void BasicMBRData::AddPart(int num, const MBRPart& newPart) {
+ partitions[num] = newPart;
+} // BasicMBRData::AddPart()
+
// Create a partition of the specified number, starting LBA, and
-// length. This function does *NO* error checking, so it's possible
+// length. This function does almost no error checking, so it's possible
// to seriously screw up a partition table using this function!
// Note: This function should NOT be used to create the 0xEE partition
// in a conventional GPT configuration, since that partition has
// specific size requirements that this function won't handle. It may
// be used for creating the 0xEE partition(s) in a hybrid MBR, though,
// since those toss the rulebook away anyhow....
-void BasicMBRData::MakePart(int num, uint32_t start, uint32_t length, int type, int bootable) {
- if ((num >= 0) && (num < MAX_MBR_PARTS)) {
- partitions[num].firstSector[0] = UINT8_C(0);
- partitions[num].firstSector[1] = UINT8_C(0);
- partitions[num].firstSector[2] = UINT8_C(0);
- partitions[num].partitionType = (uint8_t) type;
- partitions[num].lastSector[0] = UINT8_C(0);
- partitions[num].lastSector[1] = UINT8_C(0);
- partitions[num].lastSector[2] = UINT8_C(0);
- partitions[num].firstLBA = start;
- partitions[num].lengthLBA = length;
- // If this is a "real" partition, set its CHS geometry
- if (length > 0) {
- LBAtoCHS((uint64_t) start, partitions[num].firstSector);
- LBAtoCHS((uint64_t) (start + length - 1), partitions[num].lastSector);
- } // if (length > 0)
+void BasicMBRData::MakePart(int num, uint64_t start, uint64_t length, int type, int bootable) {
+ if ((num >= 0) && (num < MAX_MBR_PARTS) && (start <= UINT32_MAX) && (length <= UINT32_MAX)) {
+ partitions[num].Empty();
+ partitions[num].SetType(type);
+ partitions[num].SetLocation(start, length);
+ if (num < 4)
+ partitions[num].SetInclusion(PRIMARY);
+ else
+ partitions[num].SetInclusion(LOGICAL);
SetPartBootable(num, bootable);
- } // if valid partition number
+ } // if valid partition number & size
} // BasicMBRData::MakePart()
// Set the partition's type code.
@@ -678,8 +987,8 @@ int BasicMBRData::SetPartType(int num, int type) {
int allOK = 1;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
- if (partitions[num].lengthLBA != UINT32_C(0)) {
- partitions[num].partitionType = (uint8_t) type;
+ if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
+ allOK = partitions[num].SetType(type);
} else allOK = 0;
} else allOK = 0;
return allOK;
@@ -692,11 +1001,11 @@ int BasicMBRData::SetPartBootable(int num, int bootable) {
int allOK = 1;
if ((num >= 0) && (num < MAX_MBR_PARTS)) {
- if (partitions[num].lengthLBA != UINT32_C(0)) {
+ if (partitions[num].GetLengthLBA() != UINT32_C(0)) {
if (bootable == 0)
- partitions[num].status = UINT8_C(0);
+ partitions[num].SetStatus(UINT8_C(0x00));
else
- partitions[num].status = UINT8_C(0x80);
+ partitions[num].SetStatus(UINT8_C(0x80));
} else allOK = 0;
} else allOK = 0;
return allOK;
@@ -706,19 +1015,19 @@ int BasicMBRData::SetPartBootable(int num, int bootable) {
// 1 if partition was created, 0 otherwise. Intended for use in
// creating hybrid MBRs.
int BasicMBRData::MakeBiggestPart(int i, int type) {
- uint32_t start = UINT32_C(1); // starting point for each search
- uint32_t firstBlock; // first block in a segment
- uint32_t lastBlock; // last block in a segment
- uint32_t segmentSize; // size of segment in blocks
- uint32_t selectedSegment = UINT32_C(0); // location of largest segment
- uint32_t selectedSize = UINT32_C(0); // size of largest segment in blocks
+ uint64_t start = UINT64_C(1); // starting point for each search
+ uint64_t firstBlock; // first block in a segment
+ uint64_t lastBlock; // last block in a segment
+ uint64_t segmentSize; // size of segment in blocks
+ uint64_t selectedSegment = UINT64_C(0); // location of largest segment
+ uint64_t selectedSize = UINT64_C(0); // size of largest segment in blocks
int found = 0;
do {
firstBlock = FindFirstAvailable(start);
- if (firstBlock != UINT32_C(0)) { // something's free...
+ if (firstBlock > UINT64_C(0)) { // something's free...
lastBlock = FindLastInFree(firstBlock);
- segmentSize = lastBlock - firstBlock + UINT32_C(1);
+ segmentSize = lastBlock - firstBlock + UINT64_C(1);
if (segmentSize > selectedSize) {
selectedSize = segmentSize;
selectedSegment = firstBlock;
@@ -726,7 +1035,7 @@ int BasicMBRData::MakeBiggestPart(int i, int type) {
start = lastBlock + 1;
} // if
} while (firstBlock != 0);
- if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
+ if ((selectedSize > UINT64_C(0)) && (selectedSize < diskSize)) {
found = 1;
MakePart(i, selectedSegment, selectedSize, type, 0);
} else {
@@ -737,84 +1046,374 @@ int BasicMBRData::MakeBiggestPart(int i, int type) {
// Delete partition #i
void BasicMBRData::DeletePartition(int i) {
- int j;
-
- partitions[i].firstLBA = UINT32_C(0);
- partitions[i].lengthLBA = UINT32_C(0);
- partitions[i].status = UINT8_C(0);
- partitions[i].partitionType = UINT8_C(0);
- for (j = 0; j < 3; j++) {
- partitions[i].firstSector[j] = UINT8_C(0);
- partitions[i].lastSector[j] = UINT8_C(0);
- } // for j (CHS data blanking)
+ partitions[i].Empty();
} // BasicMBRData::DeletePartition()
+// Set the inclusion status (PRIMARY, LOGICAL, or NONE) with some sanity
+// checks to ensure the table remains legal.
+// Returns 1 on success, 0 on failure.
+int BasicMBRData::SetInclusionwChecks(int num, int inclStatus) {
+ int allOK = 1, origValue;
+
+ if (IsLegal()) {
+ if ((inclStatus == PRIMARY) || (inclStatus == LOGICAL) || (inclStatus == NONE)) {
+ origValue = partitions[num].GetInclusion();
+ partitions[num].SetInclusion(inclStatus);
+ if (!IsLegal()) {
+ partitions[num].SetInclusion(origValue);
+ cerr << "Specified change is not legal! Aborting change!\n";
+ } // if
+ } else {
+ cerr << "Invalid partition inclusion code in BasicMBRData::SetInclusionwChecks()!\n";
+ } // if/else
+ } else {
+ cerr << "Partition table is not currently in a valid state. Aborting change!\n";
+ allOK = 0;
+ } // if/else
+ return allOK;
+} // BasicMBRData::SetInclusionwChecks()
+
// Recomputes the CHS values for the specified partition and adjusts the value.
// Note that this will create a technically incorrect CHS value for EFI GPT (0xEE)
// protective partitions, but this is required by some buggy BIOSes, so I'm
// providing a function to do this deliberately at the user's command.
// This function does nothing if the partition's length is 0.
void BasicMBRData::RecomputeCHS(int partNum) {
- uint64_t firstLBA, lengthLBA;
+// uint64_t firstLBA, lengthLBA;
- firstLBA = (uint64_t) partitions[partNum].firstLBA;
+ partitions[partNum].RecomputeCHS();
+/* firstLBA = (uint64_t) partitions[partNum].firstLBA;
lengthLBA = (uint64_t) partitions[partNum].lengthLBA;
if (lengthLBA > 0) {
LBAtoCHS(firstLBA, partitions[partNum].firstSector);
LBAtoCHS(firstLBA + lengthLBA - 1, partitions[partNum].lastSector);
- } // if
+ } // if */
} // BasicMBRData::RecomputeCHS()
-// Creates an MBR extended partition holding logical partitions that
-// correspond to the list of GPT partitions in theList. The extended
-// partition is placed in position #4 (counting from 1) in the MBR.
-// The logical partition data are copied to the partitions[] array in
-// positions 4 and up (counting from 0). Neither the MBR nor the EBR
-// entries are written to disk; that is left for the WriteMBRData()
-// function.
-// Returns number of converted partitions
-int BasicMBRData::CreateLogicals(PartNotes * notes) {
- uint64_t extEndLBA = 0, extStartLBA = UINT64_MAX;
- int i = 4, numLogicals = 0;
- struct PartInfo aPart;
-
- // Find bounds of the extended partition....
- notes->Rewind();
- while (notes->GetNextInfo(&aPart) >= 0) {
- if (aPart.type == LOGICAL) {
- if (extStartLBA > aPart.firstLBA)
- extStartLBA = aPart.firstLBA;
- if (extEndLBA < aPart.lastLBA)
- extEndLBA = aPart.lastLBA;
- numLogicals++;
+// Swap the contents of two partitions.
+// Returns 1 if successful, 0 if either partition is out of range
+// (that is, not a legal number; either or both can be empty).
+// Note that if partNum1 = partNum2 and this number is in range,
+// it will be considered successful.
+int BasicMBRData::SwapPartitions(uint32_t partNum1, uint32_t partNum2) {
+ MBRPart temp;
+ int allOK = 1;
+
+ if ((partNum1 < MAX_MBR_PARTS) && (partNum2 < MAX_MBR_PARTS)) {
+ if (partNum1 != partNum2) {
+ temp = partitions[partNum1];
+ partitions[partNum1] = partitions[partNum2];
+ partitions[partNum2] = temp;
+ } // if
+ } else allOK = 0; // partition numbers are valid
+ return allOK;
+} // BasicMBRData::SwapPartitions()
+
+// Sort the MBR entries, eliminating gaps and making for a logical
+// ordering. Relies on QuickSortMBR() for the bulk of the work
+void BasicMBRData::SortMBR(int start) {
+ int i, numFound, firstPart, lastPart;
+ uint32_t fp, lp;
+
+ // First, find the last partition with data, so as not to
+ // spend needless time sorting empty entries....
+ numFound = GetPartRange(&fp, &lp);
+ firstPart = (int) fp;
+ lastPart = (int) lp;
+ if (firstPart < start)
+ firstPart = start;
+
+ // Now swap empties with the last partitions, to simplify the logic
+ // in the Quicksort function....
+ i = start;
+ while (i < lastPart) {
+ if (partitions[i].GetStartLBA() == 0) {
+ SwapPartitions(i, lastPart);
+ do {
+ lastPart--;
+ } while ((lastPart > 0) && (partitions[lastPart].GetStartLBA() == 0));
+ } // if
+ i++;
+ } // while
+
+ // If there are more empties than partitions in the range from 0 to lastPart,
+ // the above leaves lastPart set too high, so we've got to adjust it to
+ // prevent empties from migrating to the top of the list....
+ GetPartRange(&fp, &lp);
+ lastPart = (int) lp;
+
+ // Now call the recursive quick sort routine to do the real work....
+ QuickSortMBR(start, lastPart);
+} // GPTData::SortGPT()
+
+// Recursive quick sort algorithm for MBR partitions. Note that if there
+// are any empties in the specified range, they'll be sorted to the
+// start, resulting in a sorted set of partitions that begins with
+// partition 2, 3, or higher.
+void BasicMBRData::QuickSortMBR(int start, int finish) {
+ uint64_t starterValue; // starting location of median partition
+ int left, right;
+
+ left = start;
+ right = finish;
+ starterValue = partitions[(start + finish) / 2].GetStartLBA();
+ do {
+ while (partitions[left].GetStartLBA() < starterValue)
+ left++;
+ while (partitions[right].GetStartLBA() > starterValue)
+ right--;
+ if (left <= right)
+ SwapPartitions(left++, right--);
+ } while (left <= right);
+ if (start < right) QuickSortMBR(start, right);
+ if (finish > left) QuickSortMBR(left, finish);
+} // BasicMBRData::QuickSortMBR()
+
+// Delete any partitions that are too big to fit on the disk
+// or that are too big for MBR (32-bit limits).
+// This really deletes the partitions by setting values to 0.
+// Returns the number of partitions deleted in this way.
+int BasicMBRData::DeleteOversizedParts() {
+ int num = 0, i;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetStartLBA() > diskSize) || (partitions[i].GetLastLBA() > diskSize) ||
+ (partitions[i].GetStartLBA() > UINT32_MAX) || (partitions[i].GetLengthLBA() > UINT32_MAX)) {
+ partitions[i].Empty();
+ num++;
+ } // if
+ } // for
+ return num;
+} // BasicMBRData::DeleteOversizedParts()
+
+// Search for and delete extended partitions.
+// Returns the number of partitions deleted.
+int BasicMBRData::DeleteExtendedParts() {
+ int i, numDeleted = 0;
+ uint8_t type;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ type = partitions[i].GetType();
+ if (((type == 0x05) || (type == 0x0f) || (type == (0x85))) &&
+ (partitions[i].GetLengthLBA() > 0)) {
+ partitions[i].Empty();
+ numDeleted++;
+ } // if
+ } // for
+ return numDeleted;
+} // BasicMBRData::DeleteExtendedParts()
+
+// Finds any overlapping partitions and omits the smaller of the two.
+void BasicMBRData::OmitOverlaps() {
+ int i, j;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ for (j = i + 1; j < MAX_MBR_PARTS; j++) {
+ if ((partitions[i].GetInclusion() != NONE) &&
+ partitions[i].DoTheyOverlap(partitions[j])) {
+ if (partitions[i].GetLengthLBA() < partitions[j].GetLengthLBA())
+ partitions[i].SetInclusion(NONE);
+ else
+ partitions[j].SetInclusion(NONE);
+ } // if
+ } // for (j...)
+ } // for (i...)
+} // BasicMBRData::OmitOverlaps()
+
+/* // Omits all partitions; used as starting point in MakeItLegal()
+void BasicMBRData::OmitAll(void) {
+ int i;
+
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ partitions[i].SetInclusion(NONE);
+ } // for
+} // BasicMBRData::OmitAll() */
+
+// Convert as many partitions into logicals as possible, except for
+// the first partition, if possible.
+void BasicMBRData::MaximizeLogicals() {
+ int earliestPart = 0, earliestPartWas = NONE, i;
+
+ for (i = MAX_MBR_PARTS - 1; i >= 0; i--) {
+ UpdateCanBeLogical();
+ earliestPart = i;
+ if (partitions[i].CanBeLogical()) {
+ partitions[i].SetInclusion(LOGICAL);
+ } else if (partitions[i].CanBePrimary()) {
+ partitions[i].SetInclusion(PRIMARY);
+ } else {
+ partitions[i].SetInclusion(NONE);
+ } // if/elseif/else
+ } // for
+ // If we have spare primaries, convert back the earliest partition to
+ // its original state....
+ if ((NumPrimaries() < 4) && (partitions[earliestPart].GetInclusion() == LOGICAL))
+ partitions[earliestPart].SetInclusion(earliestPartWas);
+} // BasicMBRData::MaximizeLogicals()
+
+// Add primaries up to the maximum allowed, from the omitted category.
+void BasicMBRData::MaximizePrimaries() {
+ int num, i = 0;
+
+ num = NumPrimaries();
+ while ((num < 4) && (i < MAX_MBR_PARTS)) {
+ if ((partitions[i].GetInclusion() == NONE) && (partitions[i].CanBePrimary())) {
+ partitions[i].SetInclusion(PRIMARY);
+ num++;
+ UpdateCanBeLogical();
} // if
+ i++;
} // while
- extStartLBA--;
-
- if ((extStartLBA < UINT32_MAX) && ((extEndLBA - extStartLBA + 1) < UINT32_MAX)) {
- notes->Rewind();
- i = 4;
- while ((notes->GetNextInfo(&aPart) >= 0) && (i < MAX_MBR_PARTS)) {
- if (aPart.type == LOGICAL) {
- partitions[i].partitionType = aPart.hexCode;
- partitions[i].firstLBA = (uint32_t) (aPart.firstLBA - extStartLBA);
- partitions[i].lengthLBA = (uint32_t) (aPart.lastLBA - aPart.firstLBA + 1);
- LBAtoCHS(UINT64_C(1), (uint8_t *) &partitions[i].firstSector);
- LBAtoCHS(partitions[i].lengthLBA, (uint8_t *) &partitions[i].lastSector);
- partitions[i].status = aPart.active * 0x80;
+} // BasicMBRData::MaximizePrimaries()
+
+// Remove primary partitions in excess of 4, starting with the later ones,
+// in terms of the array location....
+void BasicMBRData::TrimPrimaries(void) {
+ int numToDelete, i = MAX_MBR_PARTS;
+
+ numToDelete = NumPrimaries() - 4;
+ while ((numToDelete > 0) && (i >= 0)) {
+ if (partitions[i].GetInclusion() == PRIMARY) {
+ partitions[i].SetInclusion(NONE);
+ numToDelete--;
+ } // if
+ i--;
+ } // while (numToDelete > 0)
+} // BasicMBRData::TrimPrimaries()
+
+// Locates primary partitions located between logical partitions and
+// either converts the primaries into logicals (if possible) or omits
+// them.
+void BasicMBRData::MakeLogicalsContiguous(void) {
+ uint64_t firstLogicalLBA, lastLogicalLBA;
+ int i;
+
+ firstLogicalLBA = FirstLogicalLBA();
+ lastLogicalLBA = LastLogicalLBA();
+ for (i = 0; i < MAX_MBR_PARTS; i++) {
+ if ((partitions[i].GetInclusion() == PRIMARY) &&
+ (partitions[i].GetStartLBA() >= firstLogicalLBA) &&
+ (partitions[i].GetLastLBA() <= lastLogicalLBA)) {
+ if (SectorUsedAs(partitions[i].GetStartLBA() - 1) == NONE)
+ partitions[i].SetInclusion(LOGICAL);
+ else
+ partitions[i].SetInclusion(NONE);
+ } // if
+ } // for
+} // BasicMBRData::MakeLogicalsContiguous()
+
+// If MBR data aren't legal, adjust primary/logical assignments and,
+// if necessary, drop partitions, to make the data legal.
+void BasicMBRData::MakeItLegal(void) {
+ if (!IsLegal()) {
+ DeleteOversizedParts();
+// OmitAll();
+ MaximizeLogicals();
+ MaximizePrimaries();
+ if (!AreLogicalsContiguous())
+ MakeLogicalsContiguous();
+ if (NumPrimaries() > 4)
+ TrimPrimaries();
+ OmitOverlaps();
+ } // if
+} // BasicMBRData::MakeItLegal()
+
+// Removes logical partitions and deactivated partitions from first four
+// entries (primary space).
+// Returns the number of partitions moved.
+int BasicMBRData::RemoveLogicalsFromFirstFour(void) {
+ int i, j = 4, numMoved = 0, swapped = 0;
+ MBRPart temp;
+
+ for (i = 0; i < 4; i++) {
+ if ((partitions[i].GetInclusion() != PRIMARY) && (partitions[i].GetLengthLBA() > 0)) {
+ j = 4;
+ swapped = 0;
+ do {
+ if ((partitions[j].GetInclusion() == NONE) && (partitions[j].GetLengthLBA() == 0)) {
+ temp = partitions[j];
+ partitions[j] = partitions[i];
+ partitions[i] = temp;
+ swapped = 1;
+ numMoved++;
+ } // if
+ j++;
+ } while ((j < MAX_MBR_PARTS) && !swapped);
+ if (j >= MAX_MBR_PARTS)
+ cerr << "Warning! Too many partitions in BasicMBRData::RemoveLogicalsFromFirstFour()!\n";
+ } // if
+ } // for i...
+ return numMoved;
+} // BasicMBRData::RemoveLogicalsFromFirstFour()
+
+// Move all primaries into the first four partition spaces
+// Returns the number of partitions moved.
+int BasicMBRData::MovePrimariesToFirstFour(void) {
+ int i, j = 0, numMoved = 0, swapped = 0;
+ MBRPart temp;
+
+ for (i = 4; i < MAX_MBR_PARTS; i++) {
+ if (partitions[i].GetInclusion() == PRIMARY) {
+ j = 0;
+ swapped = 0;
+ do {
+ if (partitions[j].GetInclusion() != PRIMARY) {
+ temp = partitions[j];
+ partitions[j] = partitions[i];
+ partitions[i] = temp;
+ swapped = 1;
+ numMoved++;
+ } // if
+ j++;
+ } while ((j < 4) && !swapped);
+ } // if
+ } // for
+ return numMoved;
+} // BasicMBRData::MovePrimariesToFirstFour()
+
+// Create an extended partition, if necessary, to hold the logical partitions.
+// This function also sorts the primaries into the first four positions of
+// the table.
+// Returns 1 on success, 0 on failure.
+int BasicMBRData::CreateExtended(void) {
+ int allOK = 1, i = 0, swapped = 0;
+ MBRPart temp;
+
+ if (IsLegal()) {
+ // Move logicals out of primary space...
+ RemoveLogicalsFromFirstFour();
+ // Move primaries out of logical space...
+ MovePrimariesToFirstFour();
+
+ // Create the extended partition
+ if (NumLogicals() > 0) {
+ SortMBR(4); // sort starting from 4 -- that is, logicals only
+ temp.Empty();
+ temp.SetStartLBA(FirstLogicalLBA() - 1);
+ temp.SetLengthLBA(LastLogicalLBA() - FirstLogicalLBA() + 2);
+ temp.SetType(0x0f, 1);
+ temp.SetInclusion(PRIMARY);
+ do {
+ if ((partitions[i].GetInclusion() == NONE) || (partitions[i].GetLengthLBA() == 0)) {
+ partitions[i] = temp;
+ swapped = 1;
+ } // if
i++;
+ } while ((i < 4) && !swapped);
+ if (!swapped) {
+ cerr << "Could not create extended partition; no room in primary table!\n";
+ allOK = 0;
} // if
- } // while
- MakePart(3, (uint32_t) extStartLBA, (uint32_t) (extEndLBA - extStartLBA + 1), 0x0f, 0);
- } else {
- if (numLogicals > 0) {
- cerr << "Unable to create logical partitions; they exceed the 2 TiB limit!\n";
-// cout << "extStartLBA = " << extStartLBA << ", extEndLBA = " << extEndLBA << "\n";
- }
- } // if/else
- return (i - 4);
-} // BasicMBRData::CreateLogicals()
+ } // if (NumLogicals() > 0)
+ } else allOK = 0;
+ // Do a final check for EFI GPT (0xEE) partitions & flag as a problem if found
+ // along with an extended partition
+ for (i = 0; i < MAX_MBR_PARTS; i++)
+ if (swapped && partitions[i].GetType() == 0xEE)
+ allOK = 0;
+ return allOK;
+} // BasicMBRData::CreateExtended()
/****************************************
* *
@@ -824,9 +1423,9 @@ int BasicMBRData::CreateLogicals(PartNotes * notes) {
// Finds the first free space on the disk from start onward; returns 0
// if none available....
-uint32_t BasicMBRData::FindFirstAvailable(uint32_t start) {
- uint32_t first;
- uint32_t i;
+uint64_t BasicMBRData::FindFirstAvailable(uint64_t start) {
+ uint64_t first;
+ uint64_t i;
int firstMoved;
first = start;
@@ -840,44 +1439,44 @@ uint32_t BasicMBRData::FindFirstAvailable(uint32_t start) {
firstMoved = 0;
for (i = 0; i < 4; i++) {
// Check if it's in the existing partition
- if ((first >= partitions[i].firstLBA) &&
- (first < (partitions[i].firstLBA + partitions[i].lengthLBA))) {
- first = partitions[i].firstLBA + partitions[i].lengthLBA;
+ if ((first >= partitions[i].GetStartLBA()) &&
+ (first < (partitions[i].GetStartLBA() + partitions[i].GetLengthLBA()))) {
+ first = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
firstMoved = 1;
} // if
} // for
} while (firstMoved == 1);
- if (first >= diskSize)
+ if ((first >= diskSize) || (first > UINT32_MAX))
first = 0;
return (first);
} // BasicMBRData::FindFirstAvailable()
// Finds the last free sector on the disk from start forward.
-uint32_t BasicMBRData::FindLastInFree(uint32_t start) {
- uint32_t nearestStart;
- uint32_t i;
+uint64_t BasicMBRData::FindLastInFree(uint64_t start) {
+ uint64_t nearestStart;
+ uint64_t i;
if ((diskSize <= UINT32_MAX) && (diskSize > 0))
- nearestStart = (uint32_t) diskSize - 1;
+ nearestStart = diskSize - 1;
else
nearestStart = UINT32_MAX - 1;
for (i = 0; i < 4; i++) {
- if ((nearestStart > partitions[i].firstLBA) &&
- (partitions[i].firstLBA > start)) {
- nearestStart = partitions[i].firstLBA - 1;
+ if ((nearestStart > partitions[i].GetStartLBA()) &&
+ (partitions[i].GetStartLBA() > start)) {
+ nearestStart = partitions[i].GetStartLBA() - 1;
} // if
} // for
return (nearestStart);
} // BasicMBRData::FindLastInFree()
// Finds the first free sector on the disk from start backward.
-uint32_t BasicMBRData::FindFirstInFree(uint32_t start) {
- uint32_t bestLastLBA, thisLastLBA;
+uint64_t BasicMBRData::FindFirstInFree(uint64_t start) {
+ uint64_t bestLastLBA, thisLastLBA;
int i;
bestLastLBA = 1;
for (i = 0; i < 4; i++) {
- thisLastLBA = partitions[i].firstLBA + partitions[i].lengthLBA;
+ thisLastLBA = partitions[i].GetLastLBA() + 1;
if (thisLastLBA > 0)
thisLastLBA--;
if ((thisLastLBA > bestLastLBA) && (thisLastLBA < start))
@@ -886,24 +1485,36 @@ uint32_t BasicMBRData::FindFirstInFree(uint32_t start) {
return (bestLastLBA);
} // BasicMBRData::FindFirstInFree()
-// Returns 1 if the specified sector is unallocated, 0 if it's
+// Returns NONE (unused), PRIMARY, LOGICAL, EBR (for EBR or MBR), or INVALID
+int BasicMBRData::SectorUsedAs(uint64_t sector, int topPartNum) {
+ int i = 0, usedAs = NONE;
+
+ do {
+ if ((partitions[i].GetStartLBA() <= sector) && (partitions[i].GetLastLBA() >= sector))
+ usedAs = partitions[i].GetInclusion();
+ if ((partitions[i].GetStartLBA() == (sector + 1)) && (partitions[i].GetInclusion() == LOGICAL))
+ usedAs = EBR;
+ if (sector == 0)
+ usedAs = EBR;
+ if (sector >= diskSize)
+ usedAs = INVALID;
+ i++;
+ } while ((i < topPartNum) && (usedAs == NONE));
+ return usedAs;
+} // BasicMBRData::SectorUsedAs()
+
+/* // Returns 1 if the specified sector is unallocated, 0 if it's
// allocated.
-int BasicMBRData::IsFree(uint32_t sector) {
+int BasicMBRData::IsFree(uint64_t sector, int topPartNum) {
int i, isFree = 1;
- uint32_t first, last;
- for (i = 0; i < 4; i++) {
- first = partitions[i].firstLBA;
- // Note: Weird two-line thing to avoid subtracting 1 from a 0 value
- // for an unsigned int....
- last = first + partitions[i].lengthLBA;
- if (last > 0)
- last--;
- if ((first <= sector) && (last >= sector))
+ for (i = 0; i < topPartNum; i++) {
+ if ((partitions[i].GetStartLBA() <= sector) && (partitions[i].GetLastLBA() >= sector)
+ && (partitions[i].GetInclusion() != NONE))
isFree = 0;
} // for
return isFree;
-} // BasicMBRData::IsFree()
+} // BasicMBRData::IsFree() */
/******************************************************
* *
@@ -912,50 +1523,50 @@ int BasicMBRData::IsFree(uint32_t sector) {
******************************************************/
uint8_t BasicMBRData::GetStatus(int i) {
- MBRRecord* thePart;
+ MBRPart* thePart;
uint8_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
- retval = thePart->status;
+ retval = thePart->GetStatus();
else
retval = UINT8_C(0);
return retval;
} // BasicMBRData::GetStatus()
uint8_t BasicMBRData::GetType(int i) {
- MBRRecord* thePart;
+ MBRPart* thePart;
uint8_t retval;
thePart = GetPartition(i);
if (thePart != NULL)
- retval = thePart->partitionType;
+ retval = thePart->GetType();
else
retval = UINT8_C(0);
return retval;
} // BasicMBRData::GetType()
-uint32_t BasicMBRData::GetFirstSector(int i) {
- MBRRecord* thePart;
- uint32_t retval;
+uint64_t BasicMBRData::GetFirstSector(int i) {
+ MBRPart* thePart;
+ uint64_t retval;
thePart = GetPartition(i);
if (thePart != NULL) {
- retval = thePart->firstLBA;
+ retval = thePart->GetStartLBA();
} else
retval = UINT32_C(0);
return retval;
} // BasicMBRData::GetFirstSector()
-uint32_t BasicMBRData::GetLength(int i) {
- MBRRecord* thePart;
- uint32_t retval;
+uint64_t BasicMBRData::GetLength(int i) {
+ MBRPart* thePart;
+ uint64_t retval;
thePart = GetPartition(i);
if (thePart != NULL) {
- retval = thePart->lengthLBA;
+ retval = thePart->GetLengthLBA();
} else
- retval = UINT32_C(0);
+ retval = UINT64_C(0);
return retval;
} // BasicMBRData::GetLength()
@@ -967,10 +1578,115 @@ uint32_t BasicMBRData::GetLength(int i) {
// Return a pointer to a primary or logical partition, or NULL if
// the partition is out of range....
-struct MBRRecord* BasicMBRData::GetPartition(int i) {
- MBRRecord* thePart = NULL;
+MBRPart* BasicMBRData::GetPartition(int i) {
+ MBRPart* thePart = NULL;
if ((i >= 0) && (i < MAX_MBR_PARTS))
thePart = &partitions[i];
return thePart;
} // GetPartition()
+
+/*******************************************
+ * *
+ * Functions that involve user interaction *
+ * *
+ *******************************************/
+
+// Present the MBR operations menu. Note that the 'w' option does not
+// immediately write data; that's handled by the calling function.
+// Returns the number of partitions defined on exit, or -1 if the
+// user selected the 'q' option. (Thus, the caller should save data
+// if the return value is >0, or possibly >=0 depending on intentions.)
+int BasicMBRData::DoMenu(const string& prompt) {
+ char line[255];
+ int goOn = 1, quitting = 0, retval, num, haveShownInfo = 0;
+ unsigned int hexCode = 0x00;
+
+ do {
+ cout << prompt;
+ ReadCString(line, 255);
+ switch (*line) {
+ case '\n':
+ break;
+ case 'a': case 'A':
+ num = GetNumber(1, MAX_MBR_PARTS, 1, "Toggle active flag for partition: ") - 1;
+ if (partitions[num].GetInclusion() != NONE)
+ partitions[num].SetStatus(partitions[num].GetStatus() ^ 0x80);
+ break;
+ case 'c': case 'C':
+ for (num = 0; num < MAX_MBR_PARTS; num++)
+ RecomputeCHS(num);
+ break;
+ case 'l': case 'L':
+ num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as logical: ") - 1;
+ SetInclusionwChecks(num, LOGICAL);
+ break;
+ case 'o': case 'O':
+ num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to omit: ") - 1;
+ SetInclusionwChecks(num, NONE);
+ break;
+ case 'p': case 'P':
+ if (!haveShownInfo) {
+ cout << "\n** NOTE: Partition numbers do NOT indicate final primary/logical "
+ << "status,\n** unlike in most MBR partitioning tools!\n\a";
+ cout << "\n** Extended partitions are not displayed, but will be generated "
+ << "as required.\n";
+ haveShownInfo = 1;
+ } // if
+ DisplayMBRData();
+ break;
+ case 'q': case 'Q':
+ cout << "This will abandon your changes. Are you sure? ";
+ if (GetYN() == 'Y') {
+ goOn = 0;
+ quitting = 1;
+ } // if
+ break;
+ case 'r': case 'R':
+ num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to set as primary: ") - 1;
+ SetInclusionwChecks(num, PRIMARY);
+ break;
+ case 's': case 'S':
+ SortMBR();
+ break;
+ case 't': case 'T':
+ num = GetNumber(1, MAX_MBR_PARTS, 1, "Partition to change type code: ") - 1;
+ if (partitions[num].GetLengthLBA() > 0) {
+ hexCode = 0;
+ while ((hexCode <= 0) || (hexCode > 255)) {
+ cout << "Enter an MBR hex code: ";
+ ReadCString(line, 255);
+ sscanf(line, "%x", &hexCode);
+ if (line[0] == '\n')
+ hexCode = 0x00;
+ } // while
+ partitions[num].SetType(hexCode);
+ } // if
+ break;
+ case 'w': case 'W':
+ goOn = 0;
+ break;
+ default:
+ ShowCommands();
+ break;
+ } // switch
+ } while (goOn);
+ if (quitting)
+ retval = -1;
+ else
+ retval = CountParts();
+ return (retval);
+} // BasicMBRData::DoMenu()
+
+void BasicMBRData::ShowCommands(void) {
+ cout << "a\ttoggle the active/boot flag\n";
+ cout << "c\trecompute all CHS values\n";
+ cout << "l\tset partition as logical\n";
+ cout << "o\tomit partition\n";
+ cout << "p\tprint the MBR partition table\n";
+ cout << "q\tquit without saving changes\n";
+ cout << "r\tset partition as primary\n";
+ cout << "s\tsort MBR partitions\n";
+ cout << "t\tchange partition type code\n";
+ cout << "w\twrite the MBR partition table to disk and exit\n";
+} // BasicMBRData::ShowCommands()
diff --git a/basicmbr.h b/basicmbr.h
index d758994..b8be6e4 100644
--- a/basicmbr.h
+++ b/basicmbr.h
@@ -5,16 +5,13 @@
#include <stdint.h>
#include <sys/types.h>
-#include "partnotes.h"
#include "diskio.h"
+#include "mbrpart.h"
#ifndef __BASICMBRSTRUCTS
#define __BASICMBRSTRUCTS
#define MBR_SIGNATURE UINT16_C(0xAA55)
-#define MAX_HEADS 255 /* numbered 0 - 254 */
-#define MAX_SECSPERTRACK 63 /* numbered 1 - 63 */
-#define MAX_CYLINDERS 1024 /* numbered 0 - 1023 */
// Maximum number of MBR partitions
#define MAX_MBR_PARTS 128
@@ -29,23 +26,6 @@ class PartNotes;
* *
****************************************/
-// Data for a single MBR partition record
-// Note that firstSector and lastSector are in CHS addressing, which
-// splits the bits up in a weird way.
-// On read or write of MBR entries, firstLBA is an absolute disk sector.
-// On read of logical entries, it's relative to the EBR record for that
-// partition. When writing EBR records, it's relative to the extended
-// partition's start.
-#pragma pack(1)
-struct MBRRecord {
- uint8_t status;
- uint8_t firstSector[3];
- uint8_t partitionType;
- uint8_t lastSector[3];
- uint32_t firstLBA; // see above
- uint32_t lengthLBA;
-}; // struct MBRRecord
-
// A 512-byte data structure into which the MBR can be loaded in one
// go. Also used when loading logical partitions.
#pragma pack(1)
@@ -68,19 +48,19 @@ protected:
uint16_t nulls;
// MAX_MBR_PARTS defaults to 128. This array holds both the primary and
// the logical partitions, to simplify data retrieval for GPT conversions.
- struct MBRRecord partitions[MAX_MBR_PARTS];
+ MBRPart partitions[MAX_MBR_PARTS];
uint16_t MBRSignature;
// Above are basic MBR data; now add more stuff....
uint32_t blockSize; // block size (usually 512)
uint64_t diskSize; // size in blocks
- uint64_t numHeads; // number of heads, in CHS scheme
- uint64_t numSecspTrack; // number of sectors per track, in CHS scheme
+ uint32_t numHeads; // number of heads, in CHS scheme
+ uint32_t numSecspTrack; // number of sectors per track, in CHS scheme
DiskIO* myDisk;
int canDeleteMyDisk;
string device;
MBRValidity state;
- struct MBRRecord* GetPartition(int i); // Return primary or logical partition
+ MBRPart* GetPartition(int i); // Return primary or logical partition
public:
BasicMBRData(void);
BasicMBRData(string deviceFilename);
@@ -92,51 +72,90 @@ public:
int ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1);
// ReadLogicalPart() returns last partition # read to logicals[] array,
// or -1 if there was a problem....
- int ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset,
+ int ReadLogicalPart(uint64_t extendedStart, uint64_t diskOffset,
int partNum);
int WriteMBRData(void);
int WriteMBRData(DiskIO *theDisk);
int WriteMBRData(const string & deviceFilename);
int WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t sector);
- void SetDisk(DiskIO *theDisk) {myDisk = theDisk; canDeleteMyDisk = 0;}
+ void DiskSync(void) {myDisk->DiskSync();}
+ void SetDisk(DiskIO *theDisk);
// Display data for user...
- void DisplayMBRData(int maxParts = 4);
+ void DisplayMBRData(void);
void ShowState(void);
+ // GPT checks and fixes...
+ int CheckForGPT(void);
+ int BlankGPTData(void);
+
// Functions that set or get disk metadata (size, CHS geometry, etc.)
void SetDiskSize(uint64_t ds) {diskSize = ds;}
void SetBlockSize(uint32_t bs) {blockSize = bs;}
MBRValidity GetValidity(void) {return state;}
void SetHybrid(void) {state = hybrid;} // Set hybrid flag
- void SetCHSGeom(uint32_t h, uint32_t s);
+ void ReadCHSGeom(void);
+ int GetPartRange(uint32_t* low, uint32_t* high);
int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS
- int Verify(void);
+ int FindOverlaps(void);
+ int NumPrimaries(void);
+ int NumLogicals(void);
+ int CountParts(void);
+ void UpdateCanBeLogical(void);
+ uint64_t FirstLogicalLBA(void);
+ uint64_t LastLogicalLBA(void);
+ int AreLogicalsContiguous(void);
+ int DoTheyFit(void);
+ int SpaceBeforeAllLogicals(void);
+ int IsLegal(void);
+ int FindNextInUse(int start);
// Functions to create, delete, or change partitions
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
void EmptyMBR(int clearBootloader = 1);
void EmptyBootloader(void);
- void MakePart(int num, uint32_t startLBA, uint32_t lengthLBA, int type = 0x07,
+ void AddPart(int num, const MBRPart& newPart);
+ void MakePart(int num, uint64_t startLBA, uint64_t lengthLBA, int type = 0x07,
int bootable = 0);
int SetPartType(int num, int type);
int SetPartBootable(int num, int bootable = 1);
int MakeBiggestPart(int i, int type); // Make partition filling most space
void DeletePartition(int i);
+ int SetInclusionwChecks(int num, int inclStatus);
void RecomputeCHS(int partNum);
- int CreateLogicals(PartNotes * notes);
+ int SwapPartitions(uint32_t partNum1, uint32_t partNum2);
+ void SortMBR(int start = 0);
+ void QuickSortMBR(int start, int finish);
+ int DeleteOversizedParts();
+ int DeleteExtendedParts();
+ void OmitOverlaps(void);
+// void OmitAll(void);
+ void MaximizeLogicals();
+ void MaximizePrimaries();
+ void TrimPrimaries();
+ void MakeLogicalsContiguous(void);
+ void MakeItLegal(void);
+ int RemoveLogicalsFromFirstFour(void);
+ int MovePrimariesToFirstFour(void);
+ int CreateExtended(void);
// Functions to find information on free space....
- uint32_t FindFirstAvailable(uint32_t start = 1);
- uint32_t FindLastInFree(uint32_t start);
- uint32_t FindFirstInFree(uint32_t start);
- int IsFree(uint32_t sector);
+ uint64_t FindFirstAvailable(uint64_t start = 1);
+ uint64_t FindLastInFree(uint64_t start);
+ uint64_t FindFirstInFree(uint64_t start);
+// int IsFree(uint64_t sector, int topPartNum = MAX_MBR_PARTS);
+ int SectorUsedAs(uint64_t sector, int topPartNum = MAX_MBR_PARTS);
// Functions to extract data on specific partitions....
uint8_t GetStatus(int i);
uint8_t GetType(int i);
- uint32_t GetFirstSector(int i);
- uint32_t GetLength(int i);
+ uint64_t GetFirstSector(int i);
+ uint64_t GetLength(int i);
+
+ // User interaction functions....
+ int DoMenu(const string& prompt = "\nMBR command (? for help): ");
+ void ShowCommands(void);
+
}; // struct BasicMBRData
#endif
diff --git a/current.spec b/current.spec
index 18b283b..3ae7f6c 100644
--- a/current.spec
+++ b/current.spec
@@ -1,14 +1,29 @@
-Summary: An fdisk-like partitioning tool for GPT disks
-Name: gdisk
-Version: 0.6.14
+Summary: GPT partitioning and MBR repair software
+Name: gptfdisk
+Version: 0.7.0
Release: 1%{?dist}
License: GPLv2
URL: http://www.rodsbooks.com/gdisk
Group: Applications/System
-Source: http://www.rodsbooks.com/gdisk/gdisk-0.6.14.tgz
+Source: http://www.rodsbooks.com/gdisk/gptfdisk-0.7.0.tgz
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
%description
+
+Partitioning software for GPT disks and to repair MBR
+disks. The gdisk and sgdisk utilities (in the gdisk
+package) are GPT-enabled partitioning tools; the
+fixparts utility (in the fixparts package) fixes some
+problems with MBR disks that can be created by buggy
+partitioning software.
+
+%package -n gdisk
+
+Group: Applications/System
+
+Summary: An fdisk-like partitioning tool for GPT disks
+
+%description -n gdisk
An fdisk-like partitioning tool for GPT disks. GPT
fdisk features a command-line interface, fairly direct
manipulation of partition table structures, recovery
@@ -26,19 +41,41 @@ rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0755 gdisk $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0755 sgdisk $RPM_BUILD_ROOT/usr/sbin
+install -Dp -m0755 fixparts $RPM_BUILD_ROOT/usr/sbin
install -Dp -m0644 gdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/gdisk.8
install -Dp -m0644 sgdisk.8 $RPM_BUILD_ROOT/%{_mandir}/man8/sgdisk.8
+install -Dp -m0644 fixparts.8 $RPM_BUILD_ROOT/%{_mandir}/man8/fixparts.8
%clean
rm -rf $RPM_BUILD_ROOT
-%files
+%files -n gdisk
%defattr(-,root,root -)
%doc NEWS COPYING README
/usr/sbin/gdisk
/usr/sbin/sgdisk
-%doc %{_mandir}/man8*
+%doc %{_mandir}/man8/gdisk.8*
+%doc %{_mandir}/man8/sgdisk.8*
+
+%package -n fixparts
+
+Group: Applications/System
+
+Summary: A tool for repairing certain types of damage to MBR disks
+
+%description -n fixparts
+A program that corrects errors that can creep into MBR-partitioned
+disks. Removes stray GPT data, fixes mis-sized extended partitions,
+and enables changing primary vs. logical partition status. Also
+provides a few additional partition manipulation features.
+
+%files -n fixparts
+%defattr(-,root,root -)
+%doc NEWS COPYING README
+/usr/sbin/fixparts
+%doc %{_mandir}/man8/fixparts.8*
+
%changelog
-* Sat Jan 8 2011 R Smith <rodsmith@rodsbooks.com> - 0.6.14
-- Created spec file for 0.6.14 release
+* Fri Mar 11 2011 R Smith <rodsmith@rodsbooks.com> - 0.7.0
+- Created spec file for 0.7.0 release
diff --git a/diskio-unix.cc b/diskio-unix.cc
index d65a644..238e529 100644
--- a/diskio-unix.cc
+++ b/diskio-unix.cc
@@ -22,6 +22,11 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
+
+#ifdef __linux__
+#include "linux/hdreg.h"
+#endif
+
#include <iostream>
#include "diskio.h"
@@ -160,6 +165,42 @@ int DiskIO::GetBlockSize(void) {
return (blockSize);
} // DiskIO::GetBlockSize()
+// Returns the number of heads, according to the kernel, or 255 if the
+// correct value can't be determined.
+uint32_t DiskIO::GetNumHeads(void) {
+ uint32_t numHeads = 255;
+
+#ifdef HDIO_GETGEO
+ struct hd_geometry geometry;
+
+ // If disk isn't open, try to open it....
+ if (!isOpen)
+ OpenForRead();
+
+ if (!ioctl(fd, HDIO_GETGEO, &geometry))
+ numHeads = (uint32_t) geometry.heads;
+#endif
+ return numHeads;
+} // DiskIO::GetNumHeads();
+
+// Returns the number of sectors per track, according to the kernel, or 63
+// if the correct value can't be determined.
+uint32_t DiskIO::GetNumSecsPerTrack(void) {
+ uint32_t numSecs = 63;
+
+ #ifdef HDIO_GETGEO
+ struct hd_geometry geometry;
+
+ // If disk isn't open, try to open it....
+ if (!isOpen)
+ OpenForRead();
+
+ if (!ioctl(fd, HDIO_GETGEO, &geometry))
+ numSecs = (uint32_t) geometry.sectors;
+ #endif
+ return numSecs;
+} // DiskIO::GetNumSecsPerTrack()
+
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
void DiskIO::DiskSync(void) {
diff --git a/diskio-windows.cc b/diskio-windows.cc
index 6c9aee6..b79884c 100644
--- a/diskio-windows.cc
+++ b/diskio-windows.cc
@@ -143,6 +143,18 @@ int DiskIO::GetBlockSize(void) {
return (blockSize);
} // DiskIO::GetBlockSize()
+// Returns the number of heads, according to the kernel, or 255 if the
+// correct value can't be determined.
+uint32_t DiskIO::GetNumHeads(void) {
+ return UINT32_C(255);
+} // DiskIO::GetNumHeads();
+
+// Returns the number of sectors per track, according to the kernel, or 63
+// if the correct value can't be determined.
+uint32_t DiskIO::GetNumSecsPerTrack(void) {
+ return UINT32_C(63);
+} // DiskIO::GetNumSecsPerTrack()
+
// Resync disk caches so the OS uses the new partition table. This code varies
// a lot from one OS to another.
void DiskIO::DiskSync(void) {
diff --git a/diskio.cc b/diskio.cc
index d433d3d..baf235b 100644
--- a/diskio.cc
+++ b/diskio.cc
@@ -34,7 +34,7 @@
#include "support.h"
#include "diskio.h"
-#include "gpt.h"
+//#include "gpt.h"
using namespace std;
diff --git a/diskio.h b/diskio.h
index d9f0d38..7bb01e6 100644
--- a/diskio.h
+++ b/diskio.h
@@ -31,7 +31,7 @@
#endif
#include "support.h"
-#include "parttypes.h"
+//#include "parttypes.h"
using namespace std;
@@ -67,6 +67,8 @@ class DiskIO {
int Write(void* buffer, int numBytes);
void DiskSync(void); // resync disk caches to use new partitions
int GetBlockSize(void);
+ uint32_t GetNumHeads(void);
+ uint32_t GetNumSecsPerTrack(void);
int IsOpen(void) {return isOpen;}
int IsOpenForWrite(void) {return openForWrite;}
string GetName(void) const {return realFilename;}
diff --git a/gdisk.8 b/gdisk.8
index 272677c..f872f2b 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -1,6 +1,6 @@
-.\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
-.TH "GDISK" "8" "0.6.14" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "GDISK" "8" "0.7.0" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
gdisk \- Interactive GUID partition table (GPT) manipulator
.SH "SYNOPSIS"
@@ -561,7 +561,7 @@ entering data. When only one option is possible, \fBgdisk\fR
usually bypasses the prompt entirely.
.SH "BUGS"
-As of January 2011 (version 0.6.14), \fBgdisk\fR
+As of March 2011 (version 0.7.0), \fBgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP
@@ -600,7 +600,7 @@ preserved when loading and saving partitions.
The program can load only up to 128 partitions (4 primary partitions and
124 logical partitions) when converting from MBR format. This limit can
be raised by changing the \fI#define MAX_MBR_PARTS\fR line in the
-\fImbr.h\fR source code file and recompiling; however, such a change
+\fIbasicmbr.h\fR source code file and recompiling; however, such a change
will require using a larger\-than\-normal partition table. (The limit
of 128 partitions was chosen because that number equals the 128 partitions
supported by the most common partition table size.)
@@ -674,6 +674,7 @@ Contributors:
\fBparted (8)\fR,
\fBsfdisk (8)\fR
\fBsgdisk (8)\fR
+\fBfixparts (8)\fR
\fIhttp://en.wikipedia.org/wiki/GUID_Partition_Table\fR
diff --git a/gdisk.cc b/gdisk.cc
index f786431..78d65b7 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -8,7 +8,6 @@
under the terms of the GNU GPL version 2, as detailed in the COPYING file. */
#include <stdio.h>
-//#include <getopt.h>
#include <string.h>
#include <string>
#include <iostream>
@@ -42,10 +41,7 @@ int main(int argc, char* argv[]) {
WinWarning();
cout << "Type device filename, or press <Enter> to exit: ";
device = new char[255];
- if (!fgets(device, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in main()!\n";
- exit(1);
- } // if
+ ReadCString(device, 255);
i = strlen(device);
if (i && device[i - 1] == '\n')
device[i - 1] = '\0';
@@ -88,19 +84,13 @@ void MainMenu(string filename, GPTDataTextUI* theGPT) {
do {
cout << "\nCommand (? for help): ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in MainMenu()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
switch (*line) {
case '\n':
break;
case 'b': case 'B':
cout << "Enter backup filename to save: ";
- if (!fgets(line, 255, stdin)) {
- exit(1);
- cerr << "Critical error! Failed fgets() in MainMenu()!\n";
- } // if
+ ReadCString(line, 255);
sscanf(line, "%s", buFile);
theGPT->SaveGPTBackup(buFile);
break;
@@ -188,15 +178,12 @@ void ShowCommands(void) {
// issues an exit command, such as 'w' or 'q'.
void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
char line[255], buFile[255];
- uint32_t temp1, numParts;
- int goOn = 1;
+ uint32_t numParts;
+ int goOn = 1, temp1;
do {
cout << "\nRecovery/transformation command (? for help): ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in RecoveryMenu()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
switch (*line) {
case '\n':
break;
@@ -232,17 +219,17 @@ void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
case 'g': case 'G':
numParts = theGPT->GetNumParts();
temp1 = theGPT->XFormToMBR();
- if (temp1 > 0) {
+ if (temp1 > 0)
cout << "\nConverted " << temp1 << " partitions. Finalize and exit? ";
- if (GetYN() == 'Y') {
- if ((theGPT->DestroyGPT() > 0) && (theGPT->SaveMBR()))
- goOn = 0;
- } else {
- theGPT->MakeProtectiveMBR();
- theGPT->SetGPTSize(numParts);
- cout << "Note: New protective MBR created\n\n";
- } // if/else
- } // if
+ if ((temp1 > 0) && (GetYN() == 'Y')) {
+ if ((theGPT->DestroyGPT() > 0) && (theGPT->SaveMBR())) {
+ goOn = 0;
+ } // if
+ } else {
+ theGPT->MakeProtectiveMBR();
+ theGPT->SetGPTSize(numParts);
+ cout << "Note: New protective MBR created\n\n";
+ } // if/else
break;
case 'h': case 'H':
theGPT->MakeHybrid();
@@ -252,10 +239,7 @@ void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
break;
case 'l': case 'L':
cout << "Enter backup filename to load: ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in RecoveryMenu()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
sscanf(line, "%s", buFile);
theGPT->LoadGPTBackup(buFile);
break;
@@ -329,10 +313,7 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
do {
cout << "\nExpert command (? for help): ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
switch (*line) {
case '\n':
break;
@@ -346,10 +327,7 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
if (theGPT->GetPartRange(&temp1, &temp2) > 0) {
pn = theGPT->GetPartNum();
cout << "Enter the partition's new unique GUID ('R' to randomize): ";
- if (!fgets(guidStr, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
- exit(1);
- } // if
+ ReadCString(guidStr, 255);
if ((strlen(guidStr) >= 33) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
theGPT->SetPartitionGUID(pn, (GUIDData) guidStr);
cout << "New GUID is " << theGPT->operator[](pn).GetUniqueGUID() << "\n";
@@ -371,10 +349,7 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
break;
case 'g': case 'G':
cout << "Enter the disk's unique GUID ('R' to randomize): ";
- if (!fgets(guidStr, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
- exit(1);
- } // if
+ ReadCString(guidStr, 255);
if ((strlen(guidStr) >= 33) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
theGPT->SetDiskGUID((GUIDData) guidStr);
cout << "The new disk GUID is " << theGPT->GetDiskGUID() << "\n";
@@ -423,16 +398,13 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
case 'u': case 'U':
cout << "Type device filename, or press <Enter> to exit: ";
device = new char[255];
- if (!fgets(device, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
- exit(1);
- } // if
+ ReadCString(device, 255);
i = strlen(device);
if (i && device[i - 1] == '\n')
device[i - 1] = '\0';
if (*device && strlen(device) > 0) {
secondDevice = *theGPT;
- secondDevice.SetFile(device);
+ secondDevice.SetDisk(device);
secondDevice.SaveGPTData(0);
} // if
delete[] device;
diff --git a/gpt.cc b/gpt.cc
index 309a038..652fab4 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -26,7 +26,7 @@
#include "parttypes.h"
#include "attributes.h"
#include "diskio.h"
-#include "partnotes.h"
+//#include "partnotes.h"
using namespace std;
@@ -61,7 +61,6 @@ GPTData::GPTData(void) {
sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
- srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
numParts = 0;
SetGPTSize(NUM_GPT_ENTRIES);
@@ -84,7 +83,6 @@ GPTData::GPTData(string filename) {
sectorAlignment = MIN_AF_ALIGNMENT; // Align partitions on 4096-byte boundaries by default
beQuiet = 0;
whichWasUsed = use_new;
- srand((unsigned int) time(NULL));
mainHeader.numParts = 0;
numParts = 0;
if (!LoadPartitions(filename))
@@ -609,7 +607,7 @@ int GPTData::FindInsanePartitions(void) {
// Change the filename associated with the GPT. Used for duplicating
// the partition table to a new disk and saving backups.
// Returns 1 on success, 0 on failure.
-int GPTData::SetFile(const string & deviceFilename) {
+int GPTData::SetDisk(const string & deviceFilename) {
int err, allOK = 1;
device = deviceFilename;
@@ -622,7 +620,7 @@ int GPTData::SetFile(const string & deviceFilename) {
protectiveMBR.SetDiskSize(diskSize);
protectiveMBR.SetBlockSize(blockSize);
return allOK;
-} // GPTData::SetFile()
+} // GPTData::SetDisk()
// Scan for partition data. This function loads the MBR data (regular MBR or
// protective MBR) and loads BSD disklabel data (which is probably invalid).
@@ -991,7 +989,7 @@ int GPTData::SaveGPTData(int quiet) {
if ((allOK) && (!quiet)) {
cout << "\nFinal checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING\n"
- << "PARTITIONS!!\n\nDo you want to proceed, possibly destroying your data? ";
+ << "PARTITIONS!!\n\nDo you want to proceed? ";
answer = GetYN();
if (answer == 'Y') {
cout << "OK; writing new GUID partition table (GPT).\n";
@@ -1554,58 +1552,6 @@ int GPTData::OnePartToMBR(uint32_t gptPart, int mbrPart) {
return allOK;
} // GPTData::OnePartToMBR()
-// Convert partitions to MBR form (primary and logical) and return
-// the number done. Partitions are specified in a PartNotes variable,
-// which includes pointers to GPT partition numbers. A partition number
-// of MBR_EFI_GPT means to place an EFI GPT protective partition in that
-// location in the table, and MBR_EMPTY means not to create a partition
-// in that table position. If the partition type entry for a partition
-// is 0, a default entry is used, based on the GPT partition type code.
-// Returns the number of partitions converted, NOT counting EFI GPT
-// protective partitions or extended partitions.
-int GPTData::PartsToMBR(PartNotes * notes) {
- int mbrNum = 0, numConverted = 0;
- struct PartInfo convInfo;
-
- protectiveMBR.EmptyMBR(0);
- protectiveMBR.SetDiskSize(diskSize);
- if (!notes->IsLegal())
- notes->MakeItLegal();
- notes->Rewind();
- while (notes->GetNextInfo(&convInfo) >= 0) {
- if ((convInfo.origPartNum >= 0) && (convInfo.type == PRIMARY)) {
- numConverted += OnePartToMBR((uint32_t) convInfo.origPartNum, mbrNum);
- if (convInfo.hexCode != 0)
- protectiveMBR.SetPartType(mbrNum, convInfo.hexCode);
- if (convInfo.active)
- protectiveMBR.SetPartBootable(mbrNum);
- mbrNum++;
- } // if
- if (convInfo.origPartNum == MBR_EFI_GPT)
- mbrNum++;
- } // for
- // Now go through and set sizes for MBR_EFI_GPT partitions....
- notes->Rewind();
- mbrNum = 0;
- while (notes->GetNextInfo(&convInfo) >= 0) {
- if ((convInfo.origPartNum >= 0) && (convInfo.type == PRIMARY))
- mbrNum++;
- if (convInfo.origPartNum == MBR_EFI_GPT) {
- if (protectiveMBR.FindFirstAvailable() == UINT32_C(1)) {
- protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), convInfo.hexCode);
- protectiveMBR.SetHybrid();
- } else {
- protectiveMBR.MakeBiggestPart(mbrNum, convInfo.hexCode);
- } // if/else
- mbrNum++;
- } // if
- } // while
- // Now do logical partition(s)...
- protectiveMBR.SetDisk(&myDisk);
- numConverted += protectiveMBR.CreateLogicals(notes);
- return numConverted;
-} // GPTData::PartsToMBR()
-
/**********************************************************************
* *
diff --git a/gpt.h b/gpt.h
index 3e0e206..69c06d3 100644
--- a/gpt.h
+++ b/gpt.h
@@ -11,19 +11,10 @@
#include "mbr.h"
#include "bsd.h"
#include "gptpart.h"
-#include "gptpartnotes.h"
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
-#define GPTFDISK_VERSION "0.6.15-pre1"
-
-// Constants used by GPTData::PartsToMBR(). MBR_EMPTY must be the lowest-
-// numbered value to refer to partition numbers. (Most will be 0 or positive,
-// of course.)
-#define MBR_EFI_GPT -1
-#define MBR_EMPTY -2
-
// Default values for sector alignment
#define DEFAULT_ALIGNMENT 2048
#define MAX_ALIGNMENT 65536
@@ -113,13 +104,14 @@ public:
void RecomputeCRCs(void);
void RebuildMainHeader(void);
void RebuildSecondHeader(void);
- int VerifyMBR(void) {return protectiveMBR.Verify();}
+ int VerifyMBR(void) {return protectiveMBR.FindOverlaps();}
int FindHybridMismatches(void);
int FindOverlaps(void);
int FindInsanePartitions(void);
// Load or save data from/to disk
- int SetFile(const string & deviceFilename);
+ int SetDisk(const string & deviceFilename);
+ DiskIO* GetDisk(void) {return &myDisk;}
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
void PartitionScan(void);
@@ -169,6 +161,7 @@ public:
int Align(uint64_t* sector);
// Return data about the GPT structures....
+ void SetProtectiveMBR(BasicMBRData & newMBR) {protectiveMBR = newMBR;}
int GetPartRange(uint32_t* low, uint32_t* high);
int FindFirstFreePart(void);
uint32_t GetNumParts(void) {return mainHeader.numParts;}
diff --git a/gptpart.cc b/gptpart.cc
index 63e453d..54aa618 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -36,7 +36,7 @@ GPTPart::~GPTPart(void) {
} // destructor
// Return the gdisk-specific two-byte hex code for the partition
-uint16_t GPTPart::GetHexType(void) {
+uint16_t GPTPart::GetHexType(void) const {
return partitionType.GetHexType();
} // GPTPart::GetHexType()
@@ -48,7 +48,7 @@ string GPTPart::GetTypeName(void) {
// Compute and return the partition's length (or 0 if the end is incorrectly
// set before the beginning).
-uint64_t GPTPart::GetLengthLBA(void) {
+uint64_t GPTPart::GetLengthLBA(void) const {
uint64_t length = 0;
if (firstLBA <= lastLBA)
@@ -98,10 +98,7 @@ void GPTPart::SetName(const string & theName) {
if (theName == "") { // No name specified, so get one from the user
cout << "Enter name: ";
- if (!fgets(newName, NAME_SIZE / 2 + 1, stdin)) {
- cerr << "Critical error! Failed fgets() in GPTPart::SetName()!\n";
- exit(1);
- }
+ ReadCString(newName, NAME_SIZE / 2 + 1);
// Input is likely to include a newline, so remove it....
i = strlen(newName);
@@ -203,7 +200,6 @@ void GPTPart::BlankPartition(void) {
int GPTPart::DoTheyOverlap(const GPTPart & other) {
// Don't bother checking unless these are defined (both start and end points
// are 0 for undefined partitions, so just check the start points)
-// cout << "Entering GPTPart::DoTheyOverlap()\n";
return firstLBA && other.firstLBA &&
(firstLBA <= other.lastLBA) != (lastLBA < other.firstLBA);
} // GPTPart::DoTheyOverlap()
@@ -231,10 +227,7 @@ void GPTPart::ChangeType(void) {
cout << "Current type is '" << GetTypeName() << "'\n";
do {
cout << "Hex code or GUID (L to show codes, Enter = 0700): ";
- if (!fgets(line, sizeof(line), stdin)) {
- cerr << "Critical error! Failed fgets() in GPTPart::ChangeType()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
if ((line[0] == 'L') || (line[0] == 'l')) {
partitionType.ShowAllTypes();
} else {
diff --git a/gptpart.h b/gptpart.h
index 25da6df..104a818 100644
--- a/gptpart.h
+++ b/gptpart.h
@@ -53,12 +53,12 @@ class GPTPart {
// Simple data retrieval:
PartType & GetType(void) {return partitionType;}
- uint16_t GetHexType(void);
+ uint16_t GetHexType(void) const;
string GetTypeName(void);
const GUIDData GetUniqueGUID(void) const {return uniqueGUID;}
uint64_t GetFirstLBA(void) const {return firstLBA;}
uint64_t GetLastLBA(void) const {return lastLBA;}
- uint64_t GetLengthLBA(void);
+ uint64_t GetLengthLBA(void) const;
Attributes GetAttributes(void) {return attributes;}
void ShowAttributes(uint32_t partNum) {attributes.ShowAttributes(partNum);}
string GetDescription(void);
diff --git a/gpttext.cc b/gpttext.cc
index 91391e2..e6ca8ce 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -29,7 +29,7 @@
#include <cstdio>
#include "attributes.h"
#include "gpttext.h"
-#include "gptpartnotes.h"
+//#include "gptpartnotes.h"
#include "support.h"
using namespace std;
@@ -235,7 +235,10 @@ void GPTDataTextUI::CreatePartition(void) {
partitions[partNum].ChangeType();
partitions[partNum].SetDefaultDescription();
} else {
- cout << "No free sectors available\n";
+ if (firstFreePart >= numParts)
+ cout << "No table partition entries left\n";
+ else
+ cout << "No free sectors available\n";
} // if/else
} // GPTDataTextUI::CreatePartition()
@@ -353,24 +356,22 @@ void GPTDataTextUI::ShowDetails(void) {
void GPTDataTextUI::MakeHybrid(void) {
uint32_t partNums[3];
char line[255];
- int numPartsToCvt, i, j, mbrNum, bootable = 0;
+ int numPartsToCvt, i, j, mbrNum = 0;
unsigned int hexCode = 0;
- struct PartInfo *newNote;
- PartNotes notes;
+ MBRPart hybridPart;
+ MBRData hybridMBR;
char eeFirst = 'Y'; // Whether EFI GPT (0xEE) partition comes first in table
cout << "\nWARNING! Hybrid MBRs are flaky and dangerous! If you decide not to use one,\n"
<< "just hit the Enter key at the below prompt and your MBR partition table will\n"
<< "be untouched.\n\n\a";
+ hybridMBR.SetDisk(&myDisk);
// Now get the numbers of up to three partitions to add to the
// hybrid MBR....
cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n"
<< "added to the hybrid MBR, in sequence: ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in GPTDataTextUI::MakeHybrid()!\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
numPartsToCvt = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
if (numPartsToCvt > 0) {
@@ -379,148 +380,64 @@ void GPTDataTextUI::MakeHybrid(void) {
} // if
for (i = 0; i < numPartsToCvt; i++) {
- newNote = new struct PartInfo;
- j = newNote->origPartNum = partNums[i] - 1;
+ j = partNums[i] - 1;
if (partitions[j].IsUsed()) {
mbrNum = i + (eeFirst == 'Y');
cout << "\nCreating entry for GPT partition #" << j + 1
<< " (MBR partition #" << mbrNum + 1 << ")\n";
- newNote->hexCode = GetMBRTypeCode(partitions[j].GetHexType() / 256);
- newNote->firstLBA = partitions[j].GetFirstLBA();
- newNote->lastLBA = partitions[j].GetLastLBA();
- newNote->type = PRIMARY;
+ hybridPart.SetType(GetMBRTypeCode(partitions[j].GetHexType() / 256));
+ hybridPart.SetLocation(partitions[j].GetFirstLBA(), partitions[j].GetLengthLBA());
+ hybridPart.SetInclusion(PRIMARY);
cout << "Set the bootable flag? ";
if (GetYN() == 'Y')
- newNote->active = 1;
+ hybridPart.SetStatus(1);
else
- newNote->active = 0;
- notes.AddToEnd(newNote);
+ hybridPart.SetStatus(0);
+ hybridPart.SetInclusion(PRIMARY);
} else {
- delete newNote;
cerr << "\nGPT partition #" << j + 1 << " does not exist; skipping.\n";
} // if/else
+ hybridMBR.AddPart(mbrNum, hybridPart);
} // for
if (numPartsToCvt > 0) { // User opted to create a hybrid MBR....
// Create EFI protective partition that covers the start of the disk.
// If this location (covering the main GPT data structures) is omitted,
// Linux won't find any partitions on the disk.
- newNote = new struct PartInfo;
- newNote->origPartNum = MBR_EFI_GPT;
- newNote->firstLBA = 1;
- newNote->active = 0;
- newNote->hexCode = 0xEE;
- newNote->type = PRIMARY;
+ hybridPart.SetLocation(1, hybridMBR.FindLastInFree(1));
+ hybridPart.SetStatus(0);
+ hybridPart.SetType(0xEE);
+ hybridPart.SetInclusion(PRIMARY);
// newNote firstLBA and lastLBA are computed later...
if (eeFirst == 'Y') {
- notes.AddToStart(newNote);
+ hybridMBR.AddPart(0, hybridPart);
} else {
- notes.AddToEnd(newNote);
+ hybridMBR.AddPart(3, hybridPart);
} // else
- protectiveMBR.SetHybrid();
+ hybridMBR.SetHybrid();
// ... and for good measure, if there are any partition spaces left,
// optionally create another protective EFI partition to cover as much
// space as possible....
- if (notes.GetNumPrimary() < 4) { // unused entry....
+ if (hybridMBR.CountParts() < 4) { // unused entry....
cout << "\nUnused partition space(s) found. Use one to protect more partitions? ";
if (GetYN() == 'Y') {
while ((hexCode <= 0) || (hexCode > 255)) {
cout << "Enter an MBR hex code (EE is EFI GPT, but may confuse MacOS): ";
// Comment on above: Mac OS treats disks with more than one
// 0xEE MBR partition as MBR disks, not as GPT disks.
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in GPTDataTextUI::MakeHybrid()\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
sscanf(line, "%x", &hexCode);
if (line[0] == '\n')
hexCode = 0x00;
} // while
- newNote = new struct PartInfo;
- newNote->origPartNum = MBR_EFI_GPT;
- newNote->active = 0;
- newNote->hexCode = hexCode;
- newNote->type = PRIMARY;
- // newNote firstLBA and lastLBA are computed later...
- notes.AddToEnd(newNote);
+ hybridMBR.MakeBiggestPart(3, 0xEE);
} // if (GetYN() == 'Y')
} // if unused entry
- PartsToMBR(&notes);
- if (bootable > 0)
- protectiveMBR.SetPartBootable(bootable);
+ protectiveMBR = hybridMBR;
} // if (numPartsToCvt > 0)
} // GPTDataTextUI::MakeHybrid()
-// Assign GPT partitions to primary or logical status for conversion. The
-// function first presents a suggested layout with as many logicals as
-// possible, but gives the user the option to override this suggestion.
-// Returns the number of partitions assigned (0 if problems or if the
-// user aborts)
-int GPTDataTextUI::AssignPrimaryOrLogical(GptPartNotes& notes) {
- int i, partNum, allOK = 1, changesWanted = 1, countedParts, numPrimary = 0, numLogical = 0;
- int newNumParts; // size of GPT table
-
- // Sort and resize the GPT table. Resized to clear the sector before the
- // first available sector, if possible, so as to enable turning the
- // first partition into a logical, should that be desirable/necessary.
- SortGPT();
- countedParts = newNumParts = CountParts();
- i = blockSize / GPT_SIZE;
- if ((newNumParts % i) != 0) {
- newNumParts = ((newNumParts / i) + 1) * i;
- } // if
- SetGPTSize(newNumParts);
-
- // Takes notes on existing partitions: Create an initial assignment as
- // primary or logical, set default MBR types, and then make it legal
- // (drop partitions as required to fit in the MBR and as logicals).
- allOK = (notes.PassPartitions(partitions, this, numParts, blockSize) == (int) numParts);
- for (i = 0; i < countedParts; i++)
- notes.SetMbrHexType(i, partitions[i].GetHexType() / 255);
- notes.MakeItLegal();
-
- while (allOK && changesWanted) {
- notes.ShowSummary();
- cout << "\n";
- partNum = GetNumber(-1, countedParts, -2,
- "Type partition to change, 0 to accept, -1 to abort: ");
- switch (partNum) {
- case -1:
- allOK = 0;
- break;
- case 0:
- changesWanted = 0;
- break;
- default:
- allOK = notes.MakeChange(partNum - 1);
- break;
- } // switch
- } // while
-
- i = 0;
- if (allOK)
- for (i = 0; i < countedParts; i++) {
- switch (notes.GetType(i)) {
- case PRIMARY:
- numPrimary++;
- break;
- case LOGICAL:
- numLogical++;
- break;
- } // switch
- if (notes.GetActiveStatus(i))
- protectiveMBR.SetPartBootable(i);
- } // for
-
- if (numPrimary > 4) {
- cerr << "Warning! More than four primary partitions in "
- << "GPTDataTextUI::AssignPrimaryOrLogical()!\n";
- allOK = 0;
- } // if
- return (allOK * (numPrimary + numLogical));
-} // GPTDataTextUI::AssignPrimaryOrLogical()
-
// Convert the GPT to MBR form, storing partitions in the protectiveMBR
// variable. This function is necessarily limited; it may not be able to
// convert all partitions, depending on the disk size and available space
@@ -530,44 +447,18 @@ int GPTDataTextUI::AssignPrimaryOrLogical(GptPartNotes& notes) {
// is over 0, the calling function should call DestroyGPT() to destroy
// the GPT data, call SaveMBR() to save the MBR, and then exit.
int GPTDataTextUI::XFormToMBR(void) {
- int numToConvert, numReallyConverted = 0;
- int origNumParts;
- GptPartNotes notes;
- GPTPart *tempGptParts;
uint32_t i;
- // Back up partition array, since we'll be sorting it and we want to
- // be able to restore it in case the user aborts....
- origNumParts = numParts;
- tempGptParts = new GPTPart[numParts];
- for (i = 0; i < numParts; i++)
- tempGptParts[i] = partitions[i];
-
- notes.MakeItLegal();
- numToConvert = AssignPrimaryOrLogical(notes);
-
- if (numToConvert > 0) {
- numReallyConverted = PartsToMBR(&notes);
- if (numReallyConverted != numToConvert) {
- cerr << "Error converting partitions to MBR; tried to convert "
- << numToConvert << " partitions,\nbut converted " << numReallyConverted
- << ". Aborting operation!\n";
- numReallyConverted = 0;
- protectiveMBR.MakeProtectiveMBR();
- } // if/else
- } // if
-
- // A problem or the user aborted; restore backup of unsorted and
- // original-sized partition table and delete the sorted and
- // resized one; otherwise free the backup table's memory....
- if (numReallyConverted == 0) {
- delete[] partitions;
- partitions = tempGptParts;
- SetGPTSize(origNumParts);
- } else {
- delete[] tempGptParts;
- } // if
- return numReallyConverted;
+ protectiveMBR.EmptyMBR();
+ for (i = 0; i < numParts; i++) {
+ if (partitions[i].IsUsed()) {
+ protectiveMBR.MakePart(i, partitions[i].GetFirstLBA(),
+ partitions[i].GetLengthLBA(),
+ partitions[i].GetHexType() / 0x0100, 0);
+ } // if
+ } // for
+ protectiveMBR.MakeItLegal();
+ return protectiveMBR.DoMenu();
} // GPTDataTextUI::XFormToMBR()
/*********************************************************************
@@ -589,10 +480,7 @@ int GetMBRTypeCode(int defType) {
cout << "Enter an MBR hex code (default " << hex;
cout.width(2);
cout << defType << "): " << dec;
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in GetMBRTypeCode()\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
if (line[0] == '\n')
typeCode = defType;
else
diff --git a/gpttext.h b/gpttext.h
index 642791b..cb8f1e0 100644
--- a/gpttext.h
+++ b/gpttext.h
@@ -50,7 +50,6 @@ class GPTDataTextUI : public GPTData {
int DestroyGPTwPrompt(void); // Returns 1 if user proceeds
void ShowDetails(void);
void MakeHybrid(void);
- int AssignPrimaryOrLogical(GptPartNotes& notes);
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
}; // class GPTDataTextUI
diff --git a/mbr.cc b/mbr.cc
index 415aaf6..5a36fa0 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -28,12 +28,18 @@ using namespace std;
* *
****************************************/
-// Assignment operator -- copy entire set of MBR data.
+/* // Assignment operator -- copy entire set of MBR data.
MBRData & MBRData::operator=(const MBRData & orig) {
BasicMBRData::operator=(orig);
return *this;
} // MBRData::operator=() */
+// Assignment operator -- copy entire set of MBR data.
+MBRData & MBRData::operator=(const BasicMBRData & orig) {
+ BasicMBRData::operator=(orig);
+ return *this;
+} // MBRData::operator=()
+
/*****************************************************
* *
* Functions to create, delete, or change partitions *
@@ -50,15 +56,15 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
MBRSignature = MBR_SIGNATURE;
diskSignature = UINT32_C(0);
- partitions[0].status = UINT8_C(0); // Flag the protective part. as unbootable
+ partitions[0].SetStatus(0); // Flag the protective part. as unbootable
- partitions[0].partitionType = UINT8_C(0xEE);
- partitions[0].firstLBA = UINT32_C(1);
+ partitions[0].SetType(UINT8_C(0xEE));
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
- partitions[0].lengthLBA = (uint32_t) diskSize - UINT32_C(1);
+ partitions[0].SetLocation(UINT32_C(1), (uint32_t) diskSize - UINT32_C(1));
} else { // disk is too big to represent, so fake it...
- partitions[0].lengthLBA = UINT32_MAX;
+ partitions[0].SetLocation(UINT32_C(1), UINT32_MAX);
} // if/else
+ partitions[0].SetInclusion(PRIMARY);
// Write CHS data. This maxes out the use of the disk, as much as
// possible -- even to the point of exceeding the capacity of sub-8GB
@@ -66,9 +72,9 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
// although normal MBR disks max out at 0xfeffff. FWIW, both GNU Parted
// and Apple's Disk Utility use 0xfeffff, and the latter puts that
// value in for the FIRST sector, too!
- LBAtoCHS(1, partitions[0].firstSector);
+/* LBAtoCHS(1, partitions[0].firstSector);
if (LBAtoCHS(partitions[0].lengthLBA, partitions[0].lastSector) == 0)
- partitions[0].lastSector[0] = 0xFF;
+ partitions[0].lastSector[0] = 0xFF; */
state = gpt;
} // MBRData::MakeProtectiveMBR()
@@ -76,27 +82,27 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
// Optimizes the size of the 0xEE (EFI GPT) partition
void MBRData::OptimizeEESize(void) {
int i, typeFlag = 0;
- uint32_t after;
+ uint64_t after;
for (i = 0; i < 4; i++) {
// Check for non-empty and non-0xEE partitions
- if ((partitions[i].partitionType != 0xEE) && (partitions[i].partitionType != 0x00))
+ if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetType() != 0x00))
typeFlag++;
- if (partitions[i].partitionType == 0xEE) {
+ if (partitions[i].GetType() == 0xEE) {
// Blank space before this partition; fill it....
- if (IsFree(partitions[i].firstLBA - 1)) {
- partitions[i].firstLBA = FindFirstInFree(partitions[i].firstLBA - 1);
+ if (SectorUsedAs(partitions[i].GetStartLBA() - 1, 4) == NONE) {
+ partitions[i].SetStartLBA(FindFirstInFree(partitions[i].GetStartLBA() - 1));
} // if
// Blank space after this partition; fill it....
- after = partitions[i].firstLBA + partitions[i].lengthLBA;
- if (IsFree(after)) {
- partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 1;
+ after = partitions[i].GetStartLBA() + partitions[i].GetLengthLBA();
+ if (SectorUsedAs(after, 4) == NONE) {
+ partitions[i].SetLengthLBA(FindLastInFree(after) - partitions[i].GetStartLBA() + 1);
} // if free space after
if (after > diskSize) {
if (diskSize < UINT32_MAX) { // If the disk is under 2TiB
- partitions[0].lengthLBA = (uint32_t) diskSize - partitions[i].firstLBA;
+ partitions[i].SetLengthLBA((uint32_t) diskSize - partitions[i].GetStartLBA());
} else { // disk is too big to represent, so fake it...
- partitions[0].lengthLBA = UINT32_MAX - partitions[i].firstLBA;
+ partitions[i].SetLengthLBA(UINT32_MAX - partitions[i].GetStartLBA());
} // if/else
} // if protective partition is too big
RecomputeCHS(i);
@@ -118,8 +124,8 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
start32 = (uint32_t) start64;
length32 = (uint32_t) length64;
for (i = 0; i < MAX_MBR_PARTS; i++) {
- if ((partitions[i].firstLBA == start32) && (partitions[i].lengthLBA == length32) &&
- (partitions[i].partitionType != 0xEE)) {
+ if ((partitions[i].GetType() != 0xEE) && (partitions[i].GetStartLBA() == start32)
+ && (partitions[i].GetLengthLBA() == length32)) {
DeletePartition(i);
if (state == hybrid)
OptimizeEESize();
@@ -138,7 +144,7 @@ int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
// Return the MBR data as a GPT partition....
GPTPart MBRData::AsGPT(int i) {
- MBRRecord* origPart;
+ MBRPart* origPart;
GPTPart newPart;
uint8_t origType;
uint64_t firstSector, lastSector;
@@ -146,7 +152,7 @@ GPTPart MBRData::AsGPT(int i) {
newPart.BlankPartition();
origPart = GetPartition(i);
if (origPart != NULL) {
- origType = origPart->partitionType;
+ origType = origPart->GetType();
// don't convert extended, hybrid protective, or null (non-existent)
// partitions (Note similar protection is in GPTData::XFormPartitions(),
@@ -154,10 +160,9 @@ GPTPart MBRData::AsGPT(int i) {
// context in the future....)
if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x85) &&
(origType != 0x00) && (origType != 0xEE)) {
- firstSector = (uint64_t) origPart->firstLBA;
+ firstSector = (uint64_t) origPart->GetStartLBA();
newPart.SetFirstLBA(firstSector);
- lastSector = firstSector + (uint64_t) origPart->lengthLBA;
- if (lastSector > 0) lastSector--;
+ lastSector = (uint64_t) origPart->GetLastLBA();
newPart.SetLastLBA(lastSector);
newPart.SetType(((uint16_t) origType) * 0x0100);
newPart.RandomizeUniqueGUID();
diff --git a/mbr.h b/mbr.h
index 35dfddc..5f9e0ee 100644
--- a/mbr.h
+++ b/mbr.h
@@ -26,11 +26,11 @@ using namespace std;
// Full data in tweaked MBR format
class MBRData : public BasicMBRData {
protected:
- int foo;
public:
MBRData(void) {}
MBRData(string deviceFilename) : BasicMBRData(deviceFilename) {}
- MBRData & operator=(const MBRData & orig);
+ MBRData & operator=(const BasicMBRData & orig);
+// MBRData & operator=(const MBRData & orig);
// Functions to create, delete, or change partitions
// Pass EmptyMBR 1 to clear the boot loader code, 0 to leave it intact
diff --git a/sgdisk.8 b/sgdisk.8
index 0b0b57c..6e8b2d3 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -1,6 +1,6 @@
-.\" Copyright 2010 Roderick W. Smith (rodsmith@rodsbooks.com)
+.\" Copyright 2011 Roderick W. Smith (rodsmith@rodsbooks.com)
.\" May be distributed under the GNU General Public License
-.TH "SGDISK" "8" "0.6.14" "Roderick W. Smith" "GPT fdisk Manual"
+.TH "SGDISK" "8" "0.7.0" "Roderick W. Smith" "GPT fdisk Manual"
.SH "NAME"
sgdisk \- Command\-line GUID partition table (GPT) manipulator for Linux and Unix
.SH "SYNOPSIS"
@@ -470,7 +470,7 @@ Non\-GPT disk detected and no \fI\-g\fR option
.B 4
An error prevented saving changes
.SH "BUGS"
-As of January 2011 (version 0.6.14), \fBsgdisk\fR
+As of March 2011 (version 0.7.00), \fBsgdisk\fR
should be considered beta software. Known bugs and limitations include:
.TP
@@ -506,7 +506,7 @@ preserved when loading and saving partitions.
The program can load only up to 128 partitions (4 primary partitions and
124 logical partitions) when converting from MBR format. This limit can
be raised by changing the \fI#define MAX_MBR_PARTS\fR line in the
-\fImbr.h\fR source code file and recompiling; however, such a change
+\fIbasicmbr.h\fR source code file and recompiling; however, such a change
will require using a larger\-than\-normal partition table. (The limit
of 128 partitions was chosen because that number equals the 128 partitions
supported by the most common partition table size.)
@@ -580,6 +580,7 @@ Contributors:
\fBmkfs (8)\fR,
\fBparted (8)\fR,
\fBsfdisk (8)\fR
+\fBfixparts (8)\fR
\fIhttp://en.wikipedia.org/wiki/GUID_Partition_Table\fR
diff --git a/sgdisk.cc b/sgdisk.cc
index f9b0a72..11df6ed 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -20,7 +20,7 @@
#include "gpt.h"
#include "support.h"
#include "parttypes.h"
-#include "gptpartnotes.h"
+//#include "gptpartnotes.h"
#include "attributes.h"
using namespace std;
@@ -248,12 +248,13 @@ int main(int argc, char *argv[]) {
theGPT.JustLooking(0);
if (BuildMBR(theGPT, mbrParts, 0) == 1) {
if (!pretend) {
- if (theGPT.SaveMBR())
+ if (theGPT.SaveMBR()) {
theGPT.DestroyGPT();
- else
+ } else
cerr << "Problem saving MBR!\n";
} // if
saveNonGPT = 0;
+ pretend = 1; // Not really, but works around problem if -g is used with this...
saveData = 0;
} // if
break;
@@ -312,7 +313,7 @@ int main(int argc, char *argv[]) {
break;
case 'R':
secondDevice = theGPT;
- secondDevice.SetFile(outDevice);
+ secondDevice.SetDisk(outDevice);
secondDevice.JustLooking(0);
// secondDevice.FixupMBR();
secondDevice.SaveGPTData(1);
@@ -382,8 +383,9 @@ int main(int argc, char *argv[]) {
break;
} // switch
} // while
- if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend))
+ if ((saveData) && (!neverSaveData) && (saveNonGPT) && (!pretend)) {
theGPT.SaveGPTData(1);
+ }
if (saveData && (!saveNonGPT)) {
cout << "Non-GPT disk; not saving changes. Use -g to override.\n";
retval = 3;
@@ -428,34 +430,33 @@ int main(int argc, char *argv[]) {
// Create a hybrid or regular MBR from GPT data structures
int BuildMBR(GPTData & theGPT, char* argument, int isHybrid) {
- int numParts, allOK = 1, i;
- GptPartNotes notes;
- struct PartInfo *newNote;
+ int numParts, allOK = 1, i, origPartNum;
+// GptPartNotes notes;
+// struct PartInfo *newNote;
+ MBRPart newPart;
+ BasicMBRData newMBR;
if ((&theGPT != NULL) && (argument != NULL)) {
numParts = CountColons(argument) + 1;
if (numParts <= (4 - isHybrid)) {
+ newMBR.SetDisk(theGPT.GetDisk());
for (i = 0; i < numParts; i++) {
- newNote = new struct PartInfo;
- newNote->origPartNum = GetInt(argument, i + 1) - 1;
- newNote->active = 0;
- newNote->hexCode = 0; // code to compute it from default
- newNote->type = PRIMARY;
- newNote->firstLBA = theGPT[newNote->origPartNum].GetFirstLBA();
- newNote->lastLBA = theGPT[newNote->origPartNum].GetLastLBA();
- notes.AddToEnd(newNote);
+ origPartNum = GetInt(argument, i + 1) - 1;
+ newPart.SetInclusion(PRIMARY);
+ newPart.SetLocation(theGPT[origPartNum].GetFirstLBA(),
+ theGPT[origPartNum].GetLengthLBA());
+ newPart.SetStatus(0);
+ newPart.SetType((uint8_t)(theGPT[origPartNum].GetHexType() / 0x0100));
+ newMBR.AddPart(i + isHybrid, newPart);
} // for
if (isHybrid) {
- newNote = new struct PartInfo;
- newNote->origPartNum = MBR_EFI_GPT;
- newNote->active = 0;
- newNote->hexCode = 0xEE;
- newNote->type = PRIMARY;
- // newNote firstLBA and lastLBA are computed later...
- notes.AddToStart(newNote);
+ newPart.SetInclusion(PRIMARY);
+ newPart.SetLocation(1, newMBR.FindLastInFree(1));
+ newPart.SetStatus(0);
+ newPart.SetType(0xEE);
+ newMBR.AddPart(0, newPart);
} // if
- if (theGPT.PartsToMBR(&notes) != numParts)
- allOK = 0;
+ theGPT.SetProtectiveMBR(newMBR);
} else allOK = 0;
} else allOK = 0;
if (!allOK)
diff --git a/support.cc b/support.cc
index bd0b28b..f88f021 100644
--- a/support.cc
+++ b/support.cc
@@ -31,6 +31,14 @@
using namespace std;
+char* ReadCString(char *inStr, int numchars) {
+ if (!fgets(inStr, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in ReadCString()\n";
+ exit(1);
+ } // if
+ return inStr;
+} // ReadCString()
+
// Get a numeric value from the user, between low and high (inclusive).
// Keeps looping until the user enters a value within that range.
// If user provides no input, def (default value) is returned.
@@ -66,10 +74,7 @@ char GetYN(void) {
do {
cout << "(Y/N): ";
- if (!fgets(line, 255, stdin)) {
- cerr << "Critical error! Failed fgets() in GetYN()\n";
- exit(1);
- } // if
+ ReadCString(line, 255);
sscanf(line, "%c", &response);
if (response == 'y')
response = 'Y';
@@ -316,7 +321,7 @@ uint64_t GetInt(const string & argument, int itemNum) {
} // GetInt()
// Extract string data from argument string, which should be colon-delimited
-string GetString(const string & argument, int itemNum) {
+string GetString(string argument, int itemNum) {
size_t startPos = -1, endPos = -1;
while (itemNum-- > 0) {
diff --git a/support.h b/support.h
index 6a4dcef..2c67cfb 100644
--- a/support.h
+++ b/support.h
@@ -8,6 +8,8 @@
#ifndef __GPTSUPPORT
#define __GPTSUPPORT
+#define GPTFDISK_VERSION "0.7.0"
+
#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__APPLE__)
// Darwin (Mac OS) only: disk IOCTLs are different, and there is no lseek64
// This used to use __DARWIN_UNIX03 rather than __APPLE__, but __APPLE__
@@ -22,6 +24,13 @@
#include <linux/fs.h>
#endif
+// Microsoft Visual C++ only
+#if defined (_MSC_VER)
+#define sscanf sscanf_s
+#define strcpy strcpy_s
+#define sprintf sprintf_s
+#endif
+
// Set this as a default
#define SECTOR_SIZE UINT32_C(512)
@@ -47,6 +56,7 @@
using namespace std;
+char* ReadCString(char *inStr, int numchars);
int GetNumber(int low, int high, int def, const string & prompt);
char GetYN(void);
uint64_t GetSectorNum(uint64_t low, uint64_t high, uint64_t def, uint64_t sSize, const std::string& prompt);
@@ -59,6 +69,6 @@ void ReverseBytes(void* theValue, int numBytes); // Reverses byte-order of theVa
// Extract colon-separated fields from a string....
uint64_t GetInt(const string & argument, int itemNum);
-string GetString(const string & Info, int itemNum);
+string GetString(string argument, int itemNum);
#endif