summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile354
-rw-r--r--Makefile.mac2
-rw-r--r--Makefile.mingw12
-rw-r--r--NEWS23
-rw-r--r--attributes.cc5
-rw-r--r--attributes.h2
-rw-r--r--diskio-unix.cc2
-rw-r--r--diskio.h2
-rw-r--r--gdisk.811
-rw-r--r--gdisk.cc122
-rw-r--r--gpt.cc143
-rw-r--r--gpt.h16
-rw-r--r--gptpart.cc74
-rw-r--r--gpttext.cc29
-rw-r--r--gpttext.h2
-rw-r--r--guid.cc26
-rw-r--r--guid.h2
-rw-r--r--mbr.cc964
-rw-r--r--mbr.h118
-rw-r--r--partnotes.cc162
-rw-r--r--partnotes.h24
-rw-r--r--parttypes.cc4
-rw-r--r--sgdisk.82
-rw-r--r--sgdisk.cc27
-rw-r--r--support.cc27
25 files changed, 742 insertions, 1413 deletions
diff --git a/Makefile b/Makefile
index b03f3bf..3865013 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ CXX=g++
CFLAGS+=-D_FILE_OFFSET_BITS=64
CXXFLAGS+=-Wall -D_FILE_OFFSET_BITS=64
LDFLAGS+=
-LIB_NAMES=crc32 support guid partnotes gptpart mbr gpt bsd parttypes attributes diskio diskio-unix
+LIB_NAMES=crc32 support guid partnotes gptpartnotes gptpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -31,3 +31,355 @@ $(OBJS):
$(CRITICAL_CXX_FLAGS)
# 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 99a6ea3..9c55308 100644
--- a/Makefile.mac
+++ b/Makefile.mac
@@ -2,7 +2,7 @@ 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 gptpart mbr gpt bsd parttypes attributes diskio diskio-unix
+LIB_NAMES=crc32 support guid partnotes gptpartnotes gptpart basicmbr mbr gpt bsd parttypes attributes diskio diskio-unix
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
diff --git a/Makefile.mingw b/Makefile.mingw
index 07e2de7..9f3a9a3 100644
--- a/Makefile.mingw
+++ b/Makefile.mingw
@@ -1,10 +1,10 @@
-CC=/usr/bin/i586-mingw32msvc-gcc
-CXX=/usr/bin/i586-mingw32msvc-g++
-STRIP=/usr/bin/i586-mingw32msvc-strip
+CC=/usr/bin/i686-pc-mingw32-gcc
+CXX=/usr/bin/i686-pc-mingw32-g++
+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 partnotes bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows
+LIB_NAMES=guid gptpart bsd parttypes partnotes gptpartnotes attributes crc32 basicmbr mbr gpt support diskio diskio-windows
LIB_SRCS=$(NAMES:=.cc)
LIB_OBJS=$(LIB_NAMES:=.o)
LIB_HEADERS=$(LIB_NAMES:=.h)
@@ -12,8 +12,8 @@ DEPEND= makedepend $(CFLAGS)
all: gdisk
-gdisk: $(LIB_OBJS) gpttext.o gdisk.o
- $(CXX) $(LIB_OBJS) gpttext.o gdisk.o -luuid -o gdisk.exe
+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
diff --git a/NEWS b/NEWS
index eabf53d..e90d99b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,26 @@
+0.6.15 (?/?/2011):
+------------------
+
+- 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
+ on the smaller disk. In sgdisk, the secondary GPT data are moved
+ automatically if disk sizes don't match. In gdisk, the secondary GPT data
+ are moved automatically if the target disk is smaller than the source
+ disk; if the target disk is larger than the source disk, the user is
+ given the option of making this adjustment.
+
+- Fixed --load-backup (-l) option to sgdisk, which was broken.
+
+- 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
+ experts' menu) by hitting the Enter key for the device filename.
+
+- Implemented a number of code cleanups provided by an anonymous
+ contributor.
+
0.6.14 (1/8/2011):
------------------
diff --git a/attributes.cc b/attributes.cc
index 07f909a..0abed40 100644
--- a/attributes.cc
+++ b/attributes.cc
@@ -1,8 +1,9 @@
// attributes.cc
// Class to manage partition attribute codes. These are binary bit fields,
-// of which only three are currently (2/2009) documented on Wikipedia.
+// of which only four are currently (2/2011) documented on Wikipedia, and
+// two others found from other sources.
-/* 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
diff --git a/attributes.h b/attributes.h
index 0ae4487..f6c66ff 100644
--- a/attributes.h
+++ b/attributes.h
@@ -1,4 +1,4 @@
-/* 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. */
#include <stdint.h>
diff --git a/diskio-unix.cc b/diskio-unix.cc
index b20f161..d65a644 100644
--- a/diskio-unix.cc
+++ b/diskio-unix.cc
@@ -348,7 +348,7 @@ uint64_t DiskIO::DiskSize(int *err) {
if (*err) {
sectors = sz = 0;
} // if
- if ((errno == EFBIG) || (!*err)) {
+ if ((!*err) || (errno == EFBIG)) {
*err = ioctl(fd, BLKGETSIZE64, &b);
if (*err || b == 0 || b == sz)
sectors = sz;
diff --git a/diskio.h b/diskio.h
index 9c709c5..d9f0d38 100644
--- a/diskio.h
+++ b/diskio.h
@@ -69,7 +69,7 @@ class DiskIO {
int GetBlockSize(void);
int IsOpen(void) {return isOpen;}
int IsOpenForWrite(void) {return openForWrite;}
- string GetName(void) {return realFilename;}
+ string GetName(void) const {return realFilename;}
uint64_t DiskSize(int* err);
}; // struct GPTPart
diff --git a/gdisk.8 b/gdisk.8
index 7d5d2c6..272677c 100644
--- a/gdisk.8
+++ b/gdisk.8
@@ -471,10 +471,11 @@ physical sectors (such as some Western Digital models introduced in
December of 2009) and some RAID configurations can suffer performance
problems if partitions are not aligned properly for their internal data
structures. On new disks, GPT fdisk attempts to align partitions on
-2048\-sector (1MiB) boundaries by default, which optimizes performance
-for both of these disk types. On pre\-partitioned disks, GPT fdisk
-attempts to identify the alignment value used on that disk. In either
-case, it can be changed by using this option.
+2048\-sector (1MiB) boundaries by default, which optimizes performance for
+both of these disk types. On pre\-partitioned disks, GPT fdisk attempts to
+identify the alignment value used on that disk, but will set 8-sector
+alignment on disks larger than 300 GB even if lesser alignment values are
+detected. In either case, it can be changed by using this option.
.TP
.B m
@@ -663,6 +664,8 @@ Contributors:
* Dwight Schauer (dschauer@ti.com)
+* Florian Zumbiehl (florz@florz.de)
+
.SH "SEE ALSO"
\fBcfdisk (8)\fR,
diff --git a/gdisk.cc b/gdisk.cc
index f47ec5e..f786431 100644
--- a/gdisk.cc
+++ b/gdisk.cc
@@ -4,7 +4,7 @@
//
// by Rod Smith, project began February 2009
-/* This program is copyright (c) 2009, 2010 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. */
#include <stdio.h>
@@ -29,8 +29,8 @@ void WinWarning(void);
int main(int argc, char* argv[]) {
GPTDataTextUI theGPT;
- int doMore = 1, i;
- char *device = NULL, *junk;
+ size_t i;
+ char *device = NULL;
cout << "GPT fdisk (gdisk) version " << GPTFDISK_VERSION << "\n\n";
@@ -42,25 +42,21 @@ int main(int argc, char* argv[]) {
WinWarning();
cout << "Type device filename, or press <Enter> to exit: ";
device = new char[255];
- junk = fgets(device, 255, stdin);
- if (device[0] != '\n') {
- i = (int) strlen(device);
- if (i > 0)
- if (device[i - 1] == '\n')
- device[i - 1] = '\0';
- doMore = theGPT.LoadPartitions(device);
- if (doMore) {
- MainMenu(device, &theGPT);
- } // if (doMore)
+ if (!fgets(device, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in main()!\n";
+ exit(1);
} // if
+ i = strlen(device);
+ if (i && device[i - 1] == '\n')
+ device[i - 1] = '\0';
+ if (*device && theGPT.LoadPartitions(device))
+ MainMenu(device, &theGPT);
delete[] device;
break;
case 2: // basic usage
WinWarning();
- doMore = theGPT.LoadPartitions(argv[1]);
- if (doMore) {
+ if (theGPT.LoadPartitions(argv[1]))
MainMenu(argv[1], &theGPT);
- } // if (doMore)
break;
case 3: // usage with "-l" option
if (strcmp(argv[1], "-l") == 0) {
@@ -72,8 +68,8 @@ int main(int argc, char* argv[]) {
} // if/elseif/else
if (device != NULL) {
theGPT.JustLooking();
- doMore = theGPT.LoadPartitions((string) device);
- if (doMore) theGPT.DisplayGPTData();
+ if (theGPT.LoadPartitions((string) device))
+ theGPT.DisplayGPTData();
} // if
break;
default:
@@ -85,23 +81,27 @@ int main(int argc, char* argv[]) {
// Accept a command and execute it. Returns only when the user
// wants to exit (such as after a 'w' or 'q' command).
void MainMenu(string filename, GPTDataTextUI* theGPT) {
- char command, line[255], buFile[255];
- char* junk;
+ char line[255], buFile[255];
int goOn = 1;
PartType typeHelper;
uint32_t temp1, temp2;
do {
cout << "\nCommand (? for help): ";
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in MainMenu()!\n";
+ exit(1);
+ } // if
+ switch (*line) {
case '\n':
break;
case 'b': case 'B':
cout << "Enter backup filename to save: ";
- junk = fgets(line, 255, stdin);
- sscanf(line, "%s", (char*) &buFile);
+ if (!fgets(line, 255, stdin)) {
+ exit(1);
+ cerr << "Critical error! Failed fgets() in MainMenu()!\n";
+ } // if
+ sscanf(line, "%s", buFile);
theGPT->SaveGPTBackup(buFile);
break;
case 'c': case 'C':
@@ -187,16 +187,17 @@ void ShowCommands(void) {
// Accept a recovery & transformation menu command. Returns only when the user
// issues an exit command, such as 'w' or 'q'.
void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
- char command, line[255], buFile[255];
- char* junk;
+ char line[255], buFile[255];
uint32_t temp1, numParts;
int goOn = 1;
do {
cout << "\nRecovery/transformation command (? for help): ";
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in RecoveryMenu()!\n";
+ exit(1);
+ } // if
+ switch (*line) {
case '\n':
break;
case 'b': case 'B':
@@ -251,8 +252,11 @@ void RecoveryMenu(string filename, GPTDataTextUI* theGPT) {
break;
case 'l': case 'L':
cout << "Enter backup filename to load: ";
- junk = fgets(line, 255, stdin);
- sscanf(line, "%s", (char*) &buFile);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in RecoveryMenu()!\n";
+ exit(1);
+ } // if
+ sscanf(line, "%s", buFile);
theGPT->LoadGPTBackup(buFile);
break;
case 'm': case 'M':
@@ -314,19 +318,22 @@ void ShowRecoveryCommands(void) {
// Accept an experts' menu command. Returns only after the user
// selects an exit command, such as 'w' or 'q'.
void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
- char command, line[255], *device;
- char* junk;
+ GPTData secondDevice;
+ char line[255], *device;
uint32_t pn, temp1, temp2;
- int goOn = 1, i;
+ int goOn = 1;
+ size_t i;
char guidStr[255];
GUIDData aGUID;
ostringstream prompt;
do {
cout << "\nExpert command (? for help): ";
- junk = fgets(line, 255, stdin);
- sscanf(line, "%c", &command);
- switch (command) {
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
+ exit(1);
+ } // if
+ switch (*line) {
case '\n':
break;
case 'a': case 'A':
@@ -339,7 +346,10 @@ 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): ";
- junk = fgets(guidStr, 255, stdin);
+ if (!fgets(guidStr, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
+ exit(1);
+ } // if
if ((strlen(guidStr) >= 33) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
theGPT->SetPartitionGUID(pn, (GUIDData) guidStr);
cout << "New GUID is " << theGPT->operator[](pn).GetUniqueGUID() << "\n";
@@ -361,7 +371,10 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
break;
case 'g': case 'G':
cout << "Enter the disk's unique GUID ('R' to randomize): ";
- junk = fgets(guidStr, 255, stdin);
+ if (!fgets(guidStr, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
+ exit(1);
+ } // if
if ((strlen(guidStr) >= 33) || (guidStr[0] == 'R') || (guidStr[0] == 'r')) {
theGPT->SetDiskGUID((GUIDData) guidStr);
cout << "The new disk GUID is " << theGPT->GetDiskGUID() << "\n";
@@ -395,8 +408,8 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
theGPT->DisplayGPTData();
break;
case 'q': case 'Q':
- goOn = 0;
- break;
+ goOn = 0;
+ break;
case 'r': case 'R':
RecoveryMenu(filename, theGPT);
goOn = 0;
@@ -404,21 +417,24 @@ void ExpertsMenu(string filename, GPTDataTextUI* theGPT) {
case 's': case 'S':
theGPT->ResizePartitionTable();
break;
- case 't': case 'T':
- theGPT->SwapPartitions();
- break;
+ case 't': case 'T':
+ theGPT->SwapPartitions();
+ break;
case 'u': case 'U':
cout << "Type device filename, or press <Enter> to exit: ";
device = new char[255];
- junk = fgets(device, 255, stdin);
- if (device[0] != '\n') {
- i = (int) strlen(device);
- if (i > 0)
- if (device[i - 1] == '\n')
- device[i - 1] = '\0';
+ if (!fgets(device, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in ExpertsMenu()!\n";
+ exit(1);
+ } // if
+ i = strlen(device);
+ if (i && device[i - 1] == '\n')
+ device[i - 1] = '\0';
+ if (*device && strlen(device) > 0) {
+ secondDevice = *theGPT;
+ secondDevice.SetFile(device);
+ secondDevice.SaveGPTData(0);
} // if
- if (strlen(device) > 0)
- theGPT->SaveGPTData(0, device);
delete[] device;
break;
case 'v': case 'V':
diff --git a/gpt.cc b/gpt.cc
index bcc053a..309a038 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -3,7 +3,7 @@
/* By Rod Smith, initial coding 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
@@ -96,6 +96,45 @@ GPTData::~GPTData(void) {
delete[] partitions;
} // GPTData destructor
+// Assignment operator
+GPTData & GPTData::operator=(const GPTData & orig) {
+ uint32_t i;
+
+ mainHeader = orig.mainHeader;
+ numParts = orig.numParts;
+ secondHeader = orig.secondHeader;
+ protectiveMBR = orig.protectiveMBR;
+ device = orig.device;
+ blockSize = orig.blockSize;
+ diskSize = orig.diskSize;
+ state = orig.state;
+ justLooking = orig.justLooking;
+ mainCrcOk = orig.mainCrcOk;
+ secondCrcOk = orig.secondCrcOk;
+ mainPartsCrcOk = orig.mainPartsCrcOk;
+ secondPartsCrcOk = orig.secondPartsCrcOk;
+ apmFound = orig.apmFound;
+ bsdFound = orig.bsdFound;
+ sectorAlignment = orig.sectorAlignment;
+ beQuiet = orig.beQuiet;
+ whichWasUsed = orig.whichWasUsed;
+
+ myDisk.OpenForRead(orig.myDisk.GetName());
+
+ delete[] partitions;
+ partitions = new GPTPart [numParts * sizeof (GPTPart)];
+ if (partitions != NULL) {
+ for (i = 0; i < numParts; i++) {
+ partitions[i] = orig.partitions[i];
+ }
+ } else {
+ numParts = 0;
+ cerr << "Error! Could not allocate memory for partitions in GPTData::operator=()!\n"
+ << "Continuing, but strange problems may occur!\n";
+ } // if/else
+ return *this;
+} // GPTData::operator=()
+
/*********************************************************************
* *
* Begin functions that verify data, or that adjust the verification *
@@ -107,7 +146,7 @@ GPTData::~GPTData(void) {
// do *NOT* recover from these problems. Returns the total number of
// problems identified.
int GPTData::Verify(void) {
- int problems = 0;
+ int problems = 0, alignProbs = 0;
uint32_t i, numSegments;
uint64_t totalFree, largestSegment;
@@ -210,11 +249,11 @@ int GPTData::Verify(void) {
// Now check for a few other miscellaneous problems...
// Check that the disk size will hold the data...
- if (mainHeader.backupLBA > diskSize) {
+ if (mainHeader.backupLBA >= diskSize) {
problems++;
cout << "\nProblem: Disk is too small to hold all the data!\n"
<< "(Disk size is " << diskSize << " sectors, needs to be "
- << mainHeader.backupLBA << " sectors.)\n"
+ << mainHeader.backupLBA + UINT64_C(1) << " sectors.)\n"
<< "The 'e' option on the experts' menu may fix this problem.\n";
} // if
@@ -240,14 +279,18 @@ int GPTData::Verify(void) {
cout << "\nCaution: Partition " << i + 1 << " doesn't begin on a "
<< sectorAlignment << "-sector boundary. This may\nresult "
<< "in degraded performance on some modern (2009 and later) hard disks.\n";
+ alignProbs++;
} // if
} // for
+ if (alignProbs > 0)
+ cout << "\nConsult http://www.ibm.com/developerworks/linux/library/l-4kb-sector-disks/\n"
+ << "for information on disk alignment.\n";
// Now compute available space, but only if no problems found, since
// problems could affect the results
if (problems == 0) {
totalFree = FindFreeBlocks(&numSegments, &largestSegment);
- cout << "No problems found. " << totalFree << " free sectors ("
+ cout << "\nNo problems found. " << totalFree << " free sectors ("
<< BytesToSI(totalFree, blockSize) << ") available in "
<< numSegments << "\nsegments, the largest of which is "
<< largestSegment << " (" << BytesToSI(largestSegment, blockSize)
@@ -563,6 +606,24 @@ 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 err, allOK = 1;
+
+ device = deviceFilename;
+ if (allOK && myDisk.OpenForRead(deviceFilename)) {
+ // store disk information....
+ diskSize = myDisk.DiskSize(&err);
+ blockSize = (uint32_t) myDisk.GetBlockSize();
+ } // if
+ protectiveMBR.SetDisk(&myDisk);
+ protectiveMBR.SetDiskSize(diskSize);
+ protectiveMBR.SetBlockSize(blockSize);
+ return allOK;
+} // GPTData::SetFile()
+
// Scan for partition data. This function loads the MBR data (regular MBR or
// protective MBR) and loads BSD disklabel data (which is probably invalid).
// It also looks for APM data, forces a load of GPT data, and summarizes
@@ -869,20 +930,15 @@ int GPTData::CheckTable(struct GPTHeader *header) {
return newCrcOk;
} // GPTData::CheckTable()
-// Writes GPT (and protective MBR) to disk. Returns 1 on successful
+// Writes GPT (and protective MBR) to disk. If quiet==1,
+// Returns 1 on successful
// write, 0 if there was a problem.
-int GPTData::SaveGPTData(int quiet, string filename) {
+int GPTData::SaveGPTData(int quiet) {
int allOK = 1, littleEndian;
char answer;
littleEndian = IsLittleEndian();
- if (filename == "")
- filename = device;
- if (filename == "") {
- cerr << "Device not defined.\n";
- } // if
-
// First do some final sanity checks....
// This test should only fail on read-only disks....
@@ -891,30 +947,34 @@ int GPTData::SaveGPTData(int quiet, string filename) {
allOK = 0;
} // if
+ // Check that disk is really big enough to handle the second header...
+ if (mainHeader.backupLBA >= diskSize) {
+ cerr << "Caution! Secondary header was placed beyond the disk's limits! Moving the\n"
+ << "header, but other problems may occur!\n";
+ MoveSecondHeaderToEnd();
+ } // if
+
// Is there enough space to hold the GPT headers and partition tables,
// given the partition sizes?
if (CheckGPTSize() > 0) {
allOK = 0;
} // if
- // Check that disk is really big enough to handle this...
- if (mainHeader.backupLBA > diskSize) {
- cerr << "Error! Disk is too small! The 'e' option on the experts' menu might fix the\n"
- << "problem (or it might not). Aborting!\n(Disk size is "
- << diskSize << " sectors, needs to be " << mainHeader.backupLBA << " sectors.)\n";
- allOK = 0;
- } // if
// Check that second header is properly placed. Warn and ask if this should
// be corrected if the test fails....
- if ((mainHeader.backupLBA < (diskSize - UINT64_C(1))) && (quiet == 0)) {
- cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n"
- << "correct this problem? ";
- if (GetYN() == 'Y') {
+ if (mainHeader.backupLBA < (diskSize - UINT64_C(1))) {
+ if (quiet == 0) {
+ cout << "Warning! Secondary header is placed too early on the disk! Do you want to\n"
+ << "correct this problem? ";
+ if (GetYN() == 'Y') {
+ MoveSecondHeaderToEnd();
+ cout << "Have moved second header and partition table to correct location.\n";
+ } else {
+ cout << "Have not corrected the problem. Strange problems may occur in the future!\n";
+ } // if correction requested
+ } else { // Go ahead and do correction automatically
MoveSecondHeaderToEnd();
- cout << "Have moved second header and partition table to correct location.\n";
- } else {
- cout << "Have not corrected the problem. Strange problems may occur in the future!\n";
- } // if correction requested
+ } // if/else quiet
} // if
// Check for overlapping or insane partitions....
@@ -942,7 +1002,7 @@ int GPTData::SaveGPTData(int quiet, string filename) {
// Do it!
if (allOK) {
- if (myDisk.OpenForWrite(filename)) {
+ if (myDisk.OpenForWrite()) {
// As per UEFI specs, write the secondary table and GPT first....
allOK = SavePartitionTable(myDisk, secondHeader.partitionEntriesLBA);
if (!allOK)
@@ -975,7 +1035,7 @@ int GPTData::SaveGPTData(int quiet, string filename) {
myDisk.Close();
} else {
- cerr << "Unable to open device " << filename << " for writing! Errno is "
+ cerr << "Unable to open device " << myDisk.GetName() << " for writing! Errno is "
<< errno << "! Aborting write!\n";
allOK = 0;
} // if/else
@@ -1513,24 +1573,24 @@ int GPTData::PartsToMBR(PartNotes * notes) {
notes->MakeItLegal();
notes->Rewind();
while (notes->GetNextInfo(&convInfo) >= 0) {
- if ((convInfo.gptPartNum >= 0) && (convInfo.type == PRIMARY)) {
- numConverted += OnePartToMBR((uint32_t) convInfo.gptPartNum, mbrNum);
+ 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.gptPartNum == MBR_EFI_GPT)
+ 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.gptPartNum >= 0) && (convInfo.type == PRIMARY))
+ if ((convInfo.origPartNum >= 0) && (convInfo.type == PRIMARY))
mbrNum++;
- if (convInfo.gptPartNum == MBR_EFI_GPT) {
+ if (convInfo.origPartNum == MBR_EFI_GPT) {
if (protectiveMBR.FindFirstAvailable() == UINT32_C(1)) {
protectiveMBR.MakePart(mbrNum, 1, protectiveMBR.FindLastInFree(1), convInfo.hexCode);
protectiveMBR.SetHybrid();
@@ -1803,11 +1863,22 @@ int GPTData::ClearGPTData(void) {
} // GPTData::ClearGPTData()
// Set the location of the second GPT header data to the end of the disk.
+// If the disk size has actually changed, this also adjusts the protective
+// entry in the MBR, since it's probably no longer correct.
// Used internally and called by the 'e' option on the recovery &
// transformation menu, to help users of RAID arrays who add disk space
-// to their arrays.
+// to their arrays or to adjust data structures in restore operations
+// involving unequal-sized disks.
void GPTData::MoveSecondHeaderToEnd() {
mainHeader.backupLBA = secondHeader.currentLBA = diskSize - UINT64_C(1);
+ if (mainHeader.lastUsableLBA != diskSize - mainHeader.firstUsableLBA) {
+ if (protectiveMBR.GetValidity() == hybrid) {
+ protectiveMBR.OptimizeEESize();
+ RecomputeCHS();
+ } // if
+ if (protectiveMBR.GetValidity() == gpt)
+ MakeProtectiveMBR();
+ } // if
mainHeader.lastUsableLBA = secondHeader.lastUsableLBA = diskSize - mainHeader.firstUsableLBA;
secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1);
} // GPTData::FixSecondHeaderLocation()
diff --git a/gpt.h b/gpt.h
index 9d13750..3e0e206 100644
--- a/gpt.h
+++ b/gpt.h
@@ -1,7 +1,7 @@
/* gpt.h -- GPT and data structure definitions, types, and
functions */
-/* This program is copyright (c) 2009, 2010 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. */
#include <stdint.h>
@@ -11,12 +11,12 @@
#include "mbr.h"
#include "bsd.h"
#include "gptpart.h"
-#include "partnotes.h"
+#include "gptpartnotes.h"
#ifndef __GPTSTRUCTS
#define __GPTSTRUCTS
-#define GPTFDISK_VERSION "0.6.14"
+#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,
@@ -29,9 +29,9 @@
#define MAX_ALIGNMENT 65536
#define MIN_AF_ALIGNMENT 8
-// Below constant corresponds to a ~596GiB (640MB) disk, since WD has
-// introduced a smaller Advanced Format drive
-#define SMALLEST_ADVANCED_FORMAT UINT64_C(1250263728)
+// Below constant corresponds to a ~279GiB (300GB) disk, since the
+// smallest Advanced Format drive I know of is 320GB in size
+#define SMALLEST_ADVANCED_FORMAT UINT64_C(585937500)
using namespace std;
@@ -103,6 +103,7 @@ public:
GPTData(void);
GPTData(string deviceFilename);
virtual ~GPTData(void);
+ GPTData & operator=(const GPTData & orig);
// Verify (or update) data integrity
int Verify(void);
@@ -118,6 +119,7 @@ public:
int FindInsanePartitions(void);
// Load or save data from/to disk
+ int SetFile(const string & deviceFilename);
int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);}
int WriteProtectiveMBR(void) {return protectiveMBR.WriteMBRData(&myDisk);}
void PartitionScan(void);
@@ -125,7 +127,7 @@ public:
int ForceLoadGPTData(void);
int LoadMainTable(void);
int LoadSecondTableAsMain(void);
- int SaveGPTData(int quiet = 0, string filename = "");
+ int SaveGPTData(int quiet = 0);
int SaveGPTBackup(const string & filename);
int LoadGPTBackup(const string & filename);
int SaveMBR(void);
diff --git a/gptpart.cc b/gptpart.cc
index 2af5db7..63e453d 100644
--- a/gptpart.cc
+++ b/gptpart.cc
@@ -24,16 +24,12 @@
using namespace std;
GPTPart::GPTPart(void) {
- int i;
-
partitionType.Zero();
uniqueGUID.Zero();
firstLBA = 0;
lastLBA = 0;
attributes = 0;
-
- for (i = 0; i < NAME_SIZE; i++)
- name[i] = '\0';
+ memset(name, 0, NAME_SIZE);
} // Default constructor
GPTPart::~GPTPart(void) {
@@ -94,35 +90,32 @@ void GPTPart::SetType(PartType t) {
// string. This function creates a simple-minded copy for this.
void GPTPart::SetName(const string & theName) {
char newName[NAME_SIZE];
- char *junk;
- int i;
+ size_t i;
- // Blank out new name string, just to be on the safe side....
- for (i = 0; i < NAME_SIZE; i++)
- newName[i] = '\0';
+ // Blank out new name string, so that it will terminate in a null
+ // when data are copied to it....
+ memset(newName, 0, NAME_SIZE);
if (theName == "") { // No name specified, so get one from the user
cout << "Enter name: ";
- junk = fgets(newName, NAME_SIZE / 2, stdin);
+ if (!fgets(newName, NAME_SIZE / 2 + 1, stdin)) {
+ cerr << "Critical error! Failed fgets() in GPTPart::SetName()!\n";
+ exit(1);
+ }
// Input is likely to include a newline, so remove it....
- i = (int) strlen(newName);
- if ((i > 0) && (i <= NAME_SIZE))
- if (newName[i - 1] == '\n')
- newName[i - 1] = '\0';
+ i = strlen(newName);
+ if (i && newName[i - 1] == '\n')
+ newName[i - 1] = '\0';
} else {
strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str());
} // if
// Copy the C-style ASCII string from newName into a form that the GPT
// table will accept....
- for (i = 0; i < NAME_SIZE; i++) {
- if ((i % 2) == 0) {
- name[i] = newName[(i / 2)];
- } else {
- name[i] = '\0';
- } // if/else
- } // for
+ memset(name, 0, NAME_SIZE);
+ for (i = 0; i < NAME_SIZE / 2; i++)
+ name[i * 2] = newName[i];
} // GPTPart::SetName()
// Set the name for the partition based on the current GUID partition type
@@ -132,22 +125,19 @@ void GPTPart::SetDefaultDescription(void) {
} // GPTPart::SetDefaultDescription()
GPTPart & GPTPart::operator=(const GPTPart & orig) {
- int i;
-
partitionType = orig.partitionType;
uniqueGUID = orig.uniqueGUID;
firstLBA = orig.firstLBA;
lastLBA = orig.lastLBA;
attributes = orig.attributes;
- for (i = 0; i < NAME_SIZE; i++)
- name[i] = orig.name[i];
+ memcpy(name, orig.name, NAME_SIZE);
return *this;
} // assignment operator
// Display summary information; does nothing if the partition is empty.
void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
string sizeInSI;
- int i;
+ size_t i;
if (firstLBA != 0) {
sizeInSI = BytesToSI(lastLBA - firstLBA + 1, blockSize);
@@ -159,7 +149,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) {
cout.width(14);
cout << lastLBA << " ";
cout << BytesToSI(lastLBA - firstLBA + 1, blockSize) << " ";
- for (i = 0; i < 10 - (int) sizeInSI.length(); i++)
+ for (i = 0; i < 10 - sizeInSI.length(); i++)
cout << " ";
cout.fill('0');
cout.width(4);
@@ -201,30 +191,21 @@ void GPTPart::ShowDetails(uint32_t blockSize) {
// Blank (delete) a single partition
void GPTPart::BlankPartition(void) {
- int j;
-
uniqueGUID.Zero();
partitionType.Zero();
firstLBA = 0;
lastLBA = 0;
attributes = 0;
- for (j = 0; j < NAME_SIZE; j++)
- name[j] = '\0';
+ memset(name, 0, NAME_SIZE);
} // GPTPart::BlankPartition
// Returns 1 if the two partitions overlap, 0 if they don't
int GPTPart::DoTheyOverlap(const GPTPart & other) {
- int theyDo = 0;
-
// Don't bother checking unless these are defined (both start and end points
// are 0 for undefined partitions, so just check the start points)
- if ((firstLBA != 0) && (other.firstLBA != 0)) {
- if ((firstLBA < other.lastLBA) && (lastLBA >= other.firstLBA))
- theyDo = 1;
- if ((other.firstLBA < lastLBA) && (other.lastLBA >= firstLBA))
- theyDo = 1;
- } // if
- return (theyDo);
+// cout << "Entering GPTPart::DoTheyOverlap()\n";
+ return firstLBA && other.firstLBA &&
+ (firstLBA <= other.lastLBA) != (lastLBA < other.firstLBA);
} // GPTPart::DoTheyOverlap()
// Reverse the bytes of integral data types; used on big-endian systems.
@@ -242,17 +223,18 @@ void GPTPart::ReversePartBytes(void) {
// name is the generic one for the partition type.
void GPTPart::ChangeType(void) {
char line[255];
- char* junk;
- unsigned int changeName = 0;
+ int changeName;
PartType tempType = (GUIDData) "00000000-0000-0000-0000-000000000000";
- if (GetDescription() == GetTypeName())
- changeName = UINT16_C(1);
+ changeName = (GetDescription() == GetTypeName());
cout << "Current type is '" << GetTypeName() << "'\n";
do {
cout << "Hex code or GUID (L to show codes, Enter = 0700): ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, sizeof(line), stdin)) {
+ cerr << "Critical error! Failed fgets() in GPTPart::ChangeType()!\n";
+ exit(1);
+ } // if
if ((line[0] == 'L') || (line[0] == 'l')) {
partitionType.ShowAllTypes();
} else {
diff --git a/gpttext.cc b/gpttext.cc
index 0bc0ae2..91391e2 100644
--- a/gpttext.cc
+++ b/gpttext.cc
@@ -29,7 +29,7 @@
#include <cstdio>
#include "attributes.h"
#include "gpttext.h"
-#include "partnotes.h"
+#include "gptpartnotes.h"
#include "support.h"
using namespace std;
@@ -353,7 +353,6 @@ void GPTDataTextUI::ShowDetails(void) {
void GPTDataTextUI::MakeHybrid(void) {
uint32_t partNums[3];
char line[255];
- char* junk;
int numPartsToCvt, i, j, mbrNum, bootable = 0;
unsigned int hexCode = 0;
struct PartInfo *newNote;
@@ -368,7 +367,10 @@ void GPTDataTextUI::MakeHybrid(void) {
// hybrid MBR....
cout << "Type from one to three GPT partition numbers, separated by spaces, to be\n"
<< "added to the hybrid MBR, in sequence: ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in GPTDataTextUI::MakeHybrid()!\n";
+ exit(1);
+ } // if
numPartsToCvt = sscanf(line, "%d %d %d", &partNums[0], &partNums[1], &partNums[2]);
if (numPartsToCvt > 0) {
@@ -378,7 +380,7 @@ void GPTDataTextUI::MakeHybrid(void) {
for (i = 0; i < numPartsToCvt; i++) {
newNote = new struct PartInfo;
- j = newNote->gptPartNum = partNums[i] - 1;
+ j = newNote->origPartNum = partNums[i] - 1;
if (partitions[j].IsUsed()) {
mbrNum = i + (eeFirst == 'Y');
cout << "\nCreating entry for GPT partition #" << j + 1
@@ -404,7 +406,7 @@ void GPTDataTextUI::MakeHybrid(void) {
// 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->gptPartNum = MBR_EFI_GPT;
+ newNote->origPartNum = MBR_EFI_GPT;
newNote->firstLBA = 1;
newNote->active = 0;
newNote->hexCode = 0xEE;
@@ -427,13 +429,16 @@ void GPTDataTextUI::MakeHybrid(void) {
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.
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in GPTDataTextUI::MakeHybrid()\n";
+ exit(1);
+ } // if
sscanf(line, "%x", &hexCode);
if (line[0] == '\n')
hexCode = 0x00;
} // while
newNote = new struct PartInfo;
- newNote->gptPartNum = MBR_EFI_GPT;
+ newNote->origPartNum = MBR_EFI_GPT;
newNote->active = 0;
newNote->hexCode = hexCode;
newNote->type = PRIMARY;
@@ -452,7 +457,7 @@ void GPTDataTextUI::MakeHybrid(void) {
// 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(PartNotes & notes) {
+int GPTDataTextUI::AssignPrimaryOrLogical(GptPartNotes& notes) {
int i, partNum, allOK = 1, changesWanted = 1, countedParts, numPrimary = 0, numLogical = 0;
int newNumParts; // size of GPT table
@@ -527,7 +532,7 @@ int GPTDataTextUI::AssignPrimaryOrLogical(PartNotes & notes) {
int GPTDataTextUI::XFormToMBR(void) {
int numToConvert, numReallyConverted = 0;
int origNumParts;
- PartNotes notes;
+ GptPartNotes notes;
GPTPart *tempGptParts;
uint32_t i;
@@ -576,7 +581,6 @@ int GPTDataTextUI::XFormToMBR(void) {
// Get an MBR type code from the user and return it
int GetMBRTypeCode(int defType) {
char line[255];
- char* junk;
int typeCode;
cout.setf(ios::uppercase);
@@ -585,7 +589,10 @@ int GetMBRTypeCode(int defType) {
cout << "Enter an MBR hex code (default " << hex;
cout.width(2);
cout << defType << "): " << dec;
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in GetMBRTypeCode()\n";
+ exit(1);
+ } // if
if (line[0] == '\n')
typeCode = defType;
else
diff --git a/gpttext.h b/gpttext.h
index 6d91a13..642791b 100644
--- a/gpttext.h
+++ b/gpttext.h
@@ -50,7 +50,7 @@ class GPTDataTextUI : public GPTData {
int DestroyGPTwPrompt(void); // Returns 1 if user proceeds
void ShowDetails(void);
void MakeHybrid(void);
- int AssignPrimaryOrLogical(PartNotes& notes);
+ int AssignPrimaryOrLogical(GptPartNotes& notes);
int XFormToMBR(void); // convert GPT to MBR, wiping GPT afterwards. Returns 1 if successful
}; // class GPTDataTextUI
diff --git a/guid.cc b/guid.cc
index 7b4b378..bfbc7d4 100644
--- a/guid.cc
+++ b/guid.cc
@@ -16,6 +16,7 @@
#include <stdio.h>
#include <time.h>
+#include <string.h>
#include <string>
#include <iostream>
#include "guid.h"
@@ -29,10 +30,7 @@ GUIDData::GUIDData(void) {
} // constructor
GUIDData::GUIDData(const GUIDData & orig) {
- int i;
-
- for (i = 0; i < 16; i++)
- uuidData[i] = orig.uuidData[i];
+ memcpy(uuidData, orig.uuidData, sizeof(uuidData));
} // copy constructor
GUIDData::GUIDData(const char * orig) {
@@ -43,10 +41,7 @@ GUIDData::~GUIDData(void) {
} // destructor
GUIDData & GUIDData::operator=(const GUIDData & orig) {
- int i;
-
- for (i = 0; i < 16; i++)
- uuidData[i] = orig.uuidData[i];
+ memcpy(uuidData, orig.uuidData, sizeof(uuidData));
return *this;
} // GUIDData::operator=(const GUIDData & orig)
@@ -123,11 +118,7 @@ GUIDData & GUIDData::operator=(const char * orig) {
// Erase the contents of the GUID
void GUIDData::Zero(void) {
- int i;
-
- for (i = 0; i < 16; i++) {
- uuidData[i] = 0;
- } // for
+ memset(uuidData, 0, sizeof(uuidData));
} // GUIDData::Zero()
// Set a completely random GUID value....
@@ -151,14 +142,7 @@ void GUIDData::Randomize(void) {
// Equality operator; returns 1 if the GUIDs are equal, 0 if they're unequal
int GUIDData::operator==(const GUIDData & orig) const {
- int retval = 1; // assume they're equal
- int i;
-
- for (i = 0; i < 16; i++)
- if (uuidData[i] != orig.uuidData[i])
- retval = 0;
-
- return retval;
+ return !memcmp(uuidData, orig.uuidData, sizeof(uuidData));
} // GUIDData::operator==
// Inequality operator; returns 1 if the GUIDs are unequal, 0 if they're equal
diff --git a/guid.h b/guid.h
index 224302c..d22ec86 100644
--- a/guid.h
+++ b/guid.h
@@ -22,7 +22,7 @@
#ifdef _WIN32
typedef unsigned char my_uuid_t[16];
#else
-#include </usr/include/uuid/uuid.h>
+#include <uuid/uuid.h>
typedef uuid_t my_uuid_t;
#endif
diff --git a/mbr.cc b/mbr.cc
index 1d840cc..415aaf6 100644
--- a/mbr.cc
+++ b/mbr.cc
@@ -19,8 +19,6 @@
#include <errno.h>
#include <iostream>
#include "mbr.h"
-#include "partnotes.h"
-#include "support.h"
using namespace std;
@@ -30,548 +28,11 @@ using namespace std;
* *
****************************************/
-MBRData::MBRData(void) {
- blockSize = SECTOR_SIZE;
- diskSize = 0;
- device = "";
- state = invalid;
- srand((unsigned int) time(NULL));
- numHeads = MAX_HEADS;
- numSecspTrack = MAX_SECSPERTRACK;
- myDisk = NULL;
- canDeleteMyDisk = 0;
- EmptyMBR();
-} // MBRData default constructor
-
-MBRData::MBRData(string filename) {
- blockSize = SECTOR_SIZE;
- diskSize = 0;
- device = filename;
- state = invalid;
- numHeads = MAX_HEADS;
- numSecspTrack = MAX_SECSPERTRACK;
- myDisk = NULL;
- canDeleteMyDisk = 0;
-
- srand((unsigned int) time(NULL));
- // Try to read the specified partition table, but if it fails....
- if (!ReadMBRData(filename)) {
- EmptyMBR();
- device = "";
- } // if
-} // MBRData(string filename) constructor
-
-// Free space used by myDisk only if that's OK -- sometimes it will be
-// copied from an outside source, in which case that source should handle
-// it!
-MBRData::~MBRData(void) {
- if (canDeleteMyDisk)
- delete myDisk;
-} // MBRData destructor
-
-/**********************
- * *
- * Disk I/O functions *
- * *
- **********************/
-
-// Read data from MBR. Returns 1 if read was successful (even if the
-// data isn't a valid MBR), 0 if the read failed.
-int MBRData::ReadMBRData(const string & deviceFilename) {
- int allOK = 1;
-
- if (myDisk == NULL) {
- myDisk = new DiskIO;
- canDeleteMyDisk = 1;
- } // if
- if (myDisk->OpenForRead(deviceFilename)) {
- allOK = ReadMBRData(myDisk);
- } else {
- allOK = 0;
- } // if
-
- if (allOK)
- device = deviceFilename;
-
- return allOK;
-} // MBRData::ReadMBRData(const string & deviceFilename)
-
-// Read data from MBR. If checkBlockSize == 1 (the default), the block
-// size is checked; otherwise it's set to the default (512 bytes).
-// Note that any extended partition(s) present will be explicitly stored
-// in the partitions[] array, along with their contained partitions; the
-// extended container partition(s) should be ignored by other functions.
-int MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) {
- int allOK = 1, i, j, logicalNum;
- int err = 1;
- TempMBR tempMBR;
-
- if ((myDisk != NULL) && (canDeleteMyDisk)) {
- delete myDisk;
- canDeleteMyDisk = 0;
- } // if
-
- myDisk = theDisk;
-
- // Empty existing MBR data, including the logical partitions...
- EmptyMBR(0);
-
- if (myDisk->Seek(0))
- if (myDisk->Read(&tempMBR, 512))
- err = 0;
- if (err) {
- cerr << "Problem reading disk in MBRData::ReadMBRData()!\n";
- } else {
- for (i = 0; i < 440; i++)
- code[i] = tempMBR.code[i];
- 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)
- } // for i... (reading all four partitions)
- MBRSignature = tempMBR.MBRSignature;
-
- // Reverse the byte order, if necessary
- if (IsLittleEndian() == 0) {
- ReverseBytes(&diskSignature, 4);
- ReverseBytes(&nulls, 2);
- ReverseBytes(&MBRSignature, 2);
- for (i = 0; i < 4; i++) {
- ReverseBytes(&partitions[i].firstLBA, 4);
- ReverseBytes(&partitions[i].lengthLBA, 4);
- } // for
- } // if
-
- if (MBRSignature != MBR_SIGNATURE) {
- allOK = 0;
- state = invalid;
- } // if
-
- // Find disk size
- diskSize = myDisk->DiskSize(&err);
-
- // Find block size
- if (checkBlockSize) {
- blockSize = myDisk->GetBlockSize();
- } // if (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)) {
- // Found it, so call a recursive algorithm to load everything from them....
- logicalNum = ReadLogicalPart(partitions[i].firstLBA, 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
- } // if primary partition is extended
- } // for primary partition loop
- if (allOK) { // Loaded logicals OK
- state = mbr;
- } else {
- state = invalid;
- } // if
- } // if
-
- // Check to see if it's in GPT format....
- if (allOK) {
- for (i = 0; i < 4; i++) {
- if (partitions[i].partitionType == UINT8_C(0xEE)) {
- state = gpt;
- } // if
- } // for
- } // if
-
- // If there's an EFI GPT partition, look for other partition types,
- // 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)))
- state = hybrid;
- } // for
- } // if (hybrid detection code)
- } // no initial error
- return allOK;
-} // MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize)
-
-// This is a recursive function to read all the logical partitions, following the
-// logical partition linked list from the disk and storing the basic data in the
-// partitions[] array. Returns last index to partitions[] used, or -1 if there was
-// a problem.
-// Parameters:
-// 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 MBRData::ReadLogicalPart(uint32_t extendedStart, uint32_t diskOffset, int partNum) {
- struct TempMBR ebr;
- 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.
- if ((partNum < MAX_MBR_PARTS) && (partNum >= 0)) {
- offset = (uint64_t) (extendedStart + diskOffset);
- if (myDisk->Seek(offset) == 0) { // seek to EBR record
- cerr << "Unable to seek to " << offset << "! Aborting!\n";
- partNum = -1;
- }
- if (myDisk->Read(&ebr, 512) != 512) { // Load the data....
- cerr << "Error seeking to or reading logical partition data from " << offset
- << "!\nAborting!\n";
- partNum = -1;
- } else if (IsLittleEndian() != 1) { // Reverse byte ordering of some data....
- ReverseBytes(&ebr.MBRSignature, 2);
- ReverseBytes(&ebr.partitions[0].firstLBA, 4);
- ReverseBytes(&ebr.partitions[0].lengthLBA, 4);
- ReverseBytes(&ebr.partitions[1].firstLBA, 4);
- ReverseBytes(&ebr.partitions[1].lengthLBA, 4);
- } // if/else/if
-
- if (ebr.MBRSignature != MBR_SIGNATURE) {
- partNum = -1;
- cerr << "MBR signature in logical partition invalid; read 0x";
- cerr.fill('0');
- cerr.width(4);
- cerr.setf(ios::uppercase);
- cerr << hex << ebr.MBRSignature << ", but should be 0x";
- cerr.width(4);
- cerr << MBR_SIGNATURE << dec << "\n";
- 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);
- } else {
- partNum++;
- } // if another partition
- } // Not enough space for all the logicals (or previous error encountered)
- return (partNum);
-} // MBRData::ReadLogicalPart()
-
-// Write the MBR data to the default defined device. This writes both the
-// MBR itself and any defined logical partitions, provided there's an
-// MBR extended partition.
-int MBRData::WriteMBRData(void) {
- int allOK = 1;
-
- if (myDisk != NULL) {
- if (myDisk->OpenForWrite() != 0) {
- allOK = WriteMBRData(myDisk);
- } else {
- allOK = 0;
- } // if/else
- myDisk->Close();
- } else allOK = 0;
- return allOK;
-} // MBRData::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.
-int MBRData::WriteMBRData(DiskIO *theDisk) {
- int i, j, partNum, allOK, moreLogicals = 0;
- uint32_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);
-
- // Set up tempMBR with some constant data for logical partitions...
- tempMBR.diskSignature = 0;
- for (i = 2; i < 4; i++) {
- tempMBR.partitions[i].firstLBA = tempMBR.partitions[i].lengthLBA = 0;
- tempMBR.partitions[i].partitionType = 0x00;
- for (j = 0; j < 3; j++) {
- tempMBR.partitions[i].firstSector[j] = 0;
- tempMBR.partitions[i].lastSector[j] = 0;
- } // for j
- } // for i
-
- partNum = 4;
- writeEbrTo = (uint64_t) extFirstLBA;
- // If extended partition is present, 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
- // tempMBR.partitions[1] points to next EBR or terminates EBR linked list...
- if ((partNum < MAX_MBR_PARTS - 1) && (partitions[partNum + 1].firstLBA > 0)) {
- tempMBR.partitions[1].partitionType = 0x0f;
- tempMBR.partitions[1].firstLBA = partitions[partNum + 1].firstLBA - 1;
- tempMBR.partitions[1].lengthLBA = partitions[partNum + 1].lengthLBA + 1;
- LBAtoCHS((uint64_t) tempMBR.partitions[1].firstLBA,
- (uint8_t *) &tempMBR.partitions[1].firstSector);
- LBAtoCHS(tempMBR.partitions[1].lengthLBA - extFirstLBA,
- (uint8_t *) &tempMBR.partitions[1].lastSector);
- } else {
- tempMBR.partitions[1].partitionType = 0x00;
- tempMBR.partitions[1].firstLBA = 0;
- tempMBR.partitions[1].lengthLBA = 0;
- moreLogicals = 0;
- } // if/else
- allOK = WriteMBRData(tempMBR, theDisk, writeEbrTo);
- partNum++;
- writeEbrTo = (uint64_t) tempMBR.partitions[1].firstLBA + (uint64_t) extFirstLBA;
- } // while
- return allOK;
-} // MBRData::WriteMBRData(DiskIO *theDisk)
-
-int MBRData::WriteMBRData(const string & deviceFilename) {
- device = deviceFilename;
- return WriteMBRData();
-} // MBRData::WriteMBRData(const string & deviceFilename)
-
-// Write a single MBR record to the specified sector. Used by the like-named
-// function to write both the MBR and multiple EBR (for logical partition)
-// records.
-// Returns 1 on success, 0 on failure
-int MBRData::WriteMBRData(struct TempMBR & mbr, DiskIO *theDisk, uint64_t sector) {
- int i, allOK;
-
- // Reverse the byte order, if necessary
- if (IsLittleEndian() == 0) {
- ReverseBytes(&mbr.diskSignature, 4);
- ReverseBytes(&mbr.nulls, 2);
- ReverseBytes(&mbr.MBRSignature, 2);
- for (i = 0; i < 4; i++) {
- ReverseBytes(&mbr.partitions[i].firstLBA, 4);
- ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
- } // for
- } // if
-
- // Now write the data structure...
- allOK = theDisk->OpenForWrite();
- if (allOK && theDisk->Seek(sector)) {
- if (theDisk->Write(&mbr, 512) != 512) {
- allOK = 0;
- cerr << "Error " << errno << " when saving MBR!\n";
- } // if
- } else {
- allOK = 0;
- cerr << "Error " << errno << " when seeking to MBR to write it!\n";
- } // if/else
- theDisk->Close();
-
- // Reverse the byte order back, if necessary
- if (IsLittleEndian() == 0) {
- ReverseBytes(&mbr.diskSignature, 4);
- ReverseBytes(&mbr.nulls, 2);
- ReverseBytes(&mbr.MBRSignature, 2);
- for (i = 0; i < 4; i++) {
- ReverseBytes(&mbr.partitions[i].firstLBA, 4);
- ReverseBytes(&mbr.partitions[i].lengthLBA, 4);
- } // for
- }// if
- return allOK;
-} // MBRData::WriteMBRData(uint64_t sector)
-
-/********************************************
- * *
- * Functions that display data for the user *
- * *
- ********************************************/
-
-// Show the MBR data to the user, up to the specified maximum number
-// of partitions....
-void MBRData::DisplayMBRData(int maxParts) {
- int i;
- char bootCode;
-
- if (maxParts > MAX_MBR_PARTS)
- maxParts = MAX_MBR_PARTS;
- 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.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";
- } // if
- cout.fill(' ');
- } // for
- cout << "\nDisk size is " << diskSize << " sectors ("
- << BytesToSI(diskSize, blockSize) << ")\n";
-} // MBRData::DisplayMBRData()
-
-// Displays the state, as a word, on stdout. Used for debugging & to
-// tell the user about the MBR state when the program launches....
-void MBRData::ShowState(void) {
- switch (state) {
- case invalid:
- cout << " MBR: not present\n";
- break;
- case gpt:
- cout << " MBR: protective\n";
- break;
- case hybrid:
- cout << " MBR: hybrid\n";
- break;
- case mbr:
- cout << " MBR: MBR only\n";
- break;
- default:
- cout << "\a MBR: unknown -- bug!\n";
- break;
- } // switch
-} // MBRData::ShowState()
-
-/*********************************************************************
- * *
- * Functions that set or get disk metadata (CHS geometry, disk size, *
- * etc.) *
- * *
- *********************************************************************/
-
-// 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 MBRData::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
-} // MBRData::SetCHSGeom()
-
-// 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
-// empty partition), 0 if the value is outside that range, and -1 if chs is
-// invalid.
-int MBRData::LBAtoCHS(uint64_t lba, uint8_t * chs) {
- uint64_t cylinder, head, sector; // all numbered from 0
- uint64_t remainder;
- int retval = 1;
- int done = 0;
-
- if (chs != NULL) {
- // Special case: In case of 0 LBA value, zero out CHS values....
- if (lba == 0) {
- chs[0] = chs[1] = chs[2] = UINT8_C(0);
- done = 1;
- } // if
- // If LBA value is too large for CHS, max out CHS values....
- if ((!done) && (lba >= (numHeads * numSecspTrack * MAX_CYLINDERS))) {
- chs[0] = 254;
- chs[1] = chs[2] = 255;
- done = 1;
- retval = 0;
- } // if
- // If neither of the above applies, compute CHS values....
- if (!done) {
- cylinder = lba / (uint64_t) (numHeads * numSecspTrack);
- remainder = lba - (cylinder * numHeads * numSecspTrack);
- head = remainder / numSecspTrack;
- remainder -= head * numSecspTrack;
- sector = remainder;
- if (head < numHeads)
- chs[0] = (uint8_t) head;
- else
- retval = 0;
- if (sector < numSecspTrack) {
- chs[1] = (uint8_t) ((sector + 1) + (cylinder >> 8) * 64);
- chs[2] = (uint8_t) (cylinder & UINT64_C(0xFF));
- } else {
- retval = 0;
- } // if/else
- } // if value is expressible and non-0
- } else { // Invalid (NULL) chs pointer
- retval = -1;
- } // if CHS pointer valid
- return (retval);
-} // MBRData::LBAtoCHS()
-
-// Look for problems -- overlapping partitions, etc.
-int MBRData::Verify(void) {
- int i, j, theyOverlap, numProbs = 0, numEE = 0;
- uint32_t firstLBA1, firstLBA2, lastLBA1, lastLBA2;
-
- 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) {
- numProbs++;
- cout << "\nProblem: MBR partitions " << i + 1 << " and " << j + 1
- << " overlap!\n";
- } // if
- } // for (j...)
- if (partitions[i].partitionType == 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
- } // for (i...)
- if (numEE > 1)
- cout << "\nCaution: More than one 0xEE MBR partition found. This can cause problems\n"
- << "in some OSes.\n";
-
- return numProbs;
-} // MBRData::Verify()
+// Assignment operator -- copy entire set of MBR data.
+MBRData & MBRData::operator=(const MBRData & orig) {
+ BasicMBRData::operator=(orig);
+ return *this;
+} // MBRData::operator=() */
/*****************************************************
* *
@@ -579,45 +40,6 @@ int MBRData::Verify(void) {
* *
*****************************************************/
-// Empty all data. Meant mainly for calling by constructors, but it's also
-// used by the hybrid MBR functions in the GPTData class.
-void MBRData::EmptyMBR(int clearBootloader) {
- int i;
-
- // Zero out the boot loader section, the disk signature, and the
- // 2-byte nulls area only if requested to do so. (This is the
- // default.)
- if (clearBootloader == 1) {
- EmptyBootloader();
- } // if
-
- // 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);
- } // for
- MBRSignature = MBR_SIGNATURE;
-} // MBRData::EmptyMBR()
-
-// Blank out the boot loader area. Done with the initial MBR-to-GPT
-// conversion, since MBR boot loaders don't understand GPT, and so
-// need to be replaced....
-void MBRData::EmptyBootloader(void) {
- int i;
-
- for (i = 0; i < 440; i++)
- code[i] = 0;
- nulls = 0;
-} // MBRData::EmptyBootloader
-
// Create a protective MBR. Clears the boot loader area if clearBoot > 0.
void MBRData::MakeProtectiveMBR(int clearBoot) {
@@ -651,134 +73,6 @@ void MBRData::MakeProtectiveMBR(int clearBoot) {
state = gpt;
} // MBRData::MakeProtectiveMBR()
-// Create a partition of the specified number, starting LBA, and
-// length. 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 MBRData::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)
- SetPartBootable(num, bootable);
- } // if valid partition number
-} // MBRData::MakePart()
-
-// Set the partition's type code.
-// Returns 1 if successful, 0 if not (invalid partition number)
-int MBRData::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;
- } else allOK = 0;
- } else allOK = 0;
- return allOK;
-} // MBRData::SetPartType()
-
-// Set (or remove) the partition's bootable flag. Setting it is the
-// default; pass 0 as bootable to remove the flag.
-// Returns 1 if successful, 0 if not (invalid partition number)
-int MBRData::SetPartBootable(int num, int bootable) {
- int allOK = 1;
-
- if ((num >= 0) && (num < MAX_MBR_PARTS)) {
- if (partitions[num].lengthLBA != UINT32_C(0)) {
- if (bootable == 0)
- partitions[num].status = UINT8_C(0);
- else
- partitions[num].status = UINT8_C(0x80);
- } else allOK = 0;
- } else allOK = 0;
- return allOK;
-} // MBRData::SetPartBootable()
-
-// Create a partition that fills the most available space. Returns
-// 1 if partition was created, 0 otherwise. Intended for use in
-// creating hybrid MBRs.
-int MBRData::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
- int found = 0;
-
- do {
- firstBlock = FindFirstAvailable(start);
- if (firstBlock != UINT32_C(0)) { // something's free...
- lastBlock = FindLastInFree(firstBlock);
- segmentSize = lastBlock - firstBlock + UINT32_C(1);
- if (segmentSize > selectedSize) {
- selectedSize = segmentSize;
- selectedSegment = firstBlock;
- } // if
- start = lastBlock + 1;
- } // if
- } while (firstBlock != 0);
- if ((selectedSize > UINT32_C(0)) && ((uint64_t) selectedSize < diskSize)) {
- found = 1;
- MakePart(i, selectedSegment, selectedSize, type, 0);
- } else {
- found = 0;
- } // if/else
- return found;
-} // MBRData::MakeBiggestPart(int i)
-
-// Delete partition #i
-void MBRData::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)
-} // MBRData::DeletePartition()
-
-// Delete a partition if one exists at the specified location.
-// Returns 1 if a partition was deleted, 0 otherwise....
-// Used to help keep GPT & hybrid MBR partitions in sync....
-int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
- uint32_t start32, length32;
- int i, deleted = 0;
-
- if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
- 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)) {
- DeletePartition(i);
- if (state == hybrid)
- OptimizeEESize();
- deleted = 1;
- } // if (match found)
- } // for i (partition scan)
- } // if (hybrid & GPT partition < 2TiB)
- return deleted;
-} // MBRData::DeleteByLocation()
-
// Optimizes the size of the 0xEE (EFI GPT) partition
void MBRData::OptimizeEESize(void) {
int i, typeFlag = 0;
@@ -798,168 +92,43 @@ void MBRData::OptimizeEESize(void) {
if (IsFree(after)) {
partitions[i].lengthLBA = FindLastInFree(after) - partitions[i].firstLBA + 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;
+ } else { // disk is too big to represent, so fake it...
+ partitions[0].lengthLBA = UINT32_MAX - partitions[i].firstLBA;
+ } // if/else
+ } // if protective partition is too big
+ RecomputeCHS(i);
} // if partition is 0xEE
} // for partition loop
if (typeFlag == 0) { // No non-hybrid partitions found
- MakeProtectiveMBR(); // ensure it's a fully compliant hybrid MBR.
+ MakeProtectiveMBR(); // ensure it's a fully compliant protective MBR.
} // if
} // MBRData::OptimizeEESize()
-// 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 MBRData::RecomputeCHS(int partNum) {
- uint64_t firstLBA, lengthLBA;
-
- 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
-} // MBRData::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 MBRData::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++;
- } // if
- } // 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;
- i++;
- } // 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);
-} // MBRData::CreateLogicals()
-
-/****************************************
- * *
- * Functions to find data on free space *
- * *
- ****************************************/
-
-// Finds the first free space on the disk from start onward; returns 0
-// if none available....
-uint32_t MBRData::FindFirstAvailable(uint32_t start) {
- uint32_t first;
- uint32_t i;
- int firstMoved;
-
- first = start;
-
- // ...now search through all partitions; if first is within an
- // existing partition, move it to the next sector after that
- // partition and repeat. If first was moved, set firstMoved
- // flag; repeat until firstMoved is not set, so as to catch
- // cases where partitions are out of sequential order....
- do {
- 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;
- firstMoved = 1;
- } // if
- } // for
- } while (firstMoved == 1);
- if (first >= diskSize)
- first = 0;
- return (first);
-} // MBRData::FindFirstAvailable()
-
-// Finds the last free sector on the disk from start forward.
-uint32_t MBRData::FindLastInFree(uint32_t start) {
- uint32_t nearestStart;
- uint32_t i;
-
- if ((diskSize <= UINT32_MAX) && (diskSize > 0))
- nearestStart = (uint32_t) 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
- } // for
- return (nearestStart);
-} // MBRData::FindLastInFree()
-
-// Finds the first free sector on the disk from start backward.
-uint32_t MBRData::FindFirstInFree(uint32_t start) {
- uint32_t bestLastLBA, thisLastLBA;
- int i;
-
- bestLastLBA = 1;
- for (i = 0; i < 4; i++) {
- thisLastLBA = partitions[i].firstLBA + partitions[i].lengthLBA;
- if (thisLastLBA > 0)
- thisLastLBA--;
- if ((thisLastLBA > bestLastLBA) && (thisLastLBA < start))
- bestLastLBA = thisLastLBA + 1;
- } // for
- return (bestLastLBA);
-} // MBRData::FindFirstInFree()
-
-// Returns 1 if the specified sector is unallocated, 0 if it's
-// allocated.
-int MBRData::IsFree(uint32_t sector) {
- int i, isFree = 1;
- uint32_t first, last;
+// Delete a partition if one exists at the specified location.
+// Returns 1 if a partition was deleted, 0 otherwise....
+// Used to help keep GPT & hybrid MBR partitions in sync....
+int MBRData::DeleteByLocation(uint64_t start64, uint64_t length64) {
+ uint32_t start32, length32;
+ int i, deleted = 0;
- 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))
- isFree = 0;
- } // for
- return isFree;
-} // MBRData::IsFree()
+ if ((start64 < UINT32_MAX) && (length64 < UINT32_MAX)) {
+ 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)) {
+ DeletePartition(i);
+ if (state == hybrid)
+ OptimizeEESize();
+ deleted = 1;
+ } // if (match found)
+ } // for i (partition scan)
+ } // if (hybrid & GPT partition < 2TiB)
+ return deleted;
+} // MBRData::DeleteByLocation()
/******************************************************
* *
@@ -967,54 +136,6 @@ int MBRData::IsFree(uint32_t sector) {
* *
******************************************************/
-uint8_t MBRData::GetStatus(int i) {
- MBRRecord* thePart;
- uint8_t retval;
-
- thePart = GetPartition(i);
- if (thePart != NULL)
- retval = thePart->status;
- else
- retval = UINT8_C(0);
- return retval;
-} // MBRData::GetStatus()
-
-uint8_t MBRData::GetType(int i) {
- MBRRecord* thePart;
- uint8_t retval;
-
- thePart = GetPartition(i);
- if (thePart != NULL)
- retval = thePart->partitionType;
- else
- retval = UINT8_C(0);
- return retval;
-} // MBRData::GetType()
-
-uint32_t MBRData::GetFirstSector(int i) {
- MBRRecord* thePart;
- uint32_t retval;
-
- thePart = GetPartition(i);
- if (thePart != NULL) {
- retval = thePart->firstLBA;
- } else
- retval = UINT32_C(0);
- return retval;
-} // MBRData::GetFirstSector()
-
-uint32_t MBRData::GetLength(int i) {
- MBRRecord* thePart;
- uint32_t retval;
-
- thePart = GetPartition(i);
- if (thePart != NULL) {
- retval = thePart->lengthLBA;
- } else
- retval = UINT32_C(0);
- return retval;
-} // MBRData::GetLength()
-
// Return the MBR data as a GPT partition....
GPTPart MBRData::AsGPT(int i) {
MBRRecord* origPart;
@@ -1047,18 +168,3 @@ GPTPart MBRData::AsGPT(int i) {
return newPart;
} // MBRData::AsGPT()
-/***********************
- * *
- * Protected functions *
- * *
- ***********************/
-
-// Return a pointer to a primary or logical partition, or NULL if
-// the partition is out of range....
-struct MBRRecord* MBRData::GetPartition(int i) {
- MBRRecord* thePart = NULL;
-
- if ((i >= 0) && (i < MAX_MBR_PARTS))
- thePart = &partitions[i];
- return thePart;
-} // GetPartition()
diff --git a/mbr.h b/mbr.h
index 85b1841..35dfddc 100644
--- a/mbr.h
+++ b/mbr.h
@@ -6,23 +6,16 @@
#include <stdint.h>
#include <sys/types.h>
#include "gptpart.h"
-#include "partnotes.h"
+//#include "partnotes.h"
#include "diskio.h"
+#include "basicmbr.h"
#ifndef __MBRSTRUCTS
#define __MBRSTRUCTS
-#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
-
using namespace std;
-class PartNotes;
+// class PartNotes;
/****************************************
* *
@@ -30,115 +23,22 @@ 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)
-struct TempMBR {
- uint8_t code[440];
- uint32_t diskSignature;
- uint16_t nulls;
- struct MBRRecord partitions[4];
- uint16_t MBRSignature;
-}; // struct TempMBR
-
-// Possible states of the MBR
-enum MBRValidity {invalid, gpt, hybrid, mbr};
-
// Full data in tweaked MBR format
-class MBRData {
+class MBRData : public BasicMBRData {
protected:
- uint8_t code[440];
- uint32_t diskSignature;
- 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];
- 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
- DiskIO* myDisk;
- int canDeleteMyDisk;
- string device;
- MBRValidity state;
- struct MBRRecord* GetPartition(int i); // Return primary or logical partition
+ int foo;
public:
- MBRData(void);
- MBRData(string deviceFilename);
- ~MBRData(void);
-
- // File I/O functions...
- int ReadMBRData(const string & deviceFilename);
- 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 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;}
-
- // Display data for user...
- void DisplayMBRData(int maxParts = 4);
- void ShowState(void);
-
- // Functions that set or get disk metadata (size, CHS geometry, etc.)
- void SetDiskSize(uint64_t ds) {diskSize = ds;}
- MBRValidity GetValidity(void) {return state;}
- void SetHybrid(void) {state = hybrid;} // Set hybrid flag
- void SetCHSGeom(uint32_t h, uint32_t s);
- int LBAtoCHS(uint64_t lba, uint8_t * chs); // Convert LBA to CHS
- int Verify(void);
+ MBRData(void) {}
+ MBRData(string deviceFilename) : BasicMBRData(deviceFilename) {}
+ 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
- void EmptyMBR(int clearBootloader = 1);
- void EmptyBootloader(void);
void MakeProtectiveMBR(int clearBoot = 0);
- void MakePart(int num, uint32_t startLBA, uint32_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 DeleteByLocation(uint64_t start64, uint64_t length64);
void OptimizeEESize(void);
- void RecomputeCHS(int partNum);
- int CreateLogicals(PartNotes * notes);
-
- // 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);
+ int DeleteByLocation(uint64_t start64, uint64_t length64);
// 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);
GPTPart AsGPT(int i);
}; // struct MBRData
diff --git a/partnotes.cc b/partnotes.cc
index 70196f7..a35f9c7 100644
--- a/partnotes.cc
+++ b/partnotes.cc
@@ -29,21 +29,16 @@ PartNotes::PartNotes() {
notes = NULL;
currentNote = NULL;
currentIndex = 0;
- gptParts = NULL;
- gptTableSize = 0;
+ origTableSize = 0;
blockSize = 512;
dummyNote.active = 0;
- dummyNote.gptPartNum = MBR_EMPTY;
+ dummyNote.origPartNum = MBR_EMPTY;
dummyNote.hexCode = 0xEE;
dummyNote.next = NULL;
dummyNote.spaceBefore = 0;
dummyNote.type = WILL_NOT_CONVERT;
} // PartNotes constructor
-PartNotes::PartNotes(GPTPart *parts, GPTData *gpt, int num, int s) {
- PassPartitions(parts, gpt, num, s);
-} // PartNotes constructor passing partition information
-
// Destructor. Note that we do NOT delete the gptParts array, since we just
// store a pointer to an array that's allocated by the calling function.
PartNotes::~PartNotes() {
@@ -71,59 +66,6 @@ void PartNotes::DeleteNotes(void) {
* *
*************************************************************************/
-// Creates the notes linked list with as many entries as there are
-// in-use GPT partitions. Note that the parts array must be pre-sorted!
-// If not, this function will reject the partition table.
-// Returns the number of partitions -- normally identical to num,
-// unless there were problems, in which case it returns 0.
-int PartNotes::PassPartitions(GPTPart *parts, GPTData *gpt, int num, int s) {
- int i;
- struct PartInfo *tempNote = NULL, *lastNote = NULL;
-
- if ((parts != NULL) && (num > 0)) {
- blockSize = s;
- gptParts = parts;
- gptTableSize = num;
- if (notes != NULL)
- DeleteNotes();
- for (i = 0; i < num; i++) {
- if (gptParts[i].IsUsed()){
- tempNote = new struct PartInfo;
- tempNote->next = NULL;
- tempNote->firstLBA = gptParts[i].GetFirstLBA();
- tempNote->lastLBA = gptParts[i].GetLastLBA();
- if (gpt->IsFree(gptParts[i].GetFirstLBA() - 1)) {
- tempNote->spaceBefore = 1;
- tempNote->type = LOGICAL;
- } else {
- tempNote->spaceBefore = 0;
- tempNote->type = PRIMARY;
- } // if/else
- tempNote->gptPartNum = i;
- tempNote->active = 0;
- if (lastNote == NULL) {
- lastNote = tempNote;
- notes = tempNote;
- } else {
- lastNote->next = tempNote;
- lastNote = tempNote;
- } // if/else
- } // if GPT partition in use
- } // for
- if (!IsSorted()) {
- DeleteNotes();
- gptParts = NULL;
- gptTableSize = 0;
- cerr << "The partition table must be sorted before calling PartNotes::PassPartitions()!\n";
- } // if
- } else {
- notes = NULL;
- gptParts = NULL;
- gptTableSize = 0;
- } // if/else
- return gptTableSize;
-} // PartNotes::PassPartitions
-
// Add a single partition to the end of the linked list.
// Returns 1 on success, 0 on failures.
int PartNotes::AddToEnd(struct PartInfo *newOne) {
@@ -344,10 +286,10 @@ uint8_t PartNotes::GetMbrHexType(int partNum) {
} // if/else
} // PartNotes::GetMBRHexType()
-// Return the GPT partition number associated with this note, -1 if
-// the notes list is empty, or the GPT partition number of the last
+// Return the original partition number associated with this note, -1 if
+// the notes list is empty, or the original partition number of the last
// partition if partNum is too high.
-int PartNotes::GetGptNum(int partNum) {
+int PartNotes::GetOrigNum(int partNum) {
int count = 0;
struct PartInfo *theNote;
@@ -355,11 +297,11 @@ int PartNotes::GetGptNum(int partNum) {
if (theNote != NULL) {
while ((count++ < partNum) && (theNote->next != NULL))
theNote = theNote->next;
- return theNote->gptPartNum;
+ return theNote->origPartNum;
} else {
return -1;
} // if/else
-} // PartNotes::GetGptNum()
+} // PartNotes::GetOrigNum()
// Return whether or not the partition is flagged as active (bootable)
int PartNotes::GetActiveStatus(int partNum) {
@@ -417,23 +359,6 @@ int PartNotes::FindExtended(int &start) {
return length;
} // PartNotes::FindExtended()
-// Returns 1 if the GPT partition table is sorted, 0 if not (or if the
-// pointer is NULL)
-int PartNotes::IsSorted(void) {
- int i, sorted = 1;
- uint64_t lastStartLBA = 0;
-
- if (gptParts == NULL) {
- sorted = 0;
- } else {
- for (i = 0; i < gptTableSize; i++) {
- if (lastStartLBA > gptParts[i].GetFirstLBA())
- sorted = 0;
- } // for
- } // if/else
- return sorted;
-} // PartNotes::IsSorted()
-
// Returns 1 if the set as a whole makes a legal MBR partition table
// (possibly with logicals), 0 if not
int PartNotes::IsLegal(void) {
@@ -557,7 +482,7 @@ void PartNotes::TrimSmallestExtended() {
} // for
// Find the smallest extended partition....
- shortestNum = gptTableSize + 1;
+ shortestNum = origTableSize + 1;
for (i = 0; i < numExtended; i++) {
if (extendeds[i].numLogicals < shortestNum) {
shortestNum = extendeds[i].numLogicals;
@@ -593,57 +518,8 @@ void PartNotes::TrimSmallestExtended() {
// Display summary information for the user
void PartNotes::ShowSummary(void) {
- int j;
- string sizeInSI;
- struct PartInfo *theNote;
-
- if ((gptParts != NULL) && (notes != NULL)) {
- theNote = notes;
- cout << "Sorted GPT partitions and their current conversion status:\n";
- cout << " Can Be\n";
- cout << "Number Boot Size Status Logical Code GPT Name\n";
- while (theNote != NULL) {
- if (gptParts[theNote->gptPartNum].IsUsed()) {
- cout.fill(' ');
- cout.width(4);
- cout << theNote->gptPartNum + 1 << " ";
- if (theNote->active)
- cout << " * ";
- else
- cout << " ";
- sizeInSI = BytesToSI((gptParts[theNote->gptPartNum].GetLastLBA() -
- gptParts[theNote->gptPartNum].GetFirstLBA() + 1), blockSize);
- cout << " " << sizeInSI;
- for (j = 0; j < 12 - (int) sizeInSI.length(); j++)
- cout << " ";
- switch (theNote->type) {
- case PRIMARY:
- cout << "primary ";
- break;
- case LOGICAL:
- cout << "logical ";
- break;
- case WILL_NOT_CONVERT:
- cout << "OMITTED ";
- break;
- default:
- cout << "**ERROR** ";
- break;
- } // switch
- if (theNote->spaceBefore)
- cout << "Y ";
- else
- cout << "- ";
- cout.fill('0');
- cout.width(2);
- cout.setf(ios::uppercase);
- cout << hex << (int) theNote->hexCode << " " << dec;
- cout.fill(' ');
- cout << gptParts[theNote->gptPartNum].GetDescription().substr(0, 25) << "\n";
- } // if
- theNote = theNote->next;
- } // for
- } // if
+ cerr << "Program is calling PartNotes::ShowSummary(); this is a virtual base function,\n"
+ << "and should never be called.\n";
} // PartNotes::ShowSummary()
// Interact with the user to create a change in the specified
@@ -654,7 +530,6 @@ void PartNotes::ShowSummary(void) {
int PartNotes::MakeChange(int partNum) {
int allOK = 1;
int type = 0;
- char *junk;
char line[255], command;
if (notes != NULL) {
@@ -676,7 +551,10 @@ int PartNotes::MakeChange(int partNum) {
} // switch
cout << " t - change MBR type code\n";
cout << "Action: ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in PartNotes::MakeChange()!\n";
+ exit(1);
+ } // if
sscanf(line, "%c", &command);
switch (command) {
case 'a': case 'A':
@@ -694,7 +572,10 @@ int PartNotes::MakeChange(int partNum) {
case 't': case 'T':
while (type == 0) {
cout << "Enter a 2-byte hexadecimal MBR type code: ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in PartNotes::MakeChange()\n";
+ exit(1);
+ } // if
sscanf(line, "%x", &type);
} // while
SetMbrHexType(partNum, (uint8_t) type);
@@ -711,7 +592,7 @@ int PartNotes::MakeChange(int partNum) {
// Returns 1 unless there's a dire bug.
int PartNotes::ChangeType(int partNum, int newType) {
int origType, allOK = 1;
- char *junk, line[255];
+ char line[255];
if ((notes != NULL) && IsLegal()) {
origType = GetType(partNum);
@@ -733,7 +614,10 @@ int PartNotes::ChangeType(int partNum, int newType) {
<< "another\norder, such as deleting partitions before changing others' "
<< "types.\n";
cout << "\nReverting change.\nPress <Enter> to continue: ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in PartNotes::ChangeType()\n";
+ exit(1);
+ } // if
SetType(partNum, origType);
} // if
} else allOK = 0; // if
diff --git a/partnotes.h b/partnotes.h
index 735e1df..750b75f 100644
--- a/partnotes.h
+++ b/partnotes.h
@@ -1,6 +1,6 @@
/*
partnotes.h -- Class that takes notes on GPT partitions for purpose of MBR conversion
- Copyright (C) 2010 Roderick W. Smith
+ Copyright (C) 2010-2011 Roderick W. Smith
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,8 +21,8 @@
#ifndef __PARTNOTES_H
#define __PARTNOTES_H
-#include "gpt.h"
-#include "gptpart.h"
+#include <stdint.h>
+#include <sys/types.h>
using namespace std;
@@ -33,7 +33,7 @@ using namespace std;
// Data structure used in GPT-to-MBR conversions; holds pointer to GPT
// partition number, start and end sectors, and a few MBR-specific details
struct PartInfo {
- int gptPartNum;
+ int origPartNum;
int spaceBefore; // boolean; if 1, can theoretically become a logical part.
int active; // boolean
int type; // WILL_NOT_CONVERT, PRIMARY, or LOGICAL
@@ -54,22 +54,21 @@ class PartNotes {
struct PartInfo *notes;
struct PartInfo *currentNote;
int currentIndex;
- GPTPart *gptParts;
- int gptTableSize;
int blockSize;
+ int origTableSize;
void DeleteNotes(void);
+
public:
PartNotes();
- PartNotes(GPTPart *parts, GPTData *gpt, int num, int blockSize);
~PartNotes();
// Add partition notes (little or no error checking)
- int PassPartitions(GPTPart *parts, GPTData *gpt, int num, int blockSize);
+// int PassPartitions(GPTPart *parts, GPTData *gpt, int num, int blockSize);
int AddToEnd(struct PartInfo* newOne);
int AddToStart(struct PartInfo* newOne);
void SetType(int partNum, int type); // type is PRIMARY, LOGICAL, or WILL_NOT_CONVERT
- void SetMbrHexType(int i, uint8_t type);
+ void SetMbrHexType(int partNum, uint8_t type);
void ToggleActiveStatus(int partNum);
// Retrieve data or metadata
@@ -81,12 +80,11 @@ class PartNotes {
int GetNumLogical();
int GetType(int partNum);
uint8_t GetMbrHexType(int i);
- int GetGptNum(int partNum);
+ int GetOrigNum(int partNum);
int GetActiveStatus(int partNum);
int CanBeLogical(int partNum); // returns boolean
int FindExtended(int &start);
- int IsSorted(void);
- int IsLegal(void); // returns boolean
+ int IsLegal(void); // returns Boolean
// Manipulate data or metadata
void RemoveDuplicates(void);
@@ -94,7 +92,7 @@ class PartNotes {
void TrimSmallestExtended(void);
// Interact with users, possibly changing data with error handling
- void ShowSummary(void);
+ virtual void ShowSummary(void);
int MakeChange(int partNum);
int ChangeType(int partNum, int newType);
};
diff --git a/parttypes.cc b/parttypes.cc
index c6e2098..fce2d46 100644
--- a/parttypes.cc
+++ b/parttypes.cc
@@ -2,7 +2,7 @@
// Class to manage partition type codes -- a slight variant on MBR type
// codes, GUID type codes, and associated names.
-/* 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
@@ -163,7 +163,7 @@ void PartType::AddAllTypes(void) {
AddType(0xc002, "E2A1E728-32E3-11D6-A682-7B03A0000000", "HP-UX service");
// EFI system and related partitions
- AddType(0xef00, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "EFI System"); // Parted marks Linux boot partitions as this
+ AddType(0xef00, "C12A7328-F81F-11D2-BA4B-00A0C93EC93B", "EFI System"); // Parted identifies these as having the "boot flag" set
AddType(0xef01, "024DEE41-33E7-11D3-9D69-0008C781F39F", "MBR partition scheme"); // Used to nest MBR in GPT
AddType(0xef02, "21686148-6449-6E6F-744E-656564454649", "BIOS boot partition"); // Boot loader
diff --git a/sgdisk.8 b/sgdisk.8
index 1cd2b90..0b0b57c 100644
--- a/sgdisk.8
+++ b/sgdisk.8
@@ -570,6 +570,8 @@ Contributors:
* Dwight Schauer (dschauer@ti.com)
+* Florian Zumbiehl (florz@florz.de)
+
.SH "SEE ALSO"
\fBcfdisk (8)\fR,
diff --git a/sgdisk.cc b/sgdisk.cc
index fb0e2c8..f9b0a72 100644
--- a/sgdisk.cc
+++ b/sgdisk.cc
@@ -6,7 +6,7 @@
//
// by Rod Smith, project began February 2009; sgdisk begun January 2010.
-/* This program is copyright (c) 2009, 2010 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. */
#include <stdio.h>
@@ -20,6 +20,7 @@
#include "gpt.h"
#include "support.h"
#include "parttypes.h"
+#include "gptpartnotes.h"
#include "attributes.h"
using namespace std;
@@ -30,7 +31,7 @@ int BuildMBR(GPTData& theGPT, char* argument, int isHybrid);
int CountColons(char* argument);
int main(int argc, char *argv[]) {
- GPTData theGPT;
+ GPTData theGPT, secondDevice;
uint32_t sSize;
uint64_t low, high;
int opt, numOptions = 0, saveData = 0, neverSaveData = 0;
@@ -231,9 +232,10 @@ int main(int argc, char *argv[]) {
theGPT.ShowPartDetails(infoPartNum - 1);
break;
case 'l':
- if (theGPT.LoadGPTBackup((string) backupFile) == 1)
+ if (theGPT.LoadGPTBackup((string) backupFile) == 1) {
+ theGPT.JustLooking(0);
saveData = 1;
- else {
+ } else {
saveData = 0;
neverSaveData = 1;
cerr << "Error loading backup file!\n";
@@ -309,8 +311,11 @@ int main(int argc, char *argv[]) {
} else saveData = 1;
break;
case 'R':
- theGPT.JustLooking(0);
- theGPT.SaveGPTData(1, outDevice);
+ secondDevice = theGPT;
+ secondDevice.SetFile(outDevice);
+ secondDevice.JustLooking(0);
+// secondDevice.FixupMBR();
+ secondDevice.SaveGPTData(1);
break;
case 's':
theGPT.JustLooking(0);
@@ -424,7 +429,7 @@ 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;
- PartNotes notes;
+ GptPartNotes notes;
struct PartInfo *newNote;
if ((&theGPT != NULL) && (argument != NULL)) {
@@ -432,17 +437,17 @@ int BuildMBR(GPTData & theGPT, char* argument, int isHybrid) {
if (numParts <= (4 - isHybrid)) {
for (i = 0; i < numParts; i++) {
newNote = new struct PartInfo;
- newNote->gptPartNum = GetInt(argument, i + 1) - 1;
+ 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->gptPartNum].GetFirstLBA();
- newNote->lastLBA = theGPT[newNote->gptPartNum].GetLastLBA();
+ newNote->firstLBA = theGPT[newNote->origPartNum].GetFirstLBA();
+ newNote->lastLBA = theGPT[newNote->origPartNum].GetLastLBA();
notes.AddToEnd(newNote);
} // for
if (isHybrid) {
newNote = new struct PartInfo;
- newNote->gptPartNum = MBR_EFI_GPT;
+ newNote->origPartNum = MBR_EFI_GPT;
newNote->active = 0;
newNote->hexCode = 0xEE;
newNote->type = PRIMARY;
diff --git a/support.cc b/support.cc
index ee44566..bd0b28b 100644
--- a/support.cc
+++ b/support.cc
@@ -63,11 +63,13 @@ int GetNumber(int low, int high, int def, const string & prompt) {
char GetYN(void) {
char line[255];
char response;
- char *junk;
do {
cout << "(Y/N): ";
- junk = fgets(line, 255, stdin);
+ if (!fgets(line, 255, stdin)) {
+ cerr << "Critical error! Failed fgets() in GetYN()\n";
+ exit(1);
+ } // if
sscanf(line, "%c", &response);
if (response == 'y')
response = 'Y';
@@ -306,32 +308,23 @@ void ReverseBytes(void* theValue, int numBytes) {
// Extract integer data from argument string, which should be colon-delimited
uint64_t GetInt(const string & argument, int itemNum) {
- int startPos = -1, endPos = -1;
- uint64_t retval = 0;
+ uint64_t retval;
- while (itemNum-- > 0) {
- startPos = endPos + 1;
- endPos = (int) argument.find(':', startPos);
- }
- if (endPos == (int) string::npos)
- endPos = (int) argument.length();
- endPos--;
-
- istringstream inString(argument.substr(startPos, endPos - startPos + 1));
+ istringstream inString(GetString(argument, itemNum));
inString >> retval;
return retval;
} // GetInt()
// Extract string data from argument string, which should be colon-delimited
string GetString(const string & argument, int itemNum) {
- int startPos = -1, endPos = -1;
+ size_t startPos = -1, endPos = -1;
while (itemNum-- > 0) {
startPos = endPos + 1;
- endPos = (int) argument.find(':', startPos);
+ endPos = argument.find(':', startPos);
}
- if (endPos == (int) string::npos)
- endPos = (int) argument.length();
+ if (endPos == string::npos)
+ endPos = argument.length();
endPos--;
return argument.substr(startPos, endPos - startPos + 1);