summaryrefslogtreecommitdiffstats
path: root/libparted/labels
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:16:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:16:34 +0000
commita398d2c2b5fd6ab0545d8bb019f9a970b2309404 (patch)
tree272fc7ab226258d7ceddee12c8c682c8e711c2b0 /libparted/labels
parentInitial commit. (diff)
downloadparted-a398d2c2b5fd6ab0545d8bb019f9a970b2309404.tar.xz
parted-a398d2c2b5fd6ab0545d8bb019f9a970b2309404.zip
Adding upstream version 3.6.upstream/3.6upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libparted/labels')
-rw-r--r--libparted/labels/Makefile.am60
-rw-r--r--libparted/labels/Makefile.in2063
-rw-r--r--libparted/labels/aix.c237
-rw-r--r--libparted/labels/atari.c1975
-rw-r--r--libparted/labels/bsd.c654
-rw-r--r--libparted/labels/dasd.c1032
-rw-r--r--libparted/labels/dos.c2612
-rw-r--r--libparted/labels/dvh.c896
-rw-r--r--libparted/labels/dvh.h178
-rw-r--r--libparted/labels/efi_crc32.c126
-rw-r--r--libparted/labels/fdasd.c1442
-rw-r--r--libparted/labels/gpt.c1941
-rw-r--r--libparted/labels/loop.c316
-rw-r--r--libparted/labels/mac.c1604
-rw-r--r--libparted/labels/misc.h48
-rw-r--r--libparted/labels/pc98.c813
-rw-r--r--libparted/labels/pt-common.h55
-rw-r--r--libparted/labels/pt-limit.c161
-rw-r--r--libparted/labels/pt-limit.gperf28
-rw-r--r--libparted/labels/pt-tools.c186
-rw-r--r--libparted/labels/pt-tools.h31
-rw-r--r--libparted/labels/rdb.c1167
-rw-r--r--libparted/labels/sun.c910
-rw-r--r--libparted/labels/vtoc.c1329
24 files changed, 19864 insertions, 0 deletions
diff --git a/libparted/labels/Makefile.am b/libparted/labels/Makefile.am
new file mode 100644
index 0000000..edc3860
--- /dev/null
+++ b/libparted/labels/Makefile.am
@@ -0,0 +1,60 @@
+# This file is part of GNU Parted
+# Copyright (C) 1999-2001, 2007-2014, 2019-2023 Free Software Foundation, Inc.
+#
+# This file may be modified and/or distributed without restriction.
+
+if COMPILE_FOR_S390
+S390_SRCS = dasd.c fdasd.c vtoc.c
+else
+S390_SRCS =
+endif
+
+AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
+
+partedincludedir = \
+ -I$(top_srcdir)/lib -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_srcdir)/libparted
+noinst_LTLIBRARIES = liblabels.la
+
+liblabels_la_SOURCES = \
+ $(S390_SRCS) \
+ aix.c \
+ atari.c \
+ bsd.c \
+ dos.c \
+ dvh.c \
+ dvh.h \
+ efi_crc32.c \
+ gpt.c \
+ loop.c \
+ mac.c \
+ misc.h \
+ pc98.c \
+ pt-common.h \
+ pt-tools.c \
+ pt-tools.h \
+ rdb.c \
+ sun.c
+
+liblabels_la_LIBADD = $(OS_LIBS) $(INTLLIBS) $(LIBICONV)
+
+AM_CPPFLAGS = $(partedincludedir) $(INTLINCS)
+
+# Included by 'pt-tools.c', so needs to be built early.
+BUILT_SOURCES = pt-limit.c
+MAINTAINERCLEANFILES = $(BUILT_SOURCES)
+# DOn't add this to '_SOURCES', because it's not to be compiled!
+EXTRA_DIST= pt-limit.c
+
+GPERF = gperf
+GPERF_OPTIONS = \
+ -C -N pt_limit_lookup -n -t -s 6 -k '*' --language=ANSI-C
+
+pt-limit.c: pt-limit.gperf
+ rm -f $@ $@-tmp
+ $(GPERF) $(GPERF_OPTIONS) $< \
+ | perl -ne '/__GNUC_STDC_INLINE__/ and print "static\n"; print' \
+ > $@-tmp
+ chmod a-w $@-tmp
+ mv $@-tmp $@
+EXTRA_DIST += pt-limit.gperf
diff --git a/libparted/labels/Makefile.in b/libparted/labels/Makefile.in
new file mode 100644
index 0000000..cbf6ef4
--- /dev/null
+++ b/libparted/labels/Makefile.in
@@ -0,0 +1,2063 @@
+# Makefile.in generated by automake 1.16.5 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# This file is part of GNU Parted
+# Copyright (C) 1999-2001, 2007-2014, 2019-2023 Free Software Foundation, Inc.
+#
+# This file may be modified and/or distributed without restriction.
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = libparted/labels
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/00gnulib.m4 \
+ $(top_srcdir)/m4/__inline.m4 \
+ $(top_srcdir)/m4/absolute-header.m4 $(top_srcdir)/m4/alloca.m4 \
+ $(top_srcdir)/m4/arpa_inet_h.m4 $(top_srcdir)/m4/assert.m4 \
+ $(top_srcdir)/m4/assert_h.m4 $(top_srcdir)/m4/btowc.m4 \
+ $(top_srcdir)/m4/build-to-host.m4 \
+ $(top_srcdir)/m4/builtin-expect.m4 $(top_srcdir)/m4/c-bool.m4 \
+ $(top_srcdir)/m4/calloc.m4 $(top_srcdir)/m4/canonicalize.m4 \
+ $(top_srcdir)/m4/clock_time.m4 $(top_srcdir)/m4/close.m4 \
+ $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/config-h.m4 \
+ $(top_srcdir)/m4/configmake.m4 $(top_srcdir)/m4/ctype_h.m4 \
+ $(top_srcdir)/m4/double-slash-root.m4 $(top_srcdir)/m4/dup2.m4 \
+ $(top_srcdir)/m4/eealloc.m4 $(top_srcdir)/m4/environ.m4 \
+ $(top_srcdir)/m4/errno_h.m4 $(top_srcdir)/m4/error.m4 \
+ $(top_srcdir)/m4/error_h.m4 $(top_srcdir)/m4/extensions.m4 \
+ $(top_srcdir)/m4/extern-inline.m4 $(top_srcdir)/m4/fcntl-o.m4 \
+ $(top_srcdir)/m4/fcntl.m4 $(top_srcdir)/m4/fcntl_h.m4 \
+ $(top_srcdir)/m4/fdopen.m4 $(top_srcdir)/m4/flexmember.m4 \
+ $(top_srcdir)/m4/fpending.m4 $(top_srcdir)/m4/free.m4 \
+ $(top_srcdir)/m4/fstat.m4 $(top_srcdir)/m4/fsync.m4 \
+ $(top_srcdir)/m4/ftruncate.m4 $(top_srcdir)/m4/getcwd.m4 \
+ $(top_srcdir)/m4/getdtablesize.m4 $(top_srcdir)/m4/getopt.m4 \
+ $(top_srcdir)/m4/getpagesize.m4 \
+ $(top_srcdir)/m4/getprogname.m4 $(top_srcdir)/m4/getrandom.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/gettimeofday.m4 \
+ $(top_srcdir)/m4/gnulib-common.m4 \
+ $(top_srcdir)/m4/gnulib-comp.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/include_next.m4 $(top_srcdir)/m4/inet_pton.m4 \
+ $(top_srcdir)/m4/intl-thread-locale.m4 \
+ $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/inttypes.m4 \
+ $(top_srcdir)/m4/ioctl.m4 $(top_srcdir)/m4/isblank.m4 \
+ $(top_srcdir)/m4/langinfo_h.m4 $(top_srcdir)/m4/largefile.m4 \
+ $(top_srcdir)/m4/lcmessage.m4 $(top_srcdir)/m4/lib-ignore.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/limits-h.m4 $(top_srcdir)/m4/localcharset.m4 \
+ $(top_srcdir)/m4/locale-fr.m4 $(top_srcdir)/m4/locale-ja.m4 \
+ $(top_srcdir)/m4/locale-tr.m4 $(top_srcdir)/m4/locale-zh.m4 \
+ $(top_srcdir)/m4/locale_h.m4 $(top_srcdir)/m4/localeconv.m4 \
+ $(top_srcdir)/m4/localename.m4 $(top_srcdir)/m4/lock.m4 \
+ $(top_srcdir)/m4/lseek.m4 $(top_srcdir)/m4/lstat.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/malloc.m4 $(top_srcdir)/m4/malloca.m4 \
+ $(top_srcdir)/m4/manywarnings.m4 $(top_srcdir)/m4/mbrtowc.m4 \
+ $(top_srcdir)/m4/mbsinit.m4 $(top_srcdir)/m4/mbstate_t.m4 \
+ $(top_srcdir)/m4/mbtowc.m4 $(top_srcdir)/m4/memchr.m4 \
+ $(top_srcdir)/m4/mempcpy.m4 $(top_srcdir)/m4/minmax.m4 \
+ $(top_srcdir)/m4/mkdir.m4 $(top_srcdir)/m4/mkstemp.m4 \
+ $(top_srcdir)/m4/mmap-anon.m4 $(top_srcdir)/m4/mode_t.m4 \
+ $(top_srcdir)/m4/msvc-inval.m4 \
+ $(top_srcdir)/m4/msvc-nothrow.m4 $(top_srcdir)/m4/multiarch.m4 \
+ $(top_srcdir)/m4/musl.m4 $(top_srcdir)/m4/nanosleep.m4 \
+ $(top_srcdir)/m4/netinet_in_h.m4 \
+ $(top_srcdir)/m4/nl_langinfo.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/nocrash.m4 $(top_srcdir)/m4/o-direct.m4 \
+ $(top_srcdir)/m4/off_t.m4 $(top_srcdir)/m4/open-cloexec.m4 \
+ $(top_srcdir)/m4/open-slash.m4 $(top_srcdir)/m4/open.m4 \
+ $(top_srcdir)/m4/pathmax.m4 $(top_srcdir)/m4/perror.m4 \
+ $(top_srcdir)/m4/pipe.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/priv-set.m4 $(top_srcdir)/m4/progtest.m4 \
+ $(top_srcdir)/m4/pselect.m4 $(top_srcdir)/m4/pthread-thread.m4 \
+ $(top_srcdir)/m4/pthread_h.m4 \
+ $(top_srcdir)/m4/pthread_rwlock_rdlock.m4 \
+ $(top_srcdir)/m4/pthread_sigmask.m4 $(top_srcdir)/m4/putenv.m4 \
+ $(top_srcdir)/m4/quote.m4 $(top_srcdir)/m4/quotearg.m4 \
+ $(top_srcdir)/m4/raise.m4 $(top_srcdir)/m4/rawmemchr.m4 \
+ $(top_srcdir)/m4/read.m4 $(top_srcdir)/m4/readlink.m4 \
+ $(top_srcdir)/m4/realloc.m4 $(top_srcdir)/m4/reallocarray.m4 \
+ $(top_srcdir)/m4/regex.m4 $(top_srcdir)/m4/rpmatch.m4 \
+ $(top_srcdir)/m4/safe-read.m4 $(top_srcdir)/m4/sched_h.m4 \
+ $(top_srcdir)/m4/sched_yield.m4 $(top_srcdir)/m4/select.m4 \
+ $(top_srcdir)/m4/semaphore.m4 $(top_srcdir)/m4/setenv.m4 \
+ $(top_srcdir)/m4/setlocale.m4 \
+ $(top_srcdir)/m4/setlocale_null.m4 \
+ $(top_srcdir)/m4/signal_h.m4 \
+ $(top_srcdir)/m4/signalblocking.m4 $(top_srcdir)/m4/sleep.m4 \
+ $(top_srcdir)/m4/socketlib.m4 $(top_srcdir)/m4/sockets.m4 \
+ $(top_srcdir)/m4/socklen.m4 $(top_srcdir)/m4/sockpfaf.m4 \
+ $(top_srcdir)/m4/ssize_t.m4 $(top_srcdir)/m4/stat-time.m4 \
+ $(top_srcdir)/m4/stat.m4 $(top_srcdir)/m4/stdalign.m4 \
+ $(top_srcdir)/m4/stdarg.m4 $(top_srcdir)/m4/stddef_h.m4 \
+ $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/m4/stdio_h.m4 \
+ $(top_srcdir)/m4/stdlib_h.m4 $(top_srcdir)/m4/strdup.m4 \
+ $(top_srcdir)/m4/strerror.m4 $(top_srcdir)/m4/strerror_r.m4 \
+ $(top_srcdir)/m4/string_h.m4 $(top_srcdir)/m4/strtoll.m4 \
+ $(top_srcdir)/m4/strtoull.m4 $(top_srcdir)/m4/symlink.m4 \
+ $(top_srcdir)/m4/sys_ioctl_h.m4 \
+ $(top_srcdir)/m4/sys_random_h.m4 \
+ $(top_srcdir)/m4/sys_select_h.m4 \
+ $(top_srcdir)/m4/sys_socket_h.m4 \
+ $(top_srcdir)/m4/sys_stat_h.m4 $(top_srcdir)/m4/sys_time_h.m4 \
+ $(top_srcdir)/m4/sys_types_h.m4 $(top_srcdir)/m4/sys_uio_h.m4 \
+ $(top_srcdir)/m4/tempname.m4 $(top_srcdir)/m4/thread.m4 \
+ $(top_srcdir)/m4/threadlib.m4 $(top_srcdir)/m4/time.m4 \
+ $(top_srcdir)/m4/time_h.m4 $(top_srcdir)/m4/unistd_h.m4 \
+ $(top_srcdir)/m4/unlink.m4 $(top_srcdir)/m4/unlinkdir.m4 \
+ $(top_srcdir)/m4/usleep.m4 $(top_srcdir)/m4/version-etc.m4 \
+ $(top_srcdir)/m4/visibility.m4 $(top_srcdir)/m4/warn-on-use.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/m4/wchar_h.m4 \
+ $(top_srcdir)/m4/wchar_t.m4 $(top_srcdir)/m4/wcrtomb.m4 \
+ $(top_srcdir)/m4/wctob.m4 $(top_srcdir)/m4/wctomb.m4 \
+ $(top_srcdir)/m4/wctype_h.m4 $(top_srcdir)/m4/wint_t.m4 \
+ $(top_srcdir)/m4/xalloc.m4 $(top_srcdir)/m4/xstrtol.m4 \
+ $(top_srcdir)/m4/yield.m4 $(top_srcdir)/m4/zzgnulib.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/lib/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+liblabels_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__liblabels_la_SOURCES_DIST = dasd.c fdasd.c vtoc.c aix.c atari.c \
+ bsd.c dos.c dvh.c dvh.h efi_crc32.c gpt.c loop.c mac.c misc.h \
+ pc98.c pt-common.h pt-tools.c pt-tools.h rdb.c sun.c
+@COMPILE_FOR_S390_TRUE@am__objects_1 = dasd.lo fdasd.lo vtoc.lo
+am_liblabels_la_OBJECTS = $(am__objects_1) aix.lo atari.lo bsd.lo \
+ dos.lo dvh.lo efi_crc32.lo gpt.lo loop.lo mac.lo pc98.lo \
+ pt-tools.lo rdb.lo sun.lo
+liblabels_la_OBJECTS = $(am_liblabels_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/lib
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/aix.Plo ./$(DEPDIR)/atari.Plo \
+ ./$(DEPDIR)/bsd.Plo ./$(DEPDIR)/dasd.Plo ./$(DEPDIR)/dos.Plo \
+ ./$(DEPDIR)/dvh.Plo ./$(DEPDIR)/efi_crc32.Plo \
+ ./$(DEPDIR)/fdasd.Plo ./$(DEPDIR)/gpt.Plo ./$(DEPDIR)/loop.Plo \
+ ./$(DEPDIR)/mac.Plo ./$(DEPDIR)/pc98.Plo \
+ ./$(DEPDIR)/pt-tools.Plo ./$(DEPDIR)/rdb.Plo \
+ ./$(DEPDIR)/sun.Plo ./$(DEPDIR)/vtoc.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liblabels_la_SOURCES)
+DIST_SOURCES = $(am__liblabels_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+am__DIST_COMMON = $(srcdir)/Makefile.in \
+ $(top_srcdir)/build-aux/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+pkgdatadir = @pkgdatadir@
+pkgincludedir = @pkgincludedir@
+pkglibdir = @pkglibdir@
+pkglibexecdir = @pkglibexecdir@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALLOCA_H = @ALLOCA_H@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+ASSERT_H = @ASSERT_H@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BITSIZEOF_PTRDIFF_T = @BITSIZEOF_PTRDIFF_T@
+BITSIZEOF_SIG_ATOMIC_T = @BITSIZEOF_SIG_ATOMIC_T@
+BITSIZEOF_SIZE_T = @BITSIZEOF_SIZE_T@
+BITSIZEOF_WCHAR_T = @BITSIZEOF_WCHAR_T@
+BITSIZEOF_WINT_T = @BITSIZEOF_WINT_T@
+BUILDINFO = @BUILDINFO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_VISIBILITY = @CFLAG_VISIBILITY@
+CHECK_CFLAGS = @CHECK_CFLAGS@
+CHECK_LIBS = @CHECK_LIBS@
+CLOCK_TIME_LIB = @CLOCK_TIME_LIB@
+CONFIG_INCLUDE = @CONFIG_INCLUDE@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DM_LIBS = @DM_LIBS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EMULTIHOP_HIDDEN = @EMULTIHOP_HIDDEN@
+EMULTIHOP_VALUE = @EMULTIHOP_VALUE@
+ENABLE_DEVICE_MAPPER = @ENABLE_DEVICE_MAPPER@
+ENOLINK_HIDDEN = @ENOLINK_HIDDEN@
+ENOLINK_VALUE = @ENOLINK_VALUE@
+EOVERFLOW_HIDDEN = @EOVERFLOW_HIDDEN@
+EOVERFLOW_VALUE = @EOVERFLOW_VALUE@
+ERRNO_H = @ERRNO_H@
+ERROR_H = @ERROR_H@
+ETAGS = @ETAGS@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILECMD = @FILECMD@
+GETOPT_CDEFS_H = @GETOPT_CDEFS_H@
+GETOPT_H = @GETOPT_H@
+GETRANDOM_LIB = @GETRANDOM_LIB@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GL_CFLAG_ALLOW_WARNINGS = @GL_CFLAG_ALLOW_WARNINGS@
+GL_CFLAG_GNULIB_WARNINGS = @GL_CFLAG_GNULIB_WARNINGS@
+GL_CXXFLAG_ALLOW_WARNINGS = @GL_CXXFLAG_ALLOW_WARNINGS@
+GL_GNULIB_ACCEPT = @GL_GNULIB_ACCEPT@
+GL_GNULIB_ACCEPT4 = @GL_GNULIB_ACCEPT4@
+GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@
+GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@
+GL_GNULIB_ATOLL = @GL_GNULIB_ATOLL@
+GL_GNULIB_BIND = @GL_GNULIB_BIND@
+GL_GNULIB_BTOWC = @GL_GNULIB_BTOWC@
+GL_GNULIB_CALLOC_GNU = @GL_GNULIB_CALLOC_GNU@
+GL_GNULIB_CALLOC_POSIX = @GL_GNULIB_CALLOC_POSIX@
+GL_GNULIB_CANONICALIZE_FILE_NAME = @GL_GNULIB_CANONICALIZE_FILE_NAME@
+GL_GNULIB_CHDIR = @GL_GNULIB_CHDIR@
+GL_GNULIB_CHMOD = @GL_GNULIB_CHMOD@
+GL_GNULIB_CHOWN = @GL_GNULIB_CHOWN@
+GL_GNULIB_CLOSE = @GL_GNULIB_CLOSE@
+GL_GNULIB_CONNECT = @GL_GNULIB_CONNECT@
+GL_GNULIB_COPY_FILE_RANGE = @GL_GNULIB_COPY_FILE_RANGE@
+GL_GNULIB_CREAT = @GL_GNULIB_CREAT@
+GL_GNULIB_CTIME = @GL_GNULIB_CTIME@
+GL_GNULIB_DPRINTF = @GL_GNULIB_DPRINTF@
+GL_GNULIB_DUP = @GL_GNULIB_DUP@
+GL_GNULIB_DUP2 = @GL_GNULIB_DUP2@
+GL_GNULIB_DUP3 = @GL_GNULIB_DUP3@
+GL_GNULIB_DUPLOCALE = @GL_GNULIB_DUPLOCALE@
+GL_GNULIB_ENVIRON = @GL_GNULIB_ENVIRON@
+GL_GNULIB_EUIDACCESS = @GL_GNULIB_EUIDACCESS@
+GL_GNULIB_EXECL = @GL_GNULIB_EXECL@
+GL_GNULIB_EXECLE = @GL_GNULIB_EXECLE@
+GL_GNULIB_EXECLP = @GL_GNULIB_EXECLP@
+GL_GNULIB_EXECV = @GL_GNULIB_EXECV@
+GL_GNULIB_EXECVE = @GL_GNULIB_EXECVE@
+GL_GNULIB_EXECVP = @GL_GNULIB_EXECVP@
+GL_GNULIB_EXECVPE = @GL_GNULIB_EXECVPE@
+GL_GNULIB_EXPLICIT_BZERO = @GL_GNULIB_EXPLICIT_BZERO@
+GL_GNULIB_FACCESSAT = @GL_GNULIB_FACCESSAT@
+GL_GNULIB_FCHDIR = @GL_GNULIB_FCHDIR@
+GL_GNULIB_FCHMODAT = @GL_GNULIB_FCHMODAT@
+GL_GNULIB_FCHOWNAT = @GL_GNULIB_FCHOWNAT@
+GL_GNULIB_FCLOSE = @GL_GNULIB_FCLOSE@
+GL_GNULIB_FCNTL = @GL_GNULIB_FCNTL@
+GL_GNULIB_FDATASYNC = @GL_GNULIB_FDATASYNC@
+GL_GNULIB_FDOPEN = @GL_GNULIB_FDOPEN@
+GL_GNULIB_FFLUSH = @GL_GNULIB_FFLUSH@
+GL_GNULIB_FFSL = @GL_GNULIB_FFSL@
+GL_GNULIB_FFSLL = @GL_GNULIB_FFSLL@
+GL_GNULIB_FGETC = @GL_GNULIB_FGETC@
+GL_GNULIB_FGETS = @GL_GNULIB_FGETS@
+GL_GNULIB_FOPEN = @GL_GNULIB_FOPEN@
+GL_GNULIB_FOPEN_GNU = @GL_GNULIB_FOPEN_GNU@
+GL_GNULIB_FPRINTF = @GL_GNULIB_FPRINTF@
+GL_GNULIB_FPRINTF_POSIX = @GL_GNULIB_FPRINTF_POSIX@
+GL_GNULIB_FPURGE = @GL_GNULIB_FPURGE@
+GL_GNULIB_FPUTC = @GL_GNULIB_FPUTC@
+GL_GNULIB_FPUTS = @GL_GNULIB_FPUTS@
+GL_GNULIB_FREAD = @GL_GNULIB_FREAD@
+GL_GNULIB_FREE_POSIX = @GL_GNULIB_FREE_POSIX@
+GL_GNULIB_FREOPEN = @GL_GNULIB_FREOPEN@
+GL_GNULIB_FSCANF = @GL_GNULIB_FSCANF@
+GL_GNULIB_FSEEK = @GL_GNULIB_FSEEK@
+GL_GNULIB_FSEEKO = @GL_GNULIB_FSEEKO@
+GL_GNULIB_FSTAT = @GL_GNULIB_FSTAT@
+GL_GNULIB_FSTATAT = @GL_GNULIB_FSTATAT@
+GL_GNULIB_FSYNC = @GL_GNULIB_FSYNC@
+GL_GNULIB_FTELL = @GL_GNULIB_FTELL@
+GL_GNULIB_FTELLO = @GL_GNULIB_FTELLO@
+GL_GNULIB_FTRUNCATE = @GL_GNULIB_FTRUNCATE@
+GL_GNULIB_FUTIMENS = @GL_GNULIB_FUTIMENS@
+GL_GNULIB_FWRITE = @GL_GNULIB_FWRITE@
+GL_GNULIB_GETC = @GL_GNULIB_GETC@
+GL_GNULIB_GETCHAR = @GL_GNULIB_GETCHAR@
+GL_GNULIB_GETCWD = @GL_GNULIB_GETCWD@
+GL_GNULIB_GETDELIM = @GL_GNULIB_GETDELIM@
+GL_GNULIB_GETDOMAINNAME = @GL_GNULIB_GETDOMAINNAME@
+GL_GNULIB_GETDTABLESIZE = @GL_GNULIB_GETDTABLESIZE@
+GL_GNULIB_GETENTROPY = @GL_GNULIB_GETENTROPY@
+GL_GNULIB_GETGROUPS = @GL_GNULIB_GETGROUPS@
+GL_GNULIB_GETHOSTNAME = @GL_GNULIB_GETHOSTNAME@
+GL_GNULIB_GETLINE = @GL_GNULIB_GETLINE@
+GL_GNULIB_GETLOADAVG = @GL_GNULIB_GETLOADAVG@
+GL_GNULIB_GETLOGIN = @GL_GNULIB_GETLOGIN@
+GL_GNULIB_GETLOGIN_R = @GL_GNULIB_GETLOGIN_R@
+GL_GNULIB_GETOPT_POSIX = @GL_GNULIB_GETOPT_POSIX@
+GL_GNULIB_GETPAGESIZE = @GL_GNULIB_GETPAGESIZE@
+GL_GNULIB_GETPASS = @GL_GNULIB_GETPASS@
+GL_GNULIB_GETPASS_GNU = @GL_GNULIB_GETPASS_GNU@
+GL_GNULIB_GETPEERNAME = @GL_GNULIB_GETPEERNAME@
+GL_GNULIB_GETPROGNAME = @GL_GNULIB_GETPROGNAME@
+GL_GNULIB_GETRANDOM = @GL_GNULIB_GETRANDOM@
+GL_GNULIB_GETSOCKNAME = @GL_GNULIB_GETSOCKNAME@
+GL_GNULIB_GETSOCKOPT = @GL_GNULIB_GETSOCKOPT@
+GL_GNULIB_GETSUBOPT = @GL_GNULIB_GETSUBOPT@
+GL_GNULIB_GETTIMEOFDAY = @GL_GNULIB_GETTIMEOFDAY@
+GL_GNULIB_GETUMASK = @GL_GNULIB_GETUMASK@
+GL_GNULIB_GETUSERSHELL = @GL_GNULIB_GETUSERSHELL@
+GL_GNULIB_GRANTPT = @GL_GNULIB_GRANTPT@
+GL_GNULIB_GROUP_MEMBER = @GL_GNULIB_GROUP_MEMBER@
+GL_GNULIB_IMAXABS = @GL_GNULIB_IMAXABS@
+GL_GNULIB_IMAXDIV = @GL_GNULIB_IMAXDIV@
+GL_GNULIB_INET_NTOP = @GL_GNULIB_INET_NTOP@
+GL_GNULIB_INET_PTON = @GL_GNULIB_INET_PTON@
+GL_GNULIB_IOCTL = @GL_GNULIB_IOCTL@
+GL_GNULIB_ISATTY = @GL_GNULIB_ISATTY@
+GL_GNULIB_ISBLANK = @GL_GNULIB_ISBLANK@
+GL_GNULIB_ISWBLANK = @GL_GNULIB_ISWBLANK@
+GL_GNULIB_ISWCTYPE = @GL_GNULIB_ISWCTYPE@
+GL_GNULIB_ISWDIGIT = @GL_GNULIB_ISWDIGIT@
+GL_GNULIB_ISWXDIGIT = @GL_GNULIB_ISWXDIGIT@
+GL_GNULIB_LCHMOD = @GL_GNULIB_LCHMOD@
+GL_GNULIB_LCHOWN = @GL_GNULIB_LCHOWN@
+GL_GNULIB_LINK = @GL_GNULIB_LINK@
+GL_GNULIB_LINKAT = @GL_GNULIB_LINKAT@
+GL_GNULIB_LISTEN = @GL_GNULIB_LISTEN@
+GL_GNULIB_LOCALECONV = @GL_GNULIB_LOCALECONV@
+GL_GNULIB_LOCALENAME = @GL_GNULIB_LOCALENAME@
+GL_GNULIB_LOCALTIME = @GL_GNULIB_LOCALTIME@
+GL_GNULIB_LSEEK = @GL_GNULIB_LSEEK@
+GL_GNULIB_LSTAT = @GL_GNULIB_LSTAT@
+GL_GNULIB_MALLOC_GNU = @GL_GNULIB_MALLOC_GNU@
+GL_GNULIB_MALLOC_POSIX = @GL_GNULIB_MALLOC_POSIX@
+GL_GNULIB_MBRLEN = @GL_GNULIB_MBRLEN@
+GL_GNULIB_MBRTOWC = @GL_GNULIB_MBRTOWC@
+GL_GNULIB_MBSCASECMP = @GL_GNULIB_MBSCASECMP@
+GL_GNULIB_MBSCASESTR = @GL_GNULIB_MBSCASESTR@
+GL_GNULIB_MBSCHR = @GL_GNULIB_MBSCHR@
+GL_GNULIB_MBSCSPN = @GL_GNULIB_MBSCSPN@
+GL_GNULIB_MBSINIT = @GL_GNULIB_MBSINIT@
+GL_GNULIB_MBSLEN = @GL_GNULIB_MBSLEN@
+GL_GNULIB_MBSNCASECMP = @GL_GNULIB_MBSNCASECMP@
+GL_GNULIB_MBSNLEN = @GL_GNULIB_MBSNLEN@
+GL_GNULIB_MBSNRTOWCS = @GL_GNULIB_MBSNRTOWCS@
+GL_GNULIB_MBSPBRK = @GL_GNULIB_MBSPBRK@
+GL_GNULIB_MBSPCASECMP = @GL_GNULIB_MBSPCASECMP@
+GL_GNULIB_MBSRCHR = @GL_GNULIB_MBSRCHR@
+GL_GNULIB_MBSRTOWCS = @GL_GNULIB_MBSRTOWCS@
+GL_GNULIB_MBSSEP = @GL_GNULIB_MBSSEP@
+GL_GNULIB_MBSSPN = @GL_GNULIB_MBSSPN@
+GL_GNULIB_MBSSTR = @GL_GNULIB_MBSSTR@
+GL_GNULIB_MBSTOK_R = @GL_GNULIB_MBSTOK_R@
+GL_GNULIB_MBTOWC = @GL_GNULIB_MBTOWC@
+GL_GNULIB_MDA_ACCESS = @GL_GNULIB_MDA_ACCESS@
+GL_GNULIB_MDA_CHDIR = @GL_GNULIB_MDA_CHDIR@
+GL_GNULIB_MDA_CHMOD = @GL_GNULIB_MDA_CHMOD@
+GL_GNULIB_MDA_CLOSE = @GL_GNULIB_MDA_CLOSE@
+GL_GNULIB_MDA_CREAT = @GL_GNULIB_MDA_CREAT@
+GL_GNULIB_MDA_DUP = @GL_GNULIB_MDA_DUP@
+GL_GNULIB_MDA_DUP2 = @GL_GNULIB_MDA_DUP2@
+GL_GNULIB_MDA_ECVT = @GL_GNULIB_MDA_ECVT@
+GL_GNULIB_MDA_EXECL = @GL_GNULIB_MDA_EXECL@
+GL_GNULIB_MDA_EXECLE = @GL_GNULIB_MDA_EXECLE@
+GL_GNULIB_MDA_EXECLP = @GL_GNULIB_MDA_EXECLP@
+GL_GNULIB_MDA_EXECV = @GL_GNULIB_MDA_EXECV@
+GL_GNULIB_MDA_EXECVE = @GL_GNULIB_MDA_EXECVE@
+GL_GNULIB_MDA_EXECVP = @GL_GNULIB_MDA_EXECVP@
+GL_GNULIB_MDA_EXECVPE = @GL_GNULIB_MDA_EXECVPE@
+GL_GNULIB_MDA_FCLOSEALL = @GL_GNULIB_MDA_FCLOSEALL@
+GL_GNULIB_MDA_FCVT = @GL_GNULIB_MDA_FCVT@
+GL_GNULIB_MDA_FDOPEN = @GL_GNULIB_MDA_FDOPEN@
+GL_GNULIB_MDA_FILENO = @GL_GNULIB_MDA_FILENO@
+GL_GNULIB_MDA_GCVT = @GL_GNULIB_MDA_GCVT@
+GL_GNULIB_MDA_GETCWD = @GL_GNULIB_MDA_GETCWD@
+GL_GNULIB_MDA_GETPID = @GL_GNULIB_MDA_GETPID@
+GL_GNULIB_MDA_GETW = @GL_GNULIB_MDA_GETW@
+GL_GNULIB_MDA_ISATTY = @GL_GNULIB_MDA_ISATTY@
+GL_GNULIB_MDA_LSEEK = @GL_GNULIB_MDA_LSEEK@
+GL_GNULIB_MDA_MEMCCPY = @GL_GNULIB_MDA_MEMCCPY@
+GL_GNULIB_MDA_MKDIR = @GL_GNULIB_MDA_MKDIR@
+GL_GNULIB_MDA_MKTEMP = @GL_GNULIB_MDA_MKTEMP@
+GL_GNULIB_MDA_OPEN = @GL_GNULIB_MDA_OPEN@
+GL_GNULIB_MDA_PUTENV = @GL_GNULIB_MDA_PUTENV@
+GL_GNULIB_MDA_PUTW = @GL_GNULIB_MDA_PUTW@
+GL_GNULIB_MDA_READ = @GL_GNULIB_MDA_READ@
+GL_GNULIB_MDA_RMDIR = @GL_GNULIB_MDA_RMDIR@
+GL_GNULIB_MDA_STRDUP = @GL_GNULIB_MDA_STRDUP@
+GL_GNULIB_MDA_SWAB = @GL_GNULIB_MDA_SWAB@
+GL_GNULIB_MDA_TEMPNAM = @GL_GNULIB_MDA_TEMPNAM@
+GL_GNULIB_MDA_TZSET = @GL_GNULIB_MDA_TZSET@
+GL_GNULIB_MDA_UMASK = @GL_GNULIB_MDA_UMASK@
+GL_GNULIB_MDA_UNLINK = @GL_GNULIB_MDA_UNLINK@
+GL_GNULIB_MDA_WCSDUP = @GL_GNULIB_MDA_WCSDUP@
+GL_GNULIB_MDA_WRITE = @GL_GNULIB_MDA_WRITE@
+GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
+GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
+GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
+GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@
+GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
+GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
+GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
+GL_GNULIB_MKFIFO = @GL_GNULIB_MKFIFO@
+GL_GNULIB_MKFIFOAT = @GL_GNULIB_MKFIFOAT@
+GL_GNULIB_MKNOD = @GL_GNULIB_MKNOD@
+GL_GNULIB_MKNODAT = @GL_GNULIB_MKNODAT@
+GL_GNULIB_MKOSTEMP = @GL_GNULIB_MKOSTEMP@
+GL_GNULIB_MKOSTEMPS = @GL_GNULIB_MKOSTEMPS@
+GL_GNULIB_MKSTEMP = @GL_GNULIB_MKSTEMP@
+GL_GNULIB_MKSTEMPS = @GL_GNULIB_MKSTEMPS@
+GL_GNULIB_MKTIME = @GL_GNULIB_MKTIME@
+GL_GNULIB_NANOSLEEP = @GL_GNULIB_NANOSLEEP@
+GL_GNULIB_NL_LANGINFO = @GL_GNULIB_NL_LANGINFO@
+GL_GNULIB_NONBLOCKING = @GL_GNULIB_NONBLOCKING@
+GL_GNULIB_OBSTACK_PRINTF = @GL_GNULIB_OBSTACK_PRINTF@
+GL_GNULIB_OBSTACK_PRINTF_POSIX = @GL_GNULIB_OBSTACK_PRINTF_POSIX@
+GL_GNULIB_OPEN = @GL_GNULIB_OPEN@
+GL_GNULIB_OPENAT = @GL_GNULIB_OPENAT@
+GL_GNULIB_OVERRIDES_STRUCT_STAT = @GL_GNULIB_OVERRIDES_STRUCT_STAT@
+GL_GNULIB_PCLOSE = @GL_GNULIB_PCLOSE@
+GL_GNULIB_PERROR = @GL_GNULIB_PERROR@
+GL_GNULIB_PIPE = @GL_GNULIB_PIPE@
+GL_GNULIB_PIPE2 = @GL_GNULIB_PIPE2@
+GL_GNULIB_POPEN = @GL_GNULIB_POPEN@
+GL_GNULIB_POSIX_MEMALIGN = @GL_GNULIB_POSIX_MEMALIGN@
+GL_GNULIB_POSIX_OPENPT = @GL_GNULIB_POSIX_OPENPT@
+GL_GNULIB_PREAD = @GL_GNULIB_PREAD@
+GL_GNULIB_PRINTF = @GL_GNULIB_PRINTF@
+GL_GNULIB_PRINTF_POSIX = @GL_GNULIB_PRINTF_POSIX@
+GL_GNULIB_PSELECT = @GL_GNULIB_PSELECT@
+GL_GNULIB_PTHREAD_COND = @GL_GNULIB_PTHREAD_COND@
+GL_GNULIB_PTHREAD_MUTEX = @GL_GNULIB_PTHREAD_MUTEX@
+GL_GNULIB_PTHREAD_MUTEX_TIMEDLOCK = @GL_GNULIB_PTHREAD_MUTEX_TIMEDLOCK@
+GL_GNULIB_PTHREAD_ONCE = @GL_GNULIB_PTHREAD_ONCE@
+GL_GNULIB_PTHREAD_RWLOCK = @GL_GNULIB_PTHREAD_RWLOCK@
+GL_GNULIB_PTHREAD_SIGMASK = @GL_GNULIB_PTHREAD_SIGMASK@
+GL_GNULIB_PTHREAD_SPIN = @GL_GNULIB_PTHREAD_SPIN@
+GL_GNULIB_PTHREAD_THREAD = @GL_GNULIB_PTHREAD_THREAD@
+GL_GNULIB_PTHREAD_TSS = @GL_GNULIB_PTHREAD_TSS@
+GL_GNULIB_PTSNAME = @GL_GNULIB_PTSNAME@
+GL_GNULIB_PTSNAME_R = @GL_GNULIB_PTSNAME_R@
+GL_GNULIB_PUTC = @GL_GNULIB_PUTC@
+GL_GNULIB_PUTCHAR = @GL_GNULIB_PUTCHAR@
+GL_GNULIB_PUTENV = @GL_GNULIB_PUTENV@
+GL_GNULIB_PUTS = @GL_GNULIB_PUTS@
+GL_GNULIB_PWRITE = @GL_GNULIB_PWRITE@
+GL_GNULIB_QSORT_R = @GL_GNULIB_QSORT_R@
+GL_GNULIB_RAISE = @GL_GNULIB_RAISE@
+GL_GNULIB_RANDOM = @GL_GNULIB_RANDOM@
+GL_GNULIB_RANDOM_R = @GL_GNULIB_RANDOM_R@
+GL_GNULIB_RAWMEMCHR = @GL_GNULIB_RAWMEMCHR@
+GL_GNULIB_READ = @GL_GNULIB_READ@
+GL_GNULIB_READLINK = @GL_GNULIB_READLINK@
+GL_GNULIB_READLINKAT = @GL_GNULIB_READLINKAT@
+GL_GNULIB_REALLOCARRAY = @GL_GNULIB_REALLOCARRAY@
+GL_GNULIB_REALLOC_GNU = @GL_GNULIB_REALLOC_GNU@
+GL_GNULIB_REALLOC_POSIX = @GL_GNULIB_REALLOC_POSIX@
+GL_GNULIB_REALPATH = @GL_GNULIB_REALPATH@
+GL_GNULIB_RECV = @GL_GNULIB_RECV@
+GL_GNULIB_RECVFROM = @GL_GNULIB_RECVFROM@
+GL_GNULIB_REMOVE = @GL_GNULIB_REMOVE@
+GL_GNULIB_RENAME = @GL_GNULIB_RENAME@
+GL_GNULIB_RENAMEAT = @GL_GNULIB_RENAMEAT@
+GL_GNULIB_RMDIR = @GL_GNULIB_RMDIR@
+GL_GNULIB_RPMATCH = @GL_GNULIB_RPMATCH@
+GL_GNULIB_SCANF = @GL_GNULIB_SCANF@
+GL_GNULIB_SCHED_YIELD = @GL_GNULIB_SCHED_YIELD@
+GL_GNULIB_SECURE_GETENV = @GL_GNULIB_SECURE_GETENV@
+GL_GNULIB_SELECT = @GL_GNULIB_SELECT@
+GL_GNULIB_SEND = @GL_GNULIB_SEND@
+GL_GNULIB_SENDTO = @GL_GNULIB_SENDTO@
+GL_GNULIB_SETENV = @GL_GNULIB_SETENV@
+GL_GNULIB_SETHOSTNAME = @GL_GNULIB_SETHOSTNAME@
+GL_GNULIB_SETLOCALE = @GL_GNULIB_SETLOCALE@
+GL_GNULIB_SETLOCALE_NULL = @GL_GNULIB_SETLOCALE_NULL@
+GL_GNULIB_SETSOCKOPT = @GL_GNULIB_SETSOCKOPT@
+GL_GNULIB_SHUTDOWN = @GL_GNULIB_SHUTDOWN@
+GL_GNULIB_SIGABBREV_NP = @GL_GNULIB_SIGABBREV_NP@
+GL_GNULIB_SIGACTION = @GL_GNULIB_SIGACTION@
+GL_GNULIB_SIGDESCR_NP = @GL_GNULIB_SIGDESCR_NP@
+GL_GNULIB_SIGNAL_H_SIGPIPE = @GL_GNULIB_SIGNAL_H_SIGPIPE@
+GL_GNULIB_SIGPROCMASK = @GL_GNULIB_SIGPROCMASK@
+GL_GNULIB_SLEEP = @GL_GNULIB_SLEEP@
+GL_GNULIB_SNPRINTF = @GL_GNULIB_SNPRINTF@
+GL_GNULIB_SOCKET = @GL_GNULIB_SOCKET@
+GL_GNULIB_SPRINTF_POSIX = @GL_GNULIB_SPRINTF_POSIX@
+GL_GNULIB_STAT = @GL_GNULIB_STAT@
+GL_GNULIB_STDIO_H_NONBLOCKING = @GL_GNULIB_STDIO_H_NONBLOCKING@
+GL_GNULIB_STDIO_H_SIGPIPE = @GL_GNULIB_STDIO_H_SIGPIPE@
+GL_GNULIB_STPCPY = @GL_GNULIB_STPCPY@
+GL_GNULIB_STPNCPY = @GL_GNULIB_STPNCPY@
+GL_GNULIB_STRCASESTR = @GL_GNULIB_STRCASESTR@
+GL_GNULIB_STRCHRNUL = @GL_GNULIB_STRCHRNUL@
+GL_GNULIB_STRDUP = @GL_GNULIB_STRDUP@
+GL_GNULIB_STRERROR = @GL_GNULIB_STRERROR@
+GL_GNULIB_STRERRORNAME_NP = @GL_GNULIB_STRERRORNAME_NP@
+GL_GNULIB_STRERROR_R = @GL_GNULIB_STRERROR_R@
+GL_GNULIB_STRFTIME = @GL_GNULIB_STRFTIME@
+GL_GNULIB_STRNCAT = @GL_GNULIB_STRNCAT@
+GL_GNULIB_STRNDUP = @GL_GNULIB_STRNDUP@
+GL_GNULIB_STRNLEN = @GL_GNULIB_STRNLEN@
+GL_GNULIB_STRPBRK = @GL_GNULIB_STRPBRK@
+GL_GNULIB_STRPTIME = @GL_GNULIB_STRPTIME@
+GL_GNULIB_STRSEP = @GL_GNULIB_STRSEP@
+GL_GNULIB_STRSIGNAL = @GL_GNULIB_STRSIGNAL@
+GL_GNULIB_STRSTR = @GL_GNULIB_STRSTR@
+GL_GNULIB_STRTOD = @GL_GNULIB_STRTOD@
+GL_GNULIB_STRTOIMAX = @GL_GNULIB_STRTOIMAX@
+GL_GNULIB_STRTOK_R = @GL_GNULIB_STRTOK_R@
+GL_GNULIB_STRTOL = @GL_GNULIB_STRTOL@
+GL_GNULIB_STRTOLD = @GL_GNULIB_STRTOLD@
+GL_GNULIB_STRTOLL = @GL_GNULIB_STRTOLL@
+GL_GNULIB_STRTOUL = @GL_GNULIB_STRTOUL@
+GL_GNULIB_STRTOULL = @GL_GNULIB_STRTOULL@
+GL_GNULIB_STRTOUMAX = @GL_GNULIB_STRTOUMAX@
+GL_GNULIB_STRVERSCMP = @GL_GNULIB_STRVERSCMP@
+GL_GNULIB_SYMLINK = @GL_GNULIB_SYMLINK@
+GL_GNULIB_SYMLINKAT = @GL_GNULIB_SYMLINKAT@
+GL_GNULIB_SYSTEM_POSIX = @GL_GNULIB_SYSTEM_POSIX@
+GL_GNULIB_TIME = @GL_GNULIB_TIME@
+GL_GNULIB_TIMEGM = @GL_GNULIB_TIMEGM@
+GL_GNULIB_TIMESPEC_GET = @GL_GNULIB_TIMESPEC_GET@
+GL_GNULIB_TIMESPEC_GETRES = @GL_GNULIB_TIMESPEC_GETRES@
+GL_GNULIB_TIME_R = @GL_GNULIB_TIME_R@
+GL_GNULIB_TIME_RZ = @GL_GNULIB_TIME_RZ@
+GL_GNULIB_TMPFILE = @GL_GNULIB_TMPFILE@
+GL_GNULIB_TOWCTRANS = @GL_GNULIB_TOWCTRANS@
+GL_GNULIB_TRUNCATE = @GL_GNULIB_TRUNCATE@
+GL_GNULIB_TTYNAME_R = @GL_GNULIB_TTYNAME_R@
+GL_GNULIB_TZSET = @GL_GNULIB_TZSET@
+GL_GNULIB_UNISTD_H_GETOPT = @GL_GNULIB_UNISTD_H_GETOPT@
+GL_GNULIB_UNISTD_H_NONBLOCKING = @GL_GNULIB_UNISTD_H_NONBLOCKING@
+GL_GNULIB_UNISTD_H_SIGPIPE = @GL_GNULIB_UNISTD_H_SIGPIPE@
+GL_GNULIB_UNLINK = @GL_GNULIB_UNLINK@
+GL_GNULIB_UNLINKAT = @GL_GNULIB_UNLINKAT@
+GL_GNULIB_UNLOCKPT = @GL_GNULIB_UNLOCKPT@
+GL_GNULIB_UNSETENV = @GL_GNULIB_UNSETENV@
+GL_GNULIB_USLEEP = @GL_GNULIB_USLEEP@
+GL_GNULIB_UTIMENSAT = @GL_GNULIB_UTIMENSAT@
+GL_GNULIB_VASPRINTF = @GL_GNULIB_VASPRINTF@
+GL_GNULIB_VDPRINTF = @GL_GNULIB_VDPRINTF@
+GL_GNULIB_VFPRINTF = @GL_GNULIB_VFPRINTF@
+GL_GNULIB_VFPRINTF_POSIX = @GL_GNULIB_VFPRINTF_POSIX@
+GL_GNULIB_VFSCANF = @GL_GNULIB_VFSCANF@
+GL_GNULIB_VPRINTF = @GL_GNULIB_VPRINTF@
+GL_GNULIB_VPRINTF_POSIX = @GL_GNULIB_VPRINTF_POSIX@
+GL_GNULIB_VSCANF = @GL_GNULIB_VSCANF@
+GL_GNULIB_VSNPRINTF = @GL_GNULIB_VSNPRINTF@
+GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@
+GL_GNULIB_WCPCPY = @GL_GNULIB_WCPCPY@
+GL_GNULIB_WCPNCPY = @GL_GNULIB_WCPNCPY@
+GL_GNULIB_WCRTOMB = @GL_GNULIB_WCRTOMB@
+GL_GNULIB_WCSCASECMP = @GL_GNULIB_WCSCASECMP@
+GL_GNULIB_WCSCAT = @GL_GNULIB_WCSCAT@
+GL_GNULIB_WCSCHR = @GL_GNULIB_WCSCHR@
+GL_GNULIB_WCSCMP = @GL_GNULIB_WCSCMP@
+GL_GNULIB_WCSCOLL = @GL_GNULIB_WCSCOLL@
+GL_GNULIB_WCSCPY = @GL_GNULIB_WCSCPY@
+GL_GNULIB_WCSCSPN = @GL_GNULIB_WCSCSPN@
+GL_GNULIB_WCSDUP = @GL_GNULIB_WCSDUP@
+GL_GNULIB_WCSFTIME = @GL_GNULIB_WCSFTIME@
+GL_GNULIB_WCSLEN = @GL_GNULIB_WCSLEN@
+GL_GNULIB_WCSNCASECMP = @GL_GNULIB_WCSNCASECMP@
+GL_GNULIB_WCSNCAT = @GL_GNULIB_WCSNCAT@
+GL_GNULIB_WCSNCMP = @GL_GNULIB_WCSNCMP@
+GL_GNULIB_WCSNCPY = @GL_GNULIB_WCSNCPY@
+GL_GNULIB_WCSNLEN = @GL_GNULIB_WCSNLEN@
+GL_GNULIB_WCSNRTOMBS = @GL_GNULIB_WCSNRTOMBS@
+GL_GNULIB_WCSPBRK = @GL_GNULIB_WCSPBRK@
+GL_GNULIB_WCSRCHR = @GL_GNULIB_WCSRCHR@
+GL_GNULIB_WCSRTOMBS = @GL_GNULIB_WCSRTOMBS@
+GL_GNULIB_WCSSPN = @GL_GNULIB_WCSSPN@
+GL_GNULIB_WCSSTR = @GL_GNULIB_WCSSTR@
+GL_GNULIB_WCSTOK = @GL_GNULIB_WCSTOK@
+GL_GNULIB_WCSWIDTH = @GL_GNULIB_WCSWIDTH@
+GL_GNULIB_WCSXFRM = @GL_GNULIB_WCSXFRM@
+GL_GNULIB_WCTOB = @GL_GNULIB_WCTOB@
+GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@
+GL_GNULIB_WCTRANS = @GL_GNULIB_WCTRANS@
+GL_GNULIB_WCTYPE = @GL_GNULIB_WCTYPE@
+GL_GNULIB_WCWIDTH = @GL_GNULIB_WCWIDTH@
+GL_GNULIB_WMEMCHR = @GL_GNULIB_WMEMCHR@
+GL_GNULIB_WMEMCMP = @GL_GNULIB_WMEMCMP@
+GL_GNULIB_WMEMCPY = @GL_GNULIB_WMEMCPY@
+GL_GNULIB_WMEMMOVE = @GL_GNULIB_WMEMMOVE@
+GL_GNULIB_WMEMPCPY = @GL_GNULIB_WMEMPCPY@
+GL_GNULIB_WMEMSET = @GL_GNULIB_WMEMSET@
+GL_GNULIB_WRITE = @GL_GNULIB_WRITE@
+GL_GNULIB__EXIT = @GL_GNULIB__EXIT@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@
+GNULIB_GETTIMEOFDAY = @GNULIB_GETTIMEOFDAY@
+GREP = @GREP@
+HARD_LOCALE_LIB = @HARD_LOCALE_LIB@
+HAVE_ACCEPT4 = @HAVE_ACCEPT4@
+HAVE_ALIGNED_ALLOC = @HAVE_ALIGNED_ALLOC@
+HAVE_ALLOCA_H = @HAVE_ALLOCA_H@
+HAVE_ARPA_INET_H = @HAVE_ARPA_INET_H@
+HAVE_ATOLL = @HAVE_ATOLL@
+HAVE_BTOWC = @HAVE_BTOWC@
+HAVE_C99_STDINT_H = @HAVE_C99_STDINT_H@
+HAVE_CANONICALIZE_FILE_NAME = @HAVE_CANONICALIZE_FILE_NAME@
+HAVE_CHOWN = @HAVE_CHOWN@
+HAVE_COPY_FILE_RANGE = @HAVE_COPY_FILE_RANGE@
+HAVE_CRTDEFS_H = @HAVE_CRTDEFS_H@
+HAVE_DECL_ECVT = @HAVE_DECL_ECVT@
+HAVE_DECL_ENVIRON = @HAVE_DECL_ENVIRON@
+HAVE_DECL_EXECVPE = @HAVE_DECL_EXECVPE@
+HAVE_DECL_FCHDIR = @HAVE_DECL_FCHDIR@
+HAVE_DECL_FCLOSEALL = @HAVE_DECL_FCLOSEALL@
+HAVE_DECL_FCVT = @HAVE_DECL_FCVT@
+HAVE_DECL_FDATASYNC = @HAVE_DECL_FDATASYNC@
+HAVE_DECL_FPURGE = @HAVE_DECL_FPURGE@
+HAVE_DECL_FSEEKO = @HAVE_DECL_FSEEKO@
+HAVE_DECL_FTELLO = @HAVE_DECL_FTELLO@
+HAVE_DECL_GCVT = @HAVE_DECL_GCVT@
+HAVE_DECL_GETDELIM = @HAVE_DECL_GETDELIM@
+HAVE_DECL_GETDOMAINNAME = @HAVE_DECL_GETDOMAINNAME@
+HAVE_DECL_GETLINE = @HAVE_DECL_GETLINE@
+HAVE_DECL_GETLOADAVG = @HAVE_DECL_GETLOADAVG@
+HAVE_DECL_GETLOGIN = @HAVE_DECL_GETLOGIN@
+HAVE_DECL_GETLOGIN_R = @HAVE_DECL_GETLOGIN_R@
+HAVE_DECL_GETPAGESIZE = @HAVE_DECL_GETPAGESIZE@
+HAVE_DECL_GETUSERSHELL = @HAVE_DECL_GETUSERSHELL@
+HAVE_DECL_GETW = @HAVE_DECL_GETW@
+HAVE_DECL_IMAXABS = @HAVE_DECL_IMAXABS@
+HAVE_DECL_IMAXDIV = @HAVE_DECL_IMAXDIV@
+HAVE_DECL_INET_NTOP = @HAVE_DECL_INET_NTOP@
+HAVE_DECL_INET_PTON = @HAVE_DECL_INET_PTON@
+HAVE_DECL_INITSTATE = @HAVE_DECL_INITSTATE@
+HAVE_DECL_LOCALTIME_R = @HAVE_DECL_LOCALTIME_R@
+HAVE_DECL_MEMMEM = @HAVE_DECL_MEMMEM@
+HAVE_DECL_MEMRCHR = @HAVE_DECL_MEMRCHR@
+HAVE_DECL_OBSTACK_PRINTF = @HAVE_DECL_OBSTACK_PRINTF@
+HAVE_DECL_PUTW = @HAVE_DECL_PUTW@
+HAVE_DECL_SETENV = @HAVE_DECL_SETENV@
+HAVE_DECL_SETHOSTNAME = @HAVE_DECL_SETHOSTNAME@
+HAVE_DECL_SETSTATE = @HAVE_DECL_SETSTATE@
+HAVE_DECL_SNPRINTF = @HAVE_DECL_SNPRINTF@
+HAVE_DECL_STRDUP = @HAVE_DECL_STRDUP@
+HAVE_DECL_STRERROR_R = @HAVE_DECL_STRERROR_R@
+HAVE_DECL_STRNDUP = @HAVE_DECL_STRNDUP@
+HAVE_DECL_STRNLEN = @HAVE_DECL_STRNLEN@
+HAVE_DECL_STRSIGNAL = @HAVE_DECL_STRSIGNAL@
+HAVE_DECL_STRTOIMAX = @HAVE_DECL_STRTOIMAX@
+HAVE_DECL_STRTOK_R = @HAVE_DECL_STRTOK_R@
+HAVE_DECL_STRTOUMAX = @HAVE_DECL_STRTOUMAX@
+HAVE_DECL_TRUNCATE = @HAVE_DECL_TRUNCATE@
+HAVE_DECL_TTYNAME_R = @HAVE_DECL_TTYNAME_R@
+HAVE_DECL_UNSETENV = @HAVE_DECL_UNSETENV@
+HAVE_DECL_VSNPRINTF = @HAVE_DECL_VSNPRINTF@
+HAVE_DECL_WCSDUP = @HAVE_DECL_WCSDUP@
+HAVE_DECL_WCTOB = @HAVE_DECL_WCTOB@
+HAVE_DECL_WCWIDTH = @HAVE_DECL_WCWIDTH@
+HAVE_DPRINTF = @HAVE_DPRINTF@
+HAVE_DUP3 = @HAVE_DUP3@
+HAVE_DUPLOCALE = @HAVE_DUPLOCALE@
+HAVE_ERROR = @HAVE_ERROR@
+HAVE_ERROR_AT_LINE = @HAVE_ERROR_AT_LINE@
+HAVE_ERROR_H = @HAVE_ERROR_H@
+HAVE_EUIDACCESS = @HAVE_EUIDACCESS@
+HAVE_EXECVPE = @HAVE_EXECVPE@
+HAVE_EXPLICIT_BZERO = @HAVE_EXPLICIT_BZERO@
+HAVE_FACCESSAT = @HAVE_FACCESSAT@
+HAVE_FCHDIR = @HAVE_FCHDIR@
+HAVE_FCHMODAT = @HAVE_FCHMODAT@
+HAVE_FCHOWNAT = @HAVE_FCHOWNAT@
+HAVE_FCNTL = @HAVE_FCNTL@
+HAVE_FDATASYNC = @HAVE_FDATASYNC@
+HAVE_FEATURES_H = @HAVE_FEATURES_H@
+HAVE_FFSL = @HAVE_FFSL@
+HAVE_FFSLL = @HAVE_FFSLL@
+HAVE_FREELOCALE = @HAVE_FREELOCALE@
+HAVE_FSEEKO = @HAVE_FSEEKO@
+HAVE_FSTATAT = @HAVE_FSTATAT@
+HAVE_FSYNC = @HAVE_FSYNC@
+HAVE_FTELLO = @HAVE_FTELLO@
+HAVE_FTRUNCATE = @HAVE_FTRUNCATE@
+HAVE_FUTIMENS = @HAVE_FUTIMENS@
+HAVE_GETDTABLESIZE = @HAVE_GETDTABLESIZE@
+HAVE_GETENTROPY = @HAVE_GETENTROPY@
+HAVE_GETGROUPS = @HAVE_GETGROUPS@
+HAVE_GETHOSTNAME = @HAVE_GETHOSTNAME@
+HAVE_GETLOGIN = @HAVE_GETLOGIN@
+HAVE_GETOPT_H = @HAVE_GETOPT_H@
+HAVE_GETPAGESIZE = @HAVE_GETPAGESIZE@
+HAVE_GETPASS = @HAVE_GETPASS@
+HAVE_GETPROGNAME = @HAVE_GETPROGNAME@
+HAVE_GETRANDOM = @HAVE_GETRANDOM@
+HAVE_GETSUBOPT = @HAVE_GETSUBOPT@
+HAVE_GETTIMEOFDAY = @HAVE_GETTIMEOFDAY@
+HAVE_GETUMASK = @HAVE_GETUMASK@
+HAVE_GRANTPT = @HAVE_GRANTPT@
+HAVE_GROUP_MEMBER = @HAVE_GROUP_MEMBER@
+HAVE_IMAXABS = @HAVE_IMAXABS@
+HAVE_IMAXDIV = @HAVE_IMAXDIV@
+HAVE_IMAXDIV_T = @HAVE_IMAXDIV_T@
+HAVE_INITSTATE = @HAVE_INITSTATE@
+HAVE_INTTYPES_H = @HAVE_INTTYPES_H@
+HAVE_ISBLANK = @HAVE_ISBLANK@
+HAVE_ISWBLANK = @HAVE_ISWBLANK@
+HAVE_ISWCNTRL = @HAVE_ISWCNTRL@
+HAVE_LANGINFO_ALTMON = @HAVE_LANGINFO_ALTMON@
+HAVE_LANGINFO_CODESET = @HAVE_LANGINFO_CODESET@
+HAVE_LANGINFO_ERA = @HAVE_LANGINFO_ERA@
+HAVE_LANGINFO_H = @HAVE_LANGINFO_H@
+HAVE_LANGINFO_T_FMT_AMPM = @HAVE_LANGINFO_T_FMT_AMPM@
+HAVE_LANGINFO_YESEXPR = @HAVE_LANGINFO_YESEXPR@
+HAVE_LCHMOD = @HAVE_LCHMOD@
+HAVE_LCHOWN = @HAVE_LCHOWN@
+HAVE_LINK = @HAVE_LINK@
+HAVE_LINKAT = @HAVE_LINKAT@
+HAVE_LSTAT = @HAVE_LSTAT@
+HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
+HAVE_MBRLEN = @HAVE_MBRLEN@
+HAVE_MBRTOWC = @HAVE_MBRTOWC@
+HAVE_MBSINIT = @HAVE_MBSINIT@
+HAVE_MBSLEN = @HAVE_MBSLEN@
+HAVE_MBSNRTOWCS = @HAVE_MBSNRTOWCS@
+HAVE_MBSRTOWCS = @HAVE_MBSRTOWCS@
+HAVE_MBTOWC = @HAVE_MBTOWC@
+HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@
+HAVE_MKDIRAT = @HAVE_MKDIRAT@
+HAVE_MKDTEMP = @HAVE_MKDTEMP@
+HAVE_MKFIFO = @HAVE_MKFIFO@
+HAVE_MKFIFOAT = @HAVE_MKFIFOAT@
+HAVE_MKNOD = @HAVE_MKNOD@
+HAVE_MKNODAT = @HAVE_MKNODAT@
+HAVE_MKOSTEMP = @HAVE_MKOSTEMP@
+HAVE_MKOSTEMPS = @HAVE_MKOSTEMPS@
+HAVE_MKSTEMP = @HAVE_MKSTEMP@
+HAVE_MKSTEMPS = @HAVE_MKSTEMPS@
+HAVE_MSVC_INVALID_PARAMETER_HANDLER = @HAVE_MSVC_INVALID_PARAMETER_HANDLER@
+HAVE_NANOSLEEP = @HAVE_NANOSLEEP@
+HAVE_NETINET_IN_H = @HAVE_NETINET_IN_H@
+HAVE_NEWLOCALE = @HAVE_NEWLOCALE@
+HAVE_NL_LANGINFO = @HAVE_NL_LANGINFO@
+HAVE_OPENAT = @HAVE_OPENAT@
+HAVE_OS_H = @HAVE_OS_H@
+HAVE_PCLOSE = @HAVE_PCLOSE@
+HAVE_PIPE = @HAVE_PIPE@
+HAVE_PIPE2 = @HAVE_PIPE2@
+HAVE_POPEN = @HAVE_POPEN@
+HAVE_POSIX_MEMALIGN = @HAVE_POSIX_MEMALIGN@
+HAVE_POSIX_OPENPT = @HAVE_POSIX_OPENPT@
+HAVE_POSIX_SIGNALBLOCKING = @HAVE_POSIX_SIGNALBLOCKING@
+HAVE_PREAD = @HAVE_PREAD@
+HAVE_PSELECT = @HAVE_PSELECT@
+HAVE_PTHREAD_ATTR_DESTROY = @HAVE_PTHREAD_ATTR_DESTROY@
+HAVE_PTHREAD_ATTR_GETDETACHSTATE = @HAVE_PTHREAD_ATTR_GETDETACHSTATE@
+HAVE_PTHREAD_ATTR_INIT = @HAVE_PTHREAD_ATTR_INIT@
+HAVE_PTHREAD_ATTR_SETDETACHSTATE = @HAVE_PTHREAD_ATTR_SETDETACHSTATE@
+HAVE_PTHREAD_CONDATTR_DESTROY = @HAVE_PTHREAD_CONDATTR_DESTROY@
+HAVE_PTHREAD_CONDATTR_INIT = @HAVE_PTHREAD_CONDATTR_INIT@
+HAVE_PTHREAD_COND_BROADCAST = @HAVE_PTHREAD_COND_BROADCAST@
+HAVE_PTHREAD_COND_DESTROY = @HAVE_PTHREAD_COND_DESTROY@
+HAVE_PTHREAD_COND_INIT = @HAVE_PTHREAD_COND_INIT@
+HAVE_PTHREAD_COND_SIGNAL = @HAVE_PTHREAD_COND_SIGNAL@
+HAVE_PTHREAD_COND_TIMEDWAIT = @HAVE_PTHREAD_COND_TIMEDWAIT@
+HAVE_PTHREAD_COND_WAIT = @HAVE_PTHREAD_COND_WAIT@
+HAVE_PTHREAD_CREATE = @HAVE_PTHREAD_CREATE@
+HAVE_PTHREAD_CREATE_DETACHED = @HAVE_PTHREAD_CREATE_DETACHED@
+HAVE_PTHREAD_DETACH = @HAVE_PTHREAD_DETACH@
+HAVE_PTHREAD_EQUAL = @HAVE_PTHREAD_EQUAL@
+HAVE_PTHREAD_EXIT = @HAVE_PTHREAD_EXIT@
+HAVE_PTHREAD_GETSPECIFIC = @HAVE_PTHREAD_GETSPECIFIC@
+HAVE_PTHREAD_H = @HAVE_PTHREAD_H@
+HAVE_PTHREAD_JOIN = @HAVE_PTHREAD_JOIN@
+HAVE_PTHREAD_KEY_CREATE = @HAVE_PTHREAD_KEY_CREATE@
+HAVE_PTHREAD_KEY_DELETE = @HAVE_PTHREAD_KEY_DELETE@
+HAVE_PTHREAD_MUTEXATTR_DESTROY = @HAVE_PTHREAD_MUTEXATTR_DESTROY@
+HAVE_PTHREAD_MUTEXATTR_GETROBUST = @HAVE_PTHREAD_MUTEXATTR_GETROBUST@
+HAVE_PTHREAD_MUTEXATTR_GETTYPE = @HAVE_PTHREAD_MUTEXATTR_GETTYPE@
+HAVE_PTHREAD_MUTEXATTR_INIT = @HAVE_PTHREAD_MUTEXATTR_INIT@
+HAVE_PTHREAD_MUTEXATTR_SETROBUST = @HAVE_PTHREAD_MUTEXATTR_SETROBUST@
+HAVE_PTHREAD_MUTEXATTR_SETTYPE = @HAVE_PTHREAD_MUTEXATTR_SETTYPE@
+HAVE_PTHREAD_MUTEX_DESTROY = @HAVE_PTHREAD_MUTEX_DESTROY@
+HAVE_PTHREAD_MUTEX_INIT = @HAVE_PTHREAD_MUTEX_INIT@
+HAVE_PTHREAD_MUTEX_LOCK = @HAVE_PTHREAD_MUTEX_LOCK@
+HAVE_PTHREAD_MUTEX_RECURSIVE = @HAVE_PTHREAD_MUTEX_RECURSIVE@
+HAVE_PTHREAD_MUTEX_ROBUST = @HAVE_PTHREAD_MUTEX_ROBUST@
+HAVE_PTHREAD_MUTEX_TIMEDLOCK = @HAVE_PTHREAD_MUTEX_TIMEDLOCK@
+HAVE_PTHREAD_MUTEX_TRYLOCK = @HAVE_PTHREAD_MUTEX_TRYLOCK@
+HAVE_PTHREAD_MUTEX_UNLOCK = @HAVE_PTHREAD_MUTEX_UNLOCK@
+HAVE_PTHREAD_ONCE = @HAVE_PTHREAD_ONCE@
+HAVE_PTHREAD_PROCESS_SHARED = @HAVE_PTHREAD_PROCESS_SHARED@
+HAVE_PTHREAD_RWLOCKATTR_DESTROY = @HAVE_PTHREAD_RWLOCKATTR_DESTROY@
+HAVE_PTHREAD_RWLOCKATTR_INIT = @HAVE_PTHREAD_RWLOCKATTR_INIT@
+HAVE_PTHREAD_RWLOCK_DESTROY = @HAVE_PTHREAD_RWLOCK_DESTROY@
+HAVE_PTHREAD_RWLOCK_INIT = @HAVE_PTHREAD_RWLOCK_INIT@
+HAVE_PTHREAD_RWLOCK_RDLOCK = @HAVE_PTHREAD_RWLOCK_RDLOCK@
+HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK = @HAVE_PTHREAD_RWLOCK_TIMEDRDLOCK@
+HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK = @HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK@
+HAVE_PTHREAD_RWLOCK_TRYRDLOCK = @HAVE_PTHREAD_RWLOCK_TRYRDLOCK@
+HAVE_PTHREAD_RWLOCK_TRYWRLOCK = @HAVE_PTHREAD_RWLOCK_TRYWRLOCK@
+HAVE_PTHREAD_RWLOCK_UNLOCK = @HAVE_PTHREAD_RWLOCK_UNLOCK@
+HAVE_PTHREAD_RWLOCK_WRLOCK = @HAVE_PTHREAD_RWLOCK_WRLOCK@
+HAVE_PTHREAD_SELF = @HAVE_PTHREAD_SELF@
+HAVE_PTHREAD_SETSPECIFIC = @HAVE_PTHREAD_SETSPECIFIC@
+HAVE_PTHREAD_SIGMASK = @HAVE_PTHREAD_SIGMASK@
+HAVE_PTHREAD_SPINLOCK_T = @HAVE_PTHREAD_SPINLOCK_T@
+HAVE_PTHREAD_SPIN_DESTROY = @HAVE_PTHREAD_SPIN_DESTROY@
+HAVE_PTHREAD_SPIN_INIT = @HAVE_PTHREAD_SPIN_INIT@
+HAVE_PTHREAD_SPIN_LOCK = @HAVE_PTHREAD_SPIN_LOCK@
+HAVE_PTHREAD_SPIN_TRYLOCK = @HAVE_PTHREAD_SPIN_TRYLOCK@
+HAVE_PTHREAD_SPIN_UNLOCK = @HAVE_PTHREAD_SPIN_UNLOCK@
+HAVE_PTHREAD_T = @HAVE_PTHREAD_T@
+HAVE_PTSNAME = @HAVE_PTSNAME@
+HAVE_PTSNAME_R = @HAVE_PTSNAME_R@
+HAVE_PWRITE = @HAVE_PWRITE@
+HAVE_QSORT_R = @HAVE_QSORT_R@
+HAVE_RAISE = @HAVE_RAISE@
+HAVE_RANDOM = @HAVE_RANDOM@
+HAVE_RANDOM_H = @HAVE_RANDOM_H@
+HAVE_RANDOM_R = @HAVE_RANDOM_R@
+HAVE_RAWMEMCHR = @HAVE_RAWMEMCHR@
+HAVE_READLINK = @HAVE_READLINK@
+HAVE_READLINKAT = @HAVE_READLINKAT@
+HAVE_REALLOCARRAY = @HAVE_REALLOCARRAY@
+HAVE_REALPATH = @HAVE_REALPATH@
+HAVE_RENAMEAT = @HAVE_RENAMEAT@
+HAVE_RPMATCH = @HAVE_RPMATCH@
+HAVE_SA_FAMILY_T = @HAVE_SA_FAMILY_T@
+HAVE_SCHED_H = @HAVE_SCHED_H@
+HAVE_SCHED_YIELD = @HAVE_SCHED_YIELD@
+HAVE_SECURE_GETENV = @HAVE_SECURE_GETENV@
+HAVE_SETENV = @HAVE_SETENV@
+HAVE_SETHOSTNAME = @HAVE_SETHOSTNAME@
+HAVE_SETSTATE = @HAVE_SETSTATE@
+HAVE_SIGABBREV_NP = @HAVE_SIGABBREV_NP@
+HAVE_SIGACTION = @HAVE_SIGACTION@
+HAVE_SIGDESCR_NP = @HAVE_SIGDESCR_NP@
+HAVE_SIGHANDLER_T = @HAVE_SIGHANDLER_T@
+HAVE_SIGINFO_T = @HAVE_SIGINFO_T@
+HAVE_SIGNED_SIG_ATOMIC_T = @HAVE_SIGNED_SIG_ATOMIC_T@
+HAVE_SIGNED_WCHAR_T = @HAVE_SIGNED_WCHAR_T@
+HAVE_SIGNED_WINT_T = @HAVE_SIGNED_WINT_T@
+HAVE_SIGSET_T = @HAVE_SIGSET_T@
+HAVE_SLEEP = @HAVE_SLEEP@
+HAVE_STDINT_H = @HAVE_STDINT_H@
+HAVE_STPCPY = @HAVE_STPCPY@
+HAVE_STPNCPY = @HAVE_STPNCPY@
+HAVE_STRCASESTR = @HAVE_STRCASESTR@
+HAVE_STRCHRNUL = @HAVE_STRCHRNUL@
+HAVE_STRERRORNAME_NP = @HAVE_STRERRORNAME_NP@
+HAVE_STRPBRK = @HAVE_STRPBRK@
+HAVE_STRPTIME = @HAVE_STRPTIME@
+HAVE_STRSEP = @HAVE_STRSEP@
+HAVE_STRTOD = @HAVE_STRTOD@
+HAVE_STRTOL = @HAVE_STRTOL@
+HAVE_STRTOLD = @HAVE_STRTOLD@
+HAVE_STRTOLL = @HAVE_STRTOLL@
+HAVE_STRTOUL = @HAVE_STRTOUL@
+HAVE_STRTOULL = @HAVE_STRTOULL@
+HAVE_STRUCT_RANDOM_DATA = @HAVE_STRUCT_RANDOM_DATA@
+HAVE_STRUCT_SCHED_PARAM = @HAVE_STRUCT_SCHED_PARAM@
+HAVE_STRUCT_SIGACTION_SA_SIGACTION = @HAVE_STRUCT_SIGACTION_SA_SIGACTION@
+HAVE_STRUCT_SOCKADDR_STORAGE = @HAVE_STRUCT_SOCKADDR_STORAGE@
+HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY = @HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY@
+HAVE_STRUCT_TIMEVAL = @HAVE_STRUCT_TIMEVAL@
+HAVE_STRVERSCMP = @HAVE_STRVERSCMP@
+HAVE_SYMLINK = @HAVE_SYMLINK@
+HAVE_SYMLINKAT = @HAVE_SYMLINKAT@
+HAVE_SYS_BITYPES_H = @HAVE_SYS_BITYPES_H@
+HAVE_SYS_CDEFS_H = @HAVE_SYS_CDEFS_H@
+HAVE_SYS_INTTYPES_H = @HAVE_SYS_INTTYPES_H@
+HAVE_SYS_IOCTL_H = @HAVE_SYS_IOCTL_H@
+HAVE_SYS_LOADAVG_H = @HAVE_SYS_LOADAVG_H@
+HAVE_SYS_PARAM_H = @HAVE_SYS_PARAM_H@
+HAVE_SYS_RANDOM_H = @HAVE_SYS_RANDOM_H@
+HAVE_SYS_SELECT_H = @HAVE_SYS_SELECT_H@
+HAVE_SYS_SOCKET_H = @HAVE_SYS_SOCKET_H@
+HAVE_SYS_TIME_H = @HAVE_SYS_TIME_H@
+HAVE_SYS_TYPES_H = @HAVE_SYS_TYPES_H@
+HAVE_SYS_UIO_H = @HAVE_SYS_UIO_H@
+HAVE_TIMEGM = @HAVE_TIMEGM@
+HAVE_TIMESPEC_GET = @HAVE_TIMESPEC_GET@
+HAVE_TIMESPEC_GETRES = @HAVE_TIMESPEC_GETRES@
+HAVE_TIMEZONE_T = @HAVE_TIMEZONE_T@
+HAVE_TYPE_VOLATILE_SIG_ATOMIC_T = @HAVE_TYPE_VOLATILE_SIG_ATOMIC_T@
+HAVE_UNISTD_H = @HAVE_UNISTD_H@
+HAVE_UNLINKAT = @HAVE_UNLINKAT@
+HAVE_UNLOCKPT = @HAVE_UNLOCKPT@
+HAVE_USLEEP = @HAVE_USLEEP@
+HAVE_UTIMENSAT = @HAVE_UTIMENSAT@
+HAVE_VASPRINTF = @HAVE_VASPRINTF@
+HAVE_VDPRINTF = @HAVE_VDPRINTF@
+HAVE_VISIBILITY = @HAVE_VISIBILITY@
+HAVE_WCHAR_H = @HAVE_WCHAR_H@
+HAVE_WCHAR_T = @HAVE_WCHAR_T@
+HAVE_WCPCPY = @HAVE_WCPCPY@
+HAVE_WCPNCPY = @HAVE_WCPNCPY@
+HAVE_WCRTOMB = @HAVE_WCRTOMB@
+HAVE_WCSCASECMP = @HAVE_WCSCASECMP@
+HAVE_WCSCAT = @HAVE_WCSCAT@
+HAVE_WCSCHR = @HAVE_WCSCHR@
+HAVE_WCSCMP = @HAVE_WCSCMP@
+HAVE_WCSCOLL = @HAVE_WCSCOLL@
+HAVE_WCSCPY = @HAVE_WCSCPY@
+HAVE_WCSCSPN = @HAVE_WCSCSPN@
+HAVE_WCSDUP = @HAVE_WCSDUP@
+HAVE_WCSFTIME = @HAVE_WCSFTIME@
+HAVE_WCSLEN = @HAVE_WCSLEN@
+HAVE_WCSNCASECMP = @HAVE_WCSNCASECMP@
+HAVE_WCSNCAT = @HAVE_WCSNCAT@
+HAVE_WCSNCMP = @HAVE_WCSNCMP@
+HAVE_WCSNCPY = @HAVE_WCSNCPY@
+HAVE_WCSNLEN = @HAVE_WCSNLEN@
+HAVE_WCSNRTOMBS = @HAVE_WCSNRTOMBS@
+HAVE_WCSPBRK = @HAVE_WCSPBRK@
+HAVE_WCSRCHR = @HAVE_WCSRCHR@
+HAVE_WCSRTOMBS = @HAVE_WCSRTOMBS@
+HAVE_WCSSPN = @HAVE_WCSSPN@
+HAVE_WCSSTR = @HAVE_WCSSTR@
+HAVE_WCSTOK = @HAVE_WCSTOK@
+HAVE_WCSWIDTH = @HAVE_WCSWIDTH@
+HAVE_WCSXFRM = @HAVE_WCSXFRM@
+HAVE_WCTRANS_T = @HAVE_WCTRANS_T@
+HAVE_WCTYPE_H = @HAVE_WCTYPE_H@
+HAVE_WCTYPE_T = @HAVE_WCTYPE_T@
+HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
+HAVE_WINT_T = @HAVE_WINT_T@
+HAVE_WMEMCHR = @HAVE_WMEMCHR@
+HAVE_WMEMCMP = @HAVE_WMEMCMP@
+HAVE_WMEMCPY = @HAVE_WMEMCPY@
+HAVE_WMEMMOVE = @HAVE_WMEMMOVE@
+HAVE_WMEMPCPY = @HAVE_WMEMPCPY@
+HAVE_WMEMSET = @HAVE_WMEMSET@
+HAVE_WS2TCPIP_H = @HAVE_WS2TCPIP_H@
+HAVE_XLOCALE_H = @HAVE_XLOCALE_H@
+HAVE__EXIT = @HAVE__EXIT@
+IGNORE_UNUSED_LIBRARIES_CFLAGS = @IGNORE_UNUSED_LIBRARIES_CFLAGS@
+INCLUDE_NEXT = @INCLUDE_NEXT@
+INCLUDE_NEXT_AS_FIRST_DIRECTIVE = @INCLUDE_NEXT_AS_FIRST_DIRECTIVE@
+INET_PTON_LIB = @INET_PTON_LIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
+INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
+INTLINCS = @INTLINCS@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMULTITHREAD = @LIBMULTITHREAD@
+LIBOBJS = @LIBOBJS@
+LIBPMULTITHREAD = @LIBPMULTITHREAD@
+LIBPTHREAD = @LIBPTHREAD@
+LIBS = @LIBS@
+LIBSOCKET = @LIBSOCKET@
+LIBSTDTHREAD = @LIBSTDTHREAD@
+LIBTESTS_LIBDEPS = @LIBTESTS_LIBDEPS@
+LIBTHREAD = @LIBTHREAD@
+LIBTOOL = @LIBTOOL@
+LIB_BLKID = @LIB_BLKID@
+LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@
+LIB_GETRANDOM = @LIB_GETRANDOM@
+LIB_HARD_LOCALE = @LIB_HARD_LOCALE@
+LIB_MBRTOWC = @LIB_MBRTOWC@
+LIB_NANOSLEEP = @LIB_NANOSLEEP@
+LIB_NL_LANGINFO = @LIB_NL_LANGINFO@
+LIB_PTHREAD = @LIB_PTHREAD@
+LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
+LIB_SCHED_YIELD = @LIB_SCHED_YIELD@
+LIB_SELECT = @LIB_SELECT@
+LIB_SEMAPHORE = @LIB_SEMAPHORE@
+LIB_SETLOCALE = @LIB_SETLOCALE@
+LIB_SETLOCALE_NULL = @LIB_SETLOCALE_NULL@
+LIMITS_H = @LIMITS_H@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOCALCHARSET_TESTS_ENVIRONMENT = @LOCALCHARSET_TESTS_ENVIRONMENT@
+LOCALENAME_ENHANCE_LOCALE_FUNCS = @LOCALENAME_ENHANCE_LOCALE_FUNCS@
+LOCALE_FR = @LOCALE_FR@
+LOCALE_FR_UTF8 = @LOCALE_FR_UTF8@
+LOCALE_JA = @LOCALE_JA@
+LOCALE_TR_UTF8 = @LOCALE_TR_UTF8@
+LOCALE_ZH_CN = @LOCALE_ZH_CN@
+LTALLOCA = @LTALLOCA@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBMULTITHREAD = @LTLIBMULTITHREAD@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBTHREAD = @LTLIBTHREAD@
+LT_AGE = @LT_AGE@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MBRTOWC_LIB = @MBRTOWC_LIB@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+NANOSLEEP_LIB = @NANOSLEEP_LIB@
+NETINET_IN_H = @NETINET_IN_H@
+NEXT_ARPA_INET_H = @NEXT_ARPA_INET_H@
+NEXT_ASSERT_H = @NEXT_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H = @NEXT_AS_FIRST_DIRECTIVE_ARPA_INET_H@
+NEXT_AS_FIRST_DIRECTIVE_ASSERT_H = @NEXT_AS_FIRST_DIRECTIVE_ASSERT_H@
+NEXT_AS_FIRST_DIRECTIVE_CTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_CTYPE_H@
+NEXT_AS_FIRST_DIRECTIVE_ERRNO_H = @NEXT_AS_FIRST_DIRECTIVE_ERRNO_H@
+NEXT_AS_FIRST_DIRECTIVE_ERROR_H = @NEXT_AS_FIRST_DIRECTIVE_ERROR_H@
+NEXT_AS_FIRST_DIRECTIVE_FCNTL_H = @NEXT_AS_FIRST_DIRECTIVE_FCNTL_H@
+NEXT_AS_FIRST_DIRECTIVE_GETOPT_H = @NEXT_AS_FIRST_DIRECTIVE_GETOPT_H@
+NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H = @NEXT_AS_FIRST_DIRECTIVE_INTTYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H = @NEXT_AS_FIRST_DIRECTIVE_LANGINFO_H@
+NEXT_AS_FIRST_DIRECTIVE_LIMITS_H = @NEXT_AS_FIRST_DIRECTIVE_LIMITS_H@
+NEXT_AS_FIRST_DIRECTIVE_LOCALE_H = @NEXT_AS_FIRST_DIRECTIVE_LOCALE_H@
+NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H = @NEXT_AS_FIRST_DIRECTIVE_NETINET_IN_H@
+NEXT_AS_FIRST_DIRECTIVE_PTHREAD_H = @NEXT_AS_FIRST_DIRECTIVE_PTHREAD_H@
+NEXT_AS_FIRST_DIRECTIVE_SCHED_H = @NEXT_AS_FIRST_DIRECTIVE_SCHED_H@
+NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H = @NEXT_AS_FIRST_DIRECTIVE_SIGNAL_H@
+NEXT_AS_FIRST_DIRECTIVE_STDARG_H = @NEXT_AS_FIRST_DIRECTIVE_STDARG_H@
+NEXT_AS_FIRST_DIRECTIVE_STDDEF_H = @NEXT_AS_FIRST_DIRECTIVE_STDDEF_H@
+NEXT_AS_FIRST_DIRECTIVE_STDINT_H = @NEXT_AS_FIRST_DIRECTIVE_STDINT_H@
+NEXT_AS_FIRST_DIRECTIVE_STDIO_H = @NEXT_AS_FIRST_DIRECTIVE_STDIO_H@
+NEXT_AS_FIRST_DIRECTIVE_STDLIB_H = @NEXT_AS_FIRST_DIRECTIVE_STDLIB_H@
+NEXT_AS_FIRST_DIRECTIVE_STRING_H = @NEXT_AS_FIRST_DIRECTIVE_STRING_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_IOCTL_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_RANDOM_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SELECT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_SOCKET_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_STAT_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_TYPES_H@
+NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H = @NEXT_AS_FIRST_DIRECTIVE_SYS_UIO_H@
+NEXT_AS_FIRST_DIRECTIVE_TIME_H = @NEXT_AS_FIRST_DIRECTIVE_TIME_H@
+NEXT_AS_FIRST_DIRECTIVE_UNISTD_H = @NEXT_AS_FIRST_DIRECTIVE_UNISTD_H@
+NEXT_AS_FIRST_DIRECTIVE_WCHAR_H = @NEXT_AS_FIRST_DIRECTIVE_WCHAR_H@
+NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H = @NEXT_AS_FIRST_DIRECTIVE_WCTYPE_H@
+NEXT_CTYPE_H = @NEXT_CTYPE_H@
+NEXT_ERRNO_H = @NEXT_ERRNO_H@
+NEXT_ERROR_H = @NEXT_ERROR_H@
+NEXT_FCNTL_H = @NEXT_FCNTL_H@
+NEXT_GETOPT_H = @NEXT_GETOPT_H@
+NEXT_INTTYPES_H = @NEXT_INTTYPES_H@
+NEXT_LANGINFO_H = @NEXT_LANGINFO_H@
+NEXT_LIMITS_H = @NEXT_LIMITS_H@
+NEXT_LOCALE_H = @NEXT_LOCALE_H@
+NEXT_NETINET_IN_H = @NEXT_NETINET_IN_H@
+NEXT_PTHREAD_H = @NEXT_PTHREAD_H@
+NEXT_SCHED_H = @NEXT_SCHED_H@
+NEXT_SIGNAL_H = @NEXT_SIGNAL_H@
+NEXT_STDARG_H = @NEXT_STDARG_H@
+NEXT_STDDEF_H = @NEXT_STDDEF_H@
+NEXT_STDINT_H = @NEXT_STDINT_H@
+NEXT_STDIO_H = @NEXT_STDIO_H@
+NEXT_STDLIB_H = @NEXT_STDLIB_H@
+NEXT_STRING_H = @NEXT_STRING_H@
+NEXT_SYS_IOCTL_H = @NEXT_SYS_IOCTL_H@
+NEXT_SYS_RANDOM_H = @NEXT_SYS_RANDOM_H@
+NEXT_SYS_SELECT_H = @NEXT_SYS_SELECT_H@
+NEXT_SYS_SOCKET_H = @NEXT_SYS_SOCKET_H@
+NEXT_SYS_STAT_H = @NEXT_SYS_STAT_H@
+NEXT_SYS_TIME_H = @NEXT_SYS_TIME_H@
+NEXT_SYS_TYPES_H = @NEXT_SYS_TYPES_H@
+NEXT_SYS_UIO_H = @NEXT_SYS_UIO_H@
+NEXT_TIME_H = @NEXT_TIME_H@
+NEXT_UNISTD_H = @NEXT_UNISTD_H@
+NEXT_WCHAR_H = @NEXT_WCHAR_H@
+NEXT_WCTYPE_H = @NEXT_WCTYPE_H@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OS = @OS@
+OS_LIBS = @OS_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PARTEDLDFLAGS = @PARTEDLDFLAGS@
+PARTED_LIBS = @PARTED_LIBS@
+PARTED_USABLE_TEST_DIR = @PARTED_USABLE_TEST_DIR@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POSUB = @POSUB@
+PRAGMA_COLUMNS = @PRAGMA_COLUMNS@
+PRAGMA_SYSTEM_HEADER = @PRAGMA_SYSTEM_HEADER@
+PRIPTR_PREFIX = @PRIPTR_PREFIX@
+PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
+PTHREAD_SIGMASK_LIB = @PTHREAD_SIGMASK_LIB@
+PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
+RANLIB = @RANLIB@
+REPLACE_ACCESS = @REPLACE_ACCESS@
+REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@
+REPLACE_BTOWC = @REPLACE_BTOWC@
+REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@
+REPLACE_CALLOC_FOR_CALLOC_POSIX = @REPLACE_CALLOC_FOR_CALLOC_POSIX@
+REPLACE_CANONICALIZE_FILE_NAME = @REPLACE_CANONICALIZE_FILE_NAME@
+REPLACE_CHMOD = @REPLACE_CHMOD@
+REPLACE_CHOWN = @REPLACE_CHOWN@
+REPLACE_CLOSE = @REPLACE_CLOSE@
+REPLACE_COPY_FILE_RANGE = @REPLACE_COPY_FILE_RANGE@
+REPLACE_CREAT = @REPLACE_CREAT@
+REPLACE_CTIME = @REPLACE_CTIME@
+REPLACE_DPRINTF = @REPLACE_DPRINTF@
+REPLACE_DUP = @REPLACE_DUP@
+REPLACE_DUP2 = @REPLACE_DUP2@
+REPLACE_DUP3 = @REPLACE_DUP3@
+REPLACE_DUPLOCALE = @REPLACE_DUPLOCALE@
+REPLACE_ERROR = @REPLACE_ERROR@
+REPLACE_ERROR_AT_LINE = @REPLACE_ERROR_AT_LINE@
+REPLACE_EXECL = @REPLACE_EXECL@
+REPLACE_EXECLE = @REPLACE_EXECLE@
+REPLACE_EXECLP = @REPLACE_EXECLP@
+REPLACE_EXECV = @REPLACE_EXECV@
+REPLACE_EXECVE = @REPLACE_EXECVE@
+REPLACE_EXECVP = @REPLACE_EXECVP@
+REPLACE_EXECVPE = @REPLACE_EXECVPE@
+REPLACE_FACCESSAT = @REPLACE_FACCESSAT@
+REPLACE_FCHMODAT = @REPLACE_FCHMODAT@
+REPLACE_FCHOWNAT = @REPLACE_FCHOWNAT@
+REPLACE_FCLOSE = @REPLACE_FCLOSE@
+REPLACE_FCNTL = @REPLACE_FCNTL@
+REPLACE_FDATASYNC = @REPLACE_FDATASYNC@
+REPLACE_FDOPEN = @REPLACE_FDOPEN@
+REPLACE_FFLUSH = @REPLACE_FFLUSH@
+REPLACE_FFSLL = @REPLACE_FFSLL@
+REPLACE_FOPEN = @REPLACE_FOPEN@
+REPLACE_FOPEN_FOR_FOPEN_GNU = @REPLACE_FOPEN_FOR_FOPEN_GNU@
+REPLACE_FPRINTF = @REPLACE_FPRINTF@
+REPLACE_FPURGE = @REPLACE_FPURGE@
+REPLACE_FREE = @REPLACE_FREE@
+REPLACE_FREELOCALE = @REPLACE_FREELOCALE@
+REPLACE_FREOPEN = @REPLACE_FREOPEN@
+REPLACE_FSEEK = @REPLACE_FSEEK@
+REPLACE_FSEEKO = @REPLACE_FSEEKO@
+REPLACE_FSTAT = @REPLACE_FSTAT@
+REPLACE_FSTATAT = @REPLACE_FSTATAT@
+REPLACE_FTELL = @REPLACE_FTELL@
+REPLACE_FTELLO = @REPLACE_FTELLO@
+REPLACE_FTRUNCATE = @REPLACE_FTRUNCATE@
+REPLACE_FUTIMENS = @REPLACE_FUTIMENS@
+REPLACE_GETCWD = @REPLACE_GETCWD@
+REPLACE_GETDELIM = @REPLACE_GETDELIM@
+REPLACE_GETDOMAINNAME = @REPLACE_GETDOMAINNAME@
+REPLACE_GETDTABLESIZE = @REPLACE_GETDTABLESIZE@
+REPLACE_GETENTROPY = @REPLACE_GETENTROPY@
+REPLACE_GETGROUPS = @REPLACE_GETGROUPS@
+REPLACE_GETLINE = @REPLACE_GETLINE@
+REPLACE_GETLOADAVG = @REPLACE_GETLOADAVG@
+REPLACE_GETLOGIN_R = @REPLACE_GETLOGIN_R@
+REPLACE_GETPAGESIZE = @REPLACE_GETPAGESIZE@
+REPLACE_GETPASS = @REPLACE_GETPASS@
+REPLACE_GETPASS_FOR_GETPASS_GNU = @REPLACE_GETPASS_FOR_GETPASS_GNU@
+REPLACE_GETPROGNAME = @REPLACE_GETPROGNAME@
+REPLACE_GETRANDOM = @REPLACE_GETRANDOM@
+REPLACE_GETSUBOPT = @REPLACE_GETSUBOPT@
+REPLACE_GETTIMEOFDAY = @REPLACE_GETTIMEOFDAY@
+REPLACE_GMTIME = @REPLACE_GMTIME@
+REPLACE_IMAXABS = @REPLACE_IMAXABS@
+REPLACE_IMAXDIV = @REPLACE_IMAXDIV@
+REPLACE_INET_NTOP = @REPLACE_INET_NTOP@
+REPLACE_INET_PTON = @REPLACE_INET_PTON@
+REPLACE_INITSTATE = @REPLACE_INITSTATE@
+REPLACE_IOCTL = @REPLACE_IOCTL@
+REPLACE_ISATTY = @REPLACE_ISATTY@
+REPLACE_ISWBLANK = @REPLACE_ISWBLANK@
+REPLACE_ISWCNTRL = @REPLACE_ISWCNTRL@
+REPLACE_ISWDIGIT = @REPLACE_ISWDIGIT@
+REPLACE_ISWXDIGIT = @REPLACE_ISWXDIGIT@
+REPLACE_LCHOWN = @REPLACE_LCHOWN@
+REPLACE_LINK = @REPLACE_LINK@
+REPLACE_LINKAT = @REPLACE_LINKAT@
+REPLACE_LOCALECONV = @REPLACE_LOCALECONV@
+REPLACE_LOCALTIME = @REPLACE_LOCALTIME@
+REPLACE_LOCALTIME_R = @REPLACE_LOCALTIME_R@
+REPLACE_LSEEK = @REPLACE_LSEEK@
+REPLACE_LSTAT = @REPLACE_LSTAT@
+REPLACE_MALLOC_FOR_MALLOC_GNU = @REPLACE_MALLOC_FOR_MALLOC_GNU@
+REPLACE_MALLOC_FOR_MALLOC_POSIX = @REPLACE_MALLOC_FOR_MALLOC_POSIX@
+REPLACE_MBRLEN = @REPLACE_MBRLEN@
+REPLACE_MBRTOWC = @REPLACE_MBRTOWC@
+REPLACE_MBSINIT = @REPLACE_MBSINIT@
+REPLACE_MBSNRTOWCS = @REPLACE_MBSNRTOWCS@
+REPLACE_MBSRTOWCS = @REPLACE_MBSRTOWCS@
+REPLACE_MBSTATE_T = @REPLACE_MBSTATE_T@
+REPLACE_MBTOWC = @REPLACE_MBTOWC@
+REPLACE_MEMCHR = @REPLACE_MEMCHR@
+REPLACE_MEMMEM = @REPLACE_MEMMEM@
+REPLACE_MEMPCPY = @REPLACE_MEMPCPY@
+REPLACE_MKDIR = @REPLACE_MKDIR@
+REPLACE_MKFIFO = @REPLACE_MKFIFO@
+REPLACE_MKFIFOAT = @REPLACE_MKFIFOAT@
+REPLACE_MKNOD = @REPLACE_MKNOD@
+REPLACE_MKNODAT = @REPLACE_MKNODAT@
+REPLACE_MKOSTEMP = @REPLACE_MKOSTEMP@
+REPLACE_MKOSTEMPS = @REPLACE_MKOSTEMPS@
+REPLACE_MKSTEMP = @REPLACE_MKSTEMP@
+REPLACE_MKTIME = @REPLACE_MKTIME@
+REPLACE_NANOSLEEP = @REPLACE_NANOSLEEP@
+REPLACE_NEWLOCALE = @REPLACE_NEWLOCALE@
+REPLACE_NL_LANGINFO = @REPLACE_NL_LANGINFO@
+REPLACE_NULL = @REPLACE_NULL@
+REPLACE_OBSTACK_PRINTF = @REPLACE_OBSTACK_PRINTF@
+REPLACE_OPEN = @REPLACE_OPEN@
+REPLACE_OPENAT = @REPLACE_OPENAT@
+REPLACE_PERROR = @REPLACE_PERROR@
+REPLACE_PIPE2 = @REPLACE_PIPE2@
+REPLACE_POPEN = @REPLACE_POPEN@
+REPLACE_POSIX_MEMALIGN = @REPLACE_POSIX_MEMALIGN@
+REPLACE_POSIX_OPENPT = @REPLACE_POSIX_OPENPT@
+REPLACE_PREAD = @REPLACE_PREAD@
+REPLACE_PRINTF = @REPLACE_PRINTF@
+REPLACE_PSELECT = @REPLACE_PSELECT@
+REPLACE_PTHREAD_ATTR_DESTROY = @REPLACE_PTHREAD_ATTR_DESTROY@
+REPLACE_PTHREAD_ATTR_GETDETACHSTATE = @REPLACE_PTHREAD_ATTR_GETDETACHSTATE@
+REPLACE_PTHREAD_ATTR_INIT = @REPLACE_PTHREAD_ATTR_INIT@
+REPLACE_PTHREAD_ATTR_SETDETACHSTATE = @REPLACE_PTHREAD_ATTR_SETDETACHSTATE@
+REPLACE_PTHREAD_CONDATTR_DESTROY = @REPLACE_PTHREAD_CONDATTR_DESTROY@
+REPLACE_PTHREAD_CONDATTR_INIT = @REPLACE_PTHREAD_CONDATTR_INIT@
+REPLACE_PTHREAD_COND_BROADCAST = @REPLACE_PTHREAD_COND_BROADCAST@
+REPLACE_PTHREAD_COND_DESTROY = @REPLACE_PTHREAD_COND_DESTROY@
+REPLACE_PTHREAD_COND_INIT = @REPLACE_PTHREAD_COND_INIT@
+REPLACE_PTHREAD_COND_SIGNAL = @REPLACE_PTHREAD_COND_SIGNAL@
+REPLACE_PTHREAD_COND_TIMEDWAIT = @REPLACE_PTHREAD_COND_TIMEDWAIT@
+REPLACE_PTHREAD_COND_WAIT = @REPLACE_PTHREAD_COND_WAIT@
+REPLACE_PTHREAD_CREATE = @REPLACE_PTHREAD_CREATE@
+REPLACE_PTHREAD_DETACH = @REPLACE_PTHREAD_DETACH@
+REPLACE_PTHREAD_EQUAL = @REPLACE_PTHREAD_EQUAL@
+REPLACE_PTHREAD_EXIT = @REPLACE_PTHREAD_EXIT@
+REPLACE_PTHREAD_GETSPECIFIC = @REPLACE_PTHREAD_GETSPECIFIC@
+REPLACE_PTHREAD_JOIN = @REPLACE_PTHREAD_JOIN@
+REPLACE_PTHREAD_KEY_CREATE = @REPLACE_PTHREAD_KEY_CREATE@
+REPLACE_PTHREAD_KEY_DELETE = @REPLACE_PTHREAD_KEY_DELETE@
+REPLACE_PTHREAD_MUTEXATTR_DESTROY = @REPLACE_PTHREAD_MUTEXATTR_DESTROY@
+REPLACE_PTHREAD_MUTEXATTR_GETROBUST = @REPLACE_PTHREAD_MUTEXATTR_GETROBUST@
+REPLACE_PTHREAD_MUTEXATTR_GETTYPE = @REPLACE_PTHREAD_MUTEXATTR_GETTYPE@
+REPLACE_PTHREAD_MUTEXATTR_INIT = @REPLACE_PTHREAD_MUTEXATTR_INIT@
+REPLACE_PTHREAD_MUTEXATTR_SETROBUST = @REPLACE_PTHREAD_MUTEXATTR_SETROBUST@
+REPLACE_PTHREAD_MUTEXATTR_SETTYPE = @REPLACE_PTHREAD_MUTEXATTR_SETTYPE@
+REPLACE_PTHREAD_MUTEX_DESTROY = @REPLACE_PTHREAD_MUTEX_DESTROY@
+REPLACE_PTHREAD_MUTEX_INIT = @REPLACE_PTHREAD_MUTEX_INIT@
+REPLACE_PTHREAD_MUTEX_LOCK = @REPLACE_PTHREAD_MUTEX_LOCK@
+REPLACE_PTHREAD_MUTEX_TIMEDLOCK = @REPLACE_PTHREAD_MUTEX_TIMEDLOCK@
+REPLACE_PTHREAD_MUTEX_TRYLOCK = @REPLACE_PTHREAD_MUTEX_TRYLOCK@
+REPLACE_PTHREAD_MUTEX_UNLOCK = @REPLACE_PTHREAD_MUTEX_UNLOCK@
+REPLACE_PTHREAD_ONCE = @REPLACE_PTHREAD_ONCE@
+REPLACE_PTHREAD_RWLOCKATTR_DESTROY = @REPLACE_PTHREAD_RWLOCKATTR_DESTROY@
+REPLACE_PTHREAD_RWLOCKATTR_INIT = @REPLACE_PTHREAD_RWLOCKATTR_INIT@
+REPLACE_PTHREAD_RWLOCK_DESTROY = @REPLACE_PTHREAD_RWLOCK_DESTROY@
+REPLACE_PTHREAD_RWLOCK_INIT = @REPLACE_PTHREAD_RWLOCK_INIT@
+REPLACE_PTHREAD_RWLOCK_RDLOCK = @REPLACE_PTHREAD_RWLOCK_RDLOCK@
+REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK = @REPLACE_PTHREAD_RWLOCK_TIMEDRDLOCK@
+REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK = @REPLACE_PTHREAD_RWLOCK_TIMEDWRLOCK@
+REPLACE_PTHREAD_RWLOCK_TRYRDLOCK = @REPLACE_PTHREAD_RWLOCK_TRYRDLOCK@
+REPLACE_PTHREAD_RWLOCK_TRYWRLOCK = @REPLACE_PTHREAD_RWLOCK_TRYWRLOCK@
+REPLACE_PTHREAD_RWLOCK_UNLOCK = @REPLACE_PTHREAD_RWLOCK_UNLOCK@
+REPLACE_PTHREAD_RWLOCK_WRLOCK = @REPLACE_PTHREAD_RWLOCK_WRLOCK@
+REPLACE_PTHREAD_SELF = @REPLACE_PTHREAD_SELF@
+REPLACE_PTHREAD_SETSPECIFIC = @REPLACE_PTHREAD_SETSPECIFIC@
+REPLACE_PTHREAD_SIGMASK = @REPLACE_PTHREAD_SIGMASK@
+REPLACE_PTHREAD_SPIN_DESTROY = @REPLACE_PTHREAD_SPIN_DESTROY@
+REPLACE_PTHREAD_SPIN_INIT = @REPLACE_PTHREAD_SPIN_INIT@
+REPLACE_PTHREAD_SPIN_LOCK = @REPLACE_PTHREAD_SPIN_LOCK@
+REPLACE_PTHREAD_SPIN_TRYLOCK = @REPLACE_PTHREAD_SPIN_TRYLOCK@
+REPLACE_PTHREAD_SPIN_UNLOCK = @REPLACE_PTHREAD_SPIN_UNLOCK@
+REPLACE_PTSNAME = @REPLACE_PTSNAME@
+REPLACE_PTSNAME_R = @REPLACE_PTSNAME_R@
+REPLACE_PUTENV = @REPLACE_PUTENV@
+REPLACE_PWRITE = @REPLACE_PWRITE@
+REPLACE_QSORT_R = @REPLACE_QSORT_R@
+REPLACE_RAISE = @REPLACE_RAISE@
+REPLACE_RANDOM = @REPLACE_RANDOM@
+REPLACE_RANDOM_R = @REPLACE_RANDOM_R@
+REPLACE_READ = @REPLACE_READ@
+REPLACE_READLINK = @REPLACE_READLINK@
+REPLACE_READLINKAT = @REPLACE_READLINKAT@
+REPLACE_REALLOCARRAY = @REPLACE_REALLOCARRAY@
+REPLACE_REALLOC_FOR_REALLOC_GNU = @REPLACE_REALLOC_FOR_REALLOC_GNU@
+REPLACE_REALLOC_FOR_REALLOC_POSIX = @REPLACE_REALLOC_FOR_REALLOC_POSIX@
+REPLACE_REALPATH = @REPLACE_REALPATH@
+REPLACE_REMOVE = @REPLACE_REMOVE@
+REPLACE_RENAME = @REPLACE_RENAME@
+REPLACE_RENAMEAT = @REPLACE_RENAMEAT@
+REPLACE_RMDIR = @REPLACE_RMDIR@
+REPLACE_SCHED_YIELD = @REPLACE_SCHED_YIELD@
+REPLACE_SELECT = @REPLACE_SELECT@
+REPLACE_SETENV = @REPLACE_SETENV@
+REPLACE_SETHOSTNAME = @REPLACE_SETHOSTNAME@
+REPLACE_SETLOCALE = @REPLACE_SETLOCALE@
+REPLACE_SETSTATE = @REPLACE_SETSTATE@
+REPLACE_SLEEP = @REPLACE_SLEEP@
+REPLACE_SNPRINTF = @REPLACE_SNPRINTF@
+REPLACE_SPRINTF = @REPLACE_SPRINTF@
+REPLACE_STAT = @REPLACE_STAT@
+REPLACE_STDIO_READ_FUNCS = @REPLACE_STDIO_READ_FUNCS@
+REPLACE_STDIO_WRITE_FUNCS = @REPLACE_STDIO_WRITE_FUNCS@
+REPLACE_STPCPY = @REPLACE_STPCPY@
+REPLACE_STPNCPY = @REPLACE_STPNCPY@
+REPLACE_STRCASESTR = @REPLACE_STRCASESTR@
+REPLACE_STRCHRNUL = @REPLACE_STRCHRNUL@
+REPLACE_STRDUP = @REPLACE_STRDUP@
+REPLACE_STRERROR = @REPLACE_STRERROR@
+REPLACE_STRERRORNAME_NP = @REPLACE_STRERRORNAME_NP@
+REPLACE_STRERROR_R = @REPLACE_STRERROR_R@
+REPLACE_STRFTIME = @REPLACE_STRFTIME@
+REPLACE_STRNCAT = @REPLACE_STRNCAT@
+REPLACE_STRNDUP = @REPLACE_STRNDUP@
+REPLACE_STRNLEN = @REPLACE_STRNLEN@
+REPLACE_STRSIGNAL = @REPLACE_STRSIGNAL@
+REPLACE_STRSTR = @REPLACE_STRSTR@
+REPLACE_STRTOD = @REPLACE_STRTOD@
+REPLACE_STRTOIMAX = @REPLACE_STRTOIMAX@
+REPLACE_STRTOK_R = @REPLACE_STRTOK_R@
+REPLACE_STRTOL = @REPLACE_STRTOL@
+REPLACE_STRTOLD = @REPLACE_STRTOLD@
+REPLACE_STRTOLL = @REPLACE_STRTOLL@
+REPLACE_STRTOUL = @REPLACE_STRTOUL@
+REPLACE_STRTOULL = @REPLACE_STRTOULL@
+REPLACE_STRTOUMAX = @REPLACE_STRTOUMAX@
+REPLACE_STRUCT_LCONV = @REPLACE_STRUCT_LCONV@
+REPLACE_STRUCT_TIMEVAL = @REPLACE_STRUCT_TIMEVAL@
+REPLACE_SYMLINK = @REPLACE_SYMLINK@
+REPLACE_SYMLINKAT = @REPLACE_SYMLINKAT@
+REPLACE_TIME = @REPLACE_TIME@
+REPLACE_TIMEGM = @REPLACE_TIMEGM@
+REPLACE_TIMESPEC_GET = @REPLACE_TIMESPEC_GET@
+REPLACE_TMPFILE = @REPLACE_TMPFILE@
+REPLACE_TOWLOWER = @REPLACE_TOWLOWER@
+REPLACE_TRUNCATE = @REPLACE_TRUNCATE@
+REPLACE_TTYNAME_R = @REPLACE_TTYNAME_R@
+REPLACE_TZSET = @REPLACE_TZSET@
+REPLACE_UNLINK = @REPLACE_UNLINK@
+REPLACE_UNLINKAT = @REPLACE_UNLINKAT@
+REPLACE_UNSETENV = @REPLACE_UNSETENV@
+REPLACE_USLEEP = @REPLACE_USLEEP@
+REPLACE_UTIMENSAT = @REPLACE_UTIMENSAT@
+REPLACE_VASPRINTF = @REPLACE_VASPRINTF@
+REPLACE_VDPRINTF = @REPLACE_VDPRINTF@
+REPLACE_VFPRINTF = @REPLACE_VFPRINTF@
+REPLACE_VPRINTF = @REPLACE_VPRINTF@
+REPLACE_VSNPRINTF = @REPLACE_VSNPRINTF@
+REPLACE_VSPRINTF = @REPLACE_VSPRINTF@
+REPLACE_WCRTOMB = @REPLACE_WCRTOMB@
+REPLACE_WCSFTIME = @REPLACE_WCSFTIME@
+REPLACE_WCSNRTOMBS = @REPLACE_WCSNRTOMBS@
+REPLACE_WCSRTOMBS = @REPLACE_WCSRTOMBS@
+REPLACE_WCSTOK = @REPLACE_WCSTOK@
+REPLACE_WCSWIDTH = @REPLACE_WCSWIDTH@
+REPLACE_WCTOB = @REPLACE_WCTOB@
+REPLACE_WCTOMB = @REPLACE_WCTOMB@
+REPLACE_WCWIDTH = @REPLACE_WCWIDTH@
+REPLACE_WMEMPCPY = @REPLACE_WMEMPCPY@
+REPLACE_WRITE = @REPLACE_WRITE@
+REPLACE__EXIT = @REPLACE__EXIT@
+SCHED_YIELD_LIB = @SCHED_YIELD_LIB@
+SED = @SED@
+SELECT_LIB = @SELECT_LIB@
+SETLOCALE_LIB = @SETLOCALE_LIB@
+SETLOCALE_NULL_LIB = @SETLOCALE_NULL_LIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SIG_ATOMIC_T_SUFFIX = @SIG_ATOMIC_T_SUFFIX@
+SIZE_T_SUFFIX = @SIZE_T_SUFFIX@
+STDARG_H = @STDARG_H@
+STDCKDINT_H = @STDCKDINT_H@
+STDDEF_H = @STDDEF_H@
+STDINT_H = @STDINT_H@
+STRIP = @STRIP@
+SYS_IOCTL_H_HAVE_WINSOCK2_H = @SYS_IOCTL_H_HAVE_WINSOCK2_H@
+SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @SYS_IOCTL_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+SYS_TIME_H_DEFINES_STRUCT_TIMESPEC = @SYS_TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_STRUCT_TIMESPEC = @TIME_H_DEFINES_STRUCT_TIMESPEC@
+TIME_H_DEFINES_TIME_UTC = @TIME_H_DEFINES_TIME_UTC@
+UINT32_MAX_LT_UINTMAX_MAX = @UINT32_MAX_LT_UINTMAX_MAX@
+UINT64_MAX_EQ_ULONG_MAX = @UINT64_MAX_EQ_ULONG_MAX@
+UNDEFINE_STRTOK_R = @UNDEFINE_STRTOK_R@
+UNISTD_H_DEFINES_STRUCT_TIMESPEC = @UNISTD_H_DEFINES_STRUCT_TIMESPEC@
+UNISTD_H_HAVE_SYS_RANDOM_H = @UNISTD_H_HAVE_SYS_RANDOM_H@
+UNISTD_H_HAVE_WINSOCK2_H = @UNISTD_H_HAVE_WINSOCK2_H@
+UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS = @UNISTD_H_HAVE_WINSOCK2_H_AND_USE_SOCKETS@
+USE_NLS = @USE_NLS@
+UUID_LIBS = @UUID_LIBS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+WCHAR_T_SUFFIX = @WCHAR_T_SUFFIX@
+WINDOWS_64_BIT_OFF_T = @WINDOWS_64_BIT_OFF_T@
+WINDOWS_64_BIT_ST_SIZE = @WINDOWS_64_BIT_ST_SIZE@
+WINDOWS_STAT_INODES = @WINDOWS_STAT_INODES@
+WINDOWS_STAT_TIMESPEC = @WINDOWS_STAT_TIMESPEC@
+WINT_T_SUFFIX = @WINT_T_SUFFIX@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YIELD_LIB = @YIELD_LIB@
+abs_aux_dir = @abs_aux_dir@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+bindir_c = @bindir_c@
+bindir_c_make = @bindir_c_make@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datadir_c = @datadir_c@
+datadir_c_make = @datadir_c_make@
+datarootdir = @datarootdir@
+datarootdir_c = @datarootdir_c@
+datarootdir_c_make = @datarootdir_c_make@
+docdir = @docdir@
+docdir_c = @docdir_c@
+docdir_c_make = @docdir_c_make@
+dvidir = @dvidir@
+dvidir_c = @dvidir_c@
+dvidir_c_make = @dvidir_c_make@
+exec_prefix = @exec_prefix@
+exec_prefix_c = @exec_prefix_c@
+exec_prefix_c_make = @exec_prefix_c_make@
+gl_LIBOBJDEPS = @gl_LIBOBJDEPS@
+gl_LIBOBJS = @gl_LIBOBJS@
+gl_LTLIBOBJS = @gl_LTLIBOBJS@
+gltests_LIBOBJDEPS = @gltests_LIBOBJDEPS@
+gltests_LIBOBJS = @gltests_LIBOBJS@
+gltests_LTLIBOBJS = @gltests_LTLIBOBJS@
+gltests_WITNESS = @gltests_WITNESS@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+htmldir_c = @htmldir_c@
+htmldir_c_make = @htmldir_c_make@
+includedir = @includedir@
+includedir_c = @includedir_c@
+includedir_c_make = @includedir_c_make@
+infodir = @infodir@
+infodir_c = @infodir_c@
+infodir_c_make = @infodir_c_make@
+install_sh = @install_sh@
+libdir = @libdir@
+libdir_c = @libdir_c@
+libdir_c_make = @libdir_c_make@
+libexecdir = @libexecdir@
+libexecdir_c = @libexecdir_c@
+libexecdir_c_make = @libexecdir_c_make@
+lispdir = @lispdir@
+lispdir_c = @lispdir_c@
+lispdir_c_make = @lispdir_c_make@
+localedir = @localedir@
+localedir_c = @localedir_c@
+localedir_c_make = @localedir_c_make@
+localstatedir = @localstatedir@
+localstatedir_c = @localstatedir_c@
+localstatedir_c_make = @localstatedir_c_make@
+mandir = @mandir@
+mandir_c = @mandir_c@
+mandir_c_make = @mandir_c_make@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+oldincludedir_c = @oldincludedir_c@
+oldincludedir_c_make = @oldincludedir_c_make@
+pdfdir = @pdfdir@
+pdfdir_c = @pdfdir_c@
+pdfdir_c_make = @pdfdir_c_make@
+pkgdatadir_c = @pkgdatadir_c@
+pkgdatadir_c_make = @pkgdatadir_c_make@
+pkgincludedir_c = @pkgincludedir_c@
+pkgincludedir_c_make = @pkgincludedir_c_make@
+pkglibdir_c = @pkglibdir_c@
+pkglibdir_c_make = @pkglibdir_c_make@
+pkglibexecdir_c = @pkglibexecdir_c@
+pkglibexecdir_c_make = @pkglibexecdir_c_make@
+prefix = @prefix@
+prefix_c = @prefix_c@
+prefix_c_make = @prefix_c_make@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+psdir_c = @psdir_c@
+psdir_c_make = @psdir_c_make@
+runstatedir = @runstatedir@
+runstatedir_c = @runstatedir_c@
+runstatedir_c_make = @runstatedir_c_make@
+sbindir = @sbindir@
+sbindir_c = @sbindir_c@
+sbindir_c_make = @sbindir_c_make@
+sharedstatedir = @sharedstatedir@
+sharedstatedir_c = @sharedstatedir_c@
+sharedstatedir_c_make = @sharedstatedir_c_make@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+sysconfdir_c = @sysconfdir_c@
+sysconfdir_c_make = @sysconfdir_c_make@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+@COMPILE_FOR_S390_FALSE@S390_SRCS =
+@COMPILE_FOR_S390_TRUE@S390_SRCS = dasd.c fdasd.c vtoc.c
+AM_CFLAGS = $(WARN_CFLAGS) $(WERROR_CFLAGS)
+partedincludedir = \
+ -I$(top_srcdir)/lib -I$(top_builddir)/include -I$(top_srcdir)/include \
+ -I$(top_srcdir)/libparted
+
+noinst_LTLIBRARIES = liblabels.la
+liblabels_la_SOURCES = \
+ $(S390_SRCS) \
+ aix.c \
+ atari.c \
+ bsd.c \
+ dos.c \
+ dvh.c \
+ dvh.h \
+ efi_crc32.c \
+ gpt.c \
+ loop.c \
+ mac.c \
+ misc.h \
+ pc98.c \
+ pt-common.h \
+ pt-tools.c \
+ pt-tools.h \
+ rdb.c \
+ sun.c
+
+liblabels_la_LIBADD = $(OS_LIBS) $(INTLLIBS) $(LIBICONV)
+AM_CPPFLAGS = $(partedincludedir) $(INTLINCS)
+
+# Included by 'pt-tools.c', so needs to be built early.
+BUILT_SOURCES = pt-limit.c
+MAINTAINERCLEANFILES = $(BUILT_SOURCES)
+# DOn't add this to '_SOURCES', because it's not to be compiled!
+EXTRA_DIST = pt-limit.c pt-limit.gperf
+GPERF = gperf
+GPERF_OPTIONS = \
+ -C -N pt_limit_lookup -n -t -s 6 -k '*' --language=ANSI-C
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libparted/labels/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libparted/labels/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liblabels.la: $(liblabels_la_OBJECTS) $(liblabels_la_DEPENDENCIES) $(EXTRA_liblabels_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(liblabels_la_OBJECTS) $(liblabels_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/atari.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bsd.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dasd.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dos.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dvh.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efi_crc32.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fdasd.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpt.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loop.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mac.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pc98.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pt-tools.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rdb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sun.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vtoc.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/aix.Plo
+ -rm -f ./$(DEPDIR)/atari.Plo
+ -rm -f ./$(DEPDIR)/bsd.Plo
+ -rm -f ./$(DEPDIR)/dasd.Plo
+ -rm -f ./$(DEPDIR)/dos.Plo
+ -rm -f ./$(DEPDIR)/dvh.Plo
+ -rm -f ./$(DEPDIR)/efi_crc32.Plo
+ -rm -f ./$(DEPDIR)/fdasd.Plo
+ -rm -f ./$(DEPDIR)/gpt.Plo
+ -rm -f ./$(DEPDIR)/loop.Plo
+ -rm -f ./$(DEPDIR)/mac.Plo
+ -rm -f ./$(DEPDIR)/pc98.Plo
+ -rm -f ./$(DEPDIR)/pt-tools.Plo
+ -rm -f ./$(DEPDIR)/rdb.Plo
+ -rm -f ./$(DEPDIR)/sun.Plo
+ -rm -f ./$(DEPDIR)/vtoc.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/aix.Plo
+ -rm -f ./$(DEPDIR)/atari.Plo
+ -rm -f ./$(DEPDIR)/bsd.Plo
+ -rm -f ./$(DEPDIR)/dasd.Plo
+ -rm -f ./$(DEPDIR)/dos.Plo
+ -rm -f ./$(DEPDIR)/dvh.Plo
+ -rm -f ./$(DEPDIR)/efi_crc32.Plo
+ -rm -f ./$(DEPDIR)/fdasd.Plo
+ -rm -f ./$(DEPDIR)/gpt.Plo
+ -rm -f ./$(DEPDIR)/loop.Plo
+ -rm -f ./$(DEPDIR)/mac.Plo
+ -rm -f ./$(DEPDIR)/pc98.Plo
+ -rm -f ./$(DEPDIR)/pt-tools.Plo
+ -rm -f ./$(DEPDIR)/rdb.Plo
+ -rm -f ./$(DEPDIR)/sun.Plo
+ -rm -f ./$(DEPDIR)/vtoc.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: all check install install-am install-exec install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+pt-limit.c: pt-limit.gperf
+ rm -f $@ $@-tmp
+ $(GPERF) $(GPERF_OPTIONS) $< \
+ | perl -ne '/__GNUC_STDC_INLINE__/ and print "static\n"; print' \
+ > $@-tmp
+ chmod a-w $@-tmp
+ mv $@-tmp $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libparted/labels/aix.c b/libparted/labels/aix.c
new file mode 100644
index 0000000..8adb4db
--- /dev/null
+++ b/libparted/labels/aix.c
@@ -0,0 +1,237 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2007-2014, 2019-2023 Free Software Foundation,
+ Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Matt Wilson <msw@redhat.com>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#define AIX_LABEL_MAGIC (0xc9c2d4c1UL)
+#define MAX_TOTAL_PART 16
+
+static PedDiskType aix_disk_type;
+
+static int
+aix_probe (const PedDevice *dev)
+{
+ PED_ASSERT (dev != NULL);
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+ bool found = PED_BE32_TO_CPU(*(uint32_t *)label) == AIX_LABEL_MAGIC;
+ free (label);
+ return found;
+}
+
+static PedDisk*
+aix_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+
+ disk = _ped_disk_alloc (dev, &aix_disk_type);
+ if (!disk)
+ return NULL;
+
+ return disk;
+}
+
+static PedDisk*
+aix_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &aix_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ return new_disk;
+}
+
+static void
+aix_free (PedDisk *disk)
+{
+ _ped_disk_free (disk);
+}
+
+static int
+aix_read (PedDisk* disk)
+{
+ ped_disk_delete_all (disk);
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for reading AIX disk labels is "
+ "is not implemented yet."));
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+static int
+aix_write (const PedDisk* disk)
+{
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for writing AIX disk labels is "
+ "is not implemented yet."));
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+aix_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for adding partitions to AIX disk "
+ "labels is not implemented yet."));
+ return NULL;
+}
+
+static PedPartition*
+aix_partition_duplicate (const PedPartition* part)
+{
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for duplicating partitions in AIX "
+ "disk labels is not implemented yet."));
+ return NULL;
+}
+
+static void
+aix_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ _ped_partition_free (part);
+}
+
+static int
+aix_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for setting system type of partitions "
+ "in AIX disk labels is not implemented yet."));
+ return 0;
+}
+
+static int
+aix_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ ped_exception_throw (PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Support for setting flags "
+ "in AIX disk labels is not implemented yet."));
+ return 0;
+}
+
+static int _GL_ATTRIBUTE_CONST
+aix_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ return 0;
+}
+
+
+static int
+aix_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ return 0;
+}
+
+
+static int
+aix_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return 4;
+}
+
+static bool
+aix_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = MAX_TOTAL_PART;
+ return true;
+}
+
+static int _GL_ATTRIBUTE_PURE
+aix_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+aix_partition_enumerate (PedPartition* part)
+{
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+aix_alloc_metadata (PedDisk* disk)
+{
+ return 1;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (aix)
+
+static PedDiskOps aix_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (aix_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (aix)
+};
+
+static PedDiskType aix_disk_type = {
+ next: NULL,
+ name: "aix",
+ ops: &aix_disk_ops,
+ features: 0
+};
+
+void
+ped_disk_aix_init ()
+{
+ ped_disk_type_register (&aix_disk_type);
+}
+
+void
+ped_disk_aix_done ()
+{
+ ped_disk_type_unregister (&aix_disk_type);
+}
diff --git a/libparted/labels/atari.c b/libparted/labels/atari.c
new file mode 100644
index 0000000..8ab3720
--- /dev/null
+++ b/libparted/labels/atari.c
@@ -0,0 +1,1975 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ atari.c - libparted module to manipulate Atari partition tables.
+ Copyright (C) 2000-2001, 2004, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Guillaume Knispel <k_guillaume@libertysurf.fr>
+ John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
+*/
+
+/*
+ Documentation :
+ README file of atari-fdisk
+ atari-fdisk source code
+ Linux atari partitions parser source code
+ ( fs/partitions/atari.[ch] )
+*/
+
+#include <config.h>
+
+#include <string.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <string.h>
+#include <locale.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <stddef.h>
+
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+
+/********************** Atari data and structure stuff **********************/
+
+#define BOOTABLE_CKSUM 0x1234
+#define NONBOOT_CKSUM 0x4321
+
+#define GEM_MAX ((32*1024*1024)/PED_SECTOR_SIZE_DEFAULT)
+
+#define PART_FLAG_USED 0x01
+#define PART_FLAG_BOOT_GEM 0x80 /* GEMDOS */
+#define PART_FLAG_BOOT_ASV 0x40 /* Atari System V */
+#define PART_FLAG_BOOT_BSD 0x20 /* Net(?)BSD */
+#define PART_FLAG_BOOT_LNX 0x10 /* Linux */
+#define PART_FLAG_BOOT_UNK 0x08 /* unknown / other */
+
+#define N_AHDI 4
+#define N_ICD 8
+
+#define MAXIMUM_PARTS 64
+
+/* what we put instead of id, start and size in empty */
+/* partition tables, to be able to detect it */
+#define SIGNATURE_EMPTY_TABLE "PARTEDATARI"
+#define SIGNATURE_EMPTY_SIZE 11
+
+/* to be compared to the last two bytes of 1st sector (Big Endian) */
+static const uint16_t atr_forbidden_sign[] = {
+ 0x55AA,
+ 0
+};
+
+static const char *atr_known_icd_pid[] = {
+ "BGM", "GEM", "LNX", "SWP", "RAW", NULL
+};
+
+/* static const char *atr_known_pid[] = { */
+/* "BGM", "GEM", "LNX", "MAC", "MIX", "MNX", "RAW", "SWP", "UNX", */
+/* "F32", "SV4", NULL */
+/* }; */
+
+struct _AtariPartID2BootFlag {
+ const char pid[4];
+ uint8_t flag;
+};
+typedef struct _AtariPartID2BootFlag AtariPartID2BootFlag;
+
+static AtariPartID2BootFlag atr_pid2bf[] = {
+ { "GEM", PART_FLAG_BOOT_GEM },
+ { "BGM", PART_FLAG_BOOT_GEM },
+ { "UNX", PART_FLAG_BOOT_ASV },
+ { "LNX", PART_FLAG_BOOT_LNX },
+ { "", PART_FLAG_BOOT_UNK },
+};
+
+struct _AtariFS2PartId {
+ const char* fs;
+ const char pid[4];
+ PedSector max_sectors;
+};
+typedef struct _AtariFS2PartId AtariFS2PartId;
+
+static AtariFS2PartId atr_fs2pid[] = {
+/* Other ID are available : MIX MNX <= minix
+ UNX <= Atari SysV Unix
+ SV4 <= Univ System 4 */
+ { "ext2", "LNX", INT32_MAX },
+ { "ext3", "LNX", INT32_MAX },
+ { "fat16", "GEM", GEM_MAX }, /* small partitions */
+ { "fat16", "BGM", INT32_MAX }, /* big partitions */
+ { "fat32", "F32", INT32_MAX },
+ { "hfs", "MAC", INT32_MAX },
+ { "hfs+", "MAC", INT32_MAX },
+ { "hfsx", "MAC", INT32_MAX },
+ { "jfs", "LNX", INT32_MAX },
+ { "linux-swap", "SWP", INT32_MAX },
+ { "reiserfs", "LNX", INT32_MAX },
+ { "hp-ufs", "LNX", INT32_MAX },
+ { "sun-ufs", "LNX", INT32_MAX },
+ { "xfs", "LNX", INT32_MAX },
+ { "ntfs", "RAW", INT32_MAX },
+ { "", "RAW", INT32_MAX }, /* default entry */
+ { NULL, "" , 0 } /* end of list */
+};
+
+struct __attribute__ ((packed)) _AtariRawPartition {
+ uint8_t flag; /* bit 0: active; bit 7: bootable */
+ union {
+ uint8_t empty[11]; /* Empty table */
+ struct __attribute__ ((packed)) {
+ uint8_t id[3]; /* "GEM", "BGM", "XGM", ... */
+ uint32_t start; /* start of partition */
+ uint32_t size; /* length of partition */
+ };
+ };
+};
+typedef struct _AtariRawPartition AtariRawPartition;
+
+struct __attribute__ ((packed,aligned(2))) _AtariRawTable {
+ uint8_t boot_code[0x156]; /* room for boot code */
+ AtariRawPartition icd_part[N_ICD]; /* info for ICD-partitions 5..12 */
+ uint8_t unused[0xc];
+ uint32_t hd_size; /* size of disk in blocks */
+ AtariRawPartition part[N_AHDI]; /* the four primary partitions */
+ uint32_t bsl_start; /* start of bad sector list */
+ uint32_t bsl_count; /* length of bad sector list */
+ uint16_t checksum; /* checksum for bootable disks */
+};
+typedef struct _AtariRawTable AtariRawTable;
+
+typedef enum {
+ FMT_AHDI = 0, /* AHDI v1 compatible, no ICD and no XGM */
+ FMT_XGM = 1, /* AHDI v3 with XGM / this disable ICD */
+ FMT_ICD = 2 /* ICD detected / requested because more than 4 prim */
+ /* no XGM allowed */
+} AtrFmt;
+
+struct _AtariDisk {
+ AtrFmt format;
+ int has_been_read; /* actually means has been read or written... */
+ uint32_t bsl_start; /* first sector of the Bad Sectors List */
+ uint32_t bsl_count; /* number of sectors of the BSL */
+ uint8_t HDX_comp; /* if set to one, atari_write will initialize */
+ /* the bsl area */
+};
+typedef struct _AtariDisk AtariDisk;
+
+struct _AtariPart {
+ char part_id[4]; /* ASCIIZ */
+ char icd_id[4]; /* Linux only parse a limited set of ID */
+ /* in ICD (why???), so everything else */
+ /* is translated to RAW. */
+ uint8_t flag; /* without bit 0 (entry used) */
+};
+typedef struct _AtariPart AtariPart;
+
+/* set by initialisation code to C locale */
+static locale_t atr_c_locale;
+
+static PedDiskType atari_disk_type;
+
+
+
+/******************************** Atari Code ********************************/
+
+#define ATARI_DISK(disk) ((AtariDisk*)((disk)->disk_specific))
+#define ATARI_PART(part) ((AtariPart*)((part)->disk_specific))
+
+#define atr_pid_eq(a,b) (!memcmp( (a), (b), 3 ))
+
+#define atr_pid_assign(a, b) (memcpy ( (a), (b), 3 ))
+
+#define atr_part_used(part) (((part)->flag) & PART_FLAG_USED)
+
+static int
+atr_start_size_correct (uint32_t start, uint32_t size, uint32_t hd_size)
+{
+ uint32_t end = start + size;
+
+ return end >= start
+ && 0 < start && start <= hd_size
+ && 0 < size && size <= hd_size
+ && 0 < end && end <= hd_size;
+}
+
+static int
+atr_part_correct (AtariRawPartition* part, uint32_t hd_size)
+{
+ uint32_t start, size;
+
+ start = PED_BE32_TO_CPU (part->start);
+ size = PED_BE32_TO_CPU (part->size);
+
+ return isalnum_l(part->id[0], atr_c_locale)
+ && isalnum_l(part->id[1], atr_c_locale)
+ && isalnum_l(part->id[2], atr_c_locale)
+ && atr_start_size_correct (start, size, hd_size);
+}
+
+static int _GL_ATTRIBUTE_PURE
+atr_pid_known (const char* pid, const char** pid_list)
+{
+ for (; *pid_list; pid_list++) {
+ if (atr_pid_eq(pid, *pid_list))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Recognize Parted signature in an AHDI entry, used to
+ * identify empty Atari partition tables */
+static int
+atr_is_signature_entry (AtariRawPartition* part)
+{
+ return part->flag == 0
+ && !memcmp (part->empty, SIGNATURE_EMPTY_TABLE,
+ SIGNATURE_EMPTY_SIZE );
+}
+
+/* Set Parted signature in an AHDI entry */
+static void
+atr_put_signature_entry (AtariRawPartition* part)
+{
+ part->flag = 0;
+ memcpy (part->empty, SIGNATURE_EMPTY_TABLE, SIGNATURE_EMPTY_SIZE);
+}
+
+#define atr_part_known(part, pid_list) (atr_pid_known ((part)->id, pid_list))
+
+#define atr_part_valid(part, sz) (atr_part_used(part)\
+ && atr_part_correct((part), (sz)))
+#define atr_part_trash(part, sz) (atr_part_used(part)\
+ && !atr_part_correct((part), (sz)))
+
+/* Check if this device can be used with an Atari label */
+static int
+atr_can_use_dev (const PedDevice *dev)
+{
+ /* i really don't know how atari behave with non 512 bytes */
+ /* sectors... */
+ if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Can't use Atari partition tables on disks with a "
+ "sector size not equal to %d bytes."),
+ (int)PED_SECTOR_SIZE_DEFAULT );
+ return 0;
+ }
+
+ /* the format isn't well defined enough to support > 0x7FFFFFFF */
+ /* sectors */
+ if (dev->length > INT32_MAX) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Can't use Atari partition tables on disks with more "
+ "than %d sectors."),
+ INT32_MAX );
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * The Atari disk label doesn't have any magic id
+ * so we must completely parse the layout to be sure
+ * we are really dealing with it.
+ */
+static int
+atari_probe (const PedDevice *dev)
+{
+ AtariRawTable table;
+ uint32_t rs_hd_size, parts, exts;
+ int valid_count, xgm_part, xgm_num, i;
+ int num_sign, total_count = 0;
+
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (sizeof(table) == 512);
+
+ /* Device Spec ok for Atari label? */
+ if (!atr_can_use_dev (dev))
+ return 0;
+
+ /* read the root sector */
+ if (!ped_device_read (dev, &table, 0, 1))
+ return 0;
+
+ /* number of sectors stored in the root sector > device length ? */
+ /* => just reject the Atari disk label */
+ rs_hd_size = PED_BE32_TO_CPU (table.hd_size);
+ if (rs_hd_size > dev->length
+ || rs_hd_size < 2)
+ return 0;
+
+ /* check the BSL fields */
+ if ((table.bsl_start || table.bsl_count)
+ && !atr_start_size_correct (PED_BE32_TO_CPU (table.bsl_start),
+ PED_BE32_TO_CPU (table.bsl_count),
+ rs_hd_size ) )
+ return 0;
+
+ /* scan the main AHDI fields */
+ num_sign = 0; xgm_num = 0;
+ valid_count = 0; xgm_part = 0;
+ for (i = 0; i < N_AHDI; i++) {
+ if (atr_part_valid (&table.part[i], rs_hd_size)) {
+ valid_count++;
+ total_count++;
+ if (atr_pid_eq(table.part[i].id, "XGM")) {
+ xgm_part++;
+ xgm_num = i;
+ }
+ } else if (atr_part_trash (&table.part[i], rs_hd_size)) {
+ return 0;
+ }
+ if (atr_is_signature_entry (&table.part[i]))
+ num_sign++;
+ }
+
+ /* no way to reliably detect empty Atari disk labels if
+ * they aren't using parted signature in 4 prim fields
+ * && reject multi XGM labels because Parted can't handle
+ * multiple extended partitions
+ * && reject if xgm partition in slot 0 because not allowed */
+ if ((!valid_count && num_sign != N_AHDI)
+ || xgm_part > 1
+ || (xgm_part == 1 && xgm_num == 0) )
+ return 0;
+
+ /* check coherency of each logical partitions and ARS */
+ if (xgm_part) { /* ! WARNING ! reuses "table" */
+ /* we must allow empty ext partition even if they're */
+ /* not valid because parted write the layout to the HD */
+ /* at each operation, and we can't create ext and log */
+ /* at the same time */
+ int empty_ars_allowed = 1;
+
+ parts = exts = PED_BE32_TO_CPU (table.part[xgm_num].start);
+ while (1) {
+ if (!ped_device_read (dev, &table, parts, 1))
+ return 0;
+
+ for (i = 0; i < N_AHDI-1; ++i) {
+ if (atr_part_used (&table.part[i]))
+ break;
+ }
+
+ /* we allow the ext part to be empty (see above) */
+ if (i == N_AHDI-1 && empty_ars_allowed)
+ break;
+
+ /* data partition must be in slot 0, 1 or 2 */
+ if (i == N_AHDI-1
+ || !atr_part_correct (&table.part[i], rs_hd_size
+ - parts )
+ || atr_pid_eq (table.part[i].id, "XGM"))
+ return 0;
+
+ /* If there is at least one logical partition */
+ /* then next ARS should not be empty */
+ empty_ars_allowed = 0;
+
+ total_count++;
+ if (total_count > MAXIMUM_PARTS) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Too many Atari partitions detected. "
+ " Maybe there is a loop in the XGM "
+ "linked list. Aborting.") );
+ return 0;
+ }
+
+ /* end of logical partitions? */
+ if (!atr_part_used (&table.part[i+1]))
+ break;
+
+ /* is this really the descriptor of the next ARS? */
+ if (!atr_part_correct (&table.part[i+1], rs_hd_size
+ - exts )
+ || !atr_pid_eq (table.part[i+1].id, "XGM"))
+ return 0;
+
+ parts = exts + PED_BE32_TO_CPU (table.part[i+1].start);
+ }
+ } /* no XGM so try ICD */
+ else if (atr_part_valid (&table.icd_part[0], rs_hd_size)
+ && atr_part_known (&table.icd_part[0], atr_known_icd_pid)) {
+ for (i = 1; i < N_ICD; i++) {
+ if (atr_part_trash (&table.icd_part[i], rs_hd_size))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static void
+atr_disk_reset (AtariDisk* atr_disk)
+{
+ /* Empty partition table => only AHDI needed right now */
+ atr_disk->format = FMT_AHDI;
+ /* The disk is not in sync with the actual content of the label */
+ atr_disk->has_been_read = 0;
+ /* Create an empty BSL for HDX compatibility */
+ atr_disk->bsl_start = 1;
+ atr_disk->bsl_count = 1;
+ atr_disk->HDX_comp = 1;
+}
+
+/*
+ * Must set up the PedDisk and the associated AtariDisk as if
+ * the user is doing mklabel, since in this case atari_alloc
+ * is called alone whereas when reading an existing partition
+ * table atari_read is called after atari_alloc and can overwrite
+ * the settings.
+ */
+static PedDisk*
+atari_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ AtariDisk* atr_disk;
+
+ PED_ASSERT (dev != NULL);
+
+ if (!atr_can_use_dev (dev)
+ || !(disk = _ped_disk_alloc (dev, &atari_disk_type)))
+ return NULL;
+
+ if (!(disk->disk_specific = atr_disk = ped_malloc (sizeof (AtariDisk))))
+ goto error_free_disk;
+
+ atr_disk_reset (atr_disk);
+
+ return disk;
+
+error_free_disk:
+ free (disk);
+ return NULL;
+}
+
+static PedDisk*
+atari_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ AtariDisk* old_atr_dsk;
+ AtariDisk* new_atr_dsk;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+
+ old_atr_dsk = ATARI_DISK (disk);
+ if (!(new_disk = ped_disk_new_fresh (disk->dev, &atari_disk_type)))
+ return NULL;
+ new_atr_dsk = ATARI_DISK (new_disk);
+
+ memcpy (new_atr_dsk, old_atr_dsk, sizeof(*old_atr_dsk));
+
+ return new_disk;
+}
+
+static void
+atari_free (PedDisk* disk)
+{
+ AtariDisk* atr_disk;
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ atr_disk = ATARI_DISK (disk);
+
+ _ped_disk_free (disk);
+ free (atr_disk);
+}
+
+/* Warning : ID not ASCIIZ but 3 chars long */
+static void
+atr_part_sysraw (PedPartition* part, const char* id, uint8_t flag)
+{
+ AtariPart* atr_part = ATARI_PART (part);
+
+ atr_part->flag = flag & ~PART_FLAG_USED;
+
+ atr_pid_assign (atr_part->part_id, id);
+ atr_part->part_id[3] = 0;
+
+ if (atr_pid_known (id, atr_known_icd_pid)) {
+ atr_pid_assign (atr_part->icd_id, id);
+ atr_part->icd_id[3] = 0;
+ } else {
+ atr_pid_assign (atr_part->icd_id, "RAW");
+ atr_part->icd_id[3] = 0;
+ }
+}
+
+static int
+atr_parse_add_rawpart (PedDisk* disk, PedPartitionType type, PedSector st_off,
+ int num, const AtariRawPartition* rawpart )
+{
+ PedSector start, end;
+ PedPartition* part;
+ PedConstraint* const_exact;
+ int added;
+
+ start = st_off + PED_BE32_TO_CPU (rawpart->start);
+ end = start + PED_BE32_TO_CPU (rawpart->size) - 1;
+
+ part = ped_partition_new (disk, type, NULL, start, end);
+ if (!part)
+ return 0;
+
+ /*part->num = num;*/ /* Enumeration will take care of that */
+ part->num = -1; /* Indeed we can't enumerate here
+ * because the enumerate function uses
+ * -1 do detect new partition being
+ * inserted and update the atrdisk->format */
+ if (type != PED_PARTITION_EXTENDED)
+ part->fs_type = ped_file_system_probe (&part->geom);
+ else
+ part->fs_type = NULL;
+ atr_part_sysraw (part, rawpart->id, rawpart->flag);
+
+ const_exact = ped_constraint_exact (&part->geom);
+ added = ped_disk_add_partition (disk, part, const_exact);
+ ped_constraint_destroy (const_exact);
+ if (!added) {
+ ped_partition_destroy (part);
+ return 0;
+ }
+
+ PED_ASSERT (part->num == num);
+ return 1;
+}
+
+/*
+ * Read the chained list of logical partitions.
+ * exts points to the first Auxiliary Root Sector, at the start
+ * of the extended partition.
+ * In each ARS one partition entry describes to the logical partition
+ * (start relative to the ARS position) and the next entry with ID "XGM"
+ * points to the next ARS (start relative to exts).
+ */
+static int
+atr_read_logicals (PedDisk* disk, PedSector exts, int* pnum)
+{
+ AtariRawTable table;
+ PedSector parts = exts;
+ int i, empty_ars_allowed = 1;
+
+ while (1) {
+ if (!ped_device_read (disk->dev, &table, parts, 1))
+ return 0;
+
+ for (i = 0; i < N_AHDI-1; ++i)
+ if (atr_part_used (&table.part[i]))
+ break;
+
+ if (i == N_AHDI-1 && empty_ars_allowed)
+ break;
+
+ /* data partition must be in slot 0, 1 or 2 */
+ if (i == N_AHDI-1
+ || atr_pid_eq (table.part[i].id, "XGM")) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("No data partition found in the ARS at "
+ "sector %lli."), parts );
+ return 0;
+ }
+
+ empty_ars_allowed = 0;
+
+ if (!atr_parse_add_rawpart (disk, PED_PARTITION_LOGICAL,
+ parts, *pnum, &table.part[i] ) )
+ return 0;
+
+ (*pnum)++;
+
+ /* end of logical partitions? */
+ if (!atr_part_used (&table.part[i+1]))
+ break;
+
+ if (!atr_pid_eq (table.part[i+1].id, "XGM")) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The entry of the next logical ARS is not of "
+ "type XGM in ARS at sector %lli."), parts );
+ return 0;
+ }
+
+ parts = exts + PED_BE32_TO_CPU (table.part[i+1].start);
+ }
+
+ return 1;
+}
+
+static int
+atari_read (PedDisk* disk)
+{
+ AtariRawTable table;
+ AtariDisk* atr_disk;
+ uint32_t rs_hd_size;
+ int i, pnum, xgm, pcount;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ atr_disk = ATARI_DISK (disk);
+
+ ped_disk_delete_all (disk);
+ atr_disk_reset (atr_disk);
+
+ if (!atari_probe (disk->dev)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("There doesn't seem to be an Atari partition table "
+ "on this disk (%s), or it is corrupted."),
+ disk->dev->path )
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+
+ if (!ped_device_read (disk->dev, (void*) &table, 0, 1))
+ goto error;
+
+ /* We are sure that the layout looks coherent so we
+ don't need to check too much */
+
+ rs_hd_size = PED_BE32_TO_CPU (table.hd_size);
+ atr_disk->bsl_start = PED_BE32_TO_CPU (table.bsl_start);
+ atr_disk->bsl_count = PED_BE32_TO_CPU (table.bsl_count);
+ atr_disk->HDX_comp = 0;
+
+ /* AHDI primary partitions */
+ pnum = 1; xgm = 0; pcount = 0;
+ for (i = 0; i < N_AHDI; i++) {
+ if (!atr_part_used (&table.part[i]))
+ continue;
+
+ pcount++;
+
+ if (atr_pid_eq (table.part[i].id, "XGM")) {
+
+ atr_disk->format = FMT_XGM;
+ xgm = 1;
+ if (!atr_parse_add_rawpart(disk, PED_PARTITION_EXTENDED,
+ 0, 0, &table.part[i] )
+ || !atr_read_logicals (
+ disk,
+ PED_BE32_TO_CPU (table.part[i].start),
+ &pnum ) )
+ goto error;
+
+ } else {
+
+ if (!atr_parse_add_rawpart (disk, PED_PARTITION_NORMAL,
+ 0, pnum, &table.part[i] ) )
+ goto error;
+ pnum++;
+ }
+ }
+
+ /* If no XGM partition has been found, the AHDI table is not empty, */
+ /* the first entry is valid and its ID ok for ICD, then we parse the */
+ /* ICD table. */
+ if (!xgm && pcount != 0
+ && atr_part_valid (&table.icd_part[0], rs_hd_size)
+ && atr_part_known (&table.icd_part[0], atr_known_icd_pid))
+ for (i = 0; i < N_ICD; i++) {
+
+ if (!atr_part_known (&table.icd_part[i], atr_known_icd_pid)
+ || !atr_part_used (&table.icd_part[i]))
+ continue;
+ atr_disk->format = FMT_ICD;
+
+ if (!atr_parse_add_rawpart (disk, PED_PARTITION_NORMAL,
+ 0, pnum, &table.icd_part[i] ) )
+ goto error;
+ pnum++;
+ }
+
+ atr_disk->has_been_read = 1;
+ return 1;
+
+error:
+ ped_disk_delete_all (disk);
+ atr_disk_reset (atr_disk);
+ return 0;
+}
+
+/* Returns the number of the first logical partition or -1 if not found */
+static int
+atr_find_first_log (const PedDisk* disk)
+{
+ PedPartition* part;
+ int first_log, last;
+
+ last = ped_disk_get_last_partition_num (disk);
+
+ for (first_log = 1; first_log <= last; first_log++) {
+ if ((part = ped_disk_get_partition (disk, first_log))
+ && (part->type & PED_PARTITION_LOGICAL))
+ break;
+ }
+
+ return first_log > last ? -1 : first_log;
+}
+
+#ifndef DISCOVER_ONLY
+static int
+atari_clobber (PedDevice* dev)
+{
+ AtariRawTable table;
+
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (atari_probe (dev));
+
+ if (!ped_device_read (dev, &table, 0, 1))
+ return 0;
+
+ /* clear anything but the boot code and the optional ICD table */
+ memset (table.boot_code + offsetof (AtariRawTable, hd_size),
+ 0,
+ PED_SECTOR_SIZE_DEFAULT - offsetof (AtariRawTable, hd_size));
+
+ return ped_device_write (dev, &table, 0, 1);
+}
+
+/* Computes the checksum of the root sector */
+static uint16_t
+atr_calc_rs_sum (const AtariRawTable* table)
+{
+ const uint16_t* word = (uint16_t*)(table);
+ const uint16_t* end = (uint16_t*)(table + 1);
+ uint16_t sum;
+
+ for (sum = 0; word < end; word++)
+ sum += PED_BE16_TO_CPU(*word);
+
+ return sum;
+}
+
+/* Returns 1 if the root sector is bootable, else returns 0 */
+static int
+atr_is_boot_table (const AtariRawTable* table)
+{
+ return atr_calc_rs_sum (table) == BOOTABLE_CKSUM;
+}
+
+/*
+ * Returns 1 if sign belongs to a set of `forbidden' signatures.
+ * (e.g.: 55AA which is the MSDOS siganture...)
+ * Only used for non bootable root sector since the signature of
+ * a bootable one is unique.
+ */
+static int _GL_ATTRIBUTE_PURE
+atr_sign_is_forbidden (uint16_t sign)
+{
+ const uint16_t* forbidden;
+
+ for (forbidden = atr_forbidden_sign; *forbidden; forbidden++) {
+ if (sign == *forbidden)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Updates table->checksum so the RS will be considered bootable (or not) */
+static void
+atr_table_set_boot (AtariRawTable* table, int boot)
+{
+ uint16_t boot_cksum, noboot_cksum;
+ uint16_t sum;
+
+ table->checksum = 0;
+ sum = atr_calc_rs_sum (table);
+ boot_cksum = BOOTABLE_CKSUM - sum;
+
+ if (boot) {
+ table->checksum = PED_CPU_TO_BE16 (boot_cksum);
+ return;
+ }
+
+ noboot_cksum = NONBOOT_CKSUM - sum;
+
+ while (atr_sign_is_forbidden (noboot_cksum)
+ || noboot_cksum == boot_cksum)
+ noboot_cksum++;
+
+ table->checksum = PED_CPU_TO_BE16 (noboot_cksum);
+}
+
+/* Fill an used partition entry */
+static void
+atr_fill_raw_entry (AtariRawPartition* rawpart, uint8_t flag, const char* id,
+ uint32_t start, uint32_t size )
+{
+ rawpart->flag = PART_FLAG_USED | flag;
+ atr_pid_assign (rawpart->id, id);
+ rawpart->start = PED_CPU_TO_BE32 (start);
+ rawpart->size = PED_CPU_TO_BE32 (size);
+}
+
+static int
+atr_write_logicals (const PedDisk* disk)
+{
+ AtariRawTable table;
+ PedPartition* log_curr;
+ PedPartition* log_next;
+ PedPartition* ext;
+ PedPartition* part;
+ PedSector exts;
+ PedSector parts;
+ AtariPart* atr_part;
+ int first_log, pnum, i;
+
+ PED_ASSERT (disk != NULL);
+
+ ext = ped_disk_extended_partition (disk);
+ exts = parts = ext->geom.start;
+
+ pnum = first_log = atr_find_first_log (disk);
+
+ while (1) {
+ if (pnum != -1) {
+ log_curr = ped_disk_get_partition (disk, pnum);
+ log_next = ped_disk_get_partition (disk, pnum + 1);
+ } else {
+ log_curr = log_next = NULL;
+ }
+
+ if (log_curr && !(log_curr->type & PED_PARTITION_LOGICAL))
+ log_curr = NULL;
+ if (log_next && !(log_next->type & PED_PARTITION_LOGICAL))
+ log_next = NULL;
+
+ PED_ASSERT (pnum == first_log || log_curr);
+
+ part = ped_disk_get_partition_by_sector (disk, parts);
+ if (part && ped_partition_is_active (part)) {
+ if (log_curr)
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("No room at sector %lli to store ARS "
+ "of logical partition %d."),
+ parts, pnum );
+ else
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("No room at sector %lli to store ARS."),
+ parts );
+ return 0;
+ }
+
+ if (!ped_device_read (disk->dev, &table, parts, 1))
+ return 0;
+
+ if (!log_curr) {
+ PED_ASSERT (!log_next);
+
+ for (i = 0; i < N_AHDI; i++)
+ table.part[i].flag &= ~PART_FLAG_USED;
+ } else {
+ atr_part = ATARI_PART (log_curr);
+ atr_fill_raw_entry (&table.part[0], atr_part->flag,
+ atr_part->part_id,
+ log_curr->geom.start - parts,
+ log_curr->geom.length );
+
+ for (i = 1; i < N_AHDI; i++)
+ table.part[i].flag &= ~PART_FLAG_USED;
+
+ if (log_next) {
+ atr_fill_raw_entry (&table.part[1], 0, "XGM",
+ log_next->geom.start - 1 - exts,
+ log_next->geom.length + 1 );
+ }
+ }
+
+ /* TODO: check if we can set that bootable, and when */
+ atr_table_set_boot (&table, 0);
+
+ if (!ped_device_write (disk->dev, &table, parts, 1))
+ return 0;
+
+ if (!log_next)
+ break;
+
+ parts = log_next->geom.start - 1;
+ pnum++;
+ }
+
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+_disk_logical_partition_count (const PedDisk* disk)
+{
+ PedPartition* walk;
+
+ int count = 0;
+
+ PED_ASSERT (disk != NULL);
+ for (walk = disk->part_list; walk;
+ walk = ped_disk_next_partition (disk, walk)) {
+ if (ped_partition_is_active (walk)
+ && (walk->type & PED_PARTITION_LOGICAL))
+ count++;
+ }
+
+ return count;
+}
+
+/* Load the HD size from the table and ask to fix it if != device size. */
+static int
+atr_load_fix_hdsize (const PedDisk* disk, uint32_t* rs_hd_size, AtariRawTable* table)
+{
+ AtariDisk* atr_disk = ATARI_DISK (disk);
+ int result = PED_EXCEPTION_UNHANDLED;
+
+ *rs_hd_size = PED_BE32_TO_CPU (table->hd_size);
+ if (*rs_hd_size != disk->dev->length) {
+ if (atr_disk->has_been_read) {
+ result = ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE_CANCEL,
+ _("The sector count that is stored in the "
+ "partition table does not correspond "
+ "to the size of your device. Do you "
+ "want to fix the partition table?") );
+ if (result == PED_EXCEPTION_CANCEL)
+ return 0;
+ }
+
+ if (result == PED_EXCEPTION_UNHANDLED)
+ result = PED_EXCEPTION_FIX;
+
+ if (result == PED_EXCEPTION_FIX) {
+ *rs_hd_size = disk->dev->length;
+ table->hd_size = PED_CPU_TO_BE32(*rs_hd_size);
+ }
+ }
+ return 1;
+}
+
+/* Try to init the HDX compatibility Bad Sectors List. */
+static int
+atr_empty_init_bsl (const PedDisk* disk)
+{
+ uint8_t zeros[PED_SECTOR_SIZE_DEFAULT];
+ PedSector sec;
+ PedPartition* part;
+ AtariDisk* atr_disk = ATARI_DISK (disk);
+
+ memset (zeros, 0, PED_SECTOR_SIZE_DEFAULT);
+ for (sec = atr_disk->bsl_start;
+ sec < atr_disk->bsl_start + atr_disk->bsl_count;
+ sec++ ) {
+ if (sec == atr_disk->bsl_start)
+ zeros[3] = 0xA5;
+ else
+ zeros[3] = 0;
+ part = ped_disk_get_partition_by_sector (disk, sec);
+ if (part && ped_partition_is_active (part)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("No room at sector %lli to store BSL."),
+ sec );
+ return 0;
+ }
+ ped_device_write (disk->dev, zeros, sec, 1);
+ }
+ atr_disk->HDX_comp = 0;
+ return 1;
+}
+
+static int
+atari_write (const PedDisk* disk)
+{
+ AtariRawTable table;
+ AtariDisk* atr_disk;
+ AtariPart* atr_part;
+ PedPartition* log;
+ PedPartition* ext_part;
+ PedPartition* part = NULL;
+ uint32_t rs_hd_size;
+ int i, xgm_begin, pnum, append_ext;
+ int put_sign, boot, prim_count, last_num;
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ atr_disk = ATARI_DISK (disk);
+ PED_ASSERT (atr_disk != NULL);
+
+ prim_count = ped_disk_get_primary_partition_count (disk);
+ last_num = ped_disk_get_last_partition_num (disk);
+ ext_part = ped_disk_extended_partition (disk);
+
+ /* WARNING: similar/related code in atari_enumerate */
+ xgm_begin = ((log = ped_disk_get_partition (disk, 1))
+ && (log->type & PED_PARTITION_LOGICAL));
+ PED_ASSERT (atr_disk->format != FMT_ICD || ext_part == NULL);
+ PED_ASSERT (atr_disk->format != FMT_XGM || prim_count + xgm_begin <= N_AHDI);
+ PED_ASSERT (atr_disk->format != FMT_AHDI || (ext_part == NULL && prim_count + xgm_begin <= N_AHDI));
+
+ /* Device Spec ok for Atari label? */
+ if (!atr_can_use_dev (disk->dev))
+ goto error;
+
+ if (!ped_device_read (disk->dev, (void*) &table, 0, 1))
+ goto error;
+
+ boot = atr_is_boot_table (&table);
+
+ table.bsl_start = PED_CPU_TO_BE32 (atr_disk->bsl_start);
+ table.bsl_count = PED_CPU_TO_BE32 (atr_disk->bsl_count);
+
+ /* Before anything else check the sector count and */
+ /* fix it if necessary */
+ if (!atr_load_fix_hdsize (disk, &rs_hd_size, &table))
+ goto error;
+
+ append_ext = (ext_part != NULL)
+ && (_disk_logical_partition_count (disk) == 0);
+
+ /* Fill the AHDI table */
+ put_sign = (prim_count == 0);
+ pnum = 1;
+ for (i = 0; i < N_AHDI; i++) {
+ if (pnum > last_num)
+ part = NULL;
+ else while (pnum <= last_num
+ && !(part = ped_disk_get_partition (disk, pnum)))
+ pnum++;
+
+ if (put_sign) {
+ atr_put_signature_entry (&table.part[i]);
+ continue;
+ }
+
+ if (!part && i != 0 && append_ext) {
+ part = ext_part;
+ append_ext = 0;
+ }
+
+ if (!part || (i == 0 && xgm_begin)) {
+ table.part[i].flag &= ~PART_FLAG_USED;
+ continue;
+ }
+
+ if (part->type & PED_PARTITION_LOGICAL)
+ part = ext_part;
+
+ PED_ASSERT (part != NULL);
+
+ atr_part = ATARI_PART (part);
+ atr_fill_raw_entry (&table.part[i], atr_part->flag,
+ atr_part->part_id, part->geom.start,
+ part->geom.length );
+
+ if (part->type & PED_PARTITION_EXTENDED) {
+ while (pnum <= last_num) {
+ part = ped_disk_get_partition (disk, pnum);
+ if (part &&
+ !(part->type & PED_PARTITION_LOGICAL))
+ break;
+ pnum++;
+ }
+ } else
+ pnum++;
+ }
+
+ if ((ext_part != NULL || atr_disk->format == FMT_AHDI)
+ && pnum <= last_num) {
+ ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
+ _("There were remaining partitions after filling "
+ "the main AHDI table.") );
+ goto error;
+ }
+
+ /* Leave XGM or ICD mode if uneeded */
+ if (pnum > last_num
+ && (atr_disk->format == FMT_ICD || ext_part == NULL))
+ atr_disk->format = FMT_AHDI;
+
+ /* If AHDI mode, check that no ICD will be detected */
+ /* and propose to fix */
+ if (atr_disk->format == FMT_AHDI
+ && atr_part_valid (&table.icd_part[0], rs_hd_size)
+ && atr_part_known (&table.icd_part[0], atr_known_icd_pid)) {
+ int result = PED_EXCEPTION_UNHANDLED;
+ result = ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_YES_NO_CANCEL,
+ _("The main AHDI table has been filled with all "
+ "partitions but the ICD table is not empty "
+ "so more partitions of unknown size and position "
+ "will be detected by ICD compatible software. Do "
+ "you want to invalidate the ICD table?") );
+ if (result == PED_EXCEPTION_YES
+ || result == PED_EXCEPTION_UNHANDLED)
+ table.icd_part[0].flag &= ~PART_FLAG_USED;
+ else if (result == PED_EXCEPTION_CANCEL)
+ goto error;
+ }
+
+ if (put_sign)
+ goto write_to_dev;
+
+ /* Fill the ICD table */
+ if (atr_disk->format == FMT_ICD)
+ for (i = 0; i < N_ICD; i++) {
+ if (pnum > last_num)
+ part = NULL;
+ else while (pnum <= last_num
+ && !(part = ped_disk_get_partition (disk, pnum)))
+ pnum++;
+
+ if (!part) {
+ table.icd_part[i].flag &= ~PART_FLAG_USED;
+ continue;
+ }
+
+ if (part->type & PED_PARTITION_EXTENDED
+ || part->type & PED_PARTITION_LOGICAL) {
+ ped_exception_throw (
+ PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("ICD entries can't contain extended or "
+ "logical partitions.") );
+ goto error;
+ }
+
+ atr_part = ATARI_PART (part);
+ atr_fill_raw_entry (&table.icd_part[i], atr_part->flag,
+ atr_part->icd_id, part->geom.start,
+ part->geom.length );
+
+ pnum++;
+ }
+
+ /* Write the chained list of logical partitions */
+ if (atr_disk->format == FMT_XGM) {
+ if (!atr_write_logicals (disk))
+ goto error;
+ }
+
+write_to_dev:
+ if (pnum <= last_num) {
+ ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
+ _("There were remaining partitions after filling "
+ "the tables.") );
+ goto error;
+ }
+
+ /* Do we need to do that in case of failure too??? */
+ atr_table_set_boot (&table, boot);
+
+ /* Commit the root sector... */
+ if (!ped_device_write (disk->dev, (void*) &table, 0, 1)
+ || !ped_device_sync (disk->dev))
+ goto error;
+
+ /* Try to init the HDX compatibility Bad Sectors List if needed. */
+ if (atr_disk->HDX_comp && !atr_empty_init_bsl (disk))
+ goto error;
+
+ atr_disk->has_been_read = 1;
+ return ped_device_sync (disk->dev);
+
+error:
+ atr_disk->has_been_read = 0;
+ return 0;
+}
+#endif
+
+/* If extended partition in ICD mode, generate an error and returns 1 */
+/* else returns 0 */
+static int
+atr_xgm_in_icd (const PedDisk* disk, PedPartitionType part_type)
+{
+ AtariDisk* atrdisk;
+
+ PED_ASSERT (disk != NULL);
+
+ if (part_type & PED_PARTITION_EXTENDED) {
+ atrdisk = ATARI_DISK (disk);
+ if (atrdisk->format == FMT_ICD) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("You can't use an extended XGM partition in "
+ "ICD mode (more than %d primary partitions, if "
+ "XGM is the first one it counts for two)."),
+ N_AHDI );
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static PedPartition*
+atari_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ AtariPart* atrpart;
+
+ if (atr_xgm_in_icd(disk, part_type))
+ return 0;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+ if (ped_partition_is_active (part)) {
+ part->disk_specific = atrpart = ped_malloc (sizeof (AtariPart));
+ if (!atrpart)
+ goto error_free_part;
+ memset (atrpart, 0, sizeof (AtariPart));
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ _ped_partition_free (part);
+error:
+ return NULL;
+}
+
+static PedPartition*
+atari_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+ if (ped_partition_is_active (part))
+ memcpy (new_part->disk_specific, part->disk_specific,
+ sizeof (AtariPart));
+
+ return new_part;
+}
+
+static void
+atari_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part)) {
+ PED_ASSERT (part->disk_specific != NULL);
+ free (part->disk_specific);
+ }
+ _ped_partition_free (part);
+}
+
+/* Note: fs_type is NULL for extended partitions */
+static int
+atari_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type)
+{
+ AtariPart* atrpart;
+ AtariFS2PartId* fs2id;
+ PED_ASSERT (part != NULL);
+ atrpart = ATARI_PART (part);
+ PED_ASSERT (atrpart != NULL);
+
+ part->fs_type = fs_type;
+
+ if (atr_xgm_in_icd(part->disk, part->type))
+ return 0;
+
+ if (part->type & PED_PARTITION_EXTENDED) {
+ strcpy (atrpart->part_id, "XGM");
+ strcpy (atrpart->icd_id, "XGM");
+ return 1;
+ }
+
+ if (!fs_type) {
+ strcpy (atrpart->part_id, "RAW");
+ strcpy (atrpart->icd_id, "RAW");
+ return 1;
+ }
+
+ for (fs2id = atr_fs2pid; fs2id->fs; fs2id++) {
+ if (!*fs2id->fs /* default entry */
+ || ((!strcmp (fs_type->name, fs2id->fs)
+ && part->geom.length < fs2id->max_sectors))) {
+
+ strcpy (atrpart->part_id, fs2id->pid);
+ if (atr_pid_known (fs2id->pid, atr_known_icd_pid))
+ strcpy (atrpart->icd_id, fs2id->pid);
+ else
+ strcpy (atrpart->icd_id, "RAW");
+
+ break;
+ }
+ }
+ PED_ASSERT (fs2id->fs != NULL);
+
+ return 1;
+}
+
+static int
+atari_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ AtariPart* atr_part;
+ AtariPartID2BootFlag* bf;
+
+ PED_ASSERT (part != NULL);
+ atr_part = ATARI_PART (part);
+ PED_ASSERT (atr_part != NULL);
+
+ if (flag != PED_PARTITION_BOOT)
+ return 0;
+
+ if (state == 0) {
+ atr_part->flag = 0;
+ } else {
+ for (bf = atr_pid2bf; *bf->pid; bf++) {
+ if (atr_pid_eq (bf->pid, atr_part->part_id))
+ break;
+ }
+ atr_part->flag = bf->flag;
+ }
+
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+atari_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ AtariPart* atr_part;
+
+ PED_ASSERT (part != NULL);
+ atr_part = ATARI_PART (part);
+ PED_ASSERT (atr_part != NULL);
+
+ if (flag != PED_PARTITION_BOOT)
+ return 0;
+
+ return (atr_part->flag != 0);
+}
+
+static int
+atari_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ if (flag == PED_PARTITION_BOOT)
+ return 1;
+
+ return 0;
+}
+
+/* Adapted from disk_dos */
+static PedConstraint*
+atr_log_constraint (const PedPartition* part)
+{
+ const PedGeometry* geom = &part->geom;
+ PedGeometry safe_space;
+ PedSector min_start;
+ PedSector max_end;
+ PedDisk* disk;
+ PedDevice* dev;
+ PedPartition* ext_part;
+ PedPartition* walk;
+ int first_log, not_first;
+
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->dev != NULL);
+ ext_part = ped_disk_extended_partition (part->disk);
+ PED_ASSERT (ext_part != NULL);
+
+ dev = (disk = part->disk) -> dev;
+
+ first_log = atr_find_first_log (disk);
+ if (first_log == -1)
+ first_log = part->num;
+
+ not_first = (part->num != first_log);
+
+ walk = ext_part->part_list;
+
+ min_start = ext_part->geom.start + 1 + not_first;
+ max_end = ext_part->geom.end;
+
+ while (walk != NULL
+ && ( walk->geom.start - (walk->num != first_log)
+ < geom->start - not_first
+ || walk->geom.start - (walk->num != first_log)
+ < min_start ) ) {
+ if (walk != part && ped_partition_is_active (walk))
+ min_start = walk->geom.end + 1 + not_first;
+ walk = walk->next;
+ }
+
+ while (walk && (walk == part || !ped_partition_is_active (walk)))
+ walk = walk->next;
+
+ if (walk)
+ max_end = walk->geom.start - 1 - (walk->num != first_log);
+
+ if (min_start >= max_end)
+ return NULL;
+
+ ped_geometry_init (&safe_space, dev, min_start,
+ max_end - min_start + 1);
+ return ped_constraint_new_from_max (&safe_space);
+}
+
+/* Adapted from disk_dos */
+static PedGeometry*
+art_min_extended_geom (const PedPartition* ext_part)
+{
+ PedDisk* disk = ext_part->disk;
+ PedPartition* walk;
+ PedGeometry* min_geom;
+ int first_log;
+
+ first_log = atr_find_first_log (disk);
+ if (first_log == -1)
+ return NULL;
+
+ walk = ped_disk_get_partition (disk, first_log);
+ PED_ASSERT (walk->type & PED_PARTITION_LOGICAL);
+ min_geom = ped_geometry_duplicate (&walk->geom);
+ if (!min_geom)
+ return NULL;
+ ped_geometry_set_start (min_geom, walk->geom.start - 1);
+
+ for (walk = ext_part->part_list; walk; walk = walk->next) {
+ if (!ped_partition_is_active (walk) || walk->num == first_log)
+ continue;
+ if (walk->geom.start < min_geom->start)
+ ped_geometry_set_start (min_geom, walk->geom.start - 2);
+ if (walk->geom.end > min_geom->end)
+ ped_geometry_set_end (min_geom, walk->geom.end);
+ }
+
+ return min_geom;
+}
+
+/* Adapted from disk_dos */
+static PedConstraint*
+atr_ext_constraint (const PedPartition* part)
+{
+ PedGeometry start_range;
+ PedGeometry end_range;
+ PedConstraint* constraint;
+ PedDevice* dev;
+ PedDisk* disk;
+ PedGeometry* min;
+
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->dev != NULL);
+
+ dev = (disk = part->disk) -> dev;
+ min = art_min_extended_geom (part);
+
+ if (min) {
+ ped_geometry_init (&start_range, dev, 1, min->start);
+ ped_geometry_init (&end_range, dev, min->end,
+ dev->length - min->end);
+ ped_geometry_destroy (min);
+ } else {
+ ped_geometry_init (&start_range, dev, 1, dev->length - 1);
+ ped_geometry_init (&end_range, dev, 1, dev->length - 1);
+ }
+
+ constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
+ &start_range, &end_range, 1, dev->length);
+ return constraint;
+}
+
+static PedConstraint*
+atr_prim_constraint (const PedPartition* part)
+{
+ PedDevice* dev;
+ PedGeometry max;
+
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->dev != NULL);
+
+ dev = part->disk->dev;
+
+ ped_geometry_init (&max, dev, 1, dev->length - 1);
+ return ped_constraint_new_from_max (&max);
+}
+
+/* inspiration from disk_dos */
+static PedGeometry*
+_best_solution (PedGeometry* a, PedGeometry* b)
+{
+ if (!a)
+ return b;
+ if (!b)
+ return a;
+
+ if (a->length < b->length)
+ goto choose_b;
+
+ ped_geometry_destroy (b);
+ return a;
+
+choose_b:
+ ped_geometry_destroy (a);
+ return b;
+}
+
+/* copied from disk_dos */
+static PedGeometry*
+_try_constraint (const PedPartition* part, const PedConstraint* external,
+ PedConstraint* internal)
+{
+ PedConstraint* intersection;
+ PedGeometry* solution;
+
+ intersection = ped_constraint_intersect (external, internal);
+ ped_constraint_destroy (internal);
+ if (!intersection)
+ return NULL;
+
+ solution = ped_constraint_solve_nearest (intersection, &part->geom);
+ ped_constraint_destroy (intersection);
+ return solution;
+}
+
+/*
+ * internal is either the primary or extented constraint.
+ * If there's no BSL, the is the only internal constraint considered.
+ * If there's a BSL, try to fit the partition before or after (and
+ * choose the best fit, the one which results in the greatest size...)
+ */
+static int
+atr_prim_align (PedPartition* part, const PedConstraint* constraint,
+ PedConstraint* internal)
+{
+ PedDevice* dev;
+ AtariDisk* atr_disk;
+ PedConstraint* cut;
+ PedGeometry* solution = NULL;
+ PedGeometry max;
+ PedSector bsl_end;
+
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->dev != NULL);
+ dev = part->disk->dev;
+ atr_disk = ATARI_DISK (part->disk);
+ PED_ASSERT (atr_disk != NULL);
+
+ /* No BSL */
+ if (!atr_disk->bsl_start && !atr_disk->bsl_count) {
+ /* Note: _ped_partition_attempt_align will destroy internal */
+ return _ped_partition_attempt_align(part, constraint, internal);
+ }
+
+ /* BSL, try to fit before */
+ if (atr_disk->bsl_start > 1) {
+ ped_geometry_init (&max, dev, 1, atr_disk->bsl_start - 1);
+ cut = ped_constraint_new_from_max (&max);
+ solution = _best_solution (solution,
+ _try_constraint (part, constraint,
+ ped_constraint_intersect (internal, cut)));
+ ped_constraint_destroy (cut);
+ }
+
+ /* BSL, try to fit after, take the best solution */
+ bsl_end = atr_disk->bsl_start + atr_disk->bsl_count;
+ if (bsl_end < dev->length) {
+ ped_geometry_init (&max, dev, bsl_end, dev->length - bsl_end);
+ cut = ped_constraint_new_from_max (&max);
+ solution = _best_solution (solution,
+ _try_constraint (part, constraint,
+ ped_constraint_intersect (internal, cut)));
+ ped_constraint_destroy (cut);
+ }
+
+ ped_constraint_destroy (internal);
+
+ if (solution) {
+ ped_geometry_set (&part->geom, solution->start,
+ solution->length);
+ ped_geometry_destroy (solution);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+atari_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ switch (part->type) {
+ case PED_PARTITION_LOGICAL:
+ if (_ped_partition_attempt_align (part, constraint,
+ atr_log_constraint (part) ) )
+ return 1;
+ break;
+ case PED_PARTITION_EXTENDED:
+ if (atr_prim_align (part, constraint,
+ atr_ext_constraint (part) ) )
+ return 1;
+ break;
+ default:
+ if (atr_prim_align (part, constraint,
+ atr_prim_constraint (part) ) )
+ return 1;
+ break;
+ }
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+/* increment numbers of any non logical partition found after the last */
+/* logical one, to make room for a new logical partition */
+static int
+art_room_for_logic (PedDisk* disk)
+{
+ PedPartition* part;
+ int num, last_logic, last;
+
+ /* too many partitions ? */
+ last = ped_disk_get_last_partition_num (disk);
+ if (last >= MAXIMUM_PARTS)
+ return 0;
+
+ /* find the last logical partition */
+ last_logic = 0;
+ for (num = 1; num <= last; num++) {
+ part = ped_disk_get_partition (disk, num);
+ if (part && ped_partition_is_active (part)
+ && (part->type & PED_PARTITION_LOGICAL))
+ last_logic = num;
+ }
+
+ if (!last_logic)
+ return 1;
+
+ /* increment */
+ for (num = last; num > last_logic; num--) {
+ part = ped_disk_get_partition (disk, num);
+ if (part && ped_partition_is_active (part)
+ && !(part->type & ( PED_PARTITION_LOGICAL
+ | PED_PARTITION_EXTENDED))
+ && part->num > 0 )
+ part->num++;
+ }
+
+ return 1;
+}
+
+static int
+atari_partition_enumerate (PedPartition* part)
+{
+ AtariDisk* atrdisk;
+ PedPartition* ext_part;
+ PedPartition* log;
+ int i, want_icd, want_xgm, num_max, xgm_begin, prim_count;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ atrdisk = ATARI_DISK (part->disk);
+ PED_ASSERT (atrdisk != NULL);
+
+ /* WARNING: some similar/related code in atari_write */
+ /* This is quite a <hack> : this function is probably the only way */
+ /* to know something has been / is going to be modified in the table.*/
+ /* So we detect the current operation mode (AHDI/XGM/ICD) and report */
+ /* errors (in which case we refuse to operate...) */
+
+ prim_count = ped_disk_get_primary_partition_count (part->disk);
+ ext_part = ped_disk_extended_partition (part->disk);
+
+ /* <hack in the hack> : we can't reorder (yet) , so if we begin with */
+ /* XGM the first slot must be empty */
+ xgm_begin = ((log = ped_disk_get_partition (part->disk, 1))
+ && (log->type & PED_PARTITION_LOGICAL))
+ || ((part->num == -1)
+ && (part->type & PED_PARTITION_LOGICAL)
+ && !ped_disk_get_partition (part->disk, 1));
+ /* </hack in the hack> */
+
+ PED_ASSERT (atrdisk->format != FMT_ICD || ext_part == NULL);
+ PED_ASSERT (atrdisk->format != FMT_XGM
+ || prim_count + xgm_begin <= N_AHDI);
+ PED_ASSERT (atrdisk->format != FMT_AHDI
+ || (ext_part == NULL && prim_count + xgm_begin <= N_AHDI));
+
+ want_icd = ( ( prim_count
+ + xgm_begin
+ + ( (part->num == -1)
+ && !(part->type & PED_PARTITION_LOGICAL) ) )
+ > N_AHDI );
+ want_xgm = ( (part->type & PED_PARTITION_EXTENDED)
+ || ext_part != NULL );
+
+ if (!want_xgm && !want_icd)
+ atrdisk->format = FMT_AHDI;
+ else if (want_xgm && !want_icd)
+ atrdisk->format = FMT_XGM;
+ else if (!want_xgm && want_icd)
+ atrdisk->format = FMT_ICD;
+ else {
+ if (atr_xgm_in_icd (part->disk, PED_PARTITION_EXTENDED))
+ return 0;
+ else {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("You can't use more than %d primary partitions "
+ "(ICD mode) if you use an extended XGM "
+ "partition. If XGM is the first partition "
+ "it counts for two."),
+ N_AHDI );
+ return 0;
+ }
+ }
+ /* End of </hack> */
+
+
+ /* Ext will be numbered 0 and will stay 0... */
+ if (part->num == 0)
+ return 1;
+
+ if (part->num == -1) {
+
+ /* Linux don't show the ext part itself for Atari disk labels */
+ /* so we use number 0 (could use a big number too, but that */
+ /* would be less cute ;) */
+ if (part->type & PED_PARTITION_EXTENDED) {
+ part->num = 0;
+ return 1;
+ }
+
+ switch (atrdisk->format) {
+ case FMT_AHDI:
+ case FMT_ICD:
+ num_max = N_ICD + N_AHDI;
+ break;
+ case FMT_XGM:
+ num_max = MAXIMUM_PARTS;
+ break;
+ default:
+ num_max = 0;
+ PED_ASSERT (0);
+ }
+
+ /* make room for logical partitions */
+ if (part->type & PED_PARTITION_LOGICAL) {
+ if (!art_room_for_logic (part->disk))
+ goto error_alloc_failed;
+ }
+
+ /* find an unused number */
+ for (i = 1; i <= num_max; i++) {
+ if (!ped_disk_get_partition (part->disk, i)) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ } else {
+ /* find an unused number before or don't re-number */
+ for (i = 1; i < part->num; i++) {
+ if (!ped_disk_get_partition (part->disk, i)) {
+ part->num = i;
+ }
+ }
+ return 1;
+ }
+
+ /* failed to allocate a number */
+error_alloc_failed:
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a partition number."));
+#endif
+ return 0;
+}
+
+static int
+atr_creat_add_metadata (PedDisk* disk, PedSector start, PedSector end,
+ PedPartitionType type )
+{
+ PedPartition* new_part;
+ PedConstraint* const_exact;
+ int added;
+
+ type |= PED_PARTITION_METADATA;
+ new_part = ped_partition_new (disk, type, NULL, start, end);
+ if (!new_part)
+ goto error;
+
+ const_exact = ped_constraint_exact (&new_part->geom);
+ added = ped_disk_add_partition (disk, new_part, const_exact);
+ ped_constraint_destroy (const_exact);
+ if (!added)
+ goto error_destroy_part;
+
+ return 1;
+
+error_destroy_part:
+ ped_partition_destroy (new_part);
+error:
+ return 0;
+}
+
+static int
+atari_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* ext;
+ PedPartition* log;
+ AtariDisk* atr_disk;
+ int i;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ atr_disk = ATARI_DISK (disk);
+ PED_ASSERT (atr_disk != NULL);
+
+ /* allocate 1 sector for the disk label at the start */
+ if (!atr_creat_add_metadata (disk, 0, 0, 0))
+ return 0;
+
+ /* allocate the sectors containing the BSL */
+ if (atr_disk->bsl_start || atr_disk->bsl_count) {
+ if (!atr_creat_add_metadata (disk, atr_disk->bsl_start,
+ atr_disk->bsl_start
+ + atr_disk->bsl_count - 1, 0 ) )
+ return 0;
+ }
+
+ ext = ped_disk_extended_partition (disk);
+ if (ext) {
+ if (!atr_creat_add_metadata (disk, ext->geom.start,
+ ext->geom.start,
+ PED_PARTITION_LOGICAL ) )
+ return 0;
+
+ /* Find the first logical part */
+ for (i = 1; i <= ped_disk_get_last_partition_num (disk); i++)
+ if ((log = ped_disk_get_partition (disk, i))
+ && (log->type & PED_PARTITION_LOGICAL))
+ break;
+
+ for (log = ext->part_list; log; log = log->next) {
+ if ((log->type & ( PED_PARTITION_METADATA
+ | PED_PARTITION_FREESPACE))
+ || log->num == i)
+ continue;
+
+ if (!atr_creat_add_metadata (disk, log->geom.start-1,
+ log->geom.start-1,
+ PED_PARTITION_LOGICAL ) )
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+atari_get_max_primary_partition_count (const PedDisk* disk)
+{
+ AtariDisk* atr_disk;
+
+ PED_ASSERT (disk != NULL);
+ atr_disk = ATARI_DISK (disk);
+ PED_ASSERT (atr_disk != NULL);
+
+ return atr_disk->format == FMT_XGM ? N_AHDI : N_AHDI + N_ICD;
+}
+
+static bool
+atari_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ AtariDisk* atr_disk;
+
+ PED_ASSERT (disk != NULL);
+ atr_disk = ATARI_DISK (disk);
+ PED_ASSERT (atr_disk != NULL);
+
+ *max_n = atr_disk->format == FMT_XGM ? N_AHDI : N_AHDI + N_ICD;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions(atari)
+
+static PedDiskOps atari_disk_ops = {
+ clobber: NULL_IF_DISCOVER_ONLY (atari_clobber),
+ write: NULL_IF_DISCOVER_ONLY (atari_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (atari)
+};
+
+static PedDiskType atari_disk_type = {
+ next: NULL,
+ name: "atari",
+ ops: &atari_disk_ops,
+ features: PED_DISK_TYPE_EXTENDED
+};
+
+void
+ped_disk_atari_init ()
+{
+ PED_ASSERT (sizeof (AtariRawPartition) == 12);
+ PED_ASSERT (sizeof (AtariRawTable) == 512);
+ /* GNU Libc doesn't support NULL instead of the locale name */
+ PED_ASSERT ((atr_c_locale = newlocale(LC_ALL_MASK, "C", NULL)) != NULL);
+
+ ped_disk_type_register (&atari_disk_type);
+}
+
+void
+ped_disk_atari_done ()
+{
+ ped_disk_type_unregister (&atari_disk_type);
+ freelocale(atr_c_locale);
+}
diff --git a/libparted/labels/bsd.c b/libparted/labels/bsd.c
new file mode 100644
index 0000000..38bc64c
--- /dev/null
+++ b/libparted/labels/bsd.c
@@ -0,0 +1,654 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2007-2014, 2019-2023 Free Software Foundation,
+ Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Matt Wilson <msw@redhat.com>
+*/
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+/* struct's & #define's stolen from libfdisk, which probably came from
+ * Linux...
+ */
+
+#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
+#define BSD_MAXPARTITIONS 8
+#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
+
+#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
+#define BSD_DTYPE_MSCP 2 /* MSCP */
+#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
+#define BSD_DTYPE_SCSI 4 /* SCSI */
+#define BSD_DTYPE_ESDI 5 /* ESDI interface */
+#define BSD_DTYPE_ST506 6 /* ST506 etc. */
+#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
+#define BSD_DTYPE_FLOPPY 10 /* floppy */
+
+#define BSD_BBSIZE 8192 /* size of boot area, with label */
+#define BSD_SBSIZE 8192 /* max size of fs superblock */
+
+typedef struct _BSDRawPartition BSDRawPartition;
+typedef struct _BSDRawLabel BSDRawLabel;
+typedef struct _BSDDiskData BSDDiskData;
+
+struct _BSDRawPartition { /* the partition table */
+ uint32_t p_size; /* number of sectors in partition */
+ uint32_t p_offset; /* starting sector */
+ uint32_t p_fsize; /* file system basic fragment size */
+ uint8_t p_fstype; /* file system type, see below */
+ uint8_t p_frag; /* file system fragments per block */
+ uint16_t p_cpg; /* file system cylinders per group */
+} __attribute__((packed));
+
+struct _BSDRawLabel {
+ uint32_t d_magic; /* the magic number */
+ int16_t d_type; /* drive type */
+ int16_t d_subtype; /* controller/d_type specific */
+ int8_t d_typename[16]; /* type name, e.g. "eagle" */
+ int8_t d_packname[16]; /* pack identifier */
+ uint32_t d_secsize; /* # of bytes per sector */
+ uint32_t d_nsectors; /* # of data sectors per track */
+ uint32_t d_ntracks; /* # of tracks per cylinder */
+ uint32_t d_ncylinders; /* # of data cylinders per unit */
+ uint32_t d_secpercyl; /* # of data sectors per cylinder */
+ uint32_t d_secperunit; /* # of data sectors per unit */
+ uint16_t d_sparespertrack; /* # of spare sectors per track */
+ uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
+ uint32_t d_acylinders; /* # of alt. cylinders per unit */
+ uint16_t d_rpm; /* rotational speed */
+ uint16_t d_interleave; /* hardware sector interleave */
+ uint16_t d_trackskew; /* sector 0 skew, per track */
+ uint16_t d_cylskew; /* sector 0 skew, per cylinder */
+ uint32_t d_headswitch; /* head switch time, usec */
+ uint32_t d_trkseek; /* track-to-track seek, usec */
+ uint32_t d_flags; /* generic flags */
+#define NDDATA 5
+ uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
+#define NSPARE 5
+ uint32_t d_spare[NSPARE]; /* reserved for future use */
+ uint32_t d_magic2; /* the magic number (again) */
+ uint16_t d_checksum; /* xor of data incl. partitions */
+
+ /* file system and partition information: */
+ uint16_t d_npartitions; /* number of partitions in following */
+ uint32_t d_bbsize; /* size of boot area at sn0, bytes */
+ uint32_t d_sbsize; /* max size of fs superblock, bytes */
+#define D_PARTITIONS_WORDS 59
+ BSDRawPartition d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+} __attribute__((packed, aligned(2)));
+
+struct _BSDDiskData {
+ char boot_code[64];
+ BSDRawLabel label; /* label is offset by 64 bytes */
+ char unused[172]; /* May contain more partitions */
+} __attribute__((packed, aligned(2)));
+
+typedef struct {
+ uint8_t type;
+ int boot;
+ int raid;
+ int lvm;
+} BSDPartitionData;
+
+static PedDiskType bsd_disk_type;
+
+/* XXX fixme: endian? */
+static unsigned short
+xbsd_dkcksum (BSDRawLabel *lp) {
+ const u_short* word = (u_short*)(lp);
+ const u_short* end = word + D_PARTITIONS_WORDS + PED_LE16_TO_CPU(lp->d_npartitions);
+ u_short sum;
+
+ lp->d_checksum = 0;
+ for(sum=0; word < end; word++)
+ sum ^= PED_LE16_TO_CPU(*word);
+ return sum;
+}
+
+/* XXX fixme: endian? */
+static void
+alpha_bootblock_checksum (void *boot) {
+ uint64_t* dp = (uint64_t *)boot;
+ uint64_t sum=0;
+ int i;
+
+ for (i = 0; i < 63; i++)
+ sum += dp[i];
+ dp[63] = sum;
+}
+
+static int
+bsd_probe (const PedDevice *dev)
+{
+ BSDRawLabel *label;
+
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size < 512)
+ return 0;
+
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+
+ label = &((BSDDiskData*) s0)->label;
+
+ /* check magic */
+ bool found = PED_LE32_TO_CPU (label->d_magic) == BSD_DISKMAGIC;
+ free (s0);
+ return found;
+}
+
+static PedDisk*
+bsd_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ BSDDiskData* bsd_specific;
+ BSDRawLabel *label;
+
+ PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ disk = _ped_disk_alloc ((PedDevice*)dev, &bsd_disk_type);
+ if (!disk)
+ goto error;
+ disk->disk_specific = bsd_specific = ped_calloc (sizeof (BSDDiskData));
+ if (!bsd_specific)
+ goto error_free_disk;
+
+ /* Initialize the disk label's default values */
+ label = &bsd_specific->label;
+ label->d_magic = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
+ label->d_type = PED_CPU_TO_LE16 (BSD_DTYPE_SCSI);
+ label->d_flags = 0;
+ label->d_secsize = PED_CPU_TO_LE16 (dev->sector_size);
+ label->d_nsectors = PED_CPU_TO_LE32 (dev->bios_geom.sectors);
+ label->d_ntracks = PED_CPU_TO_LE32 (dev->bios_geom.heads);
+ label->d_ncylinders = PED_CPU_TO_LE32 (dev->bios_geom.cylinders);
+ label->d_secpercyl = PED_CPU_TO_LE32 (dev->bios_geom.sectors
+ * dev->bios_geom.heads);
+ label->d_secperunit
+ = PED_CPU_TO_LE32 (dev->bios_geom.sectors
+ * dev->bios_geom.heads
+ * dev->bios_geom.cylinders);
+
+ label->d_rpm = PED_CPU_TO_LE16 (3600);
+ label->d_interleave = PED_CPU_TO_LE16 (1);
+ label->d_trackskew = 0;
+ label->d_cylskew = 0;
+ label->d_headswitch = 0;
+ label->d_trkseek = 0;
+
+ label->d_magic2 = PED_CPU_TO_LE32 (BSD_DISKMAGIC);
+ label->d_bbsize = PED_CPU_TO_LE32 (BSD_BBSIZE);
+ label->d_sbsize = PED_CPU_TO_LE32 (BSD_SBSIZE);
+
+ label->d_npartitions = 0;
+ label->d_checksum = xbsd_dkcksum (label);
+
+ return disk;
+
+error_free_disk:
+ free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk*
+bsd_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ BSDDiskData* new_bsd_data;
+ BSDDiskData* old_bsd_data = (BSDDiskData*) disk->disk_specific;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &bsd_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ new_bsd_data = (BSDDiskData*) new_disk->disk_specific;
+ memcpy (new_bsd_data, old_bsd_data, sizeof(BSDDiskData));
+ return new_disk;
+}
+
+static void
+bsd_free (PedDisk* disk)
+{
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+static int
+bsd_read (PedDisk* disk)
+{
+ BSDDiskData* bsd_specific = (BSDDiskData*) disk->disk_specific;
+ BSDRawLabel* label;
+ int i;
+
+ ped_disk_delete_all (disk);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return 0;
+
+ memcpy (bsd_specific, s0, sizeof (BSDDiskData));
+ free (s0);
+
+ label = &bsd_specific->label;
+
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ PedPartition* part;
+ BSDPartitionData* bsd_part_data;
+ PedSector start;
+ PedSector end;
+
+ if (!label->d_partitions[i - 1].p_size
+ || !label->d_partitions[i - 1].p_fstype)
+ continue;
+ start = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset);
+ end = PED_LE32_TO_CPU(label->d_partitions[i - 1].p_offset)
+ + PED_LE32_TO_CPU(label->d_partitions[i - 1].p_size) - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, start, end);
+ if (!part)
+ goto error;
+ bsd_part_data = part->disk_specific;
+ bsd_part_data->type = label->d_partitions[i - 1].p_fstype;
+ part->num = i;
+ part->fs_type = ped_file_system_probe (&part->geom);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ if (constraint_exact == NULL)
+ goto error;
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok)
+ goto error;
+ }
+
+ return 1;
+
+error:
+ return 0;
+}
+
+static void
+_probe_and_add_boot_code (const PedDisk* disk)
+{
+ BSDDiskData *old_data;
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return;
+ old_data = (BSDDiskData*) s0;
+ if (old_data->boot_code [0]
+ && old_data->label.d_magic == PED_CPU_TO_LE32 (BSD_DISKMAGIC)) {
+ BSDDiskData *bsd_specific = (BSDDiskData*) disk->disk_specific;
+ memcpy (bsd_specific, old_data, sizeof (BSDDiskData));
+ }
+ free (s0);
+}
+
+#ifndef DISCOVER_ONLY
+static int
+bsd_write (const PedDisk* disk)
+{
+ BSDDiskData* bsd_specific;
+ BSDRawLabel* label;
+ BSDPartitionData* bsd_data;
+ PedPartition* part;
+ int i;
+ int max_part = 0;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ bsd_specific = (BSDDiskData*) disk->disk_specific;
+ label = &bsd_specific->label;
+
+ if (!bsd_specific->boot_code[0])
+ _probe_and_add_boot_code (disk);
+
+ memset (label->d_partitions, 0,
+ sizeof (BSDRawPartition) * BSD_MAXPARTITIONS);
+
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ part = ped_disk_get_partition (disk, i);
+ if (!part)
+ continue;
+ bsd_data = part->disk_specific;
+ label->d_partitions[i - 1].p_fstype = bsd_data->type;
+ label->d_partitions[i - 1].p_offset
+ = PED_CPU_TO_LE32 (part->geom.start);
+ label->d_partitions[i - 1].p_size
+ = PED_CPU_TO_LE32 (part->geom.length);
+ max_part = i;
+ }
+
+ label->d_npartitions = PED_CPU_TO_LE16 (max_part + 1);
+ label->d_checksum = xbsd_dkcksum (label);
+
+ alpha_bootblock_checksum (bsd_specific);
+
+ if (!ptt_write_sector (disk, bsd_specific,
+ sizeof (BSDDiskData)))
+ goto error;
+ return ped_device_sync (disk->dev);
+
+error:
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+bsd_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ BSDPartitionData* bsd_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = bsd_data = ped_malloc (sizeof (BSDPartitionData));
+ if (!bsd_data)
+ goto error_free_part;
+ bsd_data->type = 0;
+ bsd_data->boot = 0;
+ bsd_data->raid = 0;
+ bsd_data->lvm = 0;
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return 0;
+}
+
+static PedPartition*
+bsd_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ BSDPartitionData* new_bsd_data;
+ BSDPartitionData* old_bsd_data;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_bsd_data = (BSDPartitionData*) part->disk_specific;
+ new_bsd_data = (BSDPartitionData*) new_part->disk_specific;
+ new_bsd_data->type = old_bsd_data->type;
+ new_bsd_data->boot = old_bsd_data->boot;
+ new_bsd_data->raid = old_bsd_data->raid;
+ new_bsd_data->lvm = old_bsd_data->lvm;
+ return new_part;
+}
+
+static void
+bsd_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part))
+ free (part->disk_specific);
+ _ped_partition_free (part);
+}
+
+static int
+bsd_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ BSDPartitionData* bsd_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ if (!fs_type)
+ bsd_data->type = 0x8;
+ else if (is_linux_swap (fs_type->name))
+ bsd_data->type = 0x1;
+ else
+ bsd_data->type = 0x8;
+
+ return 1;
+}
+
+static int
+bsd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ BSDPartitionData* bsd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ bsd_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ bsd_data->boot = state;
+ return 1;
+ case PED_PARTITION_RAID:
+ if (state) {
+ bsd_data->lvm = 0;
+ }
+ bsd_data->raid = state;
+ return 1;
+ case PED_PARTITION_LVM:
+ if (state) {
+ bsd_data->raid = 0;
+ }
+ bsd_data->lvm = state;
+ return 1;
+ default:
+ ;
+ }
+ return 0;
+}
+
+static int _GL_ATTRIBUTE_PURE
+bsd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ BSDPartitionData* bsd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ bsd_data = part->disk_specific;
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ return bsd_data->boot;
+
+ case PED_PARTITION_RAID:
+ return bsd_data->raid;
+
+ case PED_PARTITION_LVM:
+ return bsd_data->lvm;
+
+ default:
+ ;
+ }
+ return 0;
+}
+
+static int
+bsd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ case PED_PARTITION_RAID:
+ case PED_PARTITION_LVM:
+ return 1;
+ default:
+ ;
+ }
+ return 0;
+}
+
+
+static int
+bsd_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return BSD_MAXPARTITIONS;
+}
+
+static bool
+bsd_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
+{
+ *max_n = BSD_MAXPARTITIONS;
+ return true;
+}
+
+static PedConstraint*
+_get_constraint (const PedDevice* dev)
+{
+ PedGeometry max;
+
+ ped_geometry_init (&max, dev, 1, dev->length - 1);
+ return ped_constraint_new_from_max (&max);
+}
+
+static int
+bsd_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ if (_ped_partition_attempt_align (part, constraint,
+ _get_constraint (part->disk->dev)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+bsd_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+ for (i = 1; i <= BSD_MAXPARTITIONS; i++) {
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number */
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a bsd disklabel slot."));
+#endif
+ return 0;
+}
+
+static int
+bsd_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* allocate 1 sector for the disk label at the start */
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL, 0, 0);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (bsd)
+
+static PedDiskOps bsd_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (bsd_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (bsd)
+};
+
+static PedDiskType bsd_disk_type = {
+ next: NULL,
+ name: "bsd",
+ ops: &bsd_disk_ops,
+ features: 0
+};
+
+void
+ped_disk_bsd_init ()
+{
+ PED_ASSERT (sizeof (BSDRawPartition) == 16);
+ PED_ASSERT (sizeof (BSDRawLabel) == 276);
+
+ ped_disk_type_register (&bsd_disk_type);
+}
+
+void
+ped_disk_bsd_done ()
+{
+ ped_disk_type_unregister (&bsd_disk_type);
+}
diff --git a/libparted/labels/dasd.c b/libparted/labels/dasd.c
new file mode 100644
index 0000000..1d99458
--- /dev/null
+++ b/libparted/labels/dasd.c
@@ -0,0 +1,1032 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2007-2014, 2019-2023 Free Software Foundation,
+ Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Phil Knirsch <phil@redhat.de>
+ Harald Hoyer <harald@redhat.de>
+*/
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include <parted/vtoc.h>
+#include <parted/fdasd.h>
+#include <arch/linux.h>
+
+#include <libintl.h>
+#if ENABLE_NLS
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+#define PARTITION_LINUX_SWAP 0x82
+#define PARTITION_LINUX 0x83
+#define PARTITION_LINUX_LVM 0x8e
+#define PARTITION_LINUX_RAID 0xfd
+
+extern void ped_disk_dasd_init ();
+extern void ped_disk_dasd_done ();
+
+#define DASD_NAME "dasd"
+
+typedef struct {
+ int type;
+ int system;
+} DasdPartitionData;
+
+typedef struct {
+ unsigned int format_type;
+ unsigned int label_block;
+ volume_label_t vlabel;
+} DasdDiskSpecific;
+
+static int dasd_probe (const PedDevice *dev);
+static int dasd_read (PedDisk* disk);
+static int dasd_write (const PedDisk* disk);
+
+static PedPartition* dasd_partition_new (const PedDisk* disk,
+ PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start,
+ PedSector end);
+static PedPartition* dasd_partition_duplicate (const PedPartition *part);
+static void dasd_partition_destroy (PedPartition* part);
+static int dasd_partition_set_flag (PedPartition* part,
+ PedPartitionFlag flag,
+ int state);
+static int dasd_partition_get_flag (const PedPartition* part,
+ PedPartitionFlag flag);
+static int dasd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag);
+static int dasd_partition_align (PedPartition* part,
+ const PedConstraint* constraint);
+static int dasd_partition_enumerate (PedPartition* part);
+static int dasd_get_max_primary_partition_count (const PedDisk* disk);
+static bool dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n);
+static PedAlignment *dasd_get_partition_alignment(const PedDisk *disk);
+
+static PedDisk* dasd_alloc (const PedDevice* dev);
+static PedDisk* dasd_duplicate (const PedDisk* disk);
+static void dasd_free (PedDisk* disk);
+static int dasd_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type);
+static int dasd_alloc_metadata (PedDisk* disk);
+
+#include "pt-common.h"
+PT_define_limit_functions (dasd)
+
+static PedDiskOps dasd_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (dasd_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+ partition_set_type_id: NULL,
+ partition_get_type_id: NULL,
+ partition_set_type_uuid: NULL,
+ partition_get_type_uuid: NULL,
+
+ get_partition_alignment: dasd_get_partition_alignment,
+
+ PT_op_function_initializers (dasd)
+};
+
+static PedDiskType dasd_disk_type = {
+ next: NULL,
+ name: "dasd",
+ ops: &dasd_disk_ops,
+ features: 0
+};
+
+struct flag_id_mapping_t
+{
+ enum _PedPartitionFlag flag;
+ int type_id;
+};
+
+static const struct flag_id_mapping_t flag_id_mapping[] =
+{
+ { PED_PARTITION_LVM, PARTITION_LINUX_LVM },
+ { PED_PARTITION_RAID, PARTITION_LINUX_RAID },
+ { PED_PARTITION_SWAP, PARTITION_LINUX_SWAP },
+};
+
+static const struct flag_id_mapping_t* _GL_ATTRIBUTE_CONST
+dasd_find_flag_id_mapping (PedPartitionFlag flag)
+{
+ int n = sizeof(flag_id_mapping) / sizeof(flag_id_mapping[0]);
+
+ for (int i = 0; i < n; ++i)
+ if (flag_id_mapping[i].flag == flag)
+ return &flag_id_mapping[i];
+
+ return NULL;
+}
+
+static PedDisk*
+dasd_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific *disk_specific;
+ char volser[7];
+
+ PED_ASSERT (dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (dev);
+ disk = _ped_disk_alloc (dev, &dasd_disk_type);
+ if (!disk)
+ return NULL;
+
+ disk->disk_specific = disk_specific = ped_malloc(sizeof(DasdDiskSpecific));
+ if (!disk->disk_specific) {
+ free (disk);
+ return NULL;
+ }
+
+ /* CDL format, newer */
+ disk_specific->format_type = 2;
+ disk_specific->label_block = 2;
+
+ /* Setup volume label (for fresh disks) */
+ snprintf(volser, sizeof(volser), "0X%04X", arch_specific->devno);
+ vtoc_volume_label_init(&disk_specific->vlabel);
+ vtoc_volume_label_set_key(&disk_specific->vlabel, "VOL1");
+ vtoc_volume_label_set_label(&disk_specific->vlabel, "VOL1");
+ vtoc_volume_label_set_volser(&disk_specific->vlabel, volser);
+ vtoc_set_cchhb(&disk_specific->vlabel.vtoc,
+ VTOC_START_CC, VTOC_START_HH, 0x01);
+
+ return disk;
+}
+
+static PedDisk*
+dasd_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+
+ new_disk = ped_disk_new_fresh(disk->dev, &dasd_disk_type);
+
+ if (!new_disk)
+ return NULL;
+
+ memcpy(new_disk->disk_specific, disk->disk_specific,
+ sizeof(DasdDiskSpecific));
+
+ return new_disk;
+}
+
+static void
+dasd_free (PedDisk* disk)
+{
+ PED_ASSERT(disk != NULL);
+ /* Don't free disk->disk_specific first, in case _ped_disk_free
+ or one of its eventual callees ever accesses it. */
+ void *p = disk->disk_specific;
+ _ped_disk_free(disk);
+ free(p);
+}
+
+
+void
+ped_disk_dasd_init ()
+{
+ ped_disk_type_register(&dasd_disk_type);
+}
+
+void
+ped_disk_dasd_done ()
+{
+ ped_disk_type_unregister(&dasd_disk_type);
+}
+
+static int
+dasd_probe (const PedDevice *dev)
+{
+ LinuxSpecific* arch_specific;
+ struct fdasd_anchor anchor;
+
+ PED_ASSERT(dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC(dev);
+
+ /* add partition test here */
+ fdasd_initialize_anchor(&anchor);
+
+ if (fdasd_get_geometry(dev, &anchor, arch_specific->fd) == 0)
+ goto error_cleanup;
+
+ /* Labels are required on CDL formatted DASDs. */
+ if (fdasd_check_volume(&anchor, arch_specific->fd) &&
+ anchor.FBA_layout == 0)
+ goto error_cleanup;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+
+ error_cleanup:
+ fdasd_cleanup(&anchor);
+ ped_exception_throw(PED_EXCEPTION_ERROR,PED_EXCEPTION_IGNORE_CANCEL,
+ "Error while probing device %s.", dev->path);
+
+ return 0;
+}
+
+static int
+dasd_read (PedDisk* disk)
+{
+ int i;
+ char str[20];
+ PedDevice* dev;
+ PedPartition* part;
+ PedFileSystemType *fs;
+ PedSector start, end;
+ PedConstraint* constraint_exact;
+ partition_info_t *p;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ struct fdasd_anchor anchor;
+
+ PDEBUG;
+
+ PED_ASSERT (disk != NULL);
+ PDEBUG;
+ PED_ASSERT (disk->dev != NULL);
+ PDEBUG;
+
+ dev = disk->dev;
+
+ arch_specific = LINUX_SPECIFIC(dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ fdasd_initialize_anchor(&anchor);
+
+ if (fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd) == 0)
+ goto error_close_dev;
+
+ disk_specific->label_block = anchor.label_block;
+
+ if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
+ anchor.big_disk++;
+
+ /* check dasd for labels and vtoc */
+ if (fdasd_check_volume(&anchor, arch_specific->fd)) {
+ DasdPartitionData* dasd_data;
+
+ /* Kernel partitioning code will report 'implicit' partitions
+ * for non-CDL format DASDs even when there is no
+ * label/VTOC. */
+ if (anchor.FBA_layout == 0)
+ goto error_close_dev;
+
+ disk_specific->format_type = 1;
+
+ /* Register implicit partition */
+ ped_disk_delete_all (disk);
+
+ start = (PedSector) arch_specific->real_sector_size /
+ (PedSector) disk->dev->sector_size *
+ (PedSector) (anchor.label_block + 1);
+ end = disk->dev->length - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ start, end);
+ if (!part)
+ goto error_close_dev;
+
+ part->num = 1;
+ part->fs_type = ped_file_system_probe (&part->geom);
+ dasd_data = part->disk_specific;
+ dasd_data->type = 0;
+
+ if (!ped_disk_add_partition (disk, part, NULL))
+ goto error_close_dev;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+ }
+
+ /* Save volume label (read by fdasd_check_volume) for writing */
+ memcpy(&disk_specific->vlabel, anchor.vlabel, sizeof(volume_label_t));
+
+ ped_disk_delete_all (disk);
+
+ bool is_ldl = strncmp(anchor.vlabel->volkey,
+ vtoc_ebcdic_enc("LNX1", str, 4), 4) == 0;
+ bool is_cms = strncmp(anchor.vlabel->volkey,
+ vtoc_ebcdic_enc("CMS1", str, 4), 4) == 0;
+ if (is_ldl || is_cms) {
+ DasdPartitionData* dasd_data;
+
+ union vollabel {
+ volume_label_t ldl;
+ cms_volume_label_t cms;
+ };
+ union vollabel *cms_ptr1 = (union vollabel *) anchor.vlabel;
+ cms_volume_label_t *cms_ptr = &cms_ptr1->cms;
+ volume_label_t *ldl_ptr = &cms_ptr1->ldl;
+ int partition_start_block;
+
+ disk_specific->format_type = 1;
+
+ if (is_cms && cms_ptr->usable_count >= cms_ptr->block_count)
+ partition_start_block = 2; /* FBA DASD */
+ else
+ partition_start_block = 3; /* CKD DASD */
+
+ if (is_ldl)
+ start = (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size
+ * (long long) partition_start_block;
+ else if (cms_ptr->disk_offset == 0)
+ start = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) partition_start_block;
+ else
+ start = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) cms_ptr->disk_offset;
+
+ if (is_ldl)
+ if (ldl_ptr->ldl_version >= 0xf2)
+ end = (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size
+ * (long long) ldl_ptr->formatted_blocks - 1;
+ else
+ end = disk->dev->length - 1;
+ else
+ if (cms_ptr->disk_offset == 0)
+ end = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) cms_ptr->block_count - 1;
+ else
+ /*
+ Frankly, I do not understand why the last block
+ of the CMS reserved file is not included in the
+ partition; but this is the algorithm used by the
+ Linux kernel. See fs/partitions/ibm.c in the
+ Linux kernel source code.
+ */
+ end = (long long) cms_ptr->block_size
+ / (long long) disk->dev->sector_size
+ * (long long) (cms_ptr->block_count - 1) - 1;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL, start, end);
+ if (!part)
+ goto error_close_dev;
+
+ part->num = 1;
+ part->fs_type = ped_file_system_probe (&part->geom);
+ dasd_data = part->disk_specific;
+ dasd_data->type = 0;
+
+ if (!ped_disk_add_partition (disk, part, NULL))
+ goto error_close_dev;
+
+ fdasd_cleanup(&anchor);
+
+ return 1;
+ }
+
+ /* CDL format, newer */
+ disk_specific->format_type = 2;
+
+ p = anchor.first;
+ PDEBUG;
+
+ for (i = 1 ; i <= USABLE_PARTITIONS; i++) {
+ char *ch = p->f1->DS1DSNAM;
+ DasdPartitionData* dasd_data;
+
+
+ if (p->used != 0x01)
+ continue;
+
+ PDEBUG;
+
+ start = (long long)(long long) p->start_trk
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size;
+ end = (long long)((long long) p->end_trk + 1)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size - 1;
+ part = ped_partition_new(disk, PED_PARTITION_NORMAL, NULL,
+ start, end);
+ PDEBUG;
+
+ if (!part)
+ goto error_close_dev;
+
+ PDEBUG;
+
+ part->num = i;
+ part->fs_type = ped_file_system_probe(&part->geom);
+
+ vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ ch = strstr(p->f1->DS1DSNAM, "PART");
+
+ if (ch != NULL) {
+ strncpy(str, ch+9, 6);
+ str[6] = '\0';
+ }
+
+ dasd_data = part->disk_specific;
+
+ if (strncmp(PART_TYPE_RAID, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_RAID;
+ else if (strncmp(PART_TYPE_LVM, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_LVM;
+ else if (strncmp(PART_TYPE_SWAP, str, 6) == 0)
+ dasd_data->system = PARTITION_LINUX_SWAP;
+
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+
+ dasd_data->type = 0;
+
+ constraint_exact = ped_constraint_exact (&part->geom);
+ if (!constraint_exact)
+ goto error_close_dev;
+ if (!ped_disk_add_partition(disk, part, constraint_exact)) {
+ ped_constraint_destroy(constraint_exact);
+ goto error_close_dev;
+ }
+ ped_constraint_destroy(constraint_exact);
+
+ if (p->fspace_trk > 0) {
+ start = (long long)((long long) p->end_trk + 1)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size;
+ end = (long long)((long long) p->end_trk + 1 + p->fspace_trk)
+ * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size - 1;
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, start, end);
+
+ if (!part)
+ goto error_close_dev;
+
+ part->type = PED_PARTITION_FREESPACE;
+ constraint_exact = ped_constraint_exact(&part->geom);
+
+ if (!constraint_exact)
+ goto error_close_dev;
+ if (!ped_disk_add_partition(disk, part, constraint_exact)) {
+ ped_constraint_destroy(constraint_exact);
+ goto error_close_dev;
+ }
+
+ ped_constraint_destroy (constraint_exact);
+ }
+
+ p = p->next;
+ }
+
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 1;
+
+error_close_dev:
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 0;
+}
+
+static int
+dasd_update_type (const PedDisk* disk, struct fdasd_anchor *anchor,
+ partition_info_t *part_info[USABLE_PARTITIONS])
+{
+ PedPartition* part;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+
+ arch_specific = LINUX_SPECIFIC(disk->dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ unsigned int i;
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ partition_info_t *p;
+ char *ch = NULL;
+ DasdPartitionData* dasd_data;
+
+ PDEBUG;
+
+ part = ped_disk_get_partition(disk, i);
+ if (!part)
+ continue;
+
+ PDEBUG;
+
+ dasd_data = part->disk_specific;
+ p = part_info[i - 1];
+
+ if (!p ) {
+ PDEBUG;
+ continue;
+ }
+
+ vtoc_ebcdic_dec(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ ch = strstr(p->f1->DS1DSNAM, "PART");
+
+ PDEBUG;
+ if (ch == NULL) {
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ PDEBUG;
+ continue;
+ }
+
+ ch += 9;
+
+ switch (dasd_data->system) {
+ case PARTITION_LINUX_LVM:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_LVM, 6);
+ break;
+ case PARTITION_LINUX_RAID:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_RAID, 6);
+ break;
+ case PARTITION_LINUX:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_NATIVE, 6);
+ break;
+ case PARTITION_LINUX_SWAP:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_SWAP, 6);
+ break;
+ default:
+ PDEBUG;
+ strncpy(ch, PART_TYPE_NATIVE, 6);
+ break;
+ }
+
+ anchor->vtoc_changed++;
+ vtoc_ebcdic_enc(p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ }
+
+ return 1;
+}
+
+static int
+dasd_write (const PedDisk* disk)
+{
+ DasdPartitionData* dasd_data;
+ PedPartition* part;
+ int i;
+ partition_info_t *p;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ struct fdasd_anchor anchor;
+ partition_info_t *part_info[USABLE_PARTITIONS];
+
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+
+ PDEBUG;
+
+ /* If not formated in CDL, don't write anything. */
+ if (disk_specific->format_type == 1) {
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The partition table of DASD-LDL device cannot be changed.\n"));
+ return 1;
+ }
+
+ /* initialize the anchor */
+ fdasd_initialize_anchor(&anchor);
+ if (fdasd_get_geometry(disk->dev, &anchor, arch_specific->fd) == 0)
+ goto error;
+
+ fdasd_check_volume(&anchor, arch_specific->fd);
+ memcpy(anchor.vlabel, &disk_specific->vlabel, sizeof(volume_label_t));
+ anchor.vlabel_changed++;
+
+ if ((anchor.geo.cylinders * anchor.geo.heads) > BIG_DISK_SIZE)
+ anchor.big_disk++;
+
+ fdasd_recreate_vtoc(&anchor);
+
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ unsigned int start, stop;
+
+ PDEBUG;
+ part = ped_disk_get_partition(disk, i);
+ if (!part)
+ continue;
+
+ PDEBUG;
+
+ start = part->geom.start * disk->dev->sector_size
+ / arch_specific->real_sector_size / disk->dev->hw_geom.sectors;
+ stop = (part->geom.end + 1)
+ * disk->dev->sector_size / arch_specific->real_sector_size
+ / disk->dev->hw_geom.sectors - 1;
+
+ PDEBUG;
+ dasd_data = part->disk_specific;
+
+ p = fdasd_add_partition(&anchor, start, stop);
+ if (!p) {
+ PDEBUG;
+ goto error;
+ }
+ part_info[i - 1] = p;
+ p->type = dasd_data->system;
+ }
+
+ PDEBUG;
+
+ if (!fdasd_prepare_labels(&anchor, arch_specific->fd))
+ goto error;
+
+ dasd_update_type(disk, &anchor, part_info);
+ PDEBUG;
+
+ if (!fdasd_write_labels(&anchor, arch_specific->fd))
+ goto error;
+
+ fdasd_cleanup(&anchor);
+ return 1;
+
+error:
+ PDEBUG;
+ fdasd_cleanup(&anchor);
+ return 0;
+}
+
+static PedPartition*
+dasd_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+
+ part = _ped_partition_alloc(disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ part->disk_specific = ped_calloc (sizeof (DasdPartitionData));
+ return part;
+
+error:
+ return 0;
+}
+
+static PedPartition*
+dasd_partition_duplicate (const PedPartition *part)
+{
+ PedPartition *new_part;
+
+ new_part = ped_partition_new (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ memcpy(new_part->disk_specific, part->disk_specific,
+ sizeof(DasdPartitionData));
+
+ return new_part;
+}
+
+static void
+dasd_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT(part != NULL);
+
+ if (ped_partition_is_active(part))
+ free(part->disk_specific);
+ free(part);
+}
+
+static int
+dasd_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ DasdPartitionData* dasd_data;
+
+ PED_ASSERT(part != NULL);
+ PED_ASSERT(part->disk_specific != NULL);
+ dasd_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dasd_find_flag_id_mapping (flag);
+ if (p)
+ {
+ if (state)
+ dasd_data->system = p->type_id;
+ else if (dasd_data->system == p->type_id)
+ return dasd_partition_set_system (part, part->fs_type);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+dasd_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ DasdPartitionData* dasd_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ dasd_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dasd_find_flag_id_mapping (flag);
+ if (p)
+ return dasd_data->system == p->type_id;
+
+ return 0;
+}
+
+/*
+ * The DASD-LDL does not support flags now.
+ * So just return 0.
+*/
+static int
+dasd_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ DasdDiskSpecific* disk_specific;
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->disk_specific != NULL);
+
+ disk_specific = part->disk->disk_specific;
+
+ if (disk_specific->format_type == 1)
+ return 0;
+
+ if (dasd_find_flag_id_mapping (flag))
+ return 1;
+
+ return 0;
+}
+
+
+static int
+dasd_get_max_primary_partition_count (const PedDisk* disk)
+{
+ DasdDiskSpecific* disk_specific;
+
+ disk_specific = disk->disk_specific;
+ /* If formated in LDL, maximum partition number is 1 */
+ if (disk_specific->format_type == 1)
+ return 1;
+
+ return USABLE_PARTITIONS;
+}
+
+static bool
+dasd_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = dasd_get_max_primary_partition_count(disk);
+ return true;
+}
+
+static PedAlignment*
+dasd_get_partition_alignment(const PedDisk *disk)
+{
+ LinuxSpecific *arch_specific = LINUX_SPECIFIC(disk->dev);
+ PedSector sector_size =
+ arch_specific->real_sector_size / disk->dev->sector_size;
+
+ return ped_alignment_new(0, disk->dev->hw_geom.sectors * sector_size);
+}
+
+static PedConstraint*
+_primary_constraint (PedDisk* disk)
+{
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+ PedSector sector_size;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ PedSector start;
+
+ PDEBUG;
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+ sector_size = arch_specific->real_sector_size / disk->dev->sector_size;
+
+ if (!ped_alignment_init (&start_align, 0,
+ disk->dev->hw_geom.sectors * sector_size))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1,
+ disk->dev->hw_geom.sectors * sector_size))
+ return NULL;
+
+ start = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size);
+
+ if (!ped_geometry_init (&max_geom, disk->dev, start, disk->dev->length))
+ return NULL;
+
+ return ped_constraint_new(&start_align, &end_align, &max_geom,
+ &max_geom, 1, disk->dev->length);
+}
+
+static int
+dasd_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ DasdDiskSpecific* disk_specific;
+
+ PED_ASSERT (part != NULL);
+
+ disk_specific = part->disk->disk_specific;
+ /* If formated in LDL, ignore metadata partition */
+ if (disk_specific->format_type == 1)
+ return 1;
+
+ if (_ped_partition_attempt_align(part, constraint,
+ _primary_constraint(part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+
+ return 0;
+}
+
+static int
+dasd_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number */
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a dasd disklabel slot"));
+ return 0;
+}
+
+static int
+dasd_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type)
+{
+ DasdPartitionData* dasd_data = part->disk_specific;
+ PedSector cyl_size;
+
+ cyl_size=part->disk->dev->hw_geom.sectors * part->disk->dev->hw_geom.heads;
+ PDEBUG;
+
+ part->fs_type = fs_type;
+
+ if (!fs_type) {
+ dasd_data->system = PARTITION_LINUX;
+ PDEBUG;
+ } else if (is_linux_swap (fs_type->name)) {
+ dasd_data->system = PARTITION_LINUX_SWAP;
+ PDEBUG;
+ } else {
+ dasd_data->system = PARTITION_LINUX;
+ PDEBUG;
+ }
+
+ return 1;
+}
+
+static int
+dasd_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+ PedSector vtoc_end;
+ LinuxSpecific* arch_specific;
+ DasdDiskSpecific* disk_specific;
+ PedPartition* part = NULL; /* initialize solely to placate gcc */
+ PedPartition* new_part2;
+ PedSector trailing_meta_start, trailing_meta_end;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ arch_specific = LINUX_SPECIFIC (disk->dev);
+ disk_specific = disk->disk_specific;
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* For LDL or CMS, the leading metadata ends at the sector before
+ the start of the first partition */
+ if (disk_specific->format_type == 1) {
+ part = ped_disk_get_partition(disk, 1);
+ if (part)
+ vtoc_end = part->geom.start - 1;
+ else
+ vtoc_end = (PedSector) arch_specific->real_sector_size /
+ (PedSector) disk->dev->sector_size *
+ (PedSector) disk_specific->label_block;
+ }
+ else {
+ if (disk->dev->type == PED_DEVICE_FILE)
+ arch_specific->real_sector_size = disk->dev->sector_size;
+ /* Mark the start of the disk as metadata. */
+ vtoc_end = (FIRST_USABLE_TRK * (long long) disk->dev->hw_geom.sectors
+ * (long long) arch_specific->real_sector_size
+ / (long long) disk->dev->sector_size) - 1;
+ }
+
+ new_part = ped_partition_new (disk,PED_PARTITION_METADATA,NULL,0,vtoc_end);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ if (disk_specific->format_type == 1 && part) {
+ /*
+ For LDL or CMS there may be trailing metadata as well.
+ For example: the last block of a CMS reserved file,
+ the "recomp" area of a CMS minidisk that has been
+ formatted and then formatted again with the RECOMP
+ option specifying fewer than the maximum number of
+ cylinders, a disk that was formatted at one size,
+ backed up, then restored to a larger size disk, etc.
+ */
+ trailing_meta_start = part->geom.end + 1;
+ trailing_meta_end = (long long) disk->dev->length - 1;
+ if (trailing_meta_end >= trailing_meta_start) {
+ new_part2 = ped_partition_new (disk,PED_PARTITION_METADATA,
+ NULL, trailing_meta_start, trailing_meta_end);
+ if (!new_part2) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+ if (!ped_disk_add_partition (disk, new_part2,
+ constraint_any)) {
+ ped_partition_destroy (new_part2);
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+ }
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
diff --git a/libparted/labels/dos.c b/libparted/labels/dos.c
new file mode 100644
index 0000000..e6a0105
--- /dev/null
+++ b/libparted/labels/dos.c
@@ -0,0 +1,2612 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 1999-2001, 2004-2005, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <sys/time.h>
+#include <stdbool.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+/* this MBR boot code is loaded into 0000:7c00 by the BIOS. See mbr.s for
+ * the source, and how to build it
+ */
+
+static const char MBR_BOOT_CODE[] = {
+ 0xfa, 0xb8, 0x00, 0x10, 0x8e, 0xd0, 0xbc, 0x00,
+ 0xb0, 0xb8, 0x00, 0x00, 0x8e, 0xd8, 0x8e, 0xc0,
+ 0xfb, 0xbe, 0x00, 0x7c, 0xbf, 0x00, 0x06, 0xb9,
+ 0x00, 0x02, 0xf3, 0xa4, 0xea, 0x21, 0x06, 0x00,
+ 0x00, 0xbe, 0xbe, 0x07, 0x38, 0x04, 0x75, 0x0b,
+ 0x83, 0xc6, 0x10, 0x81, 0xfe, 0xfe, 0x07, 0x75,
+ 0xf3, 0xeb, 0x16, 0xb4, 0x02, 0xb0, 0x01, 0xbb,
+ 0x00, 0x7c, 0xb2, 0x80, 0x8a, 0x74, 0x01, 0x8b,
+ 0x4c, 0x02, 0xcd, 0x13, 0xea, 0x00, 0x7c, 0x00,
+ 0x00, 0xeb, 0xfe
+};
+
+#define MSDOS_MAGIC 0xAA55
+#define PARTITION_MAGIC_MAGIC 0xf6f6
+
+/* The maximum number of DOS primary partitions. */
+#define DOS_N_PRI_PARTITIONS 4
+
+#define PARTITION_EMPTY 0x00
+#define PARTITION_FAT12 0x01
+#define PARTITION_FAT16_SM 0x04
+#define PARTITION_DOS_EXT 0x05
+#define PARTITION_FAT16 0x06
+#define PARTITION_NTFS 0x07
+#define PARTITION_HPFS 0x07
+#define PARTITION_UDF 0x07
+#define PARTITION_FAT32 0x0b
+#define PARTITION_FAT32_LBA 0x0c
+#define PARTITION_FAT16_LBA 0x0e
+#define PARTITION_EXT_LBA 0x0f
+
+#define PART_FLAG_HIDDEN 0x10 /* Valid for FAT/NTFS only */
+#define PARTITION_FAT12_H (PARTITION_FAT12 | PART_FLAG_HIDDEN)
+#define PARTITION_FAT16_SM_H (PARTITION_FAT16_SM | PART_FLAG_HIDDEN)
+#define PARTITION_DOS_EXT_H (PARTITION_DOS_EXT | PART_FLAG_HIDDEN)
+#define PARTITION_FAT16_H (PARTITION_FAT16 | PART_FLAG_HIDDEN)
+#define PARTITION_NTFS_H (PARTITION_NTFS | PART_FLAG_HIDDEN)
+#define PARTITION_FAT32_H (PARTITION_FAT32 | PART_FLAG_HIDDEN)
+#define PARTITION_FAT32_LBA_H (PARTITION_FAT32_LBA | PART_FLAG_HIDDEN)
+#define PARTITION_FAT16_LBA_H (PARTITION_FAT16_LBA | PART_FLAG_HIDDEN)
+
+#define PARTITION_COMPAQ_DIAG 0x12
+#define PARTITION_MSFT_RECOVERY 0x27
+#define PARTITION_LDM 0x42
+#define PARTITION_LINUX_SWAP 0x82
+#define PARTITION_LINUX 0x83
+#define PARTITION_IRST 0x84
+#define PARTITION_LINUX_EXT 0x85
+#define PARTITION_LINUX_LVM 0x8e
+#define PARTITION_HFS 0xaf
+#define PARTITION_SUN_UFS 0xbf
+#define PARTITION_DELL_DIAG 0xde
+#define PARTITION_BLS_BOOT 0xea
+#define PARTITION_GPT 0xee
+#define PARTITION_ESP 0xef
+#define PARTITION_PALO 0xf0
+#define PARTITION_PREP 0x41
+#define PARTITION_LINUX_RAID 0xfd
+#define PARTITION_LINUX_LVM_OLD 0xfe
+
+struct flag_id_mapping_t
+{
+ enum _PedPartitionFlag flag;
+ unsigned char type_id;
+ unsigned char alt_type_id;
+};
+
+static const struct flag_id_mapping_t flag_id_mapping[] =
+{
+ { PED_PARTITION_BLS_BOOT, PARTITION_BLS_BOOT },
+ { PED_PARTITION_DIAG, PARTITION_COMPAQ_DIAG, PARTITION_DELL_DIAG },
+ { PED_PARTITION_ESP, PARTITION_ESP },
+ { PED_PARTITION_IRST, PARTITION_IRST },
+ { PED_PARTITION_LVM, PARTITION_LINUX_LVM, PARTITION_LINUX_LVM_OLD },
+ { PED_PARTITION_MSFT_RESERVED, PARTITION_MSFT_RECOVERY },
+ { PED_PARTITION_PALO, PARTITION_PALO },
+ { PED_PARTITION_PREP, PARTITION_PREP },
+ { PED_PARTITION_RAID, PARTITION_LINUX_RAID },
+ { PED_PARTITION_SWAP, PARTITION_LINUX_SWAP },
+};
+
+static const unsigned char skip_set_system_types[] =
+{
+ PARTITION_EXT_LBA,
+ PARTITION_DOS_EXT,
+ PARTITION_COMPAQ_DIAG,
+ PARTITION_MSFT_RECOVERY,
+ PARTITION_LINUX_LVM,
+ PARTITION_LINUX_SWAP,
+ PARTITION_LINUX_RAID,
+ PARTITION_PALO,
+ PARTITION_PREP,
+ PARTITION_IRST,
+ PARTITION_ESP,
+ PARTITION_BLS_BOOT
+};
+
+static const struct flag_id_mapping_t* _GL_ATTRIBUTE_CONST
+dos_find_flag_id_mapping (PedPartitionFlag flag)
+{
+ int n = sizeof(flag_id_mapping) / sizeof(flag_id_mapping[0]);
+
+ for (int i = 0; i < n; ++i)
+ if (flag_id_mapping[i].flag == flag)
+ return &flag_id_mapping[i];
+
+ return NULL;
+}
+
+/**
+ * Check whether the type_id supports the hidden flag. Returns true for both hidden and
+ * non-hidden id.
+ */
+static bool
+dos_type_id_supports_hidden(unsigned char type_id)
+{
+ switch (type_id)
+ {
+ case PARTITION_DOS_EXT:
+ case PARTITION_DOS_EXT_H:
+ case PARTITION_FAT12:
+ case PARTITION_FAT12_H:
+ case PARTITION_FAT16:
+ case PARTITION_FAT16_H:
+ case PARTITION_FAT16_LBA:
+ case PARTITION_FAT16_LBA_H:
+ case PARTITION_FAT16_SM:
+ case PARTITION_FAT16_SM_H:
+ case PARTITION_FAT32:
+ case PARTITION_FAT32_H:
+ case PARTITION_FAT32_LBA:
+ case PARTITION_FAT32_LBA_H:
+ case PARTITION_NTFS:
+ case PARTITION_NTFS_H:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * Check whether the type_id has the hidden flag set.
+ */
+static bool
+dos_type_id_is_hidden(unsigned char type_id)
+{
+ switch (type_id)
+ {
+ case PARTITION_DOS_EXT_H:
+ case PARTITION_FAT12_H:
+ case PARTITION_FAT16_H:
+ case PARTITION_FAT16_LBA_H:
+ case PARTITION_FAT16_SM_H:
+ case PARTITION_FAT32_H:
+ case PARTITION_FAT32_LBA_H:
+ case PARTITION_NTFS_H:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * Sets the hidden flag on type_id.
+ */
+static bool
+dos_type_id_set_hidden(unsigned char* type_id, bool state)
+{
+ PED_ASSERT (type_id);
+
+ if (!dos_type_id_supports_hidden(*type_id))
+ return false;
+
+ if (state)
+ *type_id |= PART_FLAG_HIDDEN;
+ else
+ *type_id &= ~PART_FLAG_HIDDEN;
+
+ return 1;
+}
+
+/**
+ * Check whether the type_id supports the lba flag. Returns true for both lba and non-lba
+ * id.
+ */
+static bool
+dos_type_id_supports_lba(unsigned char type_id)
+{
+ switch (type_id)
+ {
+ case PARTITION_FAT16:
+ case PARTITION_FAT16_H:
+ case PARTITION_FAT16_LBA:
+ case PARTITION_FAT16_LBA_H:
+ case PARTITION_FAT32:
+ case PARTITION_FAT32_H:
+ case PARTITION_FAT32_LBA:
+ case PARTITION_FAT32_LBA_H:
+ case PARTITION_DOS_EXT:
+ case PARTITION_EXT_LBA:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * Check whether the type_id has the lba flag set.
+ */
+static bool
+dos_type_id_is_lba(unsigned char type_id)
+{
+ switch (type_id)
+ {
+ case PARTITION_FAT16_LBA:
+ case PARTITION_FAT16_LBA_H:
+ case PARTITION_FAT32_LBA:
+ case PARTITION_FAT32_LBA_H:
+ case PARTITION_EXT_LBA:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/**
+ * Sets the lba flag on type_id.
+ */
+static bool
+dos_type_id_set_lba(unsigned char* type_id, bool state)
+{
+ PED_ASSERT (type_id);
+
+ if (!dos_type_id_supports_lba(*type_id))
+ return false;
+
+ if (state)
+ {
+ switch (*type_id)
+ {
+ case PARTITION_FAT16:
+ *type_id = PARTITION_FAT16_LBA;
+ break;
+
+ case PARTITION_FAT32:
+ *type_id = PARTITION_FAT32_LBA;
+ break;
+
+ case PARTITION_DOS_EXT:
+ *type_id = PARTITION_EXT_LBA;
+ break;
+ }
+ }
+ else
+ {
+ switch (*type_id)
+ {
+ case PARTITION_FAT16_LBA:
+ *type_id = PARTITION_FAT16;
+ break;
+
+ case PARTITION_FAT32_LBA:
+ *type_id = PARTITION_FAT32;
+ break;
+
+ case PARTITION_EXT_LBA:
+ *type_id = PARTITION_DOS_EXT;
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+/* This constant contains the maximum cylinder number that can be represented
+ * in (C,H,S) notation. Higher cylinder numbers are reserved for
+ * "too big" indicators (in which case only LBA addressing can be used).
+ * Some partition tables in the wild indicate this number is 1021.
+ * (i.e. 1022 is sometimes used to indicate "use LBA").
+ */
+#define MAX_CHS_CYLINDER 1021
+#define MAX_TOTAL_PART 64
+
+typedef struct _DosRawPartition DosRawPartition;
+typedef struct _DosRawTable DosRawTable;
+
+/* note: lots of bit-bashing here, thus, you shouldn't look inside it.
+ * Use chs_to_sector() and sector_to_chs() instead.
+ */
+typedef struct {
+ uint8_t head;
+ uint8_t sector;
+ uint8_t cylinder;
+} __attribute__((packed)) RawCHS;
+
+/* ripped from Linux source */
+struct _DosRawPartition {
+ uint8_t boot_ind; /* 00: 0x80 - active */
+ RawCHS chs_start; /* 01: */
+ uint8_t type; /* 04: partition type */
+ RawCHS chs_end; /* 05: */
+ uint32_t start; /* 08: starting sector counting from 0 */
+ uint32_t length; /* 0c: nr of sectors in partition */
+} __attribute__((packed));
+
+struct _DosRawTable {
+ char boot_code [440];
+ uint32_t mbr_signature; /* really a unique ID */
+ uint16_t Unknown;
+ DosRawPartition partitions [DOS_N_PRI_PARTITIONS];
+ uint16_t magic;
+} __attribute__((packed));
+
+/* OrigState is information we want to preserve about the partition for
+ * dealing with CHS issues
+ */
+typedef struct {
+ PedGeometry geom;
+ DosRawPartition raw_part;
+ PedSector lba_offset; /* needed for computing start/end for
+ * logical partitions */
+} OrigState;
+
+typedef struct {
+ int cylinder_alignment;
+} DosDiskData;
+
+typedef struct {
+ unsigned char system;
+ int boot;
+ OrigState* orig; /* used for CHS stuff */
+} DosPartitionData;
+
+static PedDiskType msdos_disk_type;
+
+#if 0
+From http://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html
+
+The 2-byte numbers are stored little endian (low order byte first).
+
+Here the FAT12 version, that is also the common part of the FAT12, FAT16 and FAT32 boot sectors. See further below.
+
+Bytes Content
+0-2 Jump to bootstrap (E.g. eb 3c 90; on i86: JMP 003E NOP.
+ One finds either eb xx 90, or e9 xx xx.
+ The position of the bootstrap varies.)
+3-10 OEM name/version (E.g. "IBM 3.3", "IBM 20.0", "MSDOS5.0", "MSWIN4.0".
+ Various format utilities leave their own name, like "CH-FOR18".
+ Sometimes just garbage. Microsoft recommends "MSWIN4.1".)
+ /* BIOS Parameter Block starts here */
+11-12 Number of bytes per sector (512)
+ Must be one of 512, 1024, 2048, 4096.
+13 Number of sectors per cluster (1)
+ Must be one of 1, 2, 4, 8, 16, 32, 64, 128.
+ A cluster should have at most 32768 bytes. In rare cases 65536 is OK.
+14-15 Number of reserved sectors (1)
+ FAT12 and FAT16 use 1. FAT32 uses 32.
+16 Number of FAT copies (2)
+17-18 Number of root directory entries (224)
+ 0 for FAT32. 512 is recommended for FAT16.
+19-20 Total number of sectors in the filesystem (2880)
+ (in case the partition is not FAT32 and smaller than 32 MB)
+21 Media descriptor type (f0: 1.4 MB floppy, f8: hard disk; see below)
+22-23 Number of sectors per FAT (9)
+ 0 for FAT32.
+24-25 Number of sectors per track (12)
+26-27 Number of heads (2, for a double-sided diskette)
+28-29 Number of hidden sectors (0)
+ Hidden sectors are sectors preceding the partition.
+ /* BIOS Parameter Block ends here */
+30-509 Bootstrap
+510-511 Signature 55 aa
+#endif
+
+/* There is a significant risk of misclassifying (as msdos)
+ a disk that is composed solely of a single FAT partition.
+ Return false if sector S could not be a valid FAT boot sector.
+ Otherwise, return true. */
+static bool
+maybe_FAT (unsigned char const *s)
+{
+ if (! (s[0] == 0xeb || s[0] == 0xe9))
+ return false;
+
+ uint16_t sector_size = (s[12] << 8) | s[11];
+ switch (sector_size)
+ {
+ case 512:
+ case 1024:
+ case 2048:
+ case 4096:
+ break;
+ default:
+ return false;
+ }
+
+ if (! (s[21] == 0xf0 || s[21] == 0xf8))
+ return false;
+
+ return true;
+}
+
+PedGeometry*
+fat_probe_fat16 (PedGeometry* geom);
+
+PedGeometry*
+fat_probe_fat32 (PedGeometry* geom);
+
+PedGeometry*
+ntfs_probe (PedGeometry* geom);
+
+static int
+msdos_probe (const PedDevice *dev)
+{
+ PedDiskType* disk_type;
+ DosRawTable* part_table;
+ int i;
+ PedGeometry *geom = NULL;
+ PedGeometry *fsgeom = NULL;
+
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size < sizeof *part_table)
+ return 0;
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+
+ part_table = (DosRawTable *) label;
+
+ /* check magic */
+ if (PED_LE16_TO_CPU (part_table->magic) != MSDOS_MAGIC)
+ goto probe_fail;
+
+ geom = ped_geometry_new (dev, 0, dev->length);
+ PED_ASSERT (geom);
+ fsgeom = fat_probe_fat16 (geom);
+ if (fsgeom)
+ goto probe_fail; /* fat fs looks like dos mbr */
+ fsgeom = fat_probe_fat32 (geom);
+ if (fsgeom)
+ goto probe_fail; /* fat fs looks like dos mbr */
+ fsgeom = ntfs_probe (geom);
+ if (fsgeom)
+ goto probe_fail; /* ntfs fs looks like dos mbr */
+ ped_geometry_destroy (geom);
+ geom = NULL;
+
+ /* If this is a FAT fs, fail here. Checking for the FAT signature
+ * has some false positives; instead, do what the Linux kernel does
+ * and ensure that each partition has a boot indicator that is
+ * either 0 or 0x80.
+ */
+ unsigned int n_active = 0;
+ for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
+ if (part_table->partitions[i].boot_ind == 0x80)
+ ++n_active;
+ if (part_table->partitions[i].boot_ind != 0
+ && part_table->partitions[i].boot_ind != 0x80)
+ goto probe_fail;
+ }
+
+ /* If there are no active partitions and this is probably
+ a FAT file system, do not classify it as msdos. */
+ if (n_active == 0 && maybe_FAT (label))
+ goto probe_fail;
+
+ /* If this is a GPT disk, fail here */
+ for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
+ if (part_table->partitions[i].type == PARTITION_GPT)
+ goto probe_fail;
+ }
+
+ /* If this is an AIX Physical Volume, fail here. IBMA in EBCDIC */
+ if (part_table->boot_code[0] == (char) 0xc9 &&
+ part_table->boot_code[1] == (char) 0xc2 &&
+ part_table->boot_code[2] == (char) 0xd4 &&
+ part_table->boot_code[3] == (char) 0xc1)
+ goto probe_fail;
+
+#ifdef ENABLE_PC98
+ /* HACK: it's impossible to tell PC98 and msdos disk labels apart.
+ * Someone made the signatures the same (very clever). Since
+ * PC98 has some idiosyncracies with it's boot-loader, it's detection
+ * is more reliable */
+ disk_type = ped_disk_type_get ("pc98");
+ if (disk_type && disk_type->ops->probe (dev))
+ goto probe_fail;
+#endif /* ENABLE_PC98 */
+
+ free (label);
+ return 1;
+
+ probe_fail:
+ if (geom)
+ ped_geometry_destroy (geom);
+ if (fsgeom)
+ ped_geometry_destroy (fsgeom);
+ free (label);
+ return 0;
+}
+
+static PedDisk*
+msdos_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ PED_ASSERT (dev != NULL);
+
+ disk = _ped_disk_alloc ((PedDevice*)dev, &msdos_disk_type);
+ if (disk) {
+ DosDiskData *disk_specific = ped_malloc(sizeof *disk_specific);
+ if (!disk_specific) {
+ free (disk);
+ return NULL;
+ }
+ disk_specific->cylinder_alignment = 1;
+ disk->disk_specific = disk_specific;
+ }
+
+ return disk;
+}
+
+static PedDisk*
+msdos_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &msdos_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ memcpy(new_disk->disk_specific, disk->disk_specific,
+ sizeof(DosDiskData));
+
+ return new_disk;
+}
+
+static void
+msdos_free (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+
+ DosDiskData *disk_specific = disk->disk_specific;
+ _ped_disk_free (disk);
+ free(disk_specific);
+}
+
+static int
+msdos_disk_set_flag (PedDisk *disk, PedDiskFlag flag, int state)
+{
+ DosDiskData *disk_specific = disk->disk_specific;
+ switch (flag) {
+ case PED_DISK_CYLINDER_ALIGNMENT:
+ disk_specific->cylinder_alignment = !!state;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+msdos_disk_get_flag (const PedDisk *disk, PedDiskFlag flag)
+{
+ DosDiskData *disk_specific = disk->disk_specific;
+ switch (flag) {
+ case PED_DISK_CYLINDER_ALIGNMENT:
+ return disk_specific->cylinder_alignment;
+ default:
+ return 0;
+ }
+}
+
+static int
+msdos_disk_is_flag_available (const PedDisk *disk, PedDiskFlag flag)
+{
+ switch (flag) {
+ case PED_DISK_CYLINDER_ALIGNMENT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+chs_get_cylinder (const RawCHS* chs)
+{
+ return chs->cylinder + ((chs->sector >> 6) << 8);
+}
+
+static int
+chs_get_head (const RawCHS* chs)
+{
+ return chs->head;
+}
+
+/* counts from 0 */
+static int
+chs_get_sector (const RawCHS* chs)
+{
+ return (chs->sector & 0x3f) - 1;
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+chs_to_sector (const PedDevice* dev, const PedCHSGeometry *bios_geom,
+ const RawCHS* chs)
+{
+ PedSector c; /* not measured in sectors, but need */
+ PedSector h; /* lots of bits */
+ PedSector s;
+
+ PED_ASSERT (bios_geom != NULL);
+ PED_ASSERT (chs != NULL);
+
+ c = chs_get_cylinder (chs);
+ h = chs_get_head (chs);
+ s = chs_get_sector (chs);
+
+ if (c > MAX_CHS_CYLINDER) /* MAGIC: C/H/S is irrelevant */
+ return 0;
+ if (s < 0)
+ return 0;
+ return (c * bios_geom->heads + h) * bios_geom->sectors + s;
+}
+
+static void
+sector_to_chs (const PedDevice* dev, const PedCHSGeometry* bios_geom,
+ PedSector sector, RawCHS* chs)
+{
+ PedSector real_c, real_h, real_s;
+
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (chs != NULL);
+
+ if (!bios_geom)
+ bios_geom = &dev->bios_geom;
+
+ real_c = sector / (bios_geom->heads * bios_geom->sectors);
+ real_h = (sector / bios_geom->sectors) % bios_geom->heads;
+ real_s = sector % bios_geom->sectors;
+
+ if (real_c > MAX_CHS_CYLINDER) {
+ real_c = 1023;
+ real_h = bios_geom->heads - 1;
+ real_s = bios_geom->sectors - 1;
+ }
+
+ chs->cylinder = real_c % 0x100;
+ chs->head = real_h;
+ chs->sector = real_s + 1 + (real_c >> 8 << 6);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+legacy_start (const PedDisk* disk, const PedCHSGeometry* bios_geom,
+ const DosRawPartition* raw_part)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_start);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+legacy_end (const PedDisk* disk, const PedCHSGeometry* bios_geom,
+ const DosRawPartition* raw_part)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ return chs_to_sector (disk->dev, bios_geom, &raw_part->chs_end);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+linear_start (const PedDisk* disk, const DosRawPartition* raw_part,
+ PedSector offset)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ return offset + PED_LE32_TO_CPU (raw_part->start);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+linear_end (const PedDisk* disk, const DosRawPartition* raw_part,
+ PedSector offset)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ return (linear_start (disk, raw_part, offset)
+ + (PED_LE32_TO_CPU (raw_part->length) - 1));
+}
+
+#ifndef DISCOVER_ONLY
+static int _GL_ATTRIBUTE_PURE
+partition_check_bios_geometry (PedPartition* part, PedCHSGeometry* bios_geom)
+{
+ PedSector leg_start, leg_end;
+ DosPartitionData* dos_data;
+ PedDisk* disk;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ dos_data = part->disk_specific;
+
+ if (!dos_data->orig)
+ return 1;
+
+ disk = part->disk;
+ leg_start = legacy_start (disk, bios_geom, &dos_data->orig->raw_part);
+ leg_end = legacy_end (disk, bios_geom, &dos_data->orig->raw_part);
+
+ if (leg_start && leg_start != dos_data->orig->geom.start)
+ return 0;
+ if (leg_end && leg_end != dos_data->orig->geom.end)
+ return 0;
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+disk_check_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
+{
+ PedPartition* part = NULL;
+
+ PED_ASSERT (disk != NULL);
+
+ while ((part = ped_disk_next_partition (disk, part))) {
+ if (ped_partition_is_active (part)) {
+ if (!partition_check_bios_geometry (part, bios_geom))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+probe_filesystem_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom)
+{
+ const char* ms_types[] = {"ntfs", "fat16", "fat32", NULL};
+ int i;
+ int found;
+ unsigned char* buf;
+ int sectors;
+ int heads;
+ int res = 0;
+
+ PED_ASSERT (bios_geom != NULL);
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (part->disk->dev != NULL);
+ PED_ASSERT (part->disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+
+ buf = ped_malloc (part->disk->dev->sector_size);
+
+ if (!buf)
+ return 0;
+
+ if (!part->fs_type)
+ goto end;
+
+ found = 0;
+ for (i = 0; ms_types[i]; i++) {
+ if (!strcmp(ms_types[i], part->fs_type->name))
+ found = 1;
+ }
+ if (!found)
+ goto end;
+
+ if (!ped_geometry_read(&part->geom, buf, 0, 1))
+ goto end;
+
+ /* shared by the start of all Microsoft file systems */
+ sectors = buf[0x18] + (buf[0x19] << 8);
+ heads = buf[0x1a] + (buf[0x1b] << 8);
+
+ if (sectors < 1 || sectors > 63)
+ goto end;
+ if (heads > 255 || heads < 1)
+ goto end;
+
+ bios_geom->sectors = sectors;
+ bios_geom->heads = heads;
+ bios_geom->cylinders = part->disk->dev->length / (sectors * heads);
+ res = 1;
+end:
+ free(buf);
+ return res;
+}
+
+/* This function attempts to infer the BIOS CHS geometry of the hard disk
+ * from the CHS + LBA information contained in the partition table from
+ * a single partition's entry.
+ *
+ * This involves some maths. Let (c,h,s,a) be the starting cylinder,
+ * starting head, starting sector and LBA start address of the partition.
+ * Likewise, (C,H,S,A) the end addresses. Using both of these pieces
+ * of information, we want to deduce cyl_sectors and head_sectors which
+ * are the sizes of a single cylinder and a single head, respectively.
+ *
+ * The relationships are:
+ * c*cyl_sectors + h * head_sectors + s = a
+ * C*cyl_sectors + H * head_sectors + S = A
+ *
+ * We can rewrite this in matrix form:
+ *
+ * [ c h ] [ cyl_sectors ] = [ s - a ] = [ a_ ]
+ * [ C H ] [ head_sectors ] [ S - A ] [ A_ ].
+ *
+ * (s - a is abbreviated to a_to simplify the notation.)
+ *
+ * This can be abbreviated into augmented matrix form:
+ *
+ * [ c h | a_ ]
+ * [ C H | A_ ].
+ *
+ * Solving these equations requires following the row reduction algorithm. We
+ * need to be careful about a few things though:
+ * - the equations might be linearly dependent, in which case there
+ * are many solutions.
+ * - the equations might be inconsistent, in which case there
+ * are no solutions. (Inconsistent partition table entry!)
+ * - there might be zeros, so we need to be careful about applying
+ * the algorithm. We know, however, that C > 0.
+ */
+static int
+probe_partition_for_geom (const PedPartition* part, PedCHSGeometry* bios_geom)
+{
+ DosPartitionData* dos_data;
+ RawCHS* start_chs;
+ RawCHS* end_chs;
+ PedSector c, h, s, a, a_; /* start */
+ PedSector C, H, S, A, A_; /* end */
+ PedSector dont_overflow, denum;
+ PedSector cyl_size, head_size;
+ PedSector cylinders, heads, sectors;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ PED_ASSERT (bios_geom != NULL);
+
+ dos_data = part->disk_specific;
+
+ if (!dos_data->orig)
+ return 0;
+
+ start_chs = &dos_data->orig->raw_part.chs_start;
+ c = chs_get_cylinder (start_chs);
+ h = chs_get_head (start_chs);
+ s = chs_get_sector (start_chs);
+ a = dos_data->orig->geom.start;
+ a_ = a - s;
+
+ end_chs = &dos_data->orig->raw_part.chs_end;
+ C = chs_get_cylinder (end_chs);
+ H = chs_get_head (end_chs);
+ S = chs_get_sector (end_chs);
+ A = dos_data->orig->geom.end;
+ A_ = A - S;
+
+ if (h < 0 || H < 0 || h > 254 || H > 254)
+ return 0;
+ if (c > C)
+ return 0;
+
+ /* If no geometry is feasible, then don't even bother.
+ * Useful for eliminating assertions for broken partition
+ * tables generated by Norton Ghost et al.
+ */
+ if (A > (C+1) * 255 * 63)
+ return 0;
+
+ /* Not enough information. In theory, we can do better. Should we? */
+ if (C > MAX_CHS_CYLINDER)
+ return 0;
+ if (C == 0)
+ return 0;
+
+ /* Calculate the maximum number that can be multiplied by
+ * any head count without overflowing a PedSector
+ * 2^8 = 256, 8 bits + 1(sign bit) = 9
+ */
+ dont_overflow = 1;
+ dont_overflow <<= (8*sizeof(dont_overflow)) - 9;
+ dont_overflow--;
+
+ if (a_ > dont_overflow || A_ > dont_overflow)
+ return 0;
+
+ /* The matrix is solved by :
+ *
+ * [ c h | a_] R1
+ * [ C H | A_] R2
+ *
+ * (cH - Ch) cyl_size = a_H - A_h H R1 - h R2
+ * => (if cH - Ch != 0) cyl_size = (a_H - A_h) / (cH - Ch)
+ *
+ * (Hc - hC) head_size = A_c - a_C c R2 - C R1
+ * => (if cH - Ch != 0) head_size = (A_c - a_C) / (cH - Ch)
+ *
+ * But this calculation of head_size would need
+ * not overflowing A_c or a_C
+ * So substitution is use instead, to minimize dimension
+ * of temporary results :
+ *
+ * If h != 0 : head_size = ( a_ - c cyl_size ) / h
+ * If H != 0 : head_size = ( A_ - C cyl_size ) / H
+ *
+ */
+ denum = c * H - C * h;
+ if (denum == 0)
+ return 0;
+
+ cyl_size = (a_*H - A_*h) / denum;
+ /* Check for non integer result */
+ if (cyl_size * denum != a_*H - A_*h)
+ return 0;
+
+ if (!(cyl_size > 0))
+ return 0;
+ if (!(cyl_size <= 255 * 63))
+ return 0;
+
+ if (h > 0)
+ head_size = ( a_ - c * cyl_size ) / h;
+ else if (H > 0)
+ head_size = ( A_ - C * cyl_size ) / H;
+ else {
+ /* should not happen because denum != 0 */
+ PED_ASSERT (0);
+ }
+
+ if (!(head_size > 0))
+ return 0;
+ if (!(head_size <= 63))
+ return 0;
+
+ cylinders = part->disk->dev->length / cyl_size;
+ heads = cyl_size / head_size;
+ sectors = head_size;
+
+ if (!(heads > 0))
+ return 0;
+ if (!(heads < 256))
+ return 0;
+
+ if (!(sectors > 0))
+ return 0;
+ if (!(sectors <= 63))
+ return 0;
+
+ /* Some broken OEM partitioning program(s) seem to have an out-by-one
+ * error on the end of partitions. We should offer to fix the
+ * partition table...
+ */
+ if (((C + 1) * heads + H) * sectors + S == A)
+ C++;
+
+ if (!((c * heads + h) * sectors + s == a))
+ return 0;
+ if (!((C * heads + H) * sectors + S == A))
+ return 0;
+
+ bios_geom->cylinders = cylinders;
+ bios_geom->heads = heads;
+ bios_geom->sectors = sectors;
+
+ return 1;
+}
+
+static void
+partition_probe_bios_geometry (const PedPartition* part,
+ PedCHSGeometry* bios_geom)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+ PED_ASSERT (bios_geom != NULL);
+
+ if (ped_partition_is_active (part)) {
+ if (probe_partition_for_geom (part, bios_geom))
+ return;
+ if (part->type & PED_PARTITION_EXTENDED) {
+ if (probe_filesystem_for_geom (part, bios_geom))
+ return;
+ }
+ }
+ if (part->type & PED_PARTITION_LOGICAL) {
+ PedPartition* ext_part;
+ ext_part = ped_disk_extended_partition (part->disk);
+ PED_ASSERT (ext_part != NULL);
+ partition_probe_bios_geometry (ext_part, bios_geom);
+ } else {
+ *bios_geom = part->disk->dev->bios_geom;
+ }
+}
+
+static void
+disk_probe_bios_geometry (const PedDisk* disk, PedCHSGeometry* bios_geom)
+{
+ PedPartition* part;
+
+ /* first look at the boot partition */
+ part = NULL;
+ while ((part = ped_disk_next_partition (disk, part))) {
+ if (!ped_partition_is_active (part))
+ continue;
+ if (ped_partition_get_flag (part, PED_PARTITION_BOOT)) {
+ if (probe_filesystem_for_geom (part, bios_geom))
+ return;
+ if (probe_partition_for_geom (part, bios_geom))
+ return;
+ }
+ }
+
+ /* that didn't work... try all partition table entries */
+ part = NULL;
+ while ((part = ped_disk_next_partition (disk, part))) {
+ if (ped_partition_is_active (part)) {
+ if (probe_partition_for_geom (part, bios_geom))
+ return;
+ }
+ }
+
+ /* that didn't work... look at all file systems */
+ part = NULL;
+ while ((part = ped_disk_next_partition (disk, part))) {
+ if (ped_partition_is_active (part)) {
+ if (probe_filesystem_for_geom (part, bios_geom))
+ return;
+ }
+ }
+}
+#endif /* !DISCOVER_ONLY */
+
+static int _GL_ATTRIBUTE_PURE
+raw_part_is_extended (const DosRawPartition* raw_part)
+{
+ PED_ASSERT (raw_part != NULL);
+
+ switch (raw_part->type) {
+ case PARTITION_DOS_EXT:
+ case PARTITION_EXT_LBA:
+ case PARTITION_LINUX_EXT:
+ return 1;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static PedPartition*
+raw_part_parse (const PedDisk* disk, const DosRawPartition* raw_part,
+ PedSector lba_offset, PedPartitionType type)
+{
+ PedPartition* part;
+ DosPartitionData* dos_data;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ part = ped_partition_new (
+ disk, type, NULL,
+ linear_start (disk, raw_part, lba_offset),
+ linear_end (disk, raw_part, lba_offset));
+ if (!part)
+ return NULL;
+ dos_data = part->disk_specific;
+ dos_data->system = raw_part->type;
+ dos_data->boot = raw_part->boot_ind != 0;
+ dos_data->orig = ped_malloc (sizeof (OrigState));
+ if (!dos_data->orig) {
+ ped_partition_destroy (part);
+ return NULL;
+ }
+ dos_data->orig->geom = part->geom;
+ dos_data->orig->raw_part = *raw_part;
+ dos_data->orig->lba_offset = lba_offset;
+ return part;
+}
+
+static int
+read_table (PedDisk* disk, PedSector sector, int is_extended_table)
+{
+ int i;
+ DosRawTable* table;
+ DosRawPartition* raw_part;
+ PedPartition* part;
+ PedPartitionType type;
+ PedSector lba_offset;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ void *label = NULL;
+ if (!ptt_read_sector (disk->dev, sector, &label))
+ goto error;
+
+ table = (DosRawTable *) label;
+
+ /* weird: empty extended partitions are filled with 0xf6 by PM */
+ if (is_extended_table
+ && PED_LE16_TO_CPU (table->magic) == PARTITION_MAGIC_MAGIC)
+ goto read_ok;
+
+#ifndef DISCOVER_ONLY
+ if (PED_LE16_TO_CPU (table->magic) != MSDOS_MAGIC) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
+ _("Invalid partition table on %s "
+ "-- wrong signature %x."),
+ disk->dev->path,
+ PED_LE16_TO_CPU (table->magic))
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+ goto read_ok;
+ }
+#endif
+
+ /* parse the partitions from this table */
+ for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
+ raw_part = &table->partitions [i];
+ if (raw_part->type == PARTITION_EMPTY || !raw_part->length)
+ continue;
+
+ /* process nested extended partitions after normal logical
+ * partitions, to make sure we get the order right.
+ */
+ if (is_extended_table && raw_part_is_extended (raw_part))
+ continue;
+
+ lba_offset = is_extended_table ? sector : 0;
+
+ if (linear_start (disk, raw_part, lba_offset) == sector) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Invalid partition table - recursive "
+ "partition on %s."),
+ disk->dev->path)
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+ continue; /* avoid infinite recursion */
+ }
+
+ if (is_extended_table)
+ type = PED_PARTITION_LOGICAL;
+ else if (raw_part_is_extended (raw_part))
+ type = PED_PARTITION_EXTENDED;
+ else
+ type = PED_PARTITION_NORMAL;
+
+ part = raw_part_parse (disk, raw_part, lba_offset, type);
+ if (!part)
+ goto error;
+ if (!is_extended_table)
+ part->num = i + 1;
+ if (type != PED_PARTITION_EXTENDED)
+ part->fs_type = ped_file_system_probe (&part->geom);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok)
+ goto error;
+
+ /* non-nested extended partition */
+ if (part->type == PED_PARTITION_EXTENDED) {
+ if (!read_table (disk, part->geom.start, 1))
+ goto error;
+ }
+ }
+
+ if (is_extended_table) {
+ /* process the nested extended partitions */
+ for (i = 0; i < DOS_N_PRI_PARTITIONS; i++) {
+ PedSector part_start;
+
+ raw_part = &table->partitions [i];
+ if (!raw_part_is_extended (raw_part))
+ continue;
+
+ lba_offset = ped_disk_extended_partition
+ (disk)->geom.start;
+ part_start = linear_start (disk, raw_part, lba_offset);
+ if (part_start == sector) {
+ /* recursive table - already threw an
+ * exception above.
+ */
+ continue;
+ }
+ if (!read_table (disk, part_start, 1))
+ goto error;
+ }
+ }
+
+read_ok:
+ free (label);
+ return 1;
+
+error:
+ free (label);
+ ped_disk_delete_all (disk);
+ return 0;
+}
+
+static int
+msdos_read (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ ped_disk_delete_all (disk);
+ if (!read_table (disk, 0, 0))
+ return 0;
+
+#ifndef DISCOVER_ONLY
+ /* try to figure out the correct BIOS CHS values */
+ if (!disk_check_bios_geometry (disk, &disk->dev->bios_geom)) {
+ PedCHSGeometry bios_geom = disk->dev->bios_geom;
+ disk_probe_bios_geometry (disk, &bios_geom);
+
+ /* if the geometry was wrong, then we should reread, to
+ * make sure the metadata is allocated in the right places.
+ */
+ if (disk->dev->bios_geom.cylinders != bios_geom.cylinders
+ || disk->dev->bios_geom.heads != bios_geom.heads
+ || disk->dev->bios_geom.sectors != bios_geom.sectors) {
+ disk->dev->bios_geom = bios_geom;
+ return msdos_read (disk);
+ }
+ }
+#endif
+
+ return 1;
+}
+
+#ifndef DISCOVER_ONLY
+static int
+fill_raw_part (DosRawPartition* raw_part,
+ const PedPartition* part, PedSector offset)
+{
+ DosPartitionData* dos_data;
+ PedCHSGeometry bios_geom;
+
+ PED_ASSERT (raw_part != NULL);
+ PED_ASSERT (part != NULL);
+
+ partition_probe_bios_geometry (part, &bios_geom);
+
+ dos_data = part->disk_specific;
+
+ raw_part->boot_ind = 0x80 * dos_data->boot;
+ raw_part->type = dos_data->system;
+ raw_part->start = PED_CPU_TO_LE32 (part->geom.start - offset);
+ raw_part->length = PED_CPU_TO_LE32 (part->geom.length);
+
+ sector_to_chs (part->disk->dev, &bios_geom, part->geom.start,
+ &raw_part->chs_start);
+ sector_to_chs (part->disk->dev, &bios_geom, part->geom.end,
+ &raw_part->chs_end);
+
+ if (dos_data->orig) {
+ DosRawPartition* orig_raw_part = &dos_data->orig->raw_part;
+ if (dos_data->orig->geom.start == part->geom.start)
+ raw_part->chs_start = orig_raw_part->chs_start;
+ if (dos_data->orig->geom.end == part->geom.end)
+ raw_part->chs_end = orig_raw_part->chs_end;
+ }
+
+ return 1;
+}
+
+static int
+fill_ext_raw_part_geom (DosRawPartition* raw_part,
+ const PedCHSGeometry* bios_geom,
+ const PedGeometry* geom, PedSector offset)
+{
+ PED_ASSERT (raw_part != NULL);
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (geom->dev != NULL);
+
+ raw_part->boot_ind = 0;
+ raw_part->type = PARTITION_DOS_EXT;
+ raw_part->start = PED_CPU_TO_LE32 (geom->start - offset);
+ raw_part->length = PED_CPU_TO_LE32 (geom->length);
+
+ sector_to_chs (geom->dev, bios_geom, geom->start, &raw_part->chs_start);
+ sector_to_chs (geom->dev, bios_geom, geom->start + geom->length - 1,
+ &raw_part->chs_end);
+
+ return 1;
+}
+
+static int
+write_ext_table (const PedDisk* disk,
+ PedSector sector, const PedPartition* logical)
+{
+ PedPartition* part;
+ PedSector lba_offset;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (ped_disk_extended_partition (disk) != NULL);
+ PED_ASSERT (logical != NULL);
+
+ lba_offset = ped_disk_extended_partition (disk)->geom.start;
+
+ void* s;
+ if (!ptt_read_sector (disk->dev, sector, &s))
+ return 0;
+
+ DosRawTable *table = s;
+ memset(&(table->partitions), 0, sizeof (table->partitions));
+ table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
+
+ int ok = 0;
+ if (!fill_raw_part (&table->partitions[0], logical, sector))
+ goto cleanup;
+
+ part = ped_disk_get_partition (disk, logical->num + 1);
+ if (part) {
+ PedGeometry* geom;
+ PedCHSGeometry bios_geom;
+
+ geom = ped_geometry_new (disk->dev, part->prev->geom.start,
+ part->geom.end - part->prev->geom.start + 1);
+ if (!geom)
+ goto cleanup;
+ partition_probe_bios_geometry (part, &bios_geom);
+ fill_ext_raw_part_geom (&table->partitions[1], &bios_geom,
+ geom, lba_offset);
+ ped_geometry_destroy (geom);
+
+ if (!write_ext_table (disk, part->prev->geom.start, part))
+ goto cleanup;
+ }
+
+ ok = ped_device_write (disk->dev, table, sector, 1);
+ cleanup:
+ free (s);
+ return ok;
+}
+
+static int
+write_empty_table (const PedDisk* disk, PedSector sector)
+{
+ DosRawTable table;
+ void* table_sector;
+
+ PED_ASSERT (disk != NULL);
+
+ if (ptt_read_sector (disk->dev, sector, &table_sector)) {
+ memcpy (&table, table_sector, sizeof (table));
+ free(table_sector);
+ }
+ memset (&(table.partitions), 0, sizeof (table.partitions));
+ table.magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
+
+ return ped_device_write (disk->dev, (void*) &table, sector, 1);
+}
+
+/* Find the first logical partition, and write the partition table for it.
+ */
+static int
+write_extended_partitions (const PedDisk* disk)
+{
+ PedPartition* ext_part;
+ PedPartition* part;
+ PedCHSGeometry bios_geom;
+
+ PED_ASSERT (disk != NULL);
+
+ ext_part = ped_disk_extended_partition (disk);
+ partition_probe_bios_geometry (ext_part, &bios_geom);
+ part = ped_disk_get_partition (disk, 5);
+ if (part)
+ return write_ext_table (disk, ext_part->geom.start, part);
+ else
+ return write_empty_table (disk, ext_part->geom.start);
+}
+
+static int
+msdos_write (const PedDisk* disk)
+{
+ PedPartition* part;
+ int i;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return 0;
+ DosRawTable *table = (DosRawTable *) s0;
+
+ if (!table->boot_code[0]) {
+ memset (table, 0, 512);
+ memcpy (table->boot_code, MBR_BOOT_CODE, sizeof (MBR_BOOT_CODE));
+ }
+
+ /* If there is no unique identifier, generate a random one */
+ if (!table->mbr_signature)
+ table->mbr_signature = generate_random_uint32 ();
+
+ memset (table->partitions, 0, sizeof (table->partitions));
+ table->magic = PED_CPU_TO_LE16 (MSDOS_MAGIC);
+
+ for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
+ part = ped_disk_get_partition (disk, i);
+ if (!part)
+ continue;
+
+ if (!fill_raw_part (&table->partitions [i - 1], part, 0))
+ goto write_fail;
+
+ if (part->type == PED_PARTITION_EXTENDED) {
+ if (!write_extended_partitions (disk))
+ goto write_fail;
+ }
+ }
+
+ int write_ok = ped_device_write (disk->dev, (void*) table, 0, 1);
+ free (s0);
+ if (!write_ok)
+ return 0;
+ return ped_device_sync (disk->dev);
+
+ write_fail:
+ free (s0);
+ return 0;
+
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+msdos_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ DosPartitionData* dos_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = dos_data = ped_calloc (sizeof (DosPartitionData));
+ if (!dos_data)
+ goto error_free_part;
+ dos_data->system = PARTITION_LINUX;
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return 0;
+}
+
+static PedPartition*
+msdos_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ DosPartitionData* new_dos_data;
+ DosPartitionData* old_dos_data;
+
+ new_part = ped_partition_new (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_dos_data = (DosPartitionData*) part->disk_specific;
+ new_dos_data = (DosPartitionData*) new_part->disk_specific;
+ new_dos_data->system = old_dos_data->system;
+ new_dos_data->boot = old_dos_data->boot;
+
+ if (old_dos_data->orig) {
+ new_dos_data->orig = ped_malloc (sizeof (OrigState));
+ if (!new_dos_data->orig) {
+ ped_partition_destroy (new_part);
+ return NULL;
+ }
+ new_dos_data->orig->geom = old_dos_data->orig->geom;
+ new_dos_data->orig->raw_part = old_dos_data->orig->raw_part;
+ new_dos_data->orig->lba_offset = old_dos_data->orig->lba_offset;
+ }
+ return new_part;
+}
+
+static void
+msdos_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part)) {
+ DosPartitionData* dos_data;
+ dos_data = (DosPartitionData*) part->disk_specific;
+ free (dos_data->orig);
+ free (part->disk_specific);
+ }
+ free (part);
+}
+
+/* is_skip_type checks the type against the list of types that should not be
+ * overridden by set_system. It returns a 1 if it is in the list.
+*/
+static bool
+is_skip_type(unsigned char type_id) {
+ int n = sizeof(skip_set_system_types) / sizeof(skip_set_system_types[0]);
+ for (int i = 0; i < n; ++i) {
+ if (type_id == skip_set_system_types[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int
+msdos_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type)
+{
+ DosPartitionData* dos_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ // Is this a type that should skip fs_type checking?
+ if (is_skip_type(dos_data->system)) {
+ return 1;
+ }
+
+ if (part->type & PED_PARTITION_EXTENDED) {
+ dos_data->system = PARTITION_EXT_LBA;
+ return 1;
+ }
+
+ if (!fs_type)
+ dos_data->system = PARTITION_LINUX;
+ else if (!strcmp (fs_type->name, "fat16"))
+ dos_data->system = PARTITION_FAT16;
+ else if (!strcmp (fs_type->name, "fat32"))
+ dos_data->system = PARTITION_FAT32;
+ else if (!strcmp (fs_type->name, "ntfs")
+ || !strcmp (fs_type->name, "hpfs"))
+ dos_data->system = PARTITION_NTFS;
+ else if (!strcmp (fs_type->name, "hfs")
+ || !strcmp (fs_type->name, "hfs+"))
+ dos_data->system = PARTITION_HFS;
+ else if (!strcmp (fs_type->name, "udf"))
+ dos_data->system = PARTITION_UDF;
+ else if (!strcmp (fs_type->name, "sun-ufs"))
+ dos_data->system = PARTITION_SUN_UFS;
+ else if (is_linux_swap (fs_type->name))
+ dos_data->system = PARTITION_LINUX_SWAP;
+ else
+ dos_data->system = PARTITION_LINUX;
+
+ return 1;
+}
+
+static int
+msdos_partition_set_flag (PedPartition* part,
+ PedPartitionFlag flag, int state)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ DosPartitionData* dos_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dos_find_flag_id_mapping (flag);
+ if (p)
+ {
+ if (part->type & PED_PARTITION_EXTENDED)
+ return 0;
+
+ if (state) {
+ dos_data->system = p->type_id;
+ } else if (dos_data->system == p->type_id || dos_data->system == p->alt_type_id) {
+ // Clear the type so that fs_type will be used to return it to the default
+ dos_data->system = PARTITION_LINUX;
+ return ped_partition_set_system (part, part->fs_type);
+ }
+ return 1;
+ }
+
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ {
+ return dos_type_id_set_hidden(&dos_data->system, state);
+ }
+
+ case PED_PARTITION_LBA:
+ {
+ return dos_type_id_set_lba(&dos_data->system, state);
+ }
+
+ case PED_PARTITION_BOOT:
+ {
+ dos_data->boot = state;
+
+ if (state)
+ {
+ PedDisk* disk = part->disk;
+ PedPartition* walk = ped_disk_next_partition (disk, NULL);
+ for (; walk; walk = ped_disk_next_partition (disk, walk)) {
+ if (walk == part || !ped_partition_is_active (walk))
+ continue;
+ msdos_partition_set_flag (walk, PED_PARTITION_BOOT, 0);
+ }
+ }
+
+ return 1;
+ }
+
+ default:
+ return 0;
+ }
+}
+
+static int _GL_ATTRIBUTE_PURE
+msdos_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ DosPartitionData* dos_data = part->disk_specific;
+
+ const struct flag_id_mapping_t* p = dos_find_flag_id_mapping (flag);
+ if (p)
+ return dos_data->system == p->type_id || dos_data->system == p->alt_type_id;
+
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ return dos_type_id_is_hidden(dos_data->system);
+
+ case PED_PARTITION_LBA:
+ return dos_type_id_is_lba(dos_data->system);
+
+ case PED_PARTITION_BOOT:
+ return dos_data->boot;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+msdos_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ if (dos_find_flag_id_mapping (flag))
+ return part->type != PED_PARTITION_EXTENDED;
+
+ DosPartitionData* dos_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ return dos_type_id_supports_hidden(dos_data->system);
+
+ case PED_PARTITION_LBA:
+ return dos_type_id_supports_lba(dos_data->system);
+
+ case PED_PARTITION_BOOT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+
+int
+msdos_partition_set_type_id (PedPartition* part, uint8_t id)
+{
+ DosPartitionData* dos_data = part->disk_specific;
+
+ dos_data->system = id;
+
+ return 1;
+}
+
+
+uint8_t _GL_ATTRIBUTE_PURE
+msdos_partition_get_type_id (const PedPartition* part)
+{
+ const DosPartitionData* dos_data = part->disk_specific;
+
+ return dos_data->system;
+}
+
+
+static PedGeometry*
+_try_constraint (const PedPartition* part, const PedConstraint* external,
+ PedConstraint* internal)
+{
+ PedConstraint* intersection;
+ PedGeometry* solution;
+
+ intersection = ped_constraint_intersect (external, internal);
+ ped_constraint_destroy (internal);
+ if (!intersection)
+ return NULL;
+
+ solution = ped_constraint_solve_nearest (intersection, &part->geom);
+ ped_constraint_destroy (intersection);
+ return solution;
+}
+
+static PedGeometry*
+_best_solution (const PedPartition* part, const PedCHSGeometry* bios_geom,
+ PedGeometry* a, PedGeometry* b)
+{
+ PedSector cyl_size = bios_geom->heads * bios_geom->sectors;
+ int a_cylinder;
+ int b_cylinder;
+
+ if (!a)
+ return b;
+ if (!b)
+ return a;
+
+ a_cylinder = a->start / cyl_size;
+ b_cylinder = b->start / cyl_size;
+
+ if (a_cylinder == b_cylinder) {
+ if ( (a->start / bios_geom->sectors) % bios_geom->heads
+ < (b->start / bios_geom->sectors) % bios_geom->heads)
+ goto choose_a;
+ else
+ goto choose_b;
+ } else {
+ PedSector a_delta;
+ PedSector b_delta;
+
+ a_delta = llabs (part->geom.start - a->start);
+ b_delta = llabs (part->geom.start - b->start);
+
+ if (a_delta < b_delta)
+ goto choose_a;
+ else
+ goto choose_b;
+ }
+
+ return NULL; /* never get here! */
+
+choose_a:
+ ped_geometry_destroy (b);
+ return a;
+
+choose_b:
+ ped_geometry_destroy (a);
+ return b;
+}
+
+/* This constraint is for "normal" primary partitions, that start at the
+ * beginning of a cylinder, and end at the end of a cylinder.
+ * Note: you can't start a partition at the beginning of the 1st
+ * cylinder, because that's where the partition table is! There are different
+ * rules for that - see the _primary_start_constraint.
+ */
+static PedConstraint*
+_primary_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
+ PedGeometry* min_geom)
+{
+ PedDevice* dev = disk->dev;
+ PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry start_geom;
+ PedGeometry end_geom;
+
+ if (!ped_alignment_init (&start_align, 0, cylinder_size))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, cylinder_size))
+ return NULL;
+
+ if (min_geom) {
+ if (min_geom->start < cylinder_size)
+ return NULL;
+ if (!ped_geometry_init (&start_geom, dev, cylinder_size,
+ min_geom->start + 1 - cylinder_size))
+ return NULL;
+ if (!ped_geometry_init (&end_geom, dev, min_geom->end,
+ dev->length - min_geom->end))
+ return NULL;
+ } else {
+ /* Use cylinder_size as the starting sector number
+ when the device is large enough to accommodate that.
+ Otherwise, use sector 1. */
+ PedSector start = (cylinder_size < dev->length
+ ? cylinder_size : 1);
+ if (!ped_geometry_init (&start_geom, dev, start,
+ dev->length - start))
+ return NULL;
+ if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
+ return NULL;
+ }
+
+ return ped_constraint_new (&start_align, &end_align, &start_geom,
+ &end_geom, 1, dev->length);
+}
+
+/* This constraint is for partitions starting on the first cylinder. They
+ * must start on the 2nd head of the 1st cylinder.
+ *
+ * NOTE: We don't always start on the 2nd head of the 1st cylinder. Windows
+ * Vista aligns starting partitions at sector 2048 (0x800) by default. See:
+ * http://support.microsoft.com/kb/923332
+ */
+static PedConstraint*
+_primary_start_constraint (const PedDisk* disk,
+ const PedPartition *part,
+ const PedCHSGeometry* bios_geom,
+ const PedGeometry* min_geom)
+{
+ PedDevice* dev = disk->dev;
+ PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry start_geom;
+ PedGeometry end_geom;
+ PedSector start_pos;
+
+ if (part->geom.start == 2048)
+ /* check for known Windows Vista (NTFS >= 3.1) alignments */
+ /* sector 0x800 == 2048 */
+ start_pos = 2048;
+ else
+ /* all other primary partitions on a DOS label align to */
+ /* the 2nd head of the first cylinder (0x3F == 63) */
+ start_pos = bios_geom->sectors;
+
+ if (!ped_alignment_init (&start_align, start_pos, 0))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, cylinder_size))
+ return NULL;
+ if (min_geom) {
+ if (!ped_geometry_init (&start_geom, dev, start_pos, 1))
+ return NULL;
+ if (!ped_geometry_init (&end_geom, dev, min_geom->end,
+ dev->length - min_geom->end))
+ return NULL;
+ } else {
+ if (!ped_geometry_init (&start_geom, dev, start_pos,
+ dev->length - start_pos))
+ return NULL;
+ if (!ped_geometry_init (&end_geom, dev, 0, dev->length))
+ return NULL;
+ }
+
+ return ped_constraint_new (&start_align, &end_align, &start_geom,
+ &end_geom, 1, dev->length);
+}
+
+/* constraints for logical partitions:
+ * - start_offset is the offset in the start alignment. "normally",
+ * this is bios_geom->sectors. exceptions: MINOR > 5 at the beginning of the
+ * extended partition, or MINOR == 5 in the middle of the extended partition
+ * - is_start_part == 1 if the constraint is for the first cylinder of
+ * the extended partition, or == 0 if the constraint is for the second cylinder
+ * onwards of the extended partition.
+ */
+static PedConstraint*
+_logical_constraint (const PedDisk* disk, const PedCHSGeometry* bios_geom,
+ PedSector start_offset, int is_start_part)
+{
+ PedPartition* ext_part = ped_disk_extended_partition (disk);
+ PedDevice* dev = disk->dev;
+ PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+
+ PED_ASSERT (ext_part != NULL);
+
+ if (!ped_alignment_init (&start_align, start_offset, cylinder_size))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, cylinder_size))
+ return NULL;
+ if (is_start_part) {
+ if (!ped_geometry_init (&max_geom, dev,
+ ext_part->geom.start,
+ ext_part->geom.length))
+ return NULL;
+ } else {
+ PedSector min_start;
+ PedSector max_length;
+
+ min_start = ped_round_up_to (ext_part->geom.start + 1,
+ cylinder_size);
+ max_length = ext_part->geom.end - min_start + 1;
+ if (min_start >= ext_part->geom.end)
+ return NULL;
+
+ if (!ped_geometry_init (&max_geom, dev, min_start, max_length))
+ return NULL;
+ }
+
+ return ped_constraint_new (&start_align, &end_align, &max_geom,
+ &max_geom, 1, dev->length);
+}
+
+/* returns the minimum geometry for the extended partition, given that the
+ * extended partition must contain:
+ * * all logical partitions
+ * * all partition tables for all logical partitions (except the first)
+ * * the extended partition table
+ */
+static PedGeometry*
+_get_min_extended_part_geom (const PedPartition* ext_part,
+ const PedCHSGeometry* bios_geom)
+{
+ PedDisk* disk = ext_part->disk;
+ PedSector head_size = bios_geom ? bios_geom->sectors : 1;
+ PedPartition* walk;
+ PedGeometry* min_geom;
+
+ walk = ped_disk_get_partition (disk, 5);
+ if (!walk)
+ return NULL;
+
+ min_geom = ped_geometry_duplicate (&walk->geom);
+ if (!min_geom)
+ return NULL;
+ /* We must always allow at least two sectors at the start, to leave
+ * room for LILO. See linux/fs/partitions/msdos.c.
+ */
+ ped_geometry_set_start (min_geom,
+ walk->geom.start - PED_MAX (1 * head_size, 2));
+
+ for (walk = ext_part->part_list; walk; walk = walk->next) {
+ if (!ped_partition_is_active (walk) || walk->num == 5)
+ continue;
+ if (walk->geom.start < min_geom->start)
+ ped_geometry_set_start (min_geom,
+ walk->geom.start - 2 * head_size);
+ if (walk->geom.end > min_geom->end)
+ ped_geometry_set_end (min_geom, walk->geom.end);
+ }
+
+ return min_geom;
+}
+
+static int
+_align_primary (PedPartition* part, const PedCHSGeometry* bios_geom,
+ const PedConstraint* constraint)
+{
+ PedDisk* disk = part->disk;
+ PedGeometry* min_geom = NULL;
+ PedGeometry* solution = NULL;
+
+ if (part->type == PED_PARTITION_EXTENDED)
+ min_geom = _get_min_extended_part_geom (part, bios_geom);
+
+ solution = _best_solution (part, bios_geom, solution,
+ _try_constraint (part, constraint,
+ _primary_start_constraint (disk, part,
+ bios_geom, min_geom)));
+
+ solution = _best_solution (part, bios_geom, solution,
+ _try_constraint (part, constraint,
+ _primary_constraint (disk, bios_geom,
+ min_geom)));
+
+ if (min_geom)
+ ped_geometry_destroy (min_geom);
+
+ if (solution) {
+ ped_geometry_set (&part->geom, solution->start,
+ solution->length);
+ ped_geometry_destroy (solution);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+_logical_min_start_head (const PedPartition* part,
+ const PedCHSGeometry* bios_geom,
+ const PedPartition* ext_part,
+ int is_start_ext_part)
+{
+ PedSector cylinder_size = bios_geom->sectors * bios_geom->heads;
+ PedSector base_head;
+
+ if (is_start_ext_part)
+ base_head = 1 + (ext_part->geom.start % cylinder_size)
+ / bios_geom->sectors;
+ else
+ base_head = 0;
+
+ if (part->num == 5)
+ return base_head + 0;
+ else
+ return base_head + 1;
+}
+
+/* Shamelessly copied and adapted from _partition_get_overlap_constraint
+ * (in disk.c)
+ * This should get rid of the infamous Assertion (metadata_length > 0) failed
+ * bug for extended msdos disklabels generated by Parted.
+ * 1) There always is a partition table at the start of ext_part, so we leave
+ * a one sector gap there.
+ * 2)*The partition table of part5 is always at the beginning of the ext_part
+ * so there is no need to leave a one sector gap before part5.
+ * *There always is a partition table at the beginning of each partition != 5.
+ * We don't need to worry to much about consistency with
+ * _partition_get_overlap_constraint because missing it means we are in edge
+ * cases anyway, and we don't lose anything by just refusing to do the job in
+ * those cases.
+ */
+static PedConstraint*
+_log_meta_overlap_constraint (PedPartition* part, const PedGeometry* geom)
+{
+ PedGeometry safe_space;
+ PedSector min_start;
+ PedSector max_end;
+ PedPartition* ext_part = ped_disk_extended_partition (part->disk);
+ PedPartition* walk;
+ int not_5 = (part->num != 5);
+
+ PED_ASSERT (ext_part != NULL);
+
+ walk = ext_part->part_list;
+
+ /* 1) 2) */
+ min_start = ext_part->geom.start + 1 + not_5;
+ max_end = ext_part->geom.end;
+
+ while (walk != NULL /* 2) 2) */
+ && ( walk->geom.start - (walk->num != 5) < geom->start - not_5
+ || walk->geom.start - (walk->num != 5) <= min_start )) {
+ if (walk != part && ped_partition_is_active (walk))
+ min_start = walk->geom.end + 1 + not_5; /* 2) */
+ walk = walk->next;
+ }
+
+ while (walk && (walk == part || !ped_partition_is_active (walk)))
+ walk = walk->next;
+
+ if (walk)
+ max_end = walk->geom.start - 1 - (walk->num != 5); /* 2) */
+
+ if (min_start >= max_end)
+ return NULL;
+
+ ped_geometry_init (&safe_space, part->disk->dev,
+ min_start, max_end - min_start + 1);
+ return ped_constraint_new_from_max (&safe_space);
+}
+
+static int
+_align_logical (PedPartition* part, const PedCHSGeometry* bios_geom,
+ const PedConstraint* constraint)
+{
+ PedDisk* disk = part->disk;
+ PedPartition* ext_part = ped_disk_extended_partition (disk);
+ PedSector cyl_size = bios_geom->sectors * bios_geom->heads;
+ PedSector start_base;
+ int head;
+ PedGeometry* solution = NULL;
+ PedConstraint *intersect, *log_meta_overlap;
+
+ PED_ASSERT (ext_part != NULL);
+
+ log_meta_overlap = _log_meta_overlap_constraint(part, &part->geom);
+ intersect = ped_constraint_intersect (constraint, log_meta_overlap);
+ ped_constraint_destroy (log_meta_overlap);
+ if (!intersect)
+ return 0;
+
+ start_base = ped_round_down_to (part->geom.start, cyl_size);
+
+ for (head = _logical_min_start_head (part, bios_geom, ext_part, 0);
+ head < PED_MIN (5, bios_geom->heads); head++) {
+ PedConstraint* disk_constraint;
+ PedSector start = start_base + head * bios_geom->sectors;
+
+ if (head >= _logical_min_start_head (part, bios_geom,
+ ext_part, 1))
+ disk_constraint =
+ _logical_constraint (disk, bios_geom, start, 1);
+ else
+ disk_constraint =
+ _logical_constraint (disk, bios_geom, start, 0);
+
+ solution = _best_solution (part, bios_geom, solution,
+ _try_constraint (part, intersect,
+ disk_constraint));
+ }
+
+ ped_constraint_destroy (intersect);
+
+ if (solution) {
+ ped_geometry_set (&part->geom, solution->start,
+ solution->length);
+ ped_geometry_destroy (solution);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+_align (PedPartition* part, const PedCHSGeometry* bios_geom,
+ const PedConstraint* constraint)
+{
+ if (part->type == PED_PARTITION_LOGICAL)
+ return _align_logical (part, bios_geom, constraint);
+ else
+ return _align_primary (part, bios_geom, constraint);
+}
+
+static PedConstraint*
+_no_geom_constraint (const PedDisk* disk, PedSector start, PedSector end)
+{
+ PedGeometry max;
+
+ ped_geometry_init (&max, disk->dev, start, end - start + 1);
+ return ped_constraint_new_from_max (&max);
+}
+
+static PedConstraint*
+_no_geom_extended_constraint (const PedPartition* part)
+{
+ PedDevice* dev = part->disk->dev;
+ PedGeometry* min = _get_min_extended_part_geom (part, NULL);
+ PedGeometry start_range;
+ PedGeometry end_range;
+ PedConstraint* constraint;
+
+ if (min) {
+ ped_geometry_init (&start_range, dev, 1, min->start);
+ ped_geometry_init (&end_range, dev, min->end,
+ dev->length - min->end);
+ ped_geometry_destroy (min);
+ } else {
+ ped_geometry_init (&start_range, dev, 1, dev->length - 1);
+ ped_geometry_init (&end_range, dev, 1, dev->length - 1);
+ }
+ constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
+ &start_range, &end_range, 1, dev->length);
+ return constraint;
+}
+
+static int
+_align_primary_no_geom (PedPartition* part, const PedConstraint* constraint)
+{
+ PedDisk* disk = part->disk;
+ PedGeometry* solution;
+
+ if (part->type == PED_PARTITION_EXTENDED) {
+ solution = _try_constraint (part, constraint,
+ _no_geom_extended_constraint (part));
+ } else {
+ solution = _try_constraint (part, constraint,
+ _no_geom_constraint (disk, 1,
+ disk->dev->length - 1));
+ }
+
+ if (solution) {
+ ped_geometry_set (&part->geom, solution->start,
+ solution->length);
+ ped_geometry_destroy (solution);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+_align_logical_no_geom (PedPartition* part, const PedConstraint* constraint)
+{
+ PedGeometry* solution;
+
+ solution = _try_constraint (part, constraint,
+ _log_meta_overlap_constraint (part, &part->geom));
+
+ if (solution) {
+ ped_geometry_set (&part->geom, solution->start,
+ solution->length);
+ ped_geometry_destroy (solution);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+_align_no_geom (PedPartition* part, const PedConstraint* constraint)
+{
+ if (part->type == PED_PARTITION_LOGICAL)
+ return _align_logical_no_geom (part, constraint);
+ else
+ return _align_primary_no_geom (part, constraint);
+}
+
+static int
+msdos_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PedCHSGeometry bios_geom;
+ DosPartitionData* dos_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ dos_data = part->disk_specific;
+
+ if (dos_data->system == PARTITION_LDM && dos_data->orig) {
+ PedGeometry *orig_geom = &dos_data->orig->geom;
+
+ if (ped_geometry_test_equal (&part->geom, orig_geom)
+ && ped_constraint_is_solution (constraint, &part->geom))
+ return 1;
+
+ ped_geometry_set (&part->geom, orig_geom->start,
+ orig_geom->length);
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Parted can't resize partitions managed by "
+ "Windows Dynamic Disk."));
+ return 0;
+ }
+
+ partition_probe_bios_geometry (part, &bios_geom);
+
+ DosDiskData *disk_specific = part->disk->disk_specific;
+ if (disk_specific->cylinder_alignment
+ && _align(part, &bios_geom, constraint))
+ return 1;
+ if (_align_no_geom (part, constraint))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+add_metadata_part (PedDisk* disk, PedPartitionType type, PedSector start,
+ PedSector end)
+{
+ PedPartition* new_part;
+
+ PED_ASSERT (disk != NULL);
+
+ new_part = ped_partition_new (disk, type | PED_PARTITION_METADATA, NULL,
+ start, end);
+ if (!new_part)
+ goto error;
+ if (!ped_disk_add_partition (disk, new_part, NULL))
+ goto error_destroy_new_part;
+
+ return 1;
+
+error_destroy_new_part:
+ ped_partition_destroy (new_part);
+error:
+ return 0;
+}
+
+/* There are a few objectives here:
+ * - avoid having lots of "free space" partitions lying around, to confuse
+ * the front end.
+ * - ensure that there's enough room to put in the extended partition
+ * tables, etc.
+ */
+static int
+add_logical_part_metadata (PedDisk* disk, const PedPartition* log_part)
+{
+ PedPartition* ext_part = ped_disk_extended_partition (disk);
+ PedPartition* prev = log_part->prev;
+ PedCHSGeometry bios_geom;
+ PedSector cyl_size;
+ PedSector metadata_start;
+ PedSector metadata_end;
+ PedSector metadata_length;
+
+ partition_probe_bios_geometry (ext_part, &bios_geom);
+ cyl_size = bios_geom.sectors * bios_geom.heads;
+
+ /* if there's metadata shortly before the partition (on the same
+ * cylinder), then make this new metadata partition touch the end of
+ * the other. No point having 63 bytes (or whatever) of free space
+ * partition - just confuses front-ends, etc.
+ * Otherwise, start the metadata at the start of the cylinder
+ */
+
+ metadata_end = log_part->geom.start - 1;
+ metadata_start = ped_round_down_to (metadata_end, cyl_size);
+ if (prev)
+ metadata_start = PED_MAX (metadata_start, prev->geom.end + 1);
+ else
+ metadata_start = PED_MAX (metadata_start,
+ ext_part->geom.start + 1);
+ metadata_length = metadata_end - metadata_start + 1;
+
+ /* partition 5 doesn't need to have any metadata */
+ if (log_part->num == 5 && metadata_length < bios_geom.sectors)
+ return 1;
+
+ PED_ASSERT (metadata_length > 0);
+
+ return add_metadata_part (disk, PED_PARTITION_LOGICAL,
+ metadata_start, metadata_end);
+}
+
+/*
+ * Find the starting sector number of the first non-free partition,
+ * set *SECTOR to that value, and return 1.
+ * If there is no non-free partition, don't modify *SECTOR and return 0.
+ */
+static int
+get_start_first_nonfree_part (const PedDisk* disk, PedSector *sector)
+{
+ PedPartition* walk;
+
+ // disk->part_list is the first partition on the disk.
+ if (!disk->part_list)
+ return 0;
+
+ for (walk = disk->part_list; walk; walk = walk->next) {
+ if (walk->type == PED_PARTITION_NORMAL ||
+ walk->type == PED_PARTITION_EXTENDED) {
+ *sector = walk->geom.start;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Find the ending sector number of the last non-free partition,
+ * set *SECTOR to that value, and return 1.
+ * If there is no non-free partition, don't modify *SECTOR and return 0.
+ */
+static int
+get_end_last_nonfree_part (const PedDisk* disk, PedSector *sector)
+{
+ PedPartition* last_part = NULL;
+ PedPartition* walk;
+
+ // disk->part_list is the first partition on the disk.
+ if (!disk->part_list)
+ return 0;
+
+ for (walk = disk->part_list; walk; walk = walk->next) {
+ if (walk->type == PED_PARTITION_NORMAL ||
+ walk->type == PED_PARTITION_EXTENDED) {
+ last_part = walk;
+ }
+ }
+
+ if (!last_part)
+ return 0;
+ else {
+ *sector = last_part->geom.end;
+ return 1;
+ }
+}
+
+/* Adds metadata placeholder partitions to cover the partition table (and
+ * "free" space after it that often has bootloader stuff), and the last
+ * incomplete cylinder at the end of the disk.
+ * Parted has to be mindful of the uncertainty of dev->bios_geom.
+ * It therefore makes sure this metadata doesn't overlap with partitions.
+ */
+static int
+add_startend_metadata (PedDisk* disk)
+{
+ PedDevice* dev = disk->dev;
+ PedSector cyl_size = dev->bios_geom.sectors * dev->bios_geom.heads;
+ PedSector init_start, init_end, final_start, final_end;
+
+ // Ranges for the initial and final metadata partition.
+ init_start = 0;
+ if (!get_start_first_nonfree_part(disk, &init_end))
+ init_end = dev->bios_geom.sectors - 1;
+ else
+ init_end = PED_MIN (dev->bios_geom.sectors - 1, init_end - 1);
+
+ DosDiskData *disk_specific = disk->disk_specific;
+ if (!disk_specific->cylinder_alignment)
+ final_start = dev->length - 1;
+ else if (!get_end_last_nonfree_part(disk, &final_start))
+ final_start = ped_round_down_to (dev->length, cyl_size);
+ else
+ final_start = PED_MAX (final_start + 1,
+ ped_round_down_to (dev->length, cyl_size));
+ final_end = dev->length - 1;
+
+ // Create the metadata partitions.
+ // init_end <= dev->length for devices that are _real_ small.
+ if (init_start < init_end &&
+ init_end <= dev->length &&
+ !add_metadata_part (disk, PED_PARTITION_NORMAL,
+ init_start, init_end))
+ return 0;
+
+ // init_end < final_start so they dont overlap. For very small devs.
+ if (final_start < final_end &&
+ init_end < final_start &&
+ final_end <= dev->length &&
+ !add_metadata_part (disk, PED_PARTITION_NORMAL,
+ final_start, final_end))
+ return 0;
+
+ return 1;
+}
+
+static int
+msdos_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* ext_part;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ if (!add_startend_metadata (disk))
+ return 0;
+
+ ext_part = ped_disk_extended_partition (disk);
+ if (ext_part) {
+ int i;
+ PedSector start, end;
+ PedCHSGeometry bios_geom;
+
+ for (i=5; 1; i++) {
+ PedPartition* log_part;
+ log_part = ped_disk_get_partition (disk, i);
+ if (!log_part)
+ break;
+ if (!add_logical_part_metadata (disk, log_part))
+ return 0;
+ }
+
+ partition_probe_bios_geometry (ext_part, &bios_geom);
+ start = ext_part->geom.start;
+ end = start + bios_geom.sectors - 1;
+ if (ext_part->part_list)
+ end = PED_MIN (end,
+ ext_part->part_list->geom.start - 1);
+ if (!add_metadata_part (disk, PED_PARTITION_LOGICAL,
+ start, end))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+next_primary (const PedDisk* disk)
+{
+ int i;
+ for (i=1; i<=DOS_N_PRI_PARTITIONS; i++) {
+ if (!ped_disk_get_partition (disk, i))
+ return i;
+ }
+ return -1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+next_logical (const PedDisk* disk)
+{
+ int i;
+ for (i=5; i<=MAX_TOTAL_PART; i++) {
+ if (!ped_disk_get_partition (disk, i))
+ return i;
+ }
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("cannot create any more partitions"),
+ disk->dev->path);
+ return -1;
+}
+
+static int
+msdos_partition_enumerate (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ /* don't re-number a primary partition */
+ if (part->num != -1 && part->num <= DOS_N_PRI_PARTITIONS)
+ return 1;
+
+ part->num = -1;
+
+ if (part->type & PED_PARTITION_LOGICAL)
+ part->num = next_logical (part->disk);
+ else
+ part->num = next_primary (part->disk);
+ if (part->num == -1)
+ return 0;
+ return 1;
+}
+
+static int
+msdos_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return DOS_N_PRI_PARTITIONS;
+}
+
+static bool
+msdos_get_max_supported_partition_count(const PedDisk* disk, int *max_n)
+{
+ *max_n = MAX_TOTAL_PART;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (msdos)
+
+static PedDiskOps msdos_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (msdos_write),
+
+ disk_set_flag: msdos_disk_set_flag,
+ disk_get_flag: msdos_disk_get_flag,
+ disk_is_flag_available: msdos_disk_is_flag_available,
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+ partition_set_type_id: msdos_partition_set_type_id,
+ partition_get_type_id: msdos_partition_get_type_id,
+ partition_set_type_uuid: NULL,
+ partition_get_type_uuid: NULL,
+
+ PT_op_function_initializers (msdos)
+};
+
+static PedDiskType msdos_disk_type = {
+ next: NULL,
+ name: "msdos",
+ ops: &msdos_disk_ops,
+ features: PED_DISK_TYPE_EXTENDED | PED_DISK_TYPE_PARTITION_TYPE_ID
+};
+
+void
+ped_disk_msdos_init ()
+{
+ PED_ASSERT (sizeof (DosRawPartition) == 16);
+ PED_ASSERT (sizeof (DosRawTable) == 512);
+
+ ped_disk_type_register (&msdos_disk_type);
+}
+
+void
+ped_disk_msdos_done ()
+{
+ ped_disk_type_unregister (&msdos_disk_type);
+}
diff --git a/libparted/labels/dvh.c b/libparted/labels/dvh.c
new file mode 100644
index 0000000..0f9124d
--- /dev/null
+++ b/libparted/labels/dvh.c
@@ -0,0 +1,896 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2001-2002, 2005, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#include "dvh.h"
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+/* Default size for volhdr part, same val as IRIX's fx uses */
+#define PTYPE_VOLHDR_DFLTSZ 4096
+
+/* Partition numbers that seem to be strongly held convention */
+#define PNUM_VOLHDR 8
+#define PNUM_VOLUME 10
+
+/* Other notes of interest:
+ * PED_PARTITION_EXTENDED is used for volume headers
+ * PED_PARTITION_LOGICAL is used for bootfiles
+ * PED_PARTITION_NORMAL is used for all else
+ */
+
+typedef struct _DVHDiskData {
+ struct device_parameters dev_params;
+ int swap; /* part num of swap, 0=none */
+ int root; /* part num of root, 0=none */
+ int boot; /* part num of boot, 0=none */
+} DVHDiskData;
+
+typedef struct _DVHPartData {
+ int type;
+ char name[VDNAMESIZE + 1]; /* boot volumes only */
+ int real_file_size; /* boot volumes only */
+} DVHPartData;
+
+static PedDiskType dvh_disk_type;
+
+static int
+dvh_probe (const PedDevice *dev)
+{
+ struct volume_header *vh;
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+
+ vh = (struct volume_header *) label;
+
+ bool found = PED_BE32_TO_CPU (vh->vh_magic) == VHMAGIC;
+ free (label);
+ return found;
+}
+
+static PedDisk*
+dvh_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ DVHDiskData* dvh_disk_data;
+ PedPartition* volume_part;
+ PedConstraint* constraint_any;
+
+ disk = _ped_disk_alloc (dev, &dvh_disk_type);
+ if (!disk)
+ goto error;
+
+ disk->disk_specific = dvh_disk_data
+ = ped_malloc (sizeof (DVHDiskData));
+ if (!dvh_disk_data)
+ goto error_free_disk;
+
+ memset (&dvh_disk_data->dev_params, 0,
+ sizeof (struct device_parameters));
+ dvh_disk_data->swap = 0;
+ dvh_disk_data->root = 0;
+ dvh_disk_data->boot = 0;
+
+ volume_part = ped_partition_new (disk, PED_PARTITION_EXTENDED, NULL,
+ 0, PTYPE_VOLHDR_DFLTSZ - 1);
+ if (!volume_part)
+ goto error_free_disk_specific;
+ volume_part->num = PNUM_VOLHDR + 1;
+ constraint_any = ped_constraint_any (dev);
+ if (!ped_disk_add_partition (disk, volume_part, constraint_any))
+ goto error_destroy_constraint_any;
+ ped_constraint_destroy (constraint_any);
+ return disk;
+
+error_destroy_constraint_any:
+ ped_constraint_destroy (constraint_any);
+ ped_partition_destroy (volume_part);
+error_free_disk_specific:
+ free (disk->disk_specific);
+error_free_disk:
+ free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk*
+dvh_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ DVHDiskData* new_dvh_disk_data;
+ DVHDiskData* old_dvh_disk_data = disk->disk_specific;
+
+ PED_ASSERT (old_dvh_disk_data != NULL);
+
+ new_disk = ped_disk_new_fresh (disk->dev, &dvh_disk_type);
+ if (!new_disk)
+ goto error;
+
+ new_disk->disk_specific = new_dvh_disk_data
+ = ped_malloc (sizeof (DVHDiskData));
+ if (!new_dvh_disk_data)
+ goto error_free_new_disk;
+
+ new_dvh_disk_data->dev_params = old_dvh_disk_data->dev_params;
+ return new_disk;
+
+error_free_new_disk:
+ free (new_disk);
+error:
+ return NULL;
+}
+
+static void
+dvh_free (PedDisk* disk)
+{
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+/* two's complement 32-bit checksum */
+static uint32_t _GL_ATTRIBUTE_PURE
+_checksum (const uint32_t* base, size_t size)
+{
+ uint32_t sum = 0;
+ size_t i;
+
+ for (i = 0; i < size / sizeof (uint32_t); i++)
+ sum = sum - PED_BE32_TO_CPU (base[i]);
+
+ return sum;
+}
+
+/* try to make a reasonable volume header partition... */
+static PedExceptionOption
+_handle_no_volume_header (PedDisk* disk)
+{
+ PedExceptionOption ret;
+ PedPartition* part;
+ PedConstraint* constraint;
+
+ switch (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_FIX + PED_EXCEPTION_CANCEL,
+ _("%s has no extended partition (volume header partition)."),
+ disk->dev->path)) {
+ case PED_EXCEPTION_UNHANDLED:
+ case PED_EXCEPTION_FIX:
+ default:
+ part = ped_partition_new (
+ disk, PED_PARTITION_EXTENDED, NULL,
+ 0, PTYPE_VOLHDR_DFLTSZ - 1);
+ if (!part)
+ goto error;
+ part->num = PNUM_VOLHDR + 1;
+ constraint = ped_constraint_any (part->disk->dev);
+ if (!constraint)
+ goto error_destroy_part;
+ if (!ped_disk_add_partition (disk, part, constraint))
+ goto error_destroy_constraint;
+ ped_constraint_destroy (constraint);
+ ret = PED_EXCEPTION_FIX;
+ break;
+
+ case PED_EXCEPTION_CANCEL:
+ goto error;
+ }
+ return ret;
+
+error_destroy_constraint:
+ ped_constraint_destroy (constraint);
+error_destroy_part:
+ ped_partition_destroy (part);
+error:
+ return PED_EXCEPTION_CANCEL;
+}
+
+static PedPartition*
+_parse_partition (PedDisk* disk, struct partition_table* pt)
+{
+ PedPartition* part;
+ DVHPartData* dvh_part_data;
+ PedSector start = PED_BE32_TO_CPU (pt->pt_firstlbn);
+ PedSector length = PED_BE32_TO_CPU (pt->pt_nblks);
+
+ part = ped_partition_new (disk,
+ pt->pt_type ? 0 : PED_PARTITION_EXTENDED,
+ NULL,
+ start, start + length - 1);
+ if (!part)
+ return NULL;
+
+ dvh_part_data = part->disk_specific;
+ dvh_part_data->type = PED_BE32_TO_CPU (pt->pt_type);
+ strcpy (dvh_part_data->name, "");
+
+ return part;
+}
+
+static PedPartition*
+_parse_boot_file (PedDisk* disk, struct volume_directory* vd)
+{
+ PedPartition* part;
+ DVHPartData* dvh_part_data;
+ PedSector start = PED_BE32_TO_CPU (vd->vd_lbn);
+ int length = PED_BE32_TO_CPU (vd->vd_nbytes);
+
+ part = ped_partition_new (disk, PED_PARTITION_LOGICAL, NULL,
+ start, start + length/512 - 1);
+ if (!part)
+ return NULL;
+
+ dvh_part_data = part->disk_specific;
+ dvh_part_data->real_file_size = length;
+
+ memcpy (dvh_part_data->name, vd->vd_name, VDNAMESIZE);
+ dvh_part_data->name[VDNAMESIZE] = 0;
+ return part;
+}
+
+static int dvh_write (const PedDisk* disk);
+
+/* YUCK
+ *
+ * If you remove a boot/root/swap partition, the disk->disk_specific
+ * thing isn't updated. (Probably reflects a design bug somewhere...)
+ * Anyway, the workaround is: flush stale flags whenever we allocate
+ * new partition numbers, and before we write to disk.
+ */
+static void
+_flush_stale_flags (const PedDisk* disk)
+{
+ DVHDiskData* dvh_disk_data = disk->disk_specific;
+
+ if (dvh_disk_data->root
+ && !ped_disk_get_partition (disk, dvh_disk_data->root))
+ dvh_disk_data->root = 0;
+ if (dvh_disk_data->swap
+ && !ped_disk_get_partition (disk, dvh_disk_data->swap))
+ dvh_disk_data->swap = 0;
+ if (dvh_disk_data->boot
+ && !ped_disk_get_partition (disk, dvh_disk_data->boot))
+ dvh_disk_data->boot = 0;
+}
+
+static int
+dvh_read (PedDisk* disk)
+{
+ DVHDiskData* dvh_disk_data = disk->disk_specific;
+ int i;
+ struct volume_header vh;
+ char boot_name [BFNAMESIZE + 1];
+#ifndef DISCOVER_ONLY
+ int write_back = 0;
+#endif
+
+ PED_ASSERT (dvh_disk_data != NULL);
+
+ ped_disk_delete_all (disk);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return 0;
+ memcpy (&vh, s0, sizeof vh);
+ free (s0);
+
+ if (_checksum ((uint32_t*) &vh, sizeof (struct volume_header))) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Checksum is wrong, indicating the partition "
+ "table is corrupt."))
+ == PED_EXCEPTION_CANCEL)
+ return 0;
+ }
+
+ PED_ASSERT (PED_BE32_TO_CPU (vh.vh_magic) == VHMAGIC);
+
+ dvh_disk_data->dev_params = vh.vh_dp;
+ boot_name[BFNAMESIZE] = 0;
+ strncpy (boot_name, vh.vh_bootfile, BFNAMESIZE);
+
+ /* normal partitions */
+ for (i = 0; i < NPARTAB; i++) {
+ PedPartition* part;
+
+ if (!vh.vh_pt[i].pt_nblks)
+ continue;
+ /* Skip the whole-disk partition, parted disklikes overlap */
+ if (PED_BE32_TO_CPU (vh.vh_pt[i].pt_type) == PTYPE_VOLUME)
+ continue;
+
+ part = _parse_partition (disk, &vh.vh_pt[i]);
+ if (!part)
+ goto error_delete_all;
+
+ part->fs_type = ped_file_system_probe (&part->geom);
+ part->num = i + 1;
+
+ if (PED_BE16_TO_CPU (vh.vh_rootpt) == i)
+ ped_partition_set_flag (part, PED_PARTITION_ROOT, 1);
+ if (PED_BE16_TO_CPU (vh.vh_swappt) == i)
+ ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok) {
+ ped_partition_destroy (part);
+ goto error_delete_all;
+ }
+ }
+
+ if (!ped_disk_extended_partition (disk)) {
+#ifdef DISCOVER_ONLY
+ return 1;
+#else
+ switch (_handle_no_volume_header (disk)) {
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+ case PED_EXCEPTION_IGNORE:
+ return 1;
+ case PED_EXCEPTION_FIX:
+ write_back = 1;
+ break;
+ default:
+ break;
+ }
+#endif
+ }
+
+ /* boot partitions */
+ for (i = 0; i < NVDIR; i++) {
+ PedPartition* part;
+
+ if (!vh.vh_vd[i].vd_nbytes)
+ continue;
+
+ part = _parse_boot_file (disk, &vh.vh_vd[i]);
+ if (!part)
+ goto error_delete_all;
+
+ part->fs_type = ped_file_system_probe (&part->geom);
+ part->num = NPARTAB + i + 1;
+
+ if (!strcmp (boot_name, ped_partition_get_name (part)))
+ ped_partition_set_flag (part, PED_PARTITION_BOOT, 1);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok) {
+ ped_partition_destroy (part);
+ goto error_delete_all;
+ }
+ }
+#ifndef DISCOVER_ONLY
+ if (write_back)
+ dvh_write (disk);
+#endif
+ return 1;
+
+error_delete_all:
+ ped_disk_delete_all (disk);
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+static void
+_generate_partition (PedPartition* part, struct partition_table* pt)
+{
+ DVHPartData* dvh_part_data = part->disk_specific;
+
+ /* Assert not a bootfile */
+ PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) == 0);
+
+ pt->pt_nblks = PED_CPU_TO_BE32 (part->geom.length);
+ pt->pt_firstlbn = PED_CPU_TO_BE32 (part->geom.start);
+ pt->pt_type = PED_CPU_TO_BE32 (dvh_part_data->type);
+}
+
+static void
+_generate_boot_file (PedPartition* part, struct volume_directory* vd)
+{
+ DVHPartData* dvh_part_data = part->disk_specific;
+
+ /* Assert it's a bootfile */
+ PED_ASSERT ((part->type & PED_PARTITION_LOGICAL) != 0);
+
+ vd->vd_nbytes = PED_CPU_TO_BE32 (dvh_part_data->real_file_size);
+ vd->vd_lbn = PED_CPU_TO_BE32 (part->geom.start);
+
+ memset (vd->vd_name, 0, VDNAMESIZE);
+ memcpy (vd->vd_name, dvh_part_data->name, VDNAMESIZE);
+}
+
+static int
+dvh_write (const PedDisk* disk)
+{
+ DVHDiskData* dvh_disk_data = disk->disk_specific;
+ struct volume_header vh;
+ int i;
+
+ PED_ASSERT (dvh_disk_data != NULL);
+
+ _flush_stale_flags (disk);
+
+ memset (&vh, 0, sizeof (struct volume_header));
+
+ vh.vh_magic = PED_CPU_TO_BE32 (VHMAGIC);
+ vh.vh_rootpt = PED_CPU_TO_BE16 (dvh_disk_data->root - 1);
+ vh.vh_swappt = PED_CPU_TO_BE16 (dvh_disk_data->swap - 1);
+
+ if (dvh_disk_data->boot) {
+ PedPartition* boot_part;
+ boot_part = ped_disk_get_partition (disk, dvh_disk_data->boot);
+ strcpy (vh.vh_bootfile, ped_partition_get_name (boot_part));
+ }
+
+ vh.vh_dp = dvh_disk_data->dev_params;
+ /* Set up rudimentary device geometry */
+ vh.vh_dp.dp_cyls
+ = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.cylinders);
+ vh.vh_dp.dp_trks0 = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.heads);
+ vh.vh_dp.dp_secs
+ = PED_CPU_TO_BE16 ((short)disk->dev->bios_geom.sectors);
+ vh.vh_dp.dp_secbytes = PED_CPU_TO_BE16 ((short)disk->dev->sector_size);
+
+ for (i = 0; i < NPARTAB; i++) {
+ PedPartition* part = ped_disk_get_partition (disk, i + 1);
+ if (part)
+ _generate_partition (part, &vh.vh_pt[i]);
+ }
+
+ /* whole disk partition
+ * This is only ever written here, and never modified
+ * (or even shown) as it must contain the entire disk,
+ * and parted does not like overlapping partitions
+ */
+ vh.vh_pt[PNUM_VOLUME].pt_nblks = PED_CPU_TO_BE32 (disk->dev->length);
+ vh.vh_pt[PNUM_VOLUME].pt_firstlbn = PED_CPU_TO_BE32 (0);
+ vh.vh_pt[PNUM_VOLUME].pt_type = PED_CPU_TO_BE32 (PTYPE_VOLUME);
+
+ for (i = 0; i < NVDIR; i++) {
+ PedPartition* part = ped_disk_get_partition (disk,
+ i + 1 + NPARTAB);
+ if (part)
+ _generate_boot_file (part, &vh.vh_vd[i]);
+ }
+
+ vh.vh_csum = 0;
+ vh.vh_csum = PED_CPU_TO_BE32 (_checksum ((uint32_t*) &vh,
+ sizeof (struct volume_header)));
+
+ return (ptt_write_sector (disk, &vh, sizeof vh)
+ && ped_device_sync (disk->dev));
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+dvh_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ DVHPartData* dvh_part_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (!ped_partition_is_active (part)) {
+ part->disk_specific = NULL;
+ return part;
+ }
+
+ dvh_part_data = part->disk_specific =
+ ped_malloc (sizeof (DVHPartData));
+ if (!dvh_part_data)
+ goto error_free_part;
+
+ dvh_part_data->type = (part_type == PED_PARTITION_EXTENDED)
+ ? PTYPE_VOLHDR
+ : PTYPE_RAW;
+ strcpy (dvh_part_data->name, "");
+ dvh_part_data->real_file_size = part->geom.length * 512;
+ return part;
+
+error_free_part:
+ _ped_partition_free (part);
+error:
+ return NULL;
+}
+
+static PedPartition*
+dvh_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* result;
+ DVHPartData* part_data = part->disk_specific;
+ DVHPartData* result_data;
+
+ result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (!result)
+ goto error;
+ result->num = part->num;
+
+ if (!ped_partition_is_active (part)) {
+ result->disk_specific = NULL;
+ return result;
+ }
+
+ result_data = result->disk_specific =
+ ped_malloc (sizeof (DVHPartData));
+ if (!result_data)
+ goto error_free_part;
+
+ result_data->type = part_data->type;
+ strcpy (result_data->name, part_data->name);
+ result_data->real_file_size = part_data->real_file_size;
+ return result;
+
+error_free_part:
+ _ped_partition_free (result);
+error:
+ return NULL;
+}
+
+static void
+dvh_partition_destroy (PedPartition* part)
+{
+ if (ped_partition_is_active (part)) {
+ PED_ASSERT (part->disk_specific != NULL);
+ free (part->disk_specific);
+ }
+ _ped_partition_free (part);
+}
+
+static int
+dvh_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ DVHPartData* dvh_part_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ if (part->type == PED_PARTITION_EXTENDED) {
+ dvh_part_data->type = PTYPE_VOLHDR;
+ return 1;
+ }
+
+ /* Is this a bootfile? */
+ if (part->type == PED_PARTITION_LOGICAL)
+ return 1;
+
+ if (fs_type && !strcmp (fs_type->name, "xfs"))
+ dvh_part_data->type = PTYPE_XFS;
+ else
+ dvh_part_data->type = PTYPE_RAW;
+ return 1;
+}
+
+static int
+dvh_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ DVHDiskData* dvh_disk_data = part->disk->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_ROOT:
+ if (part->type != 0 && state) {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Only primary partitions can be root "
+ "partitions."));
+#endif
+ return 0;
+ }
+ dvh_disk_data->root = state ? part->num : 0;
+ break;
+
+ case PED_PARTITION_SWAP:
+ if (part->type != 0 && state) {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Only primary partitions can be swap "
+ "partitions."));
+ return 0;
+#endif
+ }
+ dvh_disk_data->swap = state ? part->num : 0;
+ break;
+
+ case PED_PARTITION_BOOT:
+ if (part->type != PED_PARTITION_LOGICAL && state) {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Only logical partitions can be a boot "
+ "file."));
+#endif
+ return 0;
+ }
+ dvh_disk_data->boot = state ? part->num : 0;
+ break;
+
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_LBA:
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_RAID:
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+dvh_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ DVHDiskData* dvh_disk_data = part->disk->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_ROOT:
+ return dvh_disk_data->root == part->num;
+
+ case PED_PARTITION_SWAP:
+ return dvh_disk_data->swap == part->num;
+
+ case PED_PARTITION_BOOT:
+ return dvh_disk_data->boot == part->num;
+
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_LBA:
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_RAID:
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int
+dvh_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_SWAP:
+ case PED_PARTITION_BOOT:
+ return 1;
+
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_LBA:
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_RAID:
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static void
+dvh_partition_set_name (PedPartition* part, const char* name)
+{
+ DVHPartData* dvh_part_data = part->disk_specific;
+
+ if (part->type == PED_PARTITION_LOGICAL) {
+ /* Bootfile */
+ memcpy (dvh_part_data->name, name, VDNAMESIZE);
+ dvh_part_data->name[VDNAMESIZE] = 0;
+ } else {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("failed to set dvh partition name to %s:\n"
+ "Only logical partitions (boot files) have a name."),
+ name);
+#endif
+ }
+}
+
+static const char*
+dvh_partition_get_name (const PedPartition* part)
+{
+ DVHPartData* dvh_part_data = part->disk_specific;
+ return dvh_part_data->name;
+}
+
+/* The constraint for the volume header partition is different, because it must
+ * contain the first sector of the disk.
+ */
+static PedConstraint*
+_get_extended_constraint (PedDisk* disk)
+{
+ PedGeometry min_geom;
+ if (!ped_geometry_init (&min_geom, disk->dev, 0, 1))
+ return NULL;
+ return ped_constraint_new_from_min (&min_geom);
+}
+
+static PedConstraint*
+_get_primary_constraint (PedDisk* disk)
+{
+ PedGeometry max_geom;
+ if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
+ return NULL;
+ return ped_constraint_new_from_max (&max_geom);
+}
+
+static int
+dvh_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ if (_ped_partition_attempt_align (
+ part, constraint,
+ (part->type == PED_PARTITION_EXTENDED)
+ ? _get_extended_constraint (part->disk)
+ : _get_primary_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+dvh_partition_enumerate (PedPartition* part)
+{
+ int i;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+
+ _flush_stale_flags (part->disk);
+
+ if (part->type & PED_PARTITION_LOGICAL) {
+ /* Bootfile */
+ for (i = 1 + NPARTAB; i <= NPARTAB + NVDIR; i++) {
+ if (!ped_disk_get_partition (part->disk, i)) {
+ part->num = i;
+ return 1;
+ }
+ }
+ PED_ASSERT (0);
+ } else if (part->type & PED_PARTITION_EXTENDED) {
+ /* Volheader */
+ part->num = PNUM_VOLHDR + 1;
+ } else {
+ for (i = 1; i <= NPARTAB; i++) {
+ /* reserved for full volume partition */
+ if (i == PNUM_VOLUME + 1)
+ continue;
+
+ if (!ped_disk_get_partition (part->disk, i)) {
+ part->num = i;
+ return 1;
+ }
+ }
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Too many primary partitions"));
+ }
+
+ return 0;
+}
+
+static int
+dvh_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return NPARTAB;
+}
+
+static bool
+dvh_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = NPARTAB;
+ return true;
+}
+
+
+static int
+dvh_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* part;
+ PedPartition* extended_part;
+ PedPartitionType metadata_type;
+ PED_ASSERT(disk != NULL);
+
+ /* We don't need to "protect" the start of the disk from the volume
+ * header.
+ */
+ extended_part = ped_disk_extended_partition (disk);
+ if (extended_part && extended_part->geom.start == 0)
+ metadata_type = PED_PARTITION_METADATA | PED_PARTITION_LOGICAL;
+ else
+ metadata_type = PED_PARTITION_METADATA;
+
+ part = ped_partition_new (disk, metadata_type, NULL, 0, 0);
+ if (!part)
+ goto error;
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (ok)
+ return 1;
+
+ ped_partition_destroy (part);
+error:
+ return 0;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (dvh)
+
+static PedDiskOps dvh_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (dvh_write),
+
+ partition_set_name: dvh_partition_set_name,
+ partition_get_name: dvh_partition_get_name,
+ PT_op_function_initializers (dvh)
+};
+
+static PedDiskType dvh_disk_type = {
+ next: NULL,
+ name: "dvh",
+ ops: &dvh_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_EXTENDED
+};
+
+void
+ped_disk_dvh_init ()
+{
+ PED_ASSERT (sizeof (struct volume_header) == 512);
+
+ ped_disk_type_register (&dvh_disk_type);
+}
+
+void
+ped_disk_dvh_done ()
+{
+ ped_disk_type_unregister (&dvh_disk_type);
+}
diff --git a/libparted/labels/dvh.h b/libparted/labels/dvh.h
new file mode 100644
index 0000000..7e7fae7
--- /dev/null
+++ b/libparted/labels/dvh.h
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 1985 MIPS Computer Systems, Inc.
+ Copyright (C) 2000 Silicon Graphics Computer Systems, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _SYS_DVH_H
+#define _SYS_DVH_H
+
+/*
+ * Format for volume header information
+ *
+ * The volume header is a block located at the beginning of all disk
+ * media (sector 0). It contains information pertaining to physical
+ * device parameters and logical partition information.
+ *
+ * The volume header is manipulated by disk formatters/verifiers,
+ * partition builders (e.g. fx, dvhtool, and mkfs), and disk drivers.
+ *
+ * Previous versions of IRIX wrote a copy of the volume header is
+ * located at sector 0 of each track of cylinder 0. These copies were
+ * never used, and reduced the capacity of the volume header to hold large
+ * files, so this practice was discontinued.
+ * The volume header is constrained to be less than or equal to 512
+ * bytes long. A particular copy is assumed valid if no drive errors
+ * are detected, the magic number is correct, and the 32 bit 2's complement
+ * of the volume header is correct. The checksum is calculated by initially
+ * zeroing vh_csum, summing the entire structure and then storing the
+ * 2's complement of the sum. Thus a checksum to verify the volume header
+ * should be 0.
+ *
+ * The error summary table, bad sector replacement table, and boot blocks are
+ * located by searching the volume directory within the volume header.
+ *
+ * Tables are sized simply by the integral number of table records that
+ * will fit in the space indicated by the directory entry.
+ *
+ * The amount of space allocated to the volume header, replacement blocks,
+ * and other tables is user defined when the device is formatted.
+ */
+
+/*
+ * device parameters are in the volume header to determine mapping
+ * from logical block numbers to physical device addresses
+ *
+ * Linux doesn't care ...
+ */
+struct device_parameters {
+ unsigned char dp_skew; /* spiral addressing skew */
+ unsigned char dp_gap1; /* words of 0 before header */
+ unsigned char dp_gap2; /* words of 0 between hdr and data */
+ unsigned char dp_spares_cyl; /* This is for drives (such as SCSI
+ that support zone oriented sparing, where the zone is larger
+ than one track. It gets subracteded from the cylinder size
+ ( dp_trks0 * dp_sec) when doing partition size calculations */
+ unsigned short dp_cyls; /* number of usable cylinders (i.e.,
+ doesn't include cylinders reserved by the drive for badblocks,
+ etc.). For drives with variable geometry, this number may be
+ decreased so that:
+ dp_cyls * ((dp_heads * dp_trks0) - dp_spares_cyl) <= actualcapacity
+ This happens on SCSI drives such as the Wren IV and Toshiba 156
+ Also see dp_cylshi below */
+ unsigned short dp_shd0; /* starting head vol 0 */
+ unsigned short dp_trks0; /* number of tracks / cylinder vol 0*/
+ unsigned char dp_ctq_depth; /* Depth of CTQ queue */
+ unsigned char dp_cylshi; /* high byte of 24 bits of cylinder count */
+ unsigned short dp_unused; /* not used */
+ unsigned short dp_secs; /* number of sectors/track */
+ unsigned short dp_secbytes; /* length of sector in bytes */
+ unsigned short dp_interleave; /* sector interleave */
+ int dp_flags; /* controller characteristics */
+ int dp_datarate; /* bytes/sec for kernel stats */
+ int dp_nretries; /* max num retries on data error */
+ int dp_mspw; /* ms per word to xfer, for iostat */
+ unsigned short dp_xgap1; /* Gap 1 for xylogics controllers */
+ unsigned short dp_xsync; /* sync delay for xylogics controllers */
+ unsigned short dp_xrdly; /* read delay for xylogics controllers */
+ unsigned short dp_xgap2; /* gap 2 for xylogics controllers */
+ unsigned short dp_xrgate; /* read gate for xylogics controllers */
+ unsigned short dp_xwcont; /* write continuation for xylogics */
+};
+
+/*
+ * Device characterization flags
+ * (dp_flags)
+ */
+#define DP_SECTSLIP 0x00000001 /* sector slip to spare sector */
+#define DP_SECTFWD 0x00000002 /* forward to replacement sector */
+#define DP_TRKFWD 0x00000004 /* forward to replacement track */
+#define DP_MULTIVOL 0x00000008 /* multiple volumes per spindle */
+#define DP_IGNOREERRORS 0x00000010 /* transfer data regardless of errors */
+#define DP_RESEEK 0x00000020 /* recalibrate as last resort */
+#define DP_CTQ_EN 0x00000040 /* enable command tag queueing */
+
+/*
+ * Boot blocks, bad sector tables, and the error summary table, are located
+ * via the volume_directory.
+ */
+#define VDNAMESIZE 8
+
+struct volume_directory {
+ char vd_name[VDNAMESIZE]; /* name */
+ unsigned int vd_lbn; /* logical block number */
+ unsigned int vd_nbytes; /* file length in bytes */
+};
+
+/*
+ * partition table describes logical device partitions
+ * (device drivers examine this to determine mapping from logical units
+ * to cylinder groups, device formatters/verifiers examine this to determine
+ * location of replacement tracks/sectors, etc)
+ *
+ * NOTE: pt_firstlbn SHOULD BE CYLINDER ALIGNED
+ */
+struct partition_table { /* one per logical partition */
+ unsigned int pt_nblks; /* # of logical blks in partition */
+ unsigned int pt_firstlbn; /* first lbn of partition */
+ int pt_type; /* use of partition */
+};
+
+#define PTYPE_VOLHDR 0 /* partition is volume header */
+#define PTYPE_TRKREPL 1 /* partition is used for repl trks */
+#define PTYPE_SECREPL 2 /* partition is used for repl secs */
+#define PTYPE_RAW 3 /* partition is used for data */
+#define PTYPE_BSD42 4 /* partition is 4.2BSD file system */
+#define PTYPE_BSD 4 /* partition is 4.2BSD file system */
+#define PTYPE_SYSV 5 /* partition is SysV file system */
+#define PTYPE_VOLUME 6 /* partition is entire volume */
+#define PTYPE_EFS 7 /* partition is sgi EFS */
+#define PTYPE_LVOL 8 /* partition is part of a logical vol */
+#define PTYPE_RLVOL 9 /* part of a "raw" logical vol */
+#define PTYPE_XFS 10 /* partition is sgi XFS */
+#define PTYPE_XFSLOG 11 /* partition is sgi XFS log */
+#define PTYPE_XLV 12 /* partition is part of an XLV vol */
+#define PTYPE_XVM 13 /* partition is sgi XVM */
+#define NPTYPES 16
+
+#define VHMAGIC 0xbe5a941 /* randomly chosen value */
+#define NPARTAB 16 /* 16 unix partitions */
+#define NVDIR 15 /* max of 15 directory entries */
+#define BFNAMESIZE 16 /* max 16 chars in boot file name */
+
+/* Partition types for ARCS */
+#define NOT_USED 0 /* Not used */
+#define FAT_SHORT 1 /* FAT file system, 12-bit FAT entries */
+#define FAT_LONG 4 /* FAT file system, 16-bit FAT entries */
+#define EXTENDED 5 /* extended partition */
+#define HUGE 6 /* huge partition- MS/DOS 4.0 and later */
+
+/* Active flags for ARCS */
+#define BOOTABLE 0x00;
+#define NOT_BOOTABLE 0x80;
+
+struct volume_header {
+ int vh_magic; /* identifies volume header */
+ short vh_rootpt; /* root partition number */
+ short vh_swappt; /* swap partition number */
+ char vh_bootfile[BFNAMESIZE]; /* name of file to boot */
+ struct device_parameters vh_dp; /* device parameters */
+ struct volume_directory vh_vd[NVDIR]; /* other vol hdr contents */
+ struct partition_table vh_pt[NPARTAB]; /* device partition layout */
+ int vh_csum; /* volume header checksum */
+ int vh_fill; /* fill out to 512 bytes */
+};
+
+#endif /* _SYS_DVH_H */
diff --git a/libparted/labels/efi_crc32.c b/libparted/labels/efi_crc32.c
new file mode 100644
index 0000000..c25409f
--- /dev/null
+++ b/libparted/labels/efi_crc32.c
@@ -0,0 +1,126 @@
+/*
+ * Dec 5, 2000 Matt Domsch <Matt_Domsch@dell.com>
+ * - Copied crc32.c from the linux/drivers/net/cipe directory.
+ * - Now pass seed as an arg
+ * - changed unsigned long to uint32_t, added #include<stdint.h>
+ * - changed len to be an unsigned long
+ * - changed crc32val to be a register
+ * - License remains unchanged! It's still GPL-compatable!
+ */
+
+ /* ============================================================= */
+ /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */
+ /* code or tables extracted from it, as desired without restriction. */
+ /* */
+ /* First, the polynomial itself and its table of feedback terms. The */
+ /* polynomial is */
+ /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+ /* */
+ /* Note that we take it "backwards" and put the highest-order term in */
+ /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */
+ /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */
+ /* the MSB being 1. */
+ /* */
+ /* Note that the usual hardware shift register implementation, which */
+ /* is what we're using (we're merely optimizing it by doing eight-bit */
+ /* chunks at a time) shifts bits into the lowest-order term. In our */
+ /* implementation, that means shifting towards the right. Why do we */
+ /* do it this way? Because the calculated CRC must be transmitted in */
+ /* order from highest-order term to lowest-order term. UARTs transmit */
+ /* characters in order from LSB to MSB. By storing the CRC this way, */
+ /* we hand it to the UART in the order low-byte to high-byte; the UART */
+ /* sends each low-bit to hight-bit; and the result is transmission bit */
+ /* by bit from highest- to lowest-order term without requiring any bit */
+ /* shuffling on our part. Reception works similarly. */
+ /* */
+ /* The feedback terms table consists of 256, 32-bit entries. Notes: */
+ /* */
+ /* The table can be generated at runtime if desired; code to do so */
+ /* is shown later. It might not be obvious, but the feedback */
+ /* terms simply represent the results of eight shift/xor opera- */
+ /* tions for all combinations of data and CRC register values. */
+ /* */
+ /* The values must be right-shifted by eight bits by the "updcrc" */
+ /* logic; the shift must be unsigned (bring in zeroes). On some */
+ /* hardware you could probably optimize the shift in assembler by */
+ /* using byte-swap instructions. */
+ /* polynomial $edb88320 */
+ /* */
+ /* -------------------------------------------------------------------- */
+
+#include <config.h>
+#include <stdint.h>
+
+static const uint32_t crc32_tab[] = {
+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL
+ };
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+uint32_t _GL_ATTRIBUTE_PURE
+__efi_crc32(const void *buf, unsigned long len, uint32_t seed)
+{
+ unsigned long i;
+ register uint32_t crc32val;
+ const unsigned char *s = buf;
+
+ crc32val = seed;
+ for (i = 0; i < len; i ++)
+ {
+ crc32val =
+ crc32_tab[(crc32val ^ s[i]) & 0xff] ^
+ (crc32val >> 8);
+ }
+ return crc32val;
+}
diff --git a/libparted/labels/fdasd.c b/libparted/labels/fdasd.c
new file mode 100644
index 0000000..cee4d46
--- /dev/null
+++ b/libparted/labels/fdasd.c
@@ -0,0 +1,1442 @@
+/*
+ * File...........: arch/s390/tools/fdasd.c
+ * Author(s)......: Volker Sameske <sameske@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2001
+ *
+ * History of changes (starts March 2001)
+ * 2001-04-11 possibility to change volume serial added
+ * possibility to change partition type added
+ * some changes to DS4HPCHR and DS4DSREC
+ * 2001-05-03 check for invalid partition numbers added
+ * wrong free_space calculation bug fixed
+ * 2001-06-26 '-a' option added, it is now possible to add a single
+ * partition in non-interactive mode
+ * 2001-06-26 long parameter support added
+ *
+ */
+
+#include <config.h>
+#include <arch/linux.h>
+#include <parted/vtoc.h>
+#include <parted/device.h>
+#include <parted/fdasd.h>
+
+#include <parted/parted.h>
+
+#include <libintl.h>
+#if ENABLE_NLS
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static int
+getpos (fdasd_anchor_t *anc, int dsn)
+{
+ PDEBUG
+ return anc->partno[dsn];
+}
+
+static int
+getdsn (fdasd_anchor_t *anc, int pos)
+{
+ PDEBUG
+ int i;
+
+ for (i=0; i<USABLE_PARTITIONS; i++) {
+ if (anc->partno[i] == pos)
+ return i;
+ }
+
+ return -1;
+}
+
+static void
+setpos (fdasd_anchor_t *anc, int dsn, int pos)
+{
+ PDEBUG
+ anc->partno[dsn] = pos;
+}
+
+static u_int32_t
+get_usable_cylinders (fdasd_anchor_t *anc)
+{
+ u_int32_t cyl;
+
+ /* large volume */
+ if (anc->f4->DS4DEVCT.DS4DSCYL == LV_COMPAT_CYL &&
+ anc->f4->DS4DCYL > anc->f4->DS4DEVCT.DS4DSCYL)
+ return anc->f4->DS4DCYL;
+ /* normal volume */
+ if (anc->f4->DS4DEVCT.DS4DEVFG & ALTERNATE_CYLINDERS_USED)
+ cyl = anc->f4->DS4DEVCT.DS4DSCYL -
+ (u_int16_t) anc->f4->DS4DEVAC;
+ else
+ cyl = anc->f4->DS4DEVCT.DS4DSCYL;
+ return cyl;
+}
+
+static void
+get_addr_of_highest_f1_f8_label (fdasd_anchor_t *anc, cchhb_t *addr)
+{
+
+ u_int8_t record;
+ /* We have to count the follwing labels:
+ * one format 4
+ * one format 5
+ * format 7 only if we have moren then BIG_DISK_SIZE tracks
+ * one for each format 1 or format 8 label == one for each partition
+ * one for each format 9 label before the last format 8
+ * We assume that all partitions use format 8 labels when
+ * anc->formatted_cylinders > LV_COMPAT_CYL
+ * Note: Record zero is special, so block 0 on our disk is record 1!
+ */
+
+ record = anc->used_partitions + 2;
+ if (anc->big_disk)
+ record++;
+ if (anc->formatted_cylinders > LV_COMPAT_CYL)
+ record += anc->used_partitions - 1;
+ vtoc_set_cchhb(addr, VTOC_START_CC, VTOC_START_HH, record);
+}
+
+void
+fdasd_cleanup (fdasd_anchor_t *anchor)
+{
+ PDEBUG
+ int i;
+ partition_info_t *part_info, *next;
+
+ if (anchor == NULL)
+ return;
+
+ free(anchor->f4);
+ free(anchor->f5);
+ free(anchor->f7);
+ free(anchor->vlabel);
+
+ part_info = anchor->first;
+ for (i = 1; i <= USABLE_PARTITIONS && part_info != NULL; i++) {
+ next = part_info->next;
+ free(part_info->f1);
+ free(part_info);
+ part_info = next;
+ }
+}
+
+static void
+fdasd_error (fdasd_anchor_t *anc, enum fdasd_failure why, char const *str)
+{
+ PDEBUG
+ char error[2*LINE_LENGTH], *message = error;
+
+ switch (why) {
+ case unable_to_open_disk:
+ sprintf(error, "fdasd: %s -- %s\n", _("open error"), str);
+ break;
+ case unable_to_seek_disk:
+ sprintf(error, "fdasd: %s -- %s\n", _("seek error"), str);
+ break;
+ case unable_to_read_disk:
+ sprintf(error, "fdasd: %s -- %s\n", _("read error"), str);
+ break;
+ case read_only_disk:
+ sprintf(error, "fdasd: %s -- %s\n", _("write error"), str);
+ break;
+ case unable_to_ioctl:
+ sprintf(error, "fdasd: %s -- %s\n", _("ioctl() error"), str);
+ break;
+ case api_version_mismatch:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("API version mismatch"), str);
+ break;
+ case wrong_disk_type:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Unsupported disk type"), str);
+ break;
+ case wrong_disk_format:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Unsupported disk format"), str);
+ break;
+ case disk_in_use:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Disk is in use"), str);
+ break;
+ case config_syntax_error:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Syntax error in config file"), str);
+ break;
+ case vlabel_corrupted:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Volume label is corrupted"), str);
+ break;
+ case dsname_corrupted:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("A data set name is corrupted"), str);
+ break;
+ case malloc_failed:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Memory allocation failed"), str);
+ break;
+ case device_verification_failed:
+ sprintf(error, "fdasd: %s -- %s\n",
+ _("Device verification failed"),
+ _("The specified device is not a valid DASD device"));
+ break;
+ case volser_not_found:
+ sprintf(error, "fdasd: %s -- %s\n", _("VOLSER not found on device"), str);
+ break;
+ default:
+ sprintf(error, "fdasd: %s: %s\n", _("Fatal error"), str);
+ }
+
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, message);
+}
+
+/*
+ * initializes the anchor structure and allocates some
+ * memory for the labels
+ */
+void
+fdasd_initialize_anchor (fdasd_anchor_t * anc)
+{
+ PDEBUG
+ int i;
+ volume_label_t *v;
+ partition_info_t *p = NULL;
+ partition_info_t *q = NULL;
+
+ bzero(anc, sizeof(fdasd_anchor_t));
+
+ for (i=0; i<USABLE_PARTITIONS; i++)
+ setpos(anc, i, -1);
+
+ bzero(anc->confdata, sizeof(config_data_t));
+
+ anc->f4 = malloc(sizeof(format4_label_t));
+ if (anc->f4 == NULL)
+ fdasd_error(anc, malloc_failed, "FMT4 DSCB.");
+
+ anc->f5 = malloc(sizeof(format5_label_t));
+ if (anc->f5 == NULL)
+ fdasd_error(anc, malloc_failed, "FMT5 DSCB.");
+
+ anc->f7 = malloc(sizeof(format7_label_t));
+ if (anc->f7 == NULL)
+ fdasd_error(anc, malloc_failed, "FMT7 DSCB.");
+
+ /* template for all format 9 labels */
+ anc->f9 = malloc(sizeof(format9_label_t));
+ if (anc->f9 == NULL)
+ fdasd_error(anc, malloc_failed, "FMT9 DSCB.");
+
+ bzero(anc->f4, sizeof(format4_label_t));
+ bzero(anc->f5, sizeof(format5_label_t));
+ bzero(anc->f7, sizeof(format7_label_t));
+ bzero(anc->f9, sizeof(format9_label_t));
+ vtoc_init_format9_label(anc->f9);
+
+ v = malloc(sizeof(volume_label_t));
+ if (v == NULL)
+ fdasd_error(anc, malloc_failed,
+ _("No room for volume label."));
+ bzero(v, sizeof(volume_label_t));
+ anc->vlabel = v;
+
+ for (i=1; i<=USABLE_PARTITIONS; i++) {
+ p = malloc(sizeof(partition_info_t));
+ if (p == NULL)
+ fdasd_error(anc, malloc_failed,
+ _("No room for partition info."));
+ bzero(p, sizeof(partition_info_t));
+
+ /* add p to double pointered list */
+ if (i == 1) {
+ anc->first = p;
+ } else if (i == USABLE_PARTITIONS) {
+ anc->last = p;
+ p->prev = q;
+ q->next = p;
+ } else {
+ p->prev = q;
+ q->next = p;
+ }
+
+ p->f1 = malloc(sizeof(format1_label_t));
+ if (p->f1 == NULL)
+ fdasd_error(anc, malloc_failed, "FMT1 DSCB.");
+ bzero(p->f1, sizeof(format1_label_t));
+
+ q = p;
+ }
+ anc->hw_cylinders = 0;
+ anc->formatted_cylinders = 0;
+ anc->is_file = 0;
+}
+
+/*
+ * writes all changes to dasd
+ */
+static void
+fdasd_write_vtoc_labels (fdasd_anchor_t * anc, int fd)
+{
+ PDEBUG
+ partition_info_t *p;
+ unsigned long b, maxblk;
+ char dsno[6], s1[VOLSER_LENGTH + 1], s2[45], *c1, *c2, *ch;
+ int i = 0, k = 0;
+ cchhb_t f9addr;
+ format1_label_t emptyf1;
+
+ b = (cchhb2blk (&anc->vlabel->vtoc, &anc->geo) - 1) * anc->blksize;
+ if (b <= 0)
+ fdasd_error (anc, vlabel_corrupted, "");
+ maxblk = b + anc->blksize * 9; /* f4+f5+f7+3*f8+3*f9 */
+
+ /* write FMT4 DSCB */
+ vtoc_write_label (fd, b, NULL, anc->f4, NULL, NULL, NULL);
+ b += anc->blksize;
+
+ /* write FMT5 DSCB */
+ vtoc_write_label (fd, b, NULL, NULL, anc->f5, NULL, NULL);
+ b += anc->blksize;
+
+ /* write FMT7 DSCB */
+ if (anc->big_disk) {
+ vtoc_write_label (fd, b, NULL, NULL, NULL, anc->f7, NULL);
+ b += anc->blksize;
+ }
+
+ /* loop over all partitions (format 1 or format 8 DCB) */
+ for (p = anc->first; p != NULL; p = p->next) {
+
+ if (p->used != 0x01) {
+ continue;
+ }
+
+ i++;
+ strncpy (p->f1->DS1DSSN, anc->vlabel->volid, 6);
+
+ ch = p->f1->DS1DSNAM;
+ vtoc_ebcdic_dec (ch, ch, 44);
+ c1 = ch + 7;
+
+ if (getdsn (anc, i-1) > -1) {
+ /* re-use the existing data set name */
+ c2 = strchr (c1, '.');
+ if (c2 != NULL)
+ strncpy (s2, c2, 31);
+ else
+ fdasd_error (anc, dsname_corrupted, "");
+
+ strncpy (s1, anc->vlabel->volid, 6);
+ vtoc_ebcdic_dec (s1, s1, 6);
+ s1[6] = ' ';
+ strncpy (c1, s1, 7);
+ c1 = strchr (ch, ' ');
+ strncpy (c1, s2, 31);
+ } else {
+ /* create a new data set name */
+ while (getpos (anc, k) > -1)
+ k++;
+
+ setpos (anc, k, i-1);
+
+ strncpy (ch, "LINUX.V " " ", 44);
+
+ strncpy (s1, anc->vlabel->volid, 6);
+ vtoc_ebcdic_dec (s1, s1, 6);
+ strncpy (c1, s1, 6);
+
+ c1 = strchr (ch, ' ');
+ strncpy (c1, ".PART", 5);
+ c1 += 5;
+
+ sprintf (dsno, "%04d.", k + 1);
+ strncpy (c1, dsno, 5);
+
+ c1 += 5;
+ switch(p->type) {
+ case PARTITION_LINUX_LVM:
+ strncpy(c1, PART_TYPE_LVM, 6);
+ break;
+ case PARTITION_LINUX_RAID:
+ strncpy(c1, PART_TYPE_RAID, 6);
+ break;
+ case PARTITION_LINUX:
+ strncpy(c1, PART_TYPE_NATIVE, 6);
+ break;
+ case PARTITION_LINUX_SWAP:
+ strncpy(c1, PART_TYPE_SWAP, 6);
+ break;
+ default:
+ strncpy(c1, PART_TYPE_NATIVE, 6);
+ break;
+ }
+ }
+
+ vtoc_ebcdic_enc (ch, ch, 44);
+
+ if (p->f1->DS1FMTID == 0xf8 ) {
+ /* Now as we know where which label will be written, we
+ * can add the address of the format 9 label to the
+ * format 8 label. The f9 record will be written to the
+ * block after the current blk. Remember: records are of
+ * by one, so we have to add 2 and not just one.
+ */
+ vtoc_set_cchhb(&f9addr, VTOC_START_CC, VTOC_START_HH,
+ ((b / anc->blksize) % anc->geo.sectors) + 2);
+ vtoc_update_format8_label(&f9addr, p->f1);
+ vtoc_write_label(fd, b, p->f1, NULL, NULL, NULL, NULL);
+ b += anc->blksize;
+ vtoc_write_label(fd, b, NULL, NULL, NULL, NULL,
+ anc->f9);
+ b += anc->blksize;
+ } else {
+ vtoc_write_label(fd, b, p->f1, NULL, NULL, NULL, NULL);
+ b += anc->blksize;
+ }
+ }
+
+ /* write empty labels to the rest of the blocks */
+ bzero(&emptyf1, sizeof(emptyf1));
+ while (b < maxblk) {
+ vtoc_write_label(fd, b, &emptyf1, NULL, NULL, NULL, NULL);
+ b += anc->blksize;
+ }
+}
+
+/*
+ * writes all changes to dasd
+ */
+int
+fdasd_write_labels (fdasd_anchor_t * anc, int fd)
+{
+ PDEBUG
+ if (anc->vlabel_changed)
+ vtoc_write_volume_label (fd, anc->label_pos, anc->vlabel);
+
+ if (anc->vtoc_changed)
+ fdasd_write_vtoc_labels (anc, fd);
+
+ return 1;
+}
+
+/*
+ * writes all changes to dasd
+ */
+int
+fdasd_prepare_labels (fdasd_anchor_t *anc, int fd)
+{
+ PDEBUG
+ partition_info_t *p;
+ char dsno[6], s1[7], s2[45], *c1, *c2, *ch;
+ int i = 0, k = 0;
+
+ /* loop over all partitions (format 1 or format 8 DCB) */
+ for (p = anc->first; p != NULL; p = p->next) {
+
+ if (p->used != 0x01) {
+ continue;
+ }
+
+ i++;
+ strncpy (p->f1->DS1DSSN, anc->vlabel->volid, 6);
+
+ ch = p->f1->DS1DSNAM;
+ vtoc_ebcdic_dec (ch, ch, 44);
+ c1 = ch + 7;
+
+ if (getdsn (anc, i-1) > -1) {
+ /* re-use the existing data set name */
+ c2 = strchr (c1, '.');
+ if (c2 != NULL)
+ strncpy (s2, c2, 31);
+ else
+ fdasd_error (anc, dsname_corrupted, "");
+
+ strncpy (s1, anc->vlabel->volid, 6);
+ vtoc_ebcdic_dec (s1, s1, 6);
+ s1[6] = ' ';
+ strncpy (c1, s1, 7);
+ c1 = strchr (ch, ' ');
+ strncpy (c1, s2, 31);
+ } else {
+ /* create a new data set name */
+ while (getpos (anc, k) > -1)
+ k++;
+
+ setpos (anc, k, i-1);
+
+ strncpy (ch, "LINUX.V " " ", 44);
+
+ strncpy (s1, anc->vlabel->volid, 6);
+ vtoc_ebcdic_dec (s1, s1, 6);
+ strncpy (c1, s1, 6);
+
+ c1 = strchr (ch, ' ');
+ strncpy (c1, ".PART", 5);
+ c1 += 5;
+
+ sprintf (dsno, "%04d.", k + 1);
+ strncpy (c1, dsno, 5);
+
+ c1 += 5;
+ switch(p->type) {
+ case PARTITION_LINUX_LVM:
+ strncpy(c1, PART_TYPE_LVM, 6);
+ break;
+ case PARTITION_LINUX_RAID:
+ strncpy(c1, PART_TYPE_RAID, 6);
+ break;
+ case PARTITION_LINUX:
+ strncpy(c1, PART_TYPE_NATIVE, 6);
+ break;
+ case PARTITION_LINUX_SWAP:
+ strncpy(c1, PART_TYPE_SWAP, 6);
+ break;
+ default:
+ strncpy(c1, PART_TYPE_NATIVE, 6);
+ break;
+ }
+ }
+
+ vtoc_ebcdic_enc (ch, ch, 44);
+ }
+
+ return 1;
+}
+
+void
+fdasd_recreate_vtoc (fdasd_anchor_t *anc)
+{
+ PDEBUG
+ partition_info_t *p = anc->first;
+ int i;
+
+ vtoc_init_format4_label(anc->f4,
+ anc->geo.cylinders,
+ anc->formatted_cylinders,
+ anc->geo.heads,
+ anc->geo.sectors,
+ anc->blksize,
+ anc->dev_type);
+
+ vtoc_init_format5_label(anc->f5);
+ vtoc_init_format7_label(anc->f7);
+ vtoc_set_freespace(anc->f4, anc->f5, anc->f7,
+ '+', anc->verbose,
+ FIRST_USABLE_TRK,
+ anc->formatted_cylinders * anc->geo.heads - 1,
+ anc->formatted_cylinders, anc->geo.heads);
+
+ for (i = 0; i < USABLE_PARTITIONS; i++) {
+ bzero(p->f1, sizeof(format1_label_t));
+ p->used = 0x00;
+ p->start_trk = 0;
+ p->end_trk = 0;
+ p->len_trk = 0;
+ p->fspace_trk = 0;
+ p->type = 0;
+ p = p->next;
+ }
+
+ anc->used_partitions = 0;
+ anc->fspace_trk = anc->formatted_cylinders * anc->geo.heads -
+ FIRST_USABLE_TRK;
+
+ for (i=0; i<USABLE_PARTITIONS; i++)
+ setpos(anc, i, -1);
+
+ anc->vtoc_changed++;
+}
+
+ /*
+ * initialize the VOL1 volume label
+ */
+static void
+fdasd_init_volume_label(fdasd_anchor_t *anc, int fd)
+{
+ volume_label_t *vlabel = anc->vlabel;
+
+ vtoc_volume_label_init(vlabel);
+ vtoc_volume_label_set_key(vlabel, "VOL1");
+ vtoc_volume_label_set_label(vlabel, "VOL1");
+
+ vtoc_set_cchhb(&vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
+}
+
+
+/*
+ * sets some important partition data
+ * (like used, start_trk, end_trk, len_trk)
+ * by calculating these values with the
+ * information provided in the labels
+ */
+static void
+fdasd_update_partition_info (fdasd_anchor_t *anc)
+{
+ PDEBUG
+ partition_info_t *q = NULL, *p = anc->first;
+ unsigned long max = anc->formatted_cylinders * anc->geo.heads - 1;
+ int i;
+ char *ch;
+
+ anc->used_partitions = anc->geo.sectors - 2 - anc->f4->DS4DSREC;
+
+ for (i = 1; i <= USABLE_PARTITIONS; i++) {
+ if (p->f1->DS1FMTID != 0xf1 &&
+ p->f1->DS1FMTID != 0xf8) {
+ if (i == 1)
+ /* there is no partition at all */
+ anc->fspace_trk = max - FIRST_USABLE_TRK + 1;
+ else
+ /* previous partition was the last one */
+ q->fspace_trk = max - q->end_trk;
+ break;
+ }
+
+ /* this is a valid format 1 label */
+ p->used = 0x01;
+ p->start_trk = cchh2trk(&p->f1->DS1EXT1.llimit, &anc->geo);
+ p->end_trk = cchh2trk(&p->f1->DS1EXT1.ulimit, &anc->geo);
+ p->len_trk = p->end_trk - p->start_trk + 1;
+
+ if (i == 1) {
+ /* first partition, there is at least one */
+ anc->fspace_trk = p->start_trk - FIRST_USABLE_TRK;
+ } else {
+ if (i == USABLE_PARTITIONS)
+ /* last possible partition */
+ p->fspace_trk = max - p->end_trk;
+
+ /* set free space values of previous partition */
+ q->fspace_trk = p->start_trk - q->end_trk - 1;
+ }
+
+ ch = p->f1->DS1DSNAM;
+ vtoc_ebcdic_dec (ch, ch, 44);
+ if (strstr(ch, PART_TYPE_LVM))
+ p->type = PARTITION_LINUX_LVM;
+ else if (strstr(ch, PART_TYPE_RAID))
+ p->type = PARTITION_LINUX_RAID;
+ else if (strstr(ch, PART_TYPE_NATIVE))
+ p->type = PARTITION_LINUX;
+ else if (strstr(ch, PART_TYPE_SWAP))
+ p->type = PARTITION_LINUX_SWAP;
+ else
+ p->type = PARTITION_LINUX;
+ vtoc_ebcdic_enc (ch, ch, 44);
+
+ q = p;
+ p = p->next;
+ }
+}
+
+/*
+ * reorganizes all FMT1s, after that all used FMT1s should be right in
+ * front of all unused FMT1s
+ */
+static void
+fdasd_reorganize_FMT1s (fdasd_anchor_t *anc)
+{
+ PDEBUG
+ int i, j;
+ format1_label_t *ltmp;
+ partition_info_t *ptmp;
+
+ for (i=1; i<=USABLE_PARTITIONS - 1; i++) {
+ ptmp = anc->first;
+
+ for (j=1; j<=USABLE_PARTITIONS - i; j++) {
+ if (ptmp->f1->DS1FMTID < ptmp->next->f1->DS1FMTID) {
+ ltmp = ptmp->f1;
+ ptmp->f1 = ptmp->next->f1;
+ ptmp->next->f1 = ltmp;
+ }
+
+ ptmp=ptmp->next;
+ }
+ }
+}
+
+static void
+fdasd_process_valid_vtoc (fdasd_anchor_t * anc, unsigned long b, int fd)
+{
+ PDEBUG
+ int f5_counter = 0, f7_counter = 0, f1_counter = 0, oldfmt = 0;
+ int i, n, f1size = sizeof (format1_label_t);
+ partition_info_t *p = anc->first;
+ format1_label_t q;
+ char s[5], *ch;
+
+ if (anc->f4->DS4DEVCT.DS4DSCYL == LV_COMPAT_CYL &&
+ anc->f4->DS4DCYL > anc->f4->DS4DEVCT.DS4DSCYL)
+ anc->formatted_cylinders = anc->f4->DS4DCYL;
+ else
+ anc->formatted_cylinders = anc->f4->DS4DEVCT.DS4DSCYL;
+ anc->fspace_trk = anc->formatted_cylinders * anc->geo.heads -
+ FIRST_USABLE_TRK;
+ b += anc->blksize;
+
+ for (i = 1; i < anc->geo.sectors; i++) {
+ bzero (&q, f1size);
+ vtoc_read_label (fd, b, &q, NULL, NULL, NULL);
+
+ switch (q.DS1FMTID) {
+ case 0xf1:
+ case 0xf8:
+ if (p == NULL)
+ break;
+ memcpy (p->f1, &q, f1size);
+
+ n = -1;
+ vtoc_ebcdic_dec (p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+ ch = strstr (p->f1->DS1DSNAM, "PART");
+ if (ch != NULL) {
+ strncpy (s, ch + 4, 4);
+ s[4] = '\0';
+ n = atoi (s) - 1;
+ }
+
+ vtoc_ebcdic_enc (p->f1->DS1DSNAM, p->f1->DS1DSNAM, 44);
+
+ /* this dasd has data set names 0000-0002
+ but we use now 0001-0003 */
+ if (n == -1)
+ oldfmt++;
+
+ if (((oldfmt == 0) && (n < 0)) || (n >= USABLE_PARTITIONS)) {
+ /* no op */
+ } else {
+ if (oldfmt) {
+ /* correct +1 */
+ setpos (anc, n + 1, f1_counter);
+ } else {
+ setpos (anc, n, f1_counter);
+ }
+ }
+
+ p = p->next;
+ f1_counter++;
+ break;
+ case 0xf5:
+ memcpy (anc->f5, &q, f1size);
+ f5_counter++;
+ break;
+ case 0xf7:
+ if (f7_counter == 0)
+ memcpy (anc->f7, &q, f1size);
+ f7_counter++;
+ break;
+ case 0xf9:
+ /* each format 8 lable has an associated
+ * format 9 lable, but they are of no further
+ * use to us.
+ */
+ break;
+ }
+
+ b += anc->blksize;
+ }
+
+ if (oldfmt > 0) {
+ /* this is the old format PART0000 - PART0002 */
+ anc->vtoc_changed++;
+ }
+
+ if ((f5_counter == 0) || (anc->big_disk))
+ vtoc_init_format5_label (anc->f5);
+
+ if (f7_counter == 0)
+ vtoc_init_format7_label (anc->f7);
+
+ fdasd_reorganize_FMT1s (anc);
+ fdasd_update_partition_info (anc);
+}
+
+static void
+fdasd_invalid_vtoc_pointer(fdasd_anchor_t *anc)
+{
+ PDEBUG
+ anc->formatted_cylinders = anc->hw_cylinders;
+ anc->fspace_trk = anc->formatted_cylinders * anc->geo.heads
+ - FIRST_USABLE_TRK;
+ vtoc_init_format4_label(anc->f4,
+ anc->geo.cylinders, anc->formatted_cylinders,
+ anc->geo.heads, anc->geo.sectors,
+ anc->blksize, anc->dev_type);
+
+ vtoc_init_format5_label(anc->f5);
+ vtoc_init_format7_label(anc->f7);
+
+ vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+', anc->verbose,
+ FIRST_USABLE_TRK,
+ anc->formatted_cylinders * anc->geo.heads - 1,
+ anc->formatted_cylinders, anc->geo.heads);
+
+ vtoc_set_cchhb(&anc->vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
+ anc->vtoc_changed++;
+ anc->vlabel_changed++;
+}
+
+/*
+ * we have a invalid FMT4 DSCB and therefore we will re-create the VTOC
+ */
+static void
+fdasd_process_invalid_vtoc(fdasd_anchor_t *anc)
+{
+ anc->formatted_cylinders = anc->hw_cylinders;
+ anc->fspace_trk = anc->formatted_cylinders * anc->geo.heads
+ - FIRST_USABLE_TRK;
+ vtoc_init_format4_label(anc->f4,
+ anc->geo.cylinders, anc->formatted_cylinders,
+ anc->geo.heads, anc->geo.sectors,
+ anc->blksize, anc->dev_type);
+
+ vtoc_init_format5_label(anc->f5);
+ vtoc_init_format7_label(anc->f7);
+ vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+', anc->verbose,
+ FIRST_USABLE_TRK,
+ anc->formatted_cylinders * anc->geo.heads - 1,
+ anc->formatted_cylinders, anc->geo.heads);
+
+ anc->vtoc_changed++;
+}
+
+
+static int
+fdasd_valid_vtoc_pointer(fdasd_anchor_t *anc, unsigned long b, int fd)
+{
+ PDEBUG
+ char str[LINE_LENGTH];
+
+ /* VOL1 label contains valid VTOC pointer */
+ vtoc_read_label (fd, b, NULL, anc->f4, NULL, NULL);
+
+ if (anc->f4->DS4IDFMT == 0xf4) {
+ fdasd_process_valid_vtoc (anc, b, fd);
+ return 0;
+ } else {
+ fdasd_process_invalid_vtoc(anc);
+ }
+ if (strncmp(anc->vlabel->volkey, vtoc_ebcdic_enc("LNX1",str,4),4) == 0 ||
+ strncmp(anc->vlabel->volkey, vtoc_ebcdic_enc("CMS1",str,4),4) == 0)
+ return 0;
+
+ fdasd_error(anc, wrong_disk_format, _("Invalid VTOC."));
+ return 1;
+}
+
+/*
+ * check the dasd for a volume label
+ */
+int
+fdasd_check_volume (fdasd_anchor_t *anc, int fd)
+{
+ PDEBUG
+ volume_label_t *v = anc->vlabel;
+ long long b = -1;
+ char str[LINE_LENGTH];
+
+ memset(v, 0, sizeof(volume_label_t));
+ vtoc_read_volume_label (fd, anc->label_pos, v);
+
+ if (strncmp(v->vollbl, vtoc_ebcdic_enc ("VOL1", str, 4), 4) == 0) {
+ if (anc->FBA_layout != 1 ) {
+ /* found VOL1 volume label */
+ b = (cchhb2blk (&v->vtoc, &anc->geo) - 1) * anc->blksize;
+
+ if (b > 0) {
+ int rc;
+ rc = fdasd_valid_vtoc_pointer (anc, b, fd);
+
+ if (rc < 0)
+ return 1;
+ else
+ return 0;
+ } else {
+ fdasd_invalid_vtoc_pointer(anc);
+ }
+ }
+ } else if (strncmp (v->volkey, vtoc_ebcdic_enc ("LNX1", str, 4), 4) == 0 ||
+ strncmp (v->volkey, vtoc_ebcdic_enc ("CMS1", str, 4), 4) == 0) {
+ return 0;
+ } else if (anc->FBA_layout == 1) {
+ /* Some times LDL formatted disks does not
+ contain any volume label */
+ return 1;
+ } else if (! anc->is_file) {
+ /* didn't find VOL1 volume label */
+ anc->formatted_cylinders = anc->hw_cylinders;
+ anc->fspace_trk = anc->formatted_cylinders * anc->geo.heads
+ - FIRST_USABLE_TRK;
+
+ fdasd_init_volume_label(anc, fd);
+
+ vtoc_init_format4_label(anc->f4,
+ anc->geo.cylinders, anc->formatted_cylinders,
+ anc->geo.heads, anc->geo.sectors,
+ anc->blksize, anc->dev_type);
+
+ vtoc_init_format5_label(anc->f5);
+ vtoc_init_format7_label(anc->f7);
+
+ vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '+',
+ anc->verbose, FIRST_USABLE_TRK,
+ anc->formatted_cylinders * anc->geo.heads - 1,
+ anc->formatted_cylinders, anc->geo.heads);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * checks the current API version with the API version of the dasd driver
+ */
+void
+fdasd_check_api_version (fdasd_anchor_t *anc, int f)
+{
+ PDEBUG
+ int api;
+ char s[2*LINE_LENGTH];
+
+ struct stat st;
+ if (fstat (f, &st) == 0 && S_ISREG (st.st_mode)) {
+ /* skip these tests when F is a regular file. */
+ }
+ else {
+ if (ioctl(f, DASDAPIVER, &api) != 0)
+ fdasd_error(anc, unable_to_ioctl,
+ _("Could not retrieve API version."));
+
+ if (api != DASD_MIN_API_VERSION) {
+ sprintf(s, _("The current API version '%d' doesn't " \
+ "match dasd driver API version " \
+ "'%d'!"), api, DASD_MIN_API_VERSION);
+ fdasd_error(anc, api_version_mismatch, s);
+ }
+ }
+}
+
+/*
+ * The following two functions match those in the DASD ECKD device driver.
+ * They are used to compute how many records of a given size can be stored
+ * in one track.
+ */
+static unsigned int ceil_quot(unsigned int d1, unsigned int d2)
+{
+ return (d1 + (d2 - 1)) / d2;
+}
+
+/* kl: key length, dl: data length */
+static unsigned int recs_per_track(unsigned short dev_type, unsigned int kl,
+ unsigned int dl)
+{
+ unsigned int dn, kn;
+
+ switch (dev_type) {
+ case DASD_3380_TYPE:
+ if (kl)
+ return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) +
+ ceil_quot(dl + 12, 32));
+ else
+ return 1499 / (15 + ceil_quot(dl + 12, 32));
+ case DASD_3390_TYPE:
+ dn = ceil_quot(dl + 6, 232) + 1;
+ if (kl) {
+ kn = ceil_quot(kl + 6, 232) + 1;
+ return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
+ 9 + ceil_quot(dl + 6 * dn, 34));
+ } else
+ return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
+ case DASD_9345_TYPE:
+ dn = ceil_quot(dl + 6, 232) + 1;
+ if (kl) {
+ kn = ceil_quot(kl + 6, 232) + 1;
+ return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
+ ceil_quot(dl + 6 * dn, 34));
+ } else
+ return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
+ }
+ return 0;
+}
+
+/*
+ * Verify that number of tracks (heads) per cylinder and number of
+ * sectors per track match the expected values for a given device type
+ * and block size.
+ * Returns 1 for a valid match and 0 otherwise.
+ */
+static int fdasd_verify_geometry(unsigned short dev_type, int blksize,
+ struct fdasd_hd_geometry *geometry)
+{
+ unsigned int expected_sectors;
+ if (geometry->heads != 15)
+ return 0;
+ expected_sectors = recs_per_track(dev_type, 0, blksize);
+ if (geometry->sectors == expected_sectors)
+ return 1;
+ return 0;
+}
+
+/*
+ * reads dasd geometry data
+ */
+int
+fdasd_get_geometry (const PedDevice *dev, fdasd_anchor_t *anc, int f)
+{
+ PDEBUG
+ int blksize = 0;
+ dasd_information_t dasd_info;
+ struct dasd_eckd_characteristics *characteristics;
+ unsigned long long size_in_bytes;
+
+ /* We can't get geometry from a regular file,
+ so simulate something usable, for the sake of testing. */
+ struct stat st;
+ if (fstat (f, &st) == 0 && S_ISREG (st.st_mode)) {
+ PedSector n_sectors = st.st_size / dev->sector_size;
+ anc->geo.heads = 15;
+ anc->geo.sectors = 12;
+ anc->geo.cylinders
+ = (n_sectors / (anc->geo.heads * anc->geo.sectors
+ * (dev->sector_size / dev->phys_sector_size)));
+ anc->geo.start = 0;
+ blksize = 4096;
+ memcpy (dasd_info.type, "ECKD", 4);
+ dasd_info.dev_type = 13200;
+ dasd_info.label_block = 2;
+ dasd_info.devno = 513;
+ dasd_info.label_block = 2;
+ dasd_info.FBA_layout = 0;
+ anc->hw_cylinders = ((st.st_size / blksize) / anc->geo.sectors) /
+ anc->geo.heads;
+ anc->is_file = 1;
+ } else {
+ if (ioctl(f, BLKGETSIZE64, &size_in_bytes) != 0) {
+ fdasd_error(anc, unable_to_ioctl,
+ _("Could not retrieve disk size."));
+ goto error;
+ }
+
+ if (ioctl(f, HDIO_GETGEO, &anc->geo) != 0 ||
+ anc->geo.heads == 0 ||
+ anc->geo.sectors == 0 ||
+ anc->geo.cylinders == 0 ) {
+ fdasd_error(anc, unable_to_ioctl,
+ _("Could not retrieve disk geometry information."));
+ goto error;
+ }
+
+ if (ioctl(f, BLKSSZGET, &blksize) != 0) {
+ fdasd_error(anc, unable_to_ioctl,
+ _("Could not retrieve blocksize information."));
+ goto error;
+ }
+
+ /* get disk type */
+ if (ioctl(f, BIODASDINFO, &dasd_info) != 0) {
+ /* verify that the geometry matches a 3390 DASD */
+ if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize,
+ &anc->geo)) {
+ fdasd_error(anc, wrong_disk_type,
+ _("Disk geometry does not match a " \
+ "DASD device of type 3390."));
+ goto error;
+ }
+ anc->dev_type = DASD_3390_TYPE;
+ anc->hw_cylinders =
+ size_in_bytes / (blksize * anc->geo.heads * anc->geo.sectors);
+ /* The VOL1 label on a CDL formatted ECKD DASD is in block 2
+ * It will be verified later, if this position actually holds a
+ * valid label record.
+ */
+ anc->label_pos = 2 * blksize;
+ /* A devno 0 is actually a valid devno, which could exist
+ * in the system. Since we use this number only to create
+ * a default volume serial, there is no serious conflict.
+ */
+ anc->devno = 0;
+ } else {
+ characteristics = (struct dasd_eckd_characteristics *)
+ &dasd_info.characteristics;
+ if (characteristics->no_cyl == LV_COMPAT_CYL &&
+ characteristics->long_no_cyl)
+ anc->hw_cylinders = characteristics->long_no_cyl;
+ else
+ anc->hw_cylinders = characteristics->no_cyl;
+ anc->dev_type = dasd_info.dev_type;
+ anc->label_pos = dasd_info.label_block * blksize;
+ anc->devno = dasd_info.devno;
+ anc->label_block = dasd_info.label_block;
+ anc->FBA_layout = dasd_info.FBA_layout;
+ }
+
+ anc->is_file = 0;
+ }
+
+ anc->blksize = blksize;
+ return 1;
+
+ error:
+ return 0;
+}
+
+/*
+ * returns unused partition info pointer if there
+ * is a free partition, otherwise NULL
+ */
+static partition_info_t *
+fdasd_get_empty_f1_label (fdasd_anchor_t * anc)
+{
+ PDEBUG
+ if (anc->used_partitions < USABLE_PARTITIONS)
+ return anc->last;
+ else
+ return NULL;
+}
+
+/*
+ * asks for and sets some important partition data
+ */
+static int
+fdasd_get_partition_data (fdasd_anchor_t *anc, extent_t *part_extent,
+ partition_info_t *p, unsigned int *start_ptr,
+ unsigned int *stop_ptr)
+{
+ PDEBUG
+ unsigned int limit;
+ u_int32_t cc, c;
+ u_int16_t hh, h;
+ cchh_t llimit, ulimit;
+ partition_info_t *q;
+ u_int8_t b1, b2;
+ unsigned int start = *start_ptr, stop = *stop_ptr;
+ int i;
+ char *ch;
+
+ c = get_usable_cylinders(anc);
+ h = anc->f4->DS4DEVCT.DS4DSTRK;
+ limit = (h * c - 1);
+
+ /* check start value from user */
+ q = anc->first;
+ for (i = 0; i < USABLE_PARTITIONS; i++) {
+ if ( q->next == NULL )
+ break;
+
+ if (start >= q->start_trk && start <= q->end_trk) {
+ /* start is within another partition */
+ start = q->end_trk + 1;
+
+ if (start > limit) {
+ start = FIRST_USABLE_TRK;
+ q = anc->first;
+ }
+ }
+
+ if (start < q->start_trk) {
+ limit = q->start_trk - 1;
+ break;
+ }
+
+ q = q->next;
+ }
+
+ if (start == limit)
+ stop = start;
+
+ /* update partition info */
+ p->len_trk = stop - start + 1;
+ p->start_trk = start;
+ p->end_trk = stop;
+
+ cc = start / anc->geo.heads;
+ hh = start - (cc * anc->geo.heads);
+ vtoc_set_cchh(&llimit, cc, hh);
+
+ /* check for cylinder boundary */
+ if (hh == 0)
+ b1 = 0x81;
+ else
+ b1 = 0x01;
+
+ cc = stop / anc->geo.heads;
+ hh = stop - cc * anc->geo.heads;
+ vtoc_set_cchh(&ulimit, cc, hh);
+
+ /* it is always the 1st extent */
+ b2 = 0x00;
+
+ vtoc_set_extent(part_extent, b1, b2, &llimit, &ulimit);
+
+ *start_ptr = start;
+ *stop_ptr = stop;
+
+ ch = p->f1->DS1DSNAM;
+ vtoc_ebcdic_dec (ch, ch, 44);
+
+ if (strstr(ch, PART_TYPE_LVM))
+ p->type = PARTITION_LINUX_LVM;
+ else if (strstr(ch, PART_TYPE_RAID))
+ p->type = PARTITION_LINUX_RAID;
+ else if (strstr(ch, PART_TYPE_NATIVE))
+ p->type = PARTITION_LINUX;
+ else if (strstr(ch, PART_TYPE_SWAP))
+ p->type = PARTITION_LINUX_SWAP;
+ else
+ p->type = PARTITION_LINUX;
+
+ vtoc_ebcdic_enc (ch, ch, 44);
+
+ return 0;
+}
+
+static void
+fdasd_enqueue_new_partition (fdasd_anchor_t *anc)
+{
+ PDEBUG
+ partition_info_t *q = anc->first, *p = anc->last;
+ int i, k=0;
+
+ for (i=1; i<USABLE_PARTITIONS; i++) {
+ if ((q->end_trk == 0) || (p->start_trk < q->start_trk)) {
+ break;
+ } else {
+ q = q->next;
+ k++;
+ }
+ }
+
+ if (anc->first == q)
+ anc->first = p;
+
+ if (p != q) {
+ anc->last->prev->next = NULL;
+ anc->last = anc->last->prev;
+
+ p->next = q;
+ p->prev = q->prev;
+ q->prev = p;
+
+ if (p->prev != NULL)
+ p->prev->next = p;
+ }
+
+ p->used = 0x01;
+ p->type = PARTITION_LINUX;
+
+ for (i=0; i<USABLE_PARTITIONS; i++) {
+ int j = getpos(anc, i);
+ if (j >= k)
+ setpos(anc, i, j + 1);
+ }
+
+ /* update free-space counters */
+ if (anc->first == p) {
+ /* partition is the first used partition */
+ if (p->start_trk == FIRST_USABLE_TRK) {
+ /* partition starts right behind VTOC */
+ p->fspace_trk = anc->fspace_trk - p->len_trk;
+ anc->fspace_trk = 0;
+ } else {
+ /* there is some space between VTOC and partition */
+ p->fspace_trk = anc->fspace_trk - p->len_trk - p->start_trk
+ + FIRST_USABLE_TRK;
+ anc->fspace_trk = p->start_trk - FIRST_USABLE_TRK;
+ }
+ } else {
+ /* there are partitions in front of the new one */
+ if (p->start_trk == p->prev->end_trk + 1) {
+ /* new partition is right behind the previous one */
+ p->fspace_trk = p->prev->fspace_trk - p->len_trk;
+ p->prev->fspace_trk = 0;
+ } else {
+ /* there is some space between new and prev. part. */
+ p->fspace_trk = p->prev->fspace_trk - p->len_trk
+ - p->start_trk + p->prev->end_trk + 1;
+ p->prev->fspace_trk = p->start_trk - p->prev->end_trk - 1;
+ }
+ }
+}
+
+/*
+ * adds a new partition to the 'partition table'
+ */
+partition_info_t *
+fdasd_add_partition (fdasd_anchor_t *anc, unsigned int start,
+ unsigned int stop)
+{
+ PDEBUG
+ cchhb_t hf1;
+ partition_info_t *p;
+ extent_t ext;
+
+ PDEBUG;
+
+ if ((p = fdasd_get_empty_f1_label(anc)) == NULL) {
+ PDEBUG;
+ return 0;
+ }
+
+ PDEBUG;
+ if (fdasd_get_partition_data(anc, &ext, p, &start, &stop) != 0)
+ return 0;
+
+ if (anc->formatted_cylinders > LV_COMPAT_CYL) {
+ vtoc_init_format8_label(anc->blksize, &ext, p->f1);
+ } else {
+ PDEBUG;
+ vtoc_init_format1_label(anc->blksize, &ext, p->f1);
+ }
+
+ PDEBUG;
+ fdasd_enqueue_new_partition(anc);
+
+ PDEBUG;
+ anc->used_partitions += 1;
+
+ get_addr_of_highest_f1_f8_label(anc, &hf1);
+ vtoc_update_format4_label(anc->f4, &hf1, anc->f4->DS4DSREC - 1);
+
+ PDEBUG;
+
+ start = cchh2trk(&ext.llimit, &anc->geo);
+ stop = cchh2trk(&ext.ulimit, &anc->geo);
+
+ PDEBUG;
+ vtoc_set_freespace(anc->f4, anc->f5, anc->f7, '-', anc->verbose,
+ start, stop, anc->formatted_cylinders, anc->geo.heads);
+
+ anc->vtoc_changed++;
+
+ PDEBUG;
+ return p;
+}
+
+/*
+ * Check for valid volume serial characters (max. 6) - remove invalid.
+ * If volser is empty, fill with default volser.
+ */
+void fdasd_check_volser (char *volser, int devno)
+{
+ int from, to;
+
+ for (from = 0, to = 0; volser[from] && from < VOLSER_LENGTH; from++) {
+
+ if ((volser[from] >= 0x23 &&
+ volser[from] <= 0x25) ||
+ (volser[from] >= 0x30 &&
+ volser[from] <= 0x39) ||
+ (volser[from] >= 0x40 &&
+ volser[from] <= 0x5a) ||
+ (volser[from] >= 0x61 &&
+ volser[from] <= 0x7a))
+ volser[to++] = toupper(volser[from]);
+ }
+
+ volser[to] = 0x00;
+
+ if (volser[0] == 0x00)
+ sprintf(volser, "0X%04x", devno);
+}
+
+/*
+ * get volser from vtoc
+ */
+int fdasd_get_volser (fdasd_anchor_t *anc, char *volser, int fd)
+{
+ volume_label_t vlabel;
+
+ vtoc_read_volume_label(fd, anc->label_pos, &vlabel);
+ vtoc_volume_label_get_volser(&vlabel, volser);
+ return 0;
+}
+
+/* Changes the volume serial (menu option)
+ *
+ */
+void fdasd_change_volser (fdasd_anchor_t *anc, char *str)
+{
+ fdasd_check_volser(str, anc->devno);
+ vtoc_volume_label_set_volser(anc->vlabel, str);
+
+ vtoc_set_cchhb(&anc->vlabel->vtoc, VTOC_START_CC, VTOC_START_HH, 0x01);
+ anc->vlabel_changed++;
+ anc->vtoc_changed++;
+}
+
+/*
+ * re-create all VTOC labels, but use the partition information
+ * from existing VTOC
+ */
+void fdasd_reuse_vtoc (fdasd_anchor_t *anc)
+{
+ partition_info_t *part_info = anc->first;
+ struct fdasd_hd_geometry geo = anc->geo;
+ format1_label_t f1;
+ format4_label_t f4;
+ format5_label_t f5;
+ format7_label_t f7;
+
+ vtoc_init_format4_label(&f4, geo.cylinders, anc->formatted_cylinders,
+ geo.heads, geo.sectors,
+ anc->blksize, anc->dev_type);
+
+ /* reuse some FMT4 values */
+ f4.DS4HPCHR = anc->f4->DS4HPCHR;
+ f4.DS4DSREC = anc->f4->DS4DSREC;
+
+ /* re-initialize both free-space labels */
+ vtoc_init_format5_label(&f5);
+ vtoc_init_format7_label(&f7);
+
+ if (anc->fspace_trk > 0)
+ vtoc_set_freespace(&f4, &f5, &f7, '+', anc->verbose,
+ FIRST_USABLE_TRK,
+ FIRST_USABLE_TRK + anc->fspace_trk - 1,
+ anc->formatted_cylinders, geo.heads);
+
+ while (part_info != NULL) {
+ if (part_info->used != 0x01) {
+ part_info = part_info->next;
+ continue;
+ }
+
+ if (anc->formatted_cylinders > LV_COMPAT_CYL)
+ vtoc_init_format8_label(anc->blksize,
+ &part_info->f1->DS1EXT1, &f1);
+ else
+ vtoc_init_format1_label(anc->blksize,
+ &part_info->f1->DS1EXT1, &f1);
+
+
+ strncpy(f1.DS1DSNAM, part_info->f1->DS1DSNAM, 44);
+ strncpy((char *)f1.DS1DSSN, (char *)part_info->f1->DS1DSSN, 6);
+ f1.DS1CREDT = part_info->f1->DS1CREDT;
+
+ memcpy(part_info->f1, &f1, sizeof(format1_label_t));
+
+ if (part_info->fspace_trk > 0)
+ vtoc_set_freespace(&f4, &f5, &f7, '+', anc->verbose,
+ part_info->end_trk + 1,
+ part_info->end_trk +
+ part_info->fspace_trk,
+ anc->formatted_cylinders, geo.heads);
+
+ part_info = part_info->next;
+ }
+
+ /* over-write old labels with new ones */
+ memcpy(anc->f4, &f4, sizeof(format4_label_t));
+ memcpy(anc->f5, &f5, sizeof(format5_label_t));
+ memcpy(anc->f7, &f7, sizeof(format7_label_t));
+
+ anc->vtoc_changed++;
+
+ return;
+}
+
+/* vim:set tabstop=4 shiftwidth=4 softtabstop=4: */
diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
new file mode 100644
index 0000000..780fb70
--- /dev/null
+++ b/libparted/labels/gpt.c
@@ -0,0 +1,1941 @@
+/*
+ libparted - a library for manipulating disk partitions
+
+ original version by Matt Domsch <Matt_Domsch@dell.com>
+ Disclaimed into the Public Domain
+
+ Portions Copyright (C) 2001-2003, 2005-2012 Free Software Foundation, Inc.
+
+ EFI GUID Partition Table handling
+ Per Intel EFI Specification v1.02
+ http://developer.intel.com/technology/efi/efi.htm
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <parted/crc32.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <iconv.h>
+#include <langinfo.h>
+#include "xalloc.h"
+#include "xalloc-oversized.h"
+#include "verify.h"
+
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) gettext (String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#define EFI_PMBR_OSTYPE_EFI 0xEE
+#define MSDOS_MBR_SIGNATURE 0xaa55
+
+#define GPT_HEADER_SIGNATURE 0x5452415020494645LL
+
+/* NOTE: the document that describes revision 1.00 is labelled "version 1.02",
+ * so some implementors got confused...
+ */
+#define GPT_HEADER_REVISION_V1_02 0x00010200
+#define GPT_HEADER_REVISION_V1_00 0x00010000
+#define GPT_HEADER_REVISION_V0_99 0x00009900
+
+typedef uint16_t efi_char16_t; /* UNICODE character */
+typedef struct _GuidPartitionTableHeader_t GuidPartitionTableHeader_t;
+typedef struct _GuidPartitionEntryAttributes_t GuidPartitionEntryAttributes_t;
+typedef struct _GuidPartitionEntry_t GuidPartitionEntry_t;
+typedef struct _PartitionRecord_t PartitionRecord_t;
+typedef struct _LegacyMBR_t LegacyMBR_t;
+typedef struct _GPTDiskData GPTDiskData;
+
+
+typedef struct
+{
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_hi_and_reserved;
+ uint8_t clock_seq_low;
+ uint8_t node[6];
+} /* __attribute__ ((packed)) */ efi_guid_t;
+/* commented out "__attribute__ ((packed))" to work around gcc bug (fixed
+ * in gcc3.1): __attribute__ ((packed)) breaks addressing on initialized
+ * data. It turns out we don't need it in this case, so it doesn't break
+ * anything :)
+ */
+
+#define UNUSED_ENTRY_GUID \
+ ((efi_guid_t) { 0x00000000, 0x0000, 0x0000, 0x00, 0x00, \
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }})
+#define PARTITION_SYSTEM_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xC12A7328), PED_CPU_TO_LE16 (0xF81F), \
+ PED_CPU_TO_LE16 (0x11d2), 0xBA, 0x4B, \
+ { 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }})
+#define PARTITION_BIOS_GRUB_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x21686148), PED_CPU_TO_LE16 (0x6449), \
+ PED_CPU_TO_LE16 (0x6E6f), 0x74, 0x4E, \
+ { 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 }})
+#define LEGACY_MBR_PARTITION_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x024DEE41), PED_CPU_TO_LE16 (0x33E7), \
+ PED_CPU_TO_LE16 (0x11d3, 0x9D, 0x69, \
+ { 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }})
+#define PARTITION_MSFT_RESERVED_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xE3C9E316), PED_CPU_TO_LE16 (0x0B5C), \
+ PED_CPU_TO_LE16 (0x4DB8), 0x81, 0x7D, \
+ { 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE }})
+#define PARTITION_MSFT_RECOVERY \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xDE94BBA4), PED_CPU_TO_LE16 (0x06D1), \
+ PED_CPU_TO_LE16 (0x4D40), 0xA1, 0x6A, \
+ { 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC }})
+#define PARTITION_BASIC_DATA_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xEBD0A0A2), PED_CPU_TO_LE16 (0xB9E5), \
+ PED_CPU_TO_LE16 (0x4433), 0x87, 0xC0, \
+ { 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7 }})
+#define PARTITION_RAID_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xa19d880f), PED_CPU_TO_LE16 (0x05fc), \
+ PED_CPU_TO_LE16 (0x4d3b), 0xa0, 0x06, \
+ { 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e }})
+#define PARTITION_SWAP_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x0657fd6d), PED_CPU_TO_LE16 (0xa4ab), \
+ PED_CPU_TO_LE16 (0x43c4), 0x84, 0xe5, \
+ { 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f }})
+#define PARTITION_LINUX_DATA_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x0FC63DAF), PED_CPU_TO_LE16 (0x8483), \
+ PED_CPU_TO_LE16 (0x4772), 0x8E, 0x79, \
+ { 0x3D, 0x69, 0xD8, 0x47, 0x7D, 0xE4 }})
+#define PARTITION_LVM_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xe6d6d379), PED_CPU_TO_LE16 (0xf507), \
+ PED_CPU_TO_LE16 (0x44c2), 0xa2, 0x3c, \
+ { 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28 }})
+#define PARTITION_RESERVED_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x8da63339), PED_CPU_TO_LE16 (0x0007), \
+ PED_CPU_TO_LE16 (0x60c0), 0xc4, 0x36, \
+ { 0x08, 0x3a, 0xc8, 0x23, 0x09, 0x08 }})
+#define PARTITION_HPSERVICE_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xe2a1e728), PED_CPU_TO_LE16 (0x32e3), \
+ PED_CPU_TO_LE16 (0x11d6), 0xa6, 0x82, \
+ { 0x7b, 0x03, 0xa0, 0x00, 0x00, 0x00 }})
+#define PARTITION_APPLE_HFS_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x48465300), PED_CPU_TO_LE16 (0x0000), \
+ PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
+ { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
+#define PARTITION_APPLE_TV_RECOVERY_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x5265636F), PED_CPU_TO_LE16 (0x7665), \
+ PED_CPU_TO_LE16 (0x11AA), 0xaa, 0x11, \
+ { 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC }})
+#define PARTITION_PREP_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x9e1a2d38), PED_CPU_TO_LE16 (0xc612), \
+ PED_CPU_TO_LE16 (0x4316), 0xaa, 0x26, \
+ { 0x8b, 0x49, 0x52, 0x1e, 0x5a, 0x8b }})
+#define PARTITION_IRST_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xD3BFE2DE), PED_CPU_TO_LE16 (0x3DAF), \
+ PED_CPU_TO_LE16 (0x11DF), 0xba, 0x40, \
+ { 0xE3, 0xA5, 0x56, 0xD8, 0x95, 0x93 }})
+#define PARTITION_CHROMEOS_KERNEL_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xfe3a2a5d), PED_CPU_TO_LE16 (0x4f32), \
+ PED_CPU_TO_LE16 (0x41a7), 0xb7, 0x25, \
+ { 0xac, 0xcc, 0x32, 0x85, 0xa3, 0x09 }})
+#define PARTITION_BLS_BOOT_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0xbc13c2ff), PED_CPU_TO_LE16 (0x59e6), \
+ PED_CPU_TO_LE16 (0x4262), 0xa3, 0x52, \
+ { 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 }})
+#define PARTITION_LINUX_HOME_GUID \
+ ((efi_guid_t) { PED_CPU_TO_LE32 (0x933ac7e1), PED_CPU_TO_LE16 (0x2eb4), \
+ PED_CPU_TO_LE16 (0x4f13), 0xb8, 0x44, \
+ { 0x0e, 0x14, 0xe2, 0xae, 0xf9, 0x15 }})
+
+struct flag_uuid_mapping_t
+{
+ enum _PedPartitionFlag flag;
+ efi_guid_t type_uuid;
+};
+
+static const struct flag_uuid_mapping_t flag_uuid_mapping[] =
+{
+ { PED_PARTITION_APPLE_TV_RECOVERY, PARTITION_APPLE_TV_RECOVERY_GUID },
+ { PED_PARTITION_BIOS_GRUB, PARTITION_BIOS_GRUB_GUID },
+ { PED_PARTITION_BLS_BOOT, PARTITION_BLS_BOOT_GUID },
+ { PED_PARTITION_BOOT, PARTITION_SYSTEM_GUID },
+ { PED_PARTITION_CHROMEOS_KERNEL, PARTITION_CHROMEOS_KERNEL_GUID },
+ { PED_PARTITION_DIAG, PARTITION_MSFT_RECOVERY },
+ { PED_PARTITION_ESP, PARTITION_SYSTEM_GUID },
+ { PED_PARTITION_HPSERVICE, PARTITION_HPSERVICE_GUID },
+ { PED_PARTITION_IRST, PARTITION_IRST_GUID },
+ { PED_PARTITION_LINUX_HOME, PARTITION_LINUX_HOME_GUID },
+ { PED_PARTITION_LVM, PARTITION_LVM_GUID },
+ { PED_PARTITION_MSFT_DATA, PARTITION_BASIC_DATA_GUID },
+ { PED_PARTITION_MSFT_RESERVED, PARTITION_MSFT_RESERVED_GUID },
+ { PED_PARTITION_PREP, PARTITION_PREP_GUID },
+ { PED_PARTITION_RAID, PARTITION_RAID_GUID },
+ { PED_PARTITION_SWAP, PARTITION_SWAP_GUID },
+};
+
+static const efi_guid_t skip_set_system_guids[] =
+{
+ PARTITION_LVM_GUID,
+ PARTITION_SWAP_GUID,
+ PARTITION_RAID_GUID,
+ PARTITION_PREP_GUID,
+ PARTITION_SYSTEM_GUID,
+ PARTITION_BIOS_GRUB_GUID,
+ PARTITION_HPSERVICE_GUID,
+ PARTITION_MSFT_RESERVED_GUID,
+ PARTITION_BASIC_DATA_GUID,
+ PARTITION_MSFT_RECOVERY,
+ PARTITION_APPLE_TV_RECOVERY_GUID,
+ PARTITION_IRST_GUID,
+ PARTITION_CHROMEOS_KERNEL_GUID,
+ PARTITION_BLS_BOOT_GUID,
+};
+
+static const struct flag_uuid_mapping_t* _GL_ATTRIBUTE_CONST
+gpt_find_flag_uuid_mapping (PedPartitionFlag flag)
+{
+ int n = sizeof(flag_uuid_mapping) / sizeof(flag_uuid_mapping[0]);
+
+ for (int i = 0; i < n; ++i)
+ if (flag_uuid_mapping[i].flag == flag)
+ return &flag_uuid_mapping[i];
+
+ return NULL;
+}
+
+struct __attribute__ ((packed)) _GuidPartitionTableHeader_t
+{
+ uint64_t Signature;
+ uint32_t Revision;
+ uint32_t HeaderSize;
+ uint32_t HeaderCRC32;
+ uint32_t Reserved1;
+ uint64_t MyLBA;
+ uint64_t AlternateLBA;
+ uint64_t FirstUsableLBA;
+ uint64_t LastUsableLBA;
+ efi_guid_t DiskGUID;
+ uint64_t PartitionEntryLBA;
+ uint32_t NumberOfPartitionEntries;
+ uint32_t SizeOfPartitionEntry;
+ uint32_t PartitionEntryArrayCRC32;
+ uint8_t *Reserved2;
+};
+
+struct __attribute__ ((packed)) _GuidPartitionEntryAttributes_t
+{
+#ifdef __GNUC__ /* XXX narrow this down to !TinyCC */
+ uint64_t RequiredToFunction:1;
+ uint64_t NoBlockIOProtocol:1;
+ uint64_t LegacyBIOSBootable:1;
+ uint64_t Reserved:45;
+ uint64_t GuidSpecific:15;
+ uint64_t NoAutomount:1;
+#else
+# warning "Using crippled partition entry type"
+ uint32_t RequiredToFunction:1;
+ uint32_t NoBlockIOProtocol:1;
+ uint32_t LegacyBIOSBootable:1;
+ uint32_t Reserved:30;
+ uint32_t LOST:5;
+ uint32_t GuidSpecific:15;
+ uint32_t NoAutomount:1;
+#endif
+};
+
+struct __attribute__ ((packed)) _GuidPartitionEntry_t
+{
+ efi_guid_t PartitionTypeGuid;
+ efi_guid_t UniquePartitionGuid;
+ uint64_t StartingLBA;
+ uint64_t EndingLBA;
+ GuidPartitionEntryAttributes_t Attributes;
+ efi_char16_t PartitionName[36];
+};
+
+#define GPT_PMBR_LBA 0
+#define GPT_PMBR_SECTORS 1
+#define GPT_PRIMARY_HEADER_LBA 1
+#define GPT_HEADER_SECTORS 1
+#define GPT_PRIMARY_PART_TABLE_LBA 2
+
+/*
+ These values are only defaults. The actual on-disk structures
+ may define different sizes, so use those unless creating a new GPT disk!
+*/
+
+#define GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE 16384
+
+/* Number of actual partition entries should be calculated as: */
+#define GPT_DEFAULT_PARTITION_ENTRIES \
+ (GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / \
+ sizeof(GuidPartitionEntry_t))
+
+struct __attribute__ ((packed)) _PartitionRecord_t
+{
+ /* Not used by EFI firmware. Set to 0x80 to indicate that this
+ is the bootable legacy partition. */
+ uint8_t BootIndicator;
+
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartHead;
+
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartSector;
+
+ /* Start of partition in CHS address, not used by EFI firmware. */
+ uint8_t StartTrack;
+
+ /* OS type. A value of 0xEF defines an EFI system partition.
+ Other values are reserved for legacy operating systems, and
+ allocated independently of the EFI specification. */
+ uint8_t OSType;
+
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndHead;
+
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndSector;
+
+ /* End of partition in CHS address, not used by EFI firmware. */
+ uint8_t EndTrack;
+
+ /* Starting LBA address of the partition on the disk. Used by
+ EFI firmware to define the start of the partition. */
+ uint32_t StartingLBA;
+
+ /* Size of partition in LBA. Used by EFI firmware to determine
+ the size of the partition. */
+ uint32_t SizeInLBA;
+};
+
+/* Protected Master Boot Record & Legacy MBR share same structure */
+/* Needs to be packed because the u16s force misalignment. */
+struct __attribute__ ((packed)) _LegacyMBR_t
+{
+ uint8_t BootCode[440];
+ uint32_t UniqueMBRSignature;
+ uint16_t Unknown;
+ PartitionRecord_t PartitionRecord[4];
+ uint16_t Signature;
+};
+
+/* uses libparted's disk_specific field in PedDisk, to store our info */
+struct __attribute__ ((packed, aligned(8))) _GPTDiskData
+{
+ PedGeometry data_area;
+ int entry_count;
+ efi_guid_t uuid;
+ int pmbr_boot;
+ PedSector AlternateLBA;
+};
+
+/* uses libparted's disk_specific field in PedPartition, to store our info */
+typedef struct _GPTPartitionData
+{
+ efi_guid_t type;
+ efi_guid_t uuid;
+ efi_char16_t name[37];
+ char *translated_name;
+ GuidPartitionEntryAttributes_t attributes;
+} GPTPartitionData;
+
+static PedDiskType gpt_disk_type;
+
+static inline uint32_t
+pth_get_size (const PedDevice *dev)
+{
+ return GPT_HEADER_SECTORS * dev->sector_size;
+}
+
+static inline uint32_t
+pth_get_size_static (const PedDevice *dev)
+{
+ return sizeof (GuidPartitionTableHeader_t) - sizeof (uint8_t *);
+}
+
+static inline uint32_t
+pth_get_size_rsv2 (const PedDevice *dev)
+{
+ return pth_get_size (dev) - pth_get_size_static (dev);
+}
+
+static GuidPartitionTableHeader_t *
+pth_new (const PedDevice *dev)
+{
+ GuidPartitionTableHeader_t *pth =
+ ped_malloc (sizeof (GuidPartitionTableHeader_t) + sizeof (uint8_t));
+
+ pth->Reserved2 = ped_malloc (pth_get_size_rsv2 (dev));
+
+ return pth;
+}
+
+static GuidPartitionTableHeader_t *
+pth_new_zeroed (const PedDevice *dev)
+{
+ GuidPartitionTableHeader_t *pth = pth_new (dev);
+
+ memset (pth, 0, pth_get_size_static (dev));
+ memset (pth->Reserved2, 0, pth_get_size_rsv2 (dev));
+
+ return (pth);
+}
+
+static GuidPartitionTableHeader_t *
+pth_new_from_raw (const PedDevice *dev, const uint8_t *pth_raw)
+{
+ GuidPartitionTableHeader_t *pth = pth_new (dev);
+
+ PED_ASSERT (pth_raw != NULL);
+
+ memcpy (pth, pth_raw, pth_get_size_static (dev));
+ memcpy (pth->Reserved2, pth_raw + pth_get_size_static (dev),
+ pth_get_size_rsv2 (dev));
+
+ return pth;
+}
+
+static void
+pth_free (GuidPartitionTableHeader_t *pth)
+{
+ if (pth == NULL)
+ return;
+ PED_ASSERT (pth->Reserved2 != NULL);
+
+ free (pth->Reserved2);
+ free (pth);
+}
+
+static uint8_t *
+pth_get_raw (const PedDevice *dev, const GuidPartitionTableHeader_t *pth)
+{
+ PED_ASSERT (pth != NULL);
+ PED_ASSERT (pth->Reserved2 != NULL);
+
+ int size_static = pth_get_size_static (dev);
+ uint8_t *pth_raw = ped_malloc (pth_get_size (dev));
+ if (pth_raw == NULL)
+ return NULL;
+
+ memcpy (pth_raw, pth, size_static);
+ memcpy (pth_raw + size_static, pth->Reserved2, pth_get_size_rsv2 (dev));
+
+ return pth_raw;
+}
+
+/**
+ * swap_uuid_and_efi_guid() - converts between uuid formats
+ * @uuid - uuid_t in either format (converts it to the other)
+ *
+ * There are two different representations for Globally Unique Identifiers
+ * (GUIDs or UUIDs).
+ *
+ * The RFC specifies a UUID as a string of 16 bytes, essentially
+ * a big-endian array of char.
+ * Intel, in their EFI Specification, references the same RFC, but
+ * then defines a GUID as a structure of little-endian fields.
+ * Coincidentally, both structures have the same format when unparsed.
+ *
+ * When read from disk, EFI GUIDs are in struct of little endian format,
+ * and need to be converted to be treated as uuid_t in memory.
+ *
+ * When writing to disk, uuid_ts need to be converted into EFI GUIDs.
+ *
+ * Blame Intel.
+ */
+static void
+swap_uuid_and_efi_guid (efi_guid_t *guid)
+{
+ PED_ASSERT (guid != NULL);
+ guid->time_low = PED_SWAP32 (guid->time_low);
+ guid->time_mid = PED_SWAP16 (guid->time_mid);
+ guid->time_hi_and_version = PED_SWAP16 (guid->time_hi_and_version);
+}
+
+/* returns the EFI-style CRC32 value for buf
+ * This function uses the crc32 function by Gary S. Brown,
+ * but seeds the function with ~0, and xor's with ~0 at the end.
+ */
+static inline uint32_t
+efi_crc32 (const void *buf, unsigned long len)
+{
+ return (__efi_crc32 (buf, len, ~0L) ^ ~0L);
+}
+
+/* Compute the crc32 checksum of the partition table header
+ and store it in *CRC32. Return 0 upon success. Return 1
+ upon failure to allocate space. */
+static int
+pth_crc32 (const PedDevice *dev, const GuidPartitionTableHeader_t *pth,
+ uint32_t *crc32)
+{
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (pth != NULL);
+
+ uint8_t *pth_raw = pth_get_raw (dev, pth);
+ if (pth_raw == NULL)
+ return 1;
+
+ *crc32 = efi_crc32 (pth_raw, PED_LE32_TO_CPU (pth->HeaderSize));
+ free (pth_raw);
+
+ return 0;
+}
+
+static inline int
+guid_cmp (efi_guid_t left, efi_guid_t right)
+{
+ return memcmp (&left, &right, sizeof (efi_guid_t));
+}
+
+/* checks if 'mbr' is a protective MBR partition table */
+static inline int _GL_ATTRIBUTE_PURE
+_pmbr_is_valid (const LegacyMBR_t *mbr)
+{
+ int i;
+
+ PED_ASSERT (mbr != NULL);
+
+ if (mbr->Signature != PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE))
+ return 0;
+ for (i = 0; i < 4; i++)
+ {
+ if (mbr->PartitionRecord[i].OSType == EFI_PMBR_OSTYPE_EFI)
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gpt_probe (const PedDevice *dev)
+{
+ int gpt_sig_found = 0;
+
+ PED_ASSERT (dev != NULL);
+
+ if (dev->length <= 1)
+ return 0;
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+
+ if (!_pmbr_is_valid (label))
+ {
+ free (label);
+ return 0;
+ }
+ free (label);
+
+ void *pth_raw = ped_malloc (pth_get_size (dev));
+ if (ped_device_read (dev, pth_raw, 1, GPT_HEADER_SECTORS)
+ || ped_device_read (dev, pth_raw, dev->length - 1, GPT_HEADER_SECTORS))
+ {
+ GuidPartitionTableHeader_t *gpt = pth_new_from_raw (dev, pth_raw);
+ if (gpt->Signature == PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE))
+ gpt_sig_found = 1;
+ pth_free (gpt);
+ }
+ free (pth_raw);
+
+ return gpt_sig_found;
+}
+
+static PedDisk *
+gpt_alloc (const PedDevice *dev)
+{
+ PedDisk *disk;
+ GPTDiskData *gpt_disk_data;
+ PedSector data_start, data_end;
+
+ disk = _ped_disk_alloc ((PedDevice *) dev, &gpt_disk_type);
+ if (!disk)
+ goto error;
+
+ data_start = 2 + GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
+ data_end = dev->length - 2
+ - GPT_DEFAULT_PARTITION_ENTRY_ARRAY_SIZE / dev->sector_size;
+
+ /* If the device is too small to accommodate GPT headers and one data
+ sector, reject it. */
+ if (data_end < data_start)
+ {
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_OK,
+ _("device is too small for GPT"));
+ goto error_free_disk;
+ }
+
+ disk->disk_specific = gpt_disk_data = ped_malloc (sizeof (GPTDiskData));
+ if (!disk->disk_specific)
+ goto error_free_disk;
+
+ gpt_disk_data->AlternateLBA = dev->length - 1;
+ ped_geometry_init (&gpt_disk_data->data_area, dev, data_start,
+ data_end - data_start + 1);
+ gpt_disk_data->entry_count = GPT_DEFAULT_PARTITION_ENTRIES;
+ uuid_generate ((unsigned char *) &gpt_disk_data->uuid);
+ swap_uuid_and_efi_guid (&gpt_disk_data->uuid);
+ gpt_disk_data->pmbr_boot = 0;
+ return disk;
+
+error_free_disk:
+ free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk *
+gpt_duplicate (const PedDisk *disk)
+{
+ PedDisk *new_disk;
+ GPTDiskData *new_disk_data;
+ GPTDiskData *old_disk_data;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &gpt_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ old_disk_data = disk->disk_specific;
+ new_disk_data = new_disk->disk_specific;
+
+ ped_geometry_init (&new_disk_data->data_area, disk->dev,
+ old_disk_data->data_area.start,
+ old_disk_data->data_area.length);
+ new_disk_data->entry_count = old_disk_data->entry_count;
+ new_disk_data->uuid = old_disk_data->uuid;
+ new_disk_data->pmbr_boot = old_disk_data->pmbr_boot;
+ return new_disk;
+}
+
+static void
+gpt_free (PedDisk *disk)
+{
+ ped_disk_delete_all (disk);
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+/* Given GUID Partition table header, GPT, read its partition array
+ entries from DISK into malloc'd storage. Set *PTES_BYTES to the
+ number of bytes required. Upon success, return a pointer to the
+ resulting buffer. Otherwise, set errno and return NULL. */
+static void *
+gpt_read_PE_array (PedDisk const *disk, GuidPartitionTableHeader_t const *gpt,
+ size_t *ptes_bytes)
+{
+ uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
+ *ptes_bytes = p_ent_size * PED_LE32_TO_CPU(gpt->NumberOfPartitionEntries);
+ size_t ptes_sectors = ped_div_round_up (*ptes_bytes,
+ disk->dev->sector_size);
+
+ if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ void *ptes = ped_malloc (ptes_sectors * disk->dev->sector_size);
+ if (ptes == NULL)
+ return NULL;
+
+ if (!ped_device_read (disk->dev, ptes,
+ PED_LE64_TO_CPU (gpt->PartitionEntryLBA), ptes_sectors))
+ {
+ int saved_errno = errno;
+ free (ptes);
+ errno = saved_errno;
+ return NULL;
+ }
+
+ return ptes;
+}
+
+static int
+check_PE_array_CRC (PedDisk const *disk,
+ GuidPartitionTableHeader_t const *gpt, bool *valid)
+{
+ size_t ptes_bytes;
+ void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
+ if (ptes == NULL)
+ return 1;
+
+ uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
+ *valid = (ptes_crc == PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32));
+ free (ptes);
+ return 0;
+}
+
+static int
+_header_is_valid (PedDisk const *disk, GuidPartitionTableHeader_t *gpt,
+ PedSector my_lba)
+{
+ uint32_t crc, origcrc;
+ PedDevice const *dev = disk->dev;
+
+ if (PED_LE64_TO_CPU (gpt->Signature) != GPT_HEADER_SIGNATURE)
+ return 0;
+ /*
+ * "While the GUID Partition Table Header's size may increase
+ * in the future it cannot span more than one block on the
+ * device." EFI Specification, version 1.10, 11.2.2.1
+ */
+ if (PED_LE32_TO_CPU (gpt->HeaderSize) < pth_get_size_static (dev)
+ || PED_LE32_TO_CPU (gpt->HeaderSize) > dev->sector_size)
+ return 0;
+
+ /* The SizeOfPartitionEntry must be a multiple of 8 and
+ no smaller than the size of the PartitionEntry structure.
+ We also require that it be no larger than 1/16th of UINT32_MAX,
+ as an additional sanity check. */
+ uint32_t pe_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
+ if (pe_size % 8 != 0
+ || ! (sizeof (GuidPartitionEntry_t) <= pe_size
+ && pe_size <= (UINT32_MAX >> 4)))
+ return 0;
+
+ if (PED_LE64_TO_CPU (gpt->MyLBA) != my_lba)
+ return 0;
+
+ PedSector alt_lba = PED_LE64_TO_CPU (gpt->AlternateLBA);
+ /* The backup table's AlternateLBA must be 1. */
+ if (my_lba != 1 && alt_lba != 1)
+ return 0;
+
+ /* The alt_lba must never be the same as my_lba. */
+ if (alt_lba == my_lba)
+ return 0;
+
+ bool crc_match;
+ if (check_PE_array_CRC (disk, gpt, &crc_match) != 0 || !crc_match)
+ return 0;
+
+ PedSector first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
+ if (first_usable < 3)
+ return 0;
+
+ PedSector last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
+ if (last_usable < first_usable)
+ return 0;
+
+ origcrc = gpt->HeaderCRC32;
+ gpt->HeaderCRC32 = 0;
+ if (pth_crc32 (dev, gpt, &crc) != 0)
+ return 0;
+ gpt->HeaderCRC32 = origcrc;
+
+ return crc == PED_LE32_TO_CPU (origcrc);
+}
+
+/* Return the number of sectors that should be used by the
+ * partition entry table.
+ */
+static PedSector
+_ptes_sectors(PedDisk const *disk, GuidPartitionTableHeader_t const *gpt)
+{
+ size_t ptes_bytes = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry) *
+ PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
+ /* Minimum amount of space reserved is 128 128 byte entries */
+ if (ptes_bytes < 128*128)
+ ptes_bytes = 128*128;
+ return ped_div_round_up (ptes_bytes, disk->dev->sector_size);
+}
+
+/* Return the header's idea of the last sector of the disk
+ * based on LastUsableLBA and the Partition Entry table.
+ */
+static PedSector
+_hdr_disk_end(PedDisk const *disk, GuidPartitionTableHeader_t const *gpt)
+{
+ return PED_LE64_TO_CPU (gpt->LastUsableLBA) + 1 + _ptes_sectors(disk, gpt);
+}
+
+static int
+_parse_header (PedDisk *disk, const GuidPartitionTableHeader_t *gpt,
+ int *update_needed)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ PedSector first_usable;
+ PedSector last_usable;
+ PedSector last_usable_if_grown;
+
+#ifndef DISCOVER_ONLY
+ if (PED_LE32_TO_CPU (gpt->Revision) > GPT_HEADER_REVISION_V1_02)
+ {
+ if (ped_exception_throw
+ (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The format of the GPT partition table is version "
+ "%x, which is newer than what Parted can "
+ "recognise. Please report this!"),
+ PED_LE32_TO_CPU (gpt->Revision)) != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+#endif
+
+ first_usable = PED_LE64_TO_CPU (gpt->FirstUsableLBA);
+ last_usable = PED_LE64_TO_CPU (gpt->LastUsableLBA);
+
+ /* Need to check whether the volume has grown, the LastUsableLBA is
+ normally set to disk->dev->length - 2 - ptes_size (at least for parted
+ created volumes), where ptes_size is the number of entries *
+ size of each entry / sector size or 16k / sector size, whatever the greater.
+ If the volume has grown, offer the user the chance to use the new
+ space or continue with the current usable area. Only ask once per
+ parted invocation. */
+
+ last_usable_if_grown = disk->dev->length - 2 - _ptes_sectors(disk, gpt);
+
+ if (last_usable <= first_usable
+ || disk->dev->length < last_usable)
+ return 0;
+
+ if (last_usable_if_grown <= first_usable
+ || disk->dev->length < last_usable_if_grown)
+ return 0;
+
+ if (last_usable < last_usable_if_grown)
+ {
+ PedExceptionOption q;
+
+ q = ped_exception_throw
+ (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE,
+ _("Not all of the space available to %s appears "
+ "to be used, you can fix the GPT to use all of the "
+ "space (an extra %llu blocks) or continue with the "
+ "current setting? "), disk->dev->path,
+ (uint64_t) (last_usable_if_grown - last_usable));
+
+ if (q == PED_EXCEPTION_FIX)
+ {
+ last_usable = last_usable_if_grown;
+ /* clear the old backup gpt header */
+ ptt_clear_sectors (disk->dev,
+ gpt_disk_data->AlternateLBA, 1);
+ gpt_disk_data->AlternateLBA = disk->dev->length - 1;
+ *update_needed = 1;
+ }
+ }
+
+ ped_geometry_init (&gpt_disk_data->data_area, disk->dev,
+ first_usable, last_usable - first_usable + 1);
+
+ gpt_disk_data->entry_count
+ = PED_LE32_TO_CPU (gpt->NumberOfPartitionEntries);
+ PED_ASSERT (gpt_disk_data->entry_count > 0);
+ PED_ASSERT (gpt_disk_data->entry_count <= 8192);
+
+ gpt_disk_data->uuid = gpt->DiskGUID;
+
+ return 1;
+}
+
+static PedPartition *
+_parse_part_entry (PedDisk *disk, GuidPartitionEntry_t *pte)
+{
+ PedPartition *part;
+ GPTPartitionData *gpt_part_data;
+ unsigned int i;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ PED_LE64_TO_CPU (pte->StartingLBA),
+ PED_LE64_TO_CPU (pte->EndingLBA));
+ if (!part)
+ return NULL;
+
+ gpt_part_data = part->disk_specific;
+ gpt_part_data->type = pte->PartitionTypeGuid;
+ gpt_part_data->uuid = pte->UniquePartitionGuid;
+ for (i = 0; i < 36; i++)
+ gpt_part_data->name[i] = (efi_char16_t) pte->PartitionName[i];
+ gpt_part_data->name[i] = 0;
+ gpt_part_data->translated_name = 0;
+ gpt_part_data->attributes = pte->Attributes;
+
+ return part;
+}
+
+/* Read the primary GPT at sector 1 of DEV.
+ Verify its CRC and that of its partition entry array.
+ If they are valid, read the backup GPT specified by AlternateLBA.
+ If not, read the backup GPT in the last sector of the disk.
+ Return 1 if any read fails.
+ Upon successful verification of the primary GPT, set *PRIMARY_GPT, else NULL.
+ Upon successful verification of the backup GPT, set *BACKUP_GPT, else NULL.
+ If we've set *BACKUP_GPT to non-NULL, set *BACKUP_SECTOR_NUM_P to the sector
+ number in which it was found. */
+static int
+gpt_read_headers (PedDisk const *disk,
+ GuidPartitionTableHeader_t **primary_gpt,
+ GuidPartitionTableHeader_t **backup_gpt,
+ PedSector *backup_sector_num_p)
+{
+ *primary_gpt = NULL;
+ *backup_gpt = NULL;
+ PedDevice const *dev = disk->dev;
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ LegacyMBR_t *mbr;
+
+ if (!ptt_read_sector (dev, 0, (void *)&mbr))
+ return 1;
+
+ if (mbr->PartitionRecord[0].BootIndicator == 0x80)
+ gpt_disk_data->pmbr_boot = 1;
+ free (mbr);
+
+ void *s1;
+ if (!ptt_read_sector (dev, 1, &s1))
+ return 1;
+
+ GuidPartitionTableHeader_t *t = pth_new_from_raw (dev, s1);
+ free (s1);
+ if (t == NULL)
+ return 1;
+ GuidPartitionTableHeader_t *pri = t;
+
+ bool valid_primary = _header_is_valid (disk, pri, 1);
+ if (valid_primary)
+ *primary_gpt = pri;
+ else
+ pth_free (pri);
+
+ gpt_disk_data->AlternateLBA =
+ (valid_primary
+ ? PED_LE64_TO_CPU (pri->AlternateLBA)
+ : dev->length - 1);
+
+ void *s_bak;
+ if (!ptt_read_sector (dev, gpt_disk_data->AlternateLBA ,&s_bak))
+ return 1;
+ t = pth_new_from_raw (dev, s_bak);
+ free (s_bak);
+ if (t == NULL)
+ return 1;
+
+ GuidPartitionTableHeader_t *bak = t;
+ if (_header_is_valid (disk, bak, gpt_disk_data->AlternateLBA))
+ {
+ *backup_gpt = bak;
+ *backup_sector_num_p = gpt_disk_data->AlternateLBA;
+ }
+ else
+ pth_free (bak);
+
+ return 0;
+}
+
+/************************************************************
+ * Intel is changing the EFI Spec. (after v1.02) to say that a
+ * disk is considered to have a GPT label only if the GPT
+ * structures are correct, and the MBR is actually a Protective
+ * MBR (has one 0xEE type partition).
+ * Problem occurs when a GPT-partitioned disk is then
+ * edited with a legacy (non-GPT-aware) application, such as
+ * fdisk (which doesn't generally erase the PGPT or AGPT).
+ * How should such a disk get handled? As a GPT disk (throwing
+ * away the fdisk changes), or as an MSDOS disk (throwing away
+ * the GPT information). Previously, I've taken the GPT-is-right,
+ * MBR is wrong, approach, to stay consistent with the EFI Spec.
+ * Intel disagrees, saying the disk should then be treated
+ * as having a msdos label, not a GPT label. If this is true,
+ * then what's the point of having an AGPT, since if the PGPT
+ * is screwed up, likely the PMBR is too, and the PMBR becomes
+ * a single point of failure.
+ * So, in the Linux kernel, I'm going to test for PMBR, and
+ * warn if it's not there, and treat the disk as MSDOS, with a note
+ * for users to use Parted to "fix up" their disk if they
+ * really want it to be considered GPT.
+ ************************************************************/
+static int
+gpt_read (PedDisk *disk)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ int i;
+#ifndef DISCOVER_ONLY
+ int write_back = 0;
+#endif
+
+ ped_disk_delete_all (disk);
+
+ /* motivation: let the user decide about the pmbr... during
+ ped_disk_probe(), they probably didn't get a choice... */
+ if (!gpt_probe (disk->dev))
+ goto error;
+
+ GuidPartitionTableHeader_t *gpt = NULL;
+ GuidPartitionTableHeader_t *primary_gpt;
+ GuidPartitionTableHeader_t *backup_gpt;
+ PedSector backup_sector_num;
+ int read_failure = gpt_read_headers (disk, &primary_gpt, &backup_gpt,
+ &backup_sector_num);
+ if (read_failure)
+ {
+ /* This includes the case in which there used to be a GPT partition
+ table here, with an alternate LBA that extended beyond the current
+ end-of-device. It's treated as a non-match. */
+
+ /* Another possibility:
+ The primary header is ok, but backup is corrupt.
+ In the UEFI spec, this means the primary GUID table
+ is officially invalid. */
+ pth_free (backup_gpt);
+ pth_free (primary_gpt);
+ return 0;
+ }
+
+ if (primary_gpt && backup_gpt)
+ {
+ /* Both are valid. */
+#ifndef DISCOVER_ONLY
+ /* The backup header must be at the end of the disk, or at what the primary
+ * header thinks is the end of the disk.
+ */
+ gpt_disk_data->AlternateLBA = PED_LE64_TO_CPU (primary_gpt->AlternateLBA);
+ PedSector pri_disk_end = _hdr_disk_end(disk, primary_gpt);
+
+ if (gpt_disk_data->AlternateLBA != disk->dev->length -1 &&
+ gpt_disk_data->AlternateLBA != pri_disk_end)
+ {
+ if (ped_exception_throw
+ (PED_EXCEPTION_ERROR,
+ (PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE),
+ _("The backup GPT table is not at the end of the disk, as it "
+ "should be. Fix, by moving the backup to the end "
+ "(and removing the old backup)?")) == PED_EXCEPTION_FIX)
+ {
+ ptt_clear_sectors (disk->dev,
+ PED_LE64_TO_CPU (primary_gpt->AlternateLBA), 1);
+ gpt_disk_data->AlternateLBA = disk->dev->length -1;
+ write_back = 1;
+ }
+ }
+#endif /* !DISCOVER_ONLY */
+ pth_free (backup_gpt);
+ gpt = primary_gpt;
+ }
+ else if (!primary_gpt && !backup_gpt)
+ {
+ /* Both are corrupt. */
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Both the primary and backup GPT tables "
+ "are corrupt. Try making a fresh table, "
+ "and using Parted's rescue feature to "
+ "recover partitions."));
+ goto error;
+ }
+ else if (primary_gpt && !backup_gpt)
+ {
+ /* The primary header is ok, but backup is corrupt. */
+ if (ped_exception_throw
+ (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
+ _("The backup GPT table is corrupt, but the "
+ "primary appears OK, so that will be used."))
+ == PED_EXCEPTION_CANCEL)
+ goto error_free_gpt;
+
+ gpt = primary_gpt;
+ }
+ else /* !primary_gpt && backup_gpt */
+ {
+ /* primary GPT corrupt, backup is ok. */
+ if (ped_exception_throw
+ (PED_EXCEPTION_ERROR, PED_EXCEPTION_OK_CANCEL,
+ _("The primary GPT table is corrupt, but the "
+ "backup appears OK, so that will be used."))
+ == PED_EXCEPTION_CANCEL)
+ goto error_free_gpt;
+
+ gpt = backup_gpt;
+ }
+ backup_gpt = NULL;
+ primary_gpt = NULL;
+
+ if (!_parse_header (disk, gpt, &write_back))
+ goto error_free_gpt;
+
+ size_t ptes_bytes;
+ void *ptes = gpt_read_PE_array (disk, gpt, &ptes_bytes);
+ if (ptes == NULL)
+ goto error_free_gpt;
+
+ uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
+ if (ptes_crc != PED_LE32_TO_CPU (gpt->PartitionEntryArrayCRC32))
+ {
+ ped_exception_throw
+ (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("primary partition table array CRC mismatch"));
+ goto error_free_ptes;
+ }
+
+ uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
+ for (i = 0; i < gpt_disk_data->entry_count; i++)
+ {
+ GuidPartitionEntry_t *pte
+ = (GuidPartitionEntry_t *) ((char *) ptes + i * p_ent_size);
+ PedPartition *part;
+
+ if (!guid_cmp (pte->PartitionTypeGuid, UNUSED_ENTRY_GUID))
+ continue;
+
+ part = _parse_part_entry (disk, pte);
+ if (!part)
+ goto error_delete_all;
+
+ part->fs_type = ped_file_system_probe (&part->geom);
+ part->num = i + 1;
+
+ PedConstraint *constraint_exact = ped_constraint_exact (&part->geom);
+ if (!ped_disk_add_partition (disk, part, constraint_exact))
+ {
+ ped_constraint_destroy (constraint_exact);
+ ped_partition_destroy (part);
+ goto error_delete_all;
+ }
+ ped_constraint_destroy (constraint_exact);
+ }
+ free (ptes);
+
+#ifndef DISCOVER_ONLY
+ if (write_back)
+ ped_disk_commit_to_dev (disk);
+#endif
+
+ pth_free (gpt);
+ return 1;
+
+error_delete_all:
+ ped_disk_delete_all (disk);
+error_free_ptes:
+ free (ptes);
+error_free_gpt:
+ pth_free (primary_gpt);
+ pth_free (backup_gpt);
+ pth_free (gpt);
+error:
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+/* Write the protective MBR (to keep DOS happy) */
+static int
+_write_pmbr (PedDevice *dev, bool pmbr_boot)
+{
+ /* The UEFI spec is not clear about what to do with the following
+ elements of the Protective MBR (pmbr): BootCode (0-440B),
+ UniqueMBRSignature (440B-444B) and Unknown (444B-446B).
+ With this in mind, we try not to modify these elements. */
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+ LegacyMBR_t *pmbr = s0;
+
+ /* Zero out the legacy partitions. */
+ memset (pmbr->PartitionRecord, 0, sizeof pmbr->PartitionRecord);
+
+ pmbr->Signature = PED_CPU_TO_LE16 (MSDOS_MBR_SIGNATURE);
+ pmbr->PartitionRecord[0].OSType = EFI_PMBR_OSTYPE_EFI;
+ pmbr->PartitionRecord[0].StartSector = 2;
+ pmbr->PartitionRecord[0].EndHead = 0xFF;
+ pmbr->PartitionRecord[0].EndSector = 0xFF;
+ pmbr->PartitionRecord[0].EndTrack = 0xFF;
+ pmbr->PartitionRecord[0].StartingLBA = PED_CPU_TO_LE32 (1);
+ if ((dev->length - 1ULL) > 0xFFFFFFFFULL)
+ pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (0xFFFFFFFF);
+ else
+ pmbr->PartitionRecord[0].SizeInLBA = PED_CPU_TO_LE32 (dev->length - 1UL);
+ if (pmbr_boot)
+ pmbr->PartitionRecord[0].BootIndicator = 0x80;
+
+ int write_ok = ped_device_write (dev, pmbr, GPT_PMBR_LBA,
+ GPT_PMBR_SECTORS);
+ free (s0);
+ return write_ok;
+}
+
+static int
+_generate_header (const PedDisk *disk, int alternate, uint32_t ptes_crc,
+ GuidPartitionTableHeader_t **gpt_p)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ GuidPartitionTableHeader_t *gpt;
+
+ *gpt_p = pth_new_zeroed (disk->dev);
+
+ gpt = *gpt_p;
+
+ gpt->Signature = PED_CPU_TO_LE64 (GPT_HEADER_SIGNATURE);
+ gpt->Revision = PED_CPU_TO_LE32 (GPT_HEADER_REVISION_V1_00);
+
+ /* per 1.00 spec */
+ gpt->HeaderSize = PED_CPU_TO_LE32 (pth_get_size_static (disk->dev));
+ gpt->HeaderCRC32 = 0;
+ gpt->Reserved1 = 0;
+
+ if (alternate)
+ {
+ size_t ss = disk->dev->sector_size;
+ PedSector ptes_bytes = (gpt_disk_data->entry_count
+ * sizeof (GuidPartitionEntry_t));
+ PedSector ptes_sectors = (ptes_bytes + ss - 1) / ss;
+
+ gpt->MyLBA = PED_CPU_TO_LE64 (gpt_disk_data->AlternateLBA);
+ gpt->AlternateLBA = PED_CPU_TO_LE64 (1);
+ gpt->PartitionEntryLBA
+ = PED_CPU_TO_LE64 (gpt_disk_data->AlternateLBA - ptes_sectors);
+ }
+ else
+ {
+ gpt->MyLBA = PED_CPU_TO_LE64 (1);
+ gpt->AlternateLBA = PED_CPU_TO_LE64 (gpt_disk_data->AlternateLBA);
+ gpt->PartitionEntryLBA = PED_CPU_TO_LE64 (2);
+ }
+
+ gpt->FirstUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.start);
+ gpt->LastUsableLBA = PED_CPU_TO_LE64 (gpt_disk_data->data_area.end);
+ gpt->DiskGUID = gpt_disk_data->uuid;
+ gpt->NumberOfPartitionEntries
+ = PED_CPU_TO_LE32 (gpt_disk_data->entry_count);
+ gpt->SizeOfPartitionEntry = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
+ gpt->PartitionEntryArrayCRC32 = PED_CPU_TO_LE32 (ptes_crc);
+
+ uint32_t crc;
+ if (pth_crc32 (disk->dev, gpt, &crc) != 0)
+ return 1;
+
+ gpt->HeaderCRC32 = PED_CPU_TO_LE32 (crc);
+ return 0;
+}
+
+static void
+_partition_generate_part_entry (PedPartition *part, GuidPartitionEntry_t *pte)
+{
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+ unsigned int i;
+
+ PED_ASSERT (gpt_part_data != NULL);
+
+ pte->PartitionTypeGuid = gpt_part_data->type;
+ pte->UniquePartitionGuid = gpt_part_data->uuid;
+ pte->StartingLBA = PED_CPU_TO_LE64 (part->geom.start);
+ pte->EndingLBA = PED_CPU_TO_LE64 (part->geom.end);
+ pte->Attributes = gpt_part_data->attributes;
+
+ for (i = 0; i < 36; i++)
+ pte->PartitionName[i] = gpt_part_data->name[i];
+}
+
+static int
+gpt_write (const PedDisk *disk)
+{
+ GPTDiskData *gpt_disk_data;
+ uint32_t ptes_crc;
+ uint8_t *pth_raw;
+ GuidPartitionTableHeader_t *gpt;
+ PedPartition *part;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+
+ gpt_disk_data = disk->disk_specific;
+
+ size_t ptes_bytes = (gpt_disk_data->entry_count
+ * sizeof (GuidPartitionEntry_t));
+ size_t ss = disk->dev->sector_size;
+ PedSector ptes_sectors = (ptes_bytes + ss - 1) / ss;
+ /* Note that we allocate a little more than ptes_bytes,
+ when that number is not a multiple of sector size. */
+ GuidPartitionEntry_t *ptes = calloc (ptes_sectors, ss);
+ if (!ptes)
+ goto error;
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part))
+ {
+ if (part->type != 0)
+ continue;
+ _partition_generate_part_entry (part, &ptes[part->num - 1]);
+ }
+
+ ptes_crc = efi_crc32 (ptes, ptes_bytes);
+
+ /* Write protective MBR */
+ if (!_write_pmbr (disk->dev, gpt_disk_data->pmbr_boot))
+ goto error_free_ptes;
+
+ /* Write PTH and PTEs */
+ /* FIXME: Caution: this code is nearly identical to what's just below. */
+ if (_generate_header (disk, 0, ptes_crc, &gpt) != 0) {
+ pth_free(gpt);
+ goto error_free_ptes;
+ }
+ pth_raw = pth_get_raw (disk->dev, gpt);
+ pth_free (gpt);
+ if (pth_raw == NULL)
+ goto error_free_ptes;
+ int write_ok = ped_device_write (disk->dev, pth_raw, 1, 1);
+ free (pth_raw);
+ if (!write_ok)
+ goto error_free_ptes;
+ if (!ped_device_write (disk->dev, ptes, 2, ptes_sectors))
+ goto error_free_ptes;
+
+ /* Write Alternate PTH & PTEs */
+ /* FIXME: Caution: this code is nearly identical to what's just above. */
+ if (_generate_header (disk, 1, ptes_crc, &gpt) != 0) {
+ pth_free(gpt);
+ goto error_free_ptes;
+ }
+ pth_raw = pth_get_raw (disk->dev, gpt);
+ pth_free (gpt);
+ if (pth_raw == NULL)
+ goto error_free_ptes;
+ write_ok = ped_device_write (disk->dev, pth_raw, gpt_disk_data->AlternateLBA, 1);
+ free (pth_raw);
+ if (!write_ok)
+ goto error_free_ptes;
+ if (!ped_device_write (disk->dev, ptes,
+ gpt_disk_data->AlternateLBA - ptes_sectors, ptes_sectors))
+ goto error_free_ptes;
+
+ free (ptes);
+ return ped_device_sync (disk->dev);
+
+error_free_ptes:
+ free (ptes);
+error:
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static int
+add_metadata_part (PedDisk *disk, PedSector start, PedSector length)
+{
+ PedPartition *part;
+ PedConstraint *constraint_exact;
+ PED_ASSERT (disk != NULL);
+
+ part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ start, start + length - 1);
+ if (!part)
+ goto error;
+
+ constraint_exact = ped_constraint_exact (&part->geom);
+ if (!ped_disk_add_partition (disk, part, constraint_exact))
+ goto error_destroy_constraint;
+ ped_constraint_destroy (constraint_exact);
+ return 1;
+
+error_destroy_constraint:
+ ped_constraint_destroy (constraint_exact);
+ ped_partition_destroy (part);
+error:
+ return 0;
+}
+
+static PedPartition *
+gpt_partition_new (const PedDisk *disk,
+ PedPartitionType part_type,
+ const PedFileSystemType *fs_type, PedSector start,
+ PedSector end)
+{
+ PedPartition *part;
+ GPTPartitionData *gpt_part_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (part_type != 0)
+ return part;
+
+ gpt_part_data = part->disk_specific =
+ ped_malloc (sizeof (GPTPartitionData));
+ if (!gpt_part_data)
+ goto error_free_part;
+
+ gpt_part_data->type = PARTITION_LINUX_DATA_GUID;
+ gpt_part_data->translated_name = 0;
+ uuid_generate ((unsigned char *) &gpt_part_data->uuid);
+ swap_uuid_and_efi_guid (&gpt_part_data->uuid);
+ memset (gpt_part_data->name, 0, sizeof gpt_part_data->name);
+ memset (&gpt_part_data->attributes, 0, sizeof gpt_part_data->attributes);
+ return part;
+
+error_free_part:
+ _ped_partition_free (part);
+error:
+ return NULL;
+}
+
+static PedPartition *
+gpt_partition_duplicate (const PedPartition *part)
+{
+ PedPartition *result;
+ GPTPartitionData *part_data = part->disk_specific;
+ GPTPartitionData *result_data;
+
+ result = _ped_partition_alloc (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (!result)
+ goto error;
+ result->num = part->num;
+
+ if (result->type != 0)
+ return result;
+
+ result_data = result->disk_specific =
+ ped_malloc (sizeof (GPTPartitionData));
+ if (!result_data)
+ goto error_free_part;
+
+ *result_data = *part_data;
+ if (part_data->translated_name) {
+ result_data->translated_name = xstrdup (part_data->translated_name);
+ } else {
+ result_data->translated_name = 0;
+ }
+ return result;
+
+error_free_part:
+ _ped_partition_free (result);
+error:
+ return NULL;
+}
+
+static void
+gpt_partition_destroy (PedPartition *part)
+{
+ if (part->type == 0)
+ {
+ PED_ASSERT (part->disk_specific != NULL);
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+ free (gpt_part_data->translated_name);
+ free (part->disk_specific);
+ }
+
+ _ped_partition_free (part);
+}
+
+/* is_skip_guid checks the guid against the list of guids that should not be
+ * overridden by set_system. It returns a 1 if it is in the list.
+*/
+static bool
+is_skip_guid(efi_guid_t guid) {
+ int n = sizeof(skip_set_system_guids) / sizeof(skip_set_system_guids[0]);
+ for (int i = 0; i < n; ++i) {
+ if (guid_cmp(guid, skip_set_system_guids[i]) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int
+gpt_partition_set_system (PedPartition *part,
+ const PedFileSystemType *fs_type)
+{
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ PED_ASSERT (gpt_part_data != NULL);
+
+ part->fs_type = fs_type;
+
+ // Is this a GUID that should skip fs_type checking?
+ if (is_skip_guid(gpt_part_data->type)) {
+ return 1;
+ }
+
+ if (fs_type)
+ {
+ if (strncmp (fs_type->name, "fat", 3) == 0
+ || strcmp (fs_type->name, "udf") == 0
+ || strcmp (fs_type->name, "ntfs") == 0)
+ {
+ gpt_part_data->type = PARTITION_BASIC_DATA_GUID;
+ return 1;
+ }
+ if (strncmp (fs_type->name, "hfs", 3) == 0)
+ {
+ gpt_part_data->type = PARTITION_APPLE_HFS_GUID;
+ return 1;
+ }
+ if (strstr (fs_type->name, "swap"))
+ {
+ gpt_part_data->type = PARTITION_SWAP_GUID;
+ return 1;
+ }
+ }
+
+ gpt_part_data->type = PARTITION_LINUX_DATA_GUID;
+ return 1;
+}
+
+/* Allocate metadata partitions for the GPTH and PTES */
+static int
+gpt_alloc_metadata (PedDisk *disk)
+{
+ PedSector gptlength, pteslength = 0;
+ GPTDiskData *gpt_disk_data;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ gpt_disk_data = disk->disk_specific;
+
+ gptlength = ped_div_round_up (sizeof (GuidPartitionTableHeader_t),
+ disk->dev->sector_size);
+ pteslength = ped_div_round_up (gpt_disk_data->entry_count
+ * sizeof (GuidPartitionEntry_t),
+ disk->dev->sector_size);
+
+ /* metadata at the start of the disk includes the MBR */
+ if (!add_metadata_part (disk, GPT_PMBR_LBA,
+ GPT_PMBR_SECTORS + gptlength + pteslength))
+ return 0;
+
+ /* metadata at the end of the disk */
+ if (!add_metadata_part (disk, disk->dev->length - gptlength - pteslength,
+ gptlength + pteslength))
+ return 0;
+
+ return 1;
+}
+
+/* Does nothing, as the read/new/destroy functions maintain part->num */
+static int
+gpt_partition_enumerate (PedPartition *part)
+{
+ GPTDiskData *gpt_disk_data = part->disk->disk_specific;
+ int i;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+
+ for (i = 1; i <= gpt_disk_data->entry_count; i++)
+ {
+ if (!ped_disk_get_partition (part->disk, i))
+ {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ PED_ASSERT (0);
+
+ return 0; /* used if debug is disabled */
+}
+
+static int
+gpt_disk_set_flag (PedDisk *disk, PedDiskFlag flag, int state)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ switch (flag)
+ {
+ case PED_DISK_GPT_PMBR_BOOT:
+ gpt_disk_data->pmbr_boot = state;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+gpt_disk_is_flag_available(const PedDisk *disk, PedDiskFlag flag)
+{
+ switch (flag)
+ {
+ case PED_DISK_GPT_PMBR_BOOT:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static uint8_t*
+gpt_disk_get_uuid (const PedDisk *disk)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+
+ efi_guid_t uuid = gpt_disk_data->uuid;
+
+ /* uuid is always LE, while uint8_t is always kind of BE */
+
+ uuid.time_low = PED_SWAP32(uuid.time_low);
+ uuid.time_mid = PED_SWAP16(uuid.time_mid);
+ uuid.time_hi_and_version = PED_SWAP16(uuid.time_hi_and_version);
+
+ uint8_t *buf = ped_malloc(sizeof (uuid_t));
+ memcpy(buf, &uuid, sizeof (uuid_t));
+ return buf;
+}
+
+static int
+gpt_disk_get_flag (const PedDisk *disk, PedDiskFlag flag)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+ switch (flag)
+ {
+ case PED_DISK_GPT_PMBR_BOOT:
+ return gpt_disk_data->pmbr_boot;
+ break;
+ default:
+ return 0;
+ }
+}
+
+static int
+gpt_partition_set_flag (PedPartition *part, PedPartitionFlag flag, int state)
+{
+ GPTPartitionData *gpt_part_data;
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ gpt_part_data = part->disk_specific;
+
+ const struct flag_uuid_mapping_t* p = gpt_find_flag_uuid_mapping (flag);
+ if (p)
+ {
+ if (state) {
+ gpt_part_data->type = p->type_uuid;
+ } else if (guid_cmp (gpt_part_data->type, p->type_uuid) == 0) {
+ // Clear the GUID so that fs_type will be used to return it to the default
+ gpt_part_data->type = PARTITION_LINUX_DATA_GUID;
+ return gpt_partition_set_system (part, part->fs_type);
+ }
+ return 1;
+ }
+
+ switch (flag)
+ {
+ case PED_PARTITION_HIDDEN:
+ gpt_part_data->attributes.RequiredToFunction = state;
+ return 1;
+ case PED_PARTITION_LEGACY_BOOT:
+ gpt_part_data->attributes.LegacyBIOSBootable = state;
+ return 1;
+ case PED_PARTITION_NO_AUTOMOUNT:
+ gpt_part_data->attributes.NoAutomount = state;
+ return 1;
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_LBA:
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+gpt_partition_get_flag (const PedPartition *part, PedPartitionFlag flag)
+{
+ GPTPartitionData *gpt_part_data;
+ PED_ASSERT (part->disk_specific != NULL);
+ gpt_part_data = part->disk_specific;
+
+ const struct flag_uuid_mapping_t* p = gpt_find_flag_uuid_mapping (flag);
+ if (p)
+ return guid_cmp (gpt_part_data->type, p->type_uuid) == 0;
+
+ switch (flag)
+ {
+ case PED_PARTITION_HIDDEN:
+ return gpt_part_data->attributes.RequiredToFunction;
+ case PED_PARTITION_LEGACY_BOOT:
+ return gpt_part_data->attributes.LegacyBIOSBootable;
+ case PED_PARTITION_NO_AUTOMOUNT:
+ return gpt_part_data->attributes.NoAutomount;
+ case PED_PARTITION_LBA:
+ case PED_PARTITION_ROOT:
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static int
+gpt_partition_is_flag_available (const PedPartition *part,
+ PedPartitionFlag flag)
+{
+ if (gpt_find_flag_uuid_mapping (flag))
+ return 1;
+
+ switch (flag)
+ {
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_LEGACY_BOOT:
+ case PED_PARTITION_NO_AUTOMOUNT:
+ return 1;
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_LBA:
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+static void
+gpt_partition_set_name (PedPartition *part, const char *name)
+{
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ free(gpt_part_data->translated_name);
+ gpt_part_data->translated_name = xstrdup(name);
+ iconv_t conv = iconv_open ("UCS-2LE", nl_langinfo (CODESET));
+ if (conv == (iconv_t)-1)
+ goto err;
+ char *inbuff = gpt_part_data->translated_name;
+ char *outbuff = (char *)&gpt_part_data->name;
+ size_t inbuffsize = strlen (inbuff) + 1;
+ size_t outbuffsize = 72;
+ if (iconv (conv, &inbuff, &inbuffsize, &outbuff, &outbuffsize) == -1)
+ goto err;
+ iconv_close (conv);
+ return;
+ err:
+ ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("failed to translate partition name"));
+ iconv_close (conv);
+}
+
+static const char *
+gpt_partition_get_name (const PedPartition *part)
+{
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+ if (gpt_part_data->translated_name == NULL)
+ {
+ char buffer[200];
+ iconv_t conv = iconv_open (nl_langinfo (CODESET), "UCS-2LE");
+ if (conv == (iconv_t)-1)
+ goto err;
+ char *inbuff = (char *)&gpt_part_data->name;
+ char *outbuff = buffer;
+ size_t inbuffsize = 72;
+ size_t outbuffsize = sizeof(buffer);
+ if (iconv (conv, &inbuff, &inbuffsize, &outbuff, &outbuffsize) == -1)
+ goto err;
+ iconv_close (conv);
+ *outbuff = 0;
+ gpt_part_data->translated_name = xstrdup (buffer);
+ return gpt_part_data->translated_name;
+ err:
+ ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("failed to translate partition name"));
+ iconv_close (conv);
+ return "";
+ }
+ return gpt_part_data->translated_name;
+}
+
+
+static int
+gpt_partition_set_type_uuid (PedPartition *part, const uint8_t *uuid)
+{
+ GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ efi_guid_t* type_uuid = &gpt_part_data->type;
+ memcpy(type_uuid, uuid, sizeof (efi_guid_t));
+
+ /* type_uuid is always LE, while uint8_t is always kind of BE */
+
+ type_uuid->time_low = PED_SWAP32(type_uuid->time_low);
+ type_uuid->time_mid = PED_SWAP16(type_uuid->time_mid);
+ type_uuid->time_hi_and_version = PED_SWAP16(type_uuid->time_hi_and_version);
+
+ return 1;
+}
+
+
+static uint8_t*
+gpt_partition_get_type_uuid (const PedPartition *part)
+{
+ const GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ efi_guid_t type_uuid = gpt_part_data->type;
+
+ /* type_uuid is always LE, while uint8_t is always kind of BE */
+
+ type_uuid.time_low = PED_SWAP32(type_uuid.time_low);
+ type_uuid.time_mid = PED_SWAP16(type_uuid.time_mid);
+ type_uuid.time_hi_and_version = PED_SWAP16(type_uuid.time_hi_and_version);
+
+ uint8_t *buf = ped_malloc(sizeof (uuid_t));
+ memcpy(buf, &type_uuid, sizeof (uuid_t));
+ return buf;
+}
+
+static uint8_t*
+gpt_partition_get_uuid (const PedPartition *part)
+{
+ const GPTPartitionData *gpt_part_data = part->disk_specific;
+
+ efi_guid_t uuid = gpt_part_data->uuid;
+
+ /* uuid is always LE, while uint8_t is always kind of BE */
+
+ uuid.time_low = PED_SWAP32(uuid.time_low);
+ uuid.time_mid = PED_SWAP16(uuid.time_mid);
+ uuid.time_hi_and_version = PED_SWAP16(uuid.time_hi_and_version);
+
+ uint8_t *buf = ped_malloc(sizeof (uuid_t));
+ memcpy(buf, &uuid, sizeof (uuid_t));
+ return buf;
+}
+
+static int
+gpt_get_max_primary_partition_count (const PedDisk *disk)
+{
+ const GPTDiskData *gpt_disk_data = disk->disk_specific;
+ return gpt_disk_data->entry_count;
+}
+
+/*
+ * From (http://developer.apple.com/technotes/tn2006/tn2166.html Chapter 5).
+ * According to the specs the first LBA (LBA0) is not relevant (it exists
+ * to maintain compatibility). on the second LBA(LBA1) gpt places the
+ * header. The header is as big as the block size. After the header we
+ * find the Entry array. Each element of said array, describes each
+ * partition. One can have as much elements as can fit between the end of
+ * the second LBA (where the header ends) and the FirstUsableLBA.
+ * FirstUsableLBA is the first logical block that is used for contents
+ * and is defined in header.
+ *
+ * /---------------------------------------------------\
+ * | BLOCK0 | HEADER | Entry Array | First Usable LBA |
+ * | | BLOCK1 | | |
+ * \---------------------------------------------------/
+ * / \
+ * /----------/ \----------\
+ * /-----------------------------------------\
+ * | E1 | E2 | E3 |...............| EN |
+ * \-----------------------------------------/
+ *
+ * The number of possible partitions or supported partitions is:
+ * SP = FirstUsableLBA*Blocksize - 2*Blocksize / SizeOfPartitionEntry
+ * SP = Blocksize(FirstusableLBA - 2) / SizeOfPartitoinEntry
+ */
+static bool
+gpt_get_max_supported_partition_count (const PedDisk *disk, int *max_n)
+{
+ GuidPartitionTableHeader_t *pth = NULL;
+ uint8_t *pth_raw = ped_malloc (pth_get_size (disk->dev));
+
+ if (ped_device_read (disk->dev, pth_raw, 1, GPT_HEADER_SECTORS)
+ || ped_device_read (disk->dev, pth_raw,
+ disk->dev->length, GPT_HEADER_SECTORS))
+ pth = pth_new_from_raw (disk->dev, pth_raw);
+ free (pth_raw);
+
+ if (pth == NULL)
+ return false;
+
+ if (!_header_is_valid (disk, pth, 1))
+ {
+ pth->FirstUsableLBA = PED_CPU_TO_LE64 (34);
+ pth->SizeOfPartitionEntry
+ = PED_CPU_TO_LE32 (sizeof (GuidPartitionEntry_t));
+ }
+
+ *max_n = (disk->dev->sector_size * (PED_LE64_TO_CPU (pth->FirstUsableLBA) - 2)
+ / PED_LE32_TO_CPU (pth->SizeOfPartitionEntry));
+ pth_free (pth);
+ return true;
+}
+
+static PedConstraint *
+_non_metadata_constraint (const PedDisk *disk)
+{
+ GPTDiskData *gpt_disk_data = disk->disk_specific;
+
+ return ped_constraint_new_from_max (&gpt_disk_data->data_area);
+}
+
+static int
+gpt_partition_align (PedPartition *part, const PedConstraint *constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ if (_ped_partition_attempt_align (part, constraint,
+ _non_metadata_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (gpt)
+
+static PedDiskOps gpt_disk_ops =
+{
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (gpt_write),
+
+ partition_set_name: gpt_partition_set_name,
+ partition_get_name: gpt_partition_get_name,
+ partition_set_type_id: NULL,
+ partition_get_type_id: NULL,
+ partition_set_type_uuid: gpt_partition_set_type_uuid,
+ partition_get_type_uuid: gpt_partition_get_type_uuid,
+ partition_get_uuid: gpt_partition_get_uuid,
+ disk_set_flag: gpt_disk_set_flag,
+ disk_get_flag: gpt_disk_get_flag,
+ disk_is_flag_available: gpt_disk_is_flag_available,
+ disk_get_uuid: gpt_disk_get_uuid,
+
+ PT_op_function_initializers (gpt)
+};
+
+static PedDiskType gpt_disk_type =
+{
+ next: NULL,
+ name: "gpt",
+ ops: &gpt_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME | PED_DISK_TYPE_PARTITION_TYPE_UUID |
+ PED_DISK_TYPE_DISK_UUID | PED_DISK_TYPE_PARTITION_UUID
+};
+
+void
+ped_disk_gpt_init ()
+{
+ ped_disk_type_register (&gpt_disk_type);
+}
+
+void
+ped_disk_gpt_done ()
+{
+ ped_disk_type_unregister (&gpt_disk_type);
+}
+
+verify (sizeof (GuidPartitionEntryAttributes_t) == 8);
+verify (sizeof (GuidPartitionEntry_t) == 128);
diff --git a/libparted/labels/loop.c b/libparted/labels/loop.c
new file mode 100644
index 0000000..45d169d
--- /dev/null
+++ b/libparted/labels/loop.c
@@ -0,0 +1,316 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 1999-2000, 2007-2014, 2019-2023 Free Software Foundation,
+ Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#define LOOP_SIGNATURE "GNU Parted Loopback 0"
+
+static PedDiskType loop_disk_type;
+
+static PedDisk* loop_alloc (const PedDevice* dev);
+static void loop_free (PedDisk* disk);
+
+static int
+loop_probe (const PedDevice* dev)
+{
+ PedDisk *disk = loop_alloc (dev);
+ if (!disk)
+ goto error;
+
+ void *buf;
+ if (!ptt_read_sector (dev, 0, &buf))
+ goto error_destroy_disk;
+ int found_sig = !strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE));
+ free (buf);
+
+ int result;
+ if (found_sig) {
+ result = 1;
+ } else {
+ PedGeometry* geom;
+
+ geom = ped_geometry_new (dev, 0, disk->dev->length);
+ if (!geom)
+ goto error_destroy_disk;
+ result = ped_file_system_probe (geom) != NULL;
+ ped_geometry_destroy (geom);
+ }
+ loop_free (disk);
+ return result;
+
+error_destroy_disk:
+ loop_free (disk);
+error:
+ return 0;
+}
+
+static PedDisk*
+loop_alloc (const PedDevice* dev)
+{
+ PED_ASSERT (dev != NULL);
+
+ if (dev->length < 256)
+ return NULL;
+ PedDisk *disk = _ped_disk_alloc ((PedDevice*)dev, &loop_disk_type);
+ PED_ASSERT (disk != NULL);
+ PedGeometry *geom = ped_geometry_new (dev, 0, dev->length);
+ PED_ASSERT (geom != NULL);
+ PedPartition *part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, geom->start, geom->end);
+ PED_ASSERT (part != NULL);
+ ped_geometry_destroy (geom);
+ PedConstraint *constraint_any = ped_constraint_any (dev);
+ if (!ped_disk_add_partition (disk, part, constraint_any))
+ goto error;
+ ped_constraint_destroy (constraint_any);
+ return disk;
+ error:
+ ped_constraint_destroy (constraint_any);
+ ped_disk_destroy (disk);
+ return NULL;
+}
+
+static PedDisk*
+loop_duplicate (const PedDisk* disk)
+{
+ return ped_disk_new_fresh (disk->dev, &loop_disk_type);
+}
+
+static void
+loop_free (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+
+ _ped_disk_free (disk);
+}
+
+static int
+loop_read (PedDisk* disk)
+{
+ PedDevice* dev = NULL;
+ PedGeometry* geom;
+ PedFileSystemType* fs_type;
+ PedPartition* part;
+ PedConstraint* constraint_any;
+
+ PED_ASSERT (disk != NULL);
+ dev = disk->dev;
+ constraint_any = ped_constraint_any (dev);
+
+ ped_disk_delete_all (disk);
+
+ void *buf;
+ if (!ptt_read_sector (dev, 0, &buf))
+ goto error;
+
+ int found_sig = !strncmp (buf, LOOP_SIGNATURE, strlen (LOOP_SIGNATURE));
+ free (buf);
+ geom = ped_geometry_new (dev, 0, dev->length);
+ if (!geom)
+ goto error;
+
+ fs_type = ped_file_system_probe (geom);
+ if (!fs_type && !found_sig)
+ goto error_free_geom;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ fs_type, geom->start, geom->end);
+ ped_geometry_destroy (geom);
+ if (!part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, part, constraint_any))
+ goto error;
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error_free_geom:
+ ped_geometry_destroy (geom);
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+static int
+loop_write (const PedDisk* disk)
+{
+ size_t buflen = disk->dev->sector_size;
+ char *buf = alloca (buflen);
+ PedPartition *part = ped_disk_get_partition (disk, 1);
+ /* if there is already a filesystem on the disk, we don't need to write the signature */
+ if (part && part->fs_type)
+ return 1;
+ if (!ped_device_read (disk->dev, buf, 0, 1))
+ return 0;
+ strcpy (buf, LOOP_SIGNATURE);
+
+ return ped_device_write (disk->dev, buf, 0, 1);
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+loop_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ return NULL;
+ part->disk_specific = NULL;
+ return part;
+}
+
+static PedPartition*
+loop_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* result;
+
+ result = ped_partition_new (part->disk, part->type, part->fs_type,
+ part->geom.start, part->geom.end);
+ if (result == NULL)
+ return NULL;
+ result->num = part->num;
+ return result;
+}
+
+static void
+loop_partition_destroy (PedPartition* part)
+{
+ free (part);
+}
+
+static int
+loop_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ part->fs_type = fs_type;
+ return 1;
+}
+
+static int
+loop_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ return 0;
+}
+
+static int
+loop_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ return 0;
+}
+
+static int
+loop_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PedGeometry* new_geom;
+
+ new_geom = ped_constraint_solve_nearest (constraint, &part->geom);
+ if (!new_geom) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the "
+ "partition."));
+ return 0;
+ }
+ ped_geometry_set (&part->geom, new_geom->start, new_geom->length);
+ ped_geometry_destroy (new_geom);
+ return 1;
+}
+
+static int
+loop_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ return 0;
+}
+
+static int
+loop_partition_enumerate (PedPartition* part)
+{
+ part->num = 1;
+ return 1;
+}
+
+static int
+loop_alloc_metadata (PedDisk* disk)
+{
+ return 1;
+}
+
+static int
+loop_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return 1;
+}
+
+static bool
+loop_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = 1;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (loop)
+
+static PedDiskOps loop_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (loop_write),
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (loop)
+};
+
+static PedDiskType loop_disk_type = {
+ next: NULL,
+ name: "loop",
+ ops: &loop_disk_ops,
+ features: 0
+};
+
+void
+ped_disk_loop_init ()
+{
+ ped_disk_type_register (&loop_disk_type);
+}
+
+void
+ped_disk_loop_done ()
+{
+ ped_disk_type_unregister (&loop_disk_type);
+}
diff --git a/libparted/labels/mac.c b/libparted/labels/mac.c
new file mode 100644
index 0000000..6711d87
--- /dev/null
+++ b/libparted/labels/mac.c
@@ -0,0 +1,1604 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 2002, 2004, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+
+/* struct's hacked from Linux source: fs/partitions/mac.h
+ * I believe it was originally written by Paul Mackerras (from comments in
+ * Quik source)
+ *
+ * See also:
+ * http://developer.apple.com/documentation/mac/Devices/Devices-126.html
+ * http://developer.apple.com/documentation/mac/Devices/Devices-121.html
+ * http://devworld.apple.com/technotes/tn/tn1189.html
+ *
+ * Partition types:
+ * Apple_Bootstrap new-world (HFS) boot partition
+ * Apple_partition_map partition map (table)
+ * Apple_Driver device driver
+ * Apple_Driver43 SCSI Manager 4.3 device driver
+ * Apple_MFS original Macintosh File System
+ * Apple_HFS Hierarchical File System (and +)
+ * Apple_HFSX HFS+ with case sensitivity and more
+ * Apple_UNIX_SVR2 UNIX file system (UFS?)
+ * Apple_PRODOS ProDOS file system
+ * Apple_Free unused space
+ * Apple_Scratch empty
+ * Apple_Void padding for iso9660
+ * Apple_Extra an unused partition map entry
+ *
+ * Quick explanation:
+ * ------------------
+ * Terminology:
+ *
+ * Parted Apple
+ * ------ -----
+ * device disk/device
+ * disk no equivalent.
+ * partition volume or partition
+ * sector block
+ *
+ * * All space must be accounted for, except block 0 (driver block) and
+ * block 1-X (the partition map: i.e. lots of MacRawPartitions)
+ *
+ * * It's really hard to grow/shrink the number of MacRawPartition
+ * entries in the partition map, because the first partition starts
+ * immediately after the partition map. When we can move the start of
+ * HFS and ext2 partitions, this problem will disappear ;-)
+ */
+
+#define MAC_PARTITION_MAGIC_1 0x5453 /* old */
+#define MAC_PARTITION_MAGIC_2 0x504d
+#define MAC_DISK_MAGIC 0x4552
+
+#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */
+
+typedef struct _MacRawPartition MacRawPartition;
+typedef struct _MacRawDisk MacRawDisk;
+typedef struct _MacDeviceDriver MacDeviceDriver;
+typedef struct _MacPartitionData MacPartitionData;
+typedef struct _MacDiskData MacDiskData;
+
+struct __attribute__ ((packed)) _MacRawPartition {
+ uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
+ uint16_t res1;
+ uint32_t map_count; /* # blocks in partition map */
+ uint32_t start_block; /* absolute starting block # of partition */
+ uint32_t block_count; /* number of blocks in partition */
+ char name[32]; /* partition name */
+ char type[32]; /* string type description */
+ uint32_t data_start; /* rel block # of first data block */
+ uint32_t data_count; /* number of data blocks */
+ uint32_t status; /* partition status bits */
+ uint32_t boot_start;
+ uint32_t boot_count;
+ uint32_t boot_load;
+ uint32_t boot_load2;
+ uint32_t boot_entry;
+ uint32_t boot_entry2;
+ uint32_t boot_cksum;
+ char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
+ uint32_t driver_sig;
+ char _padding[372];
+};
+
+/* Driver descriptor structure, in block 0 */
+struct __attribute__ ((packed)) _MacRawDisk {
+ uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
+ uint16_t block_size; /* physical sector size */
+ uint32_t block_count; /* size of device in blocks */
+ uint16_t dev_type; /* reserved */
+ uint16_t dev_id; /* reserved */
+ uint32_t data; /* reserved */
+ uint16_t driver_count; /* # of driver descriptor entries */
+ uint8_t driverlist[488];/* info about available drivers */
+ uint16_t padding[3]; /* pad to 512 bytes */
+};
+
+struct __attribute__ ((packed)) _MacDeviceDriver {
+ uint32_t block; /* startblock in MacRawDisk->block_size units */
+ uint16_t size; /* size in 512 byte units */
+ uint16_t type; /* operating system type (MacOS = 1) */
+};
+
+struct _MacPartitionData {
+ char volume_name[33]; /* eg: "Games" */
+ char system_name[33]; /* eg: "Apple_Unix_SVR2" */
+ char processor_name[17];
+
+ int is_boot;
+ int is_driver;
+ int has_driver;
+ int is_root;
+ int is_swap;
+ int is_lvm;
+ int is_raid;
+
+ PedSector data_region_length;
+ PedSector boot_region_length;
+
+ uint32_t boot_base_address;
+ uint32_t boot_entry_address;
+ uint32_t boot_checksum;
+
+ uint32_t status;
+ uint32_t driver_sig;
+};
+
+struct _MacDiskData {
+ int ghost_size; /* sectors per "driver" block */
+ int part_map_entry_count; /* # entries (incl. ghost) */
+ int part_map_entry_num; /* partition map location */
+
+ int active_part_entry_count; /* # real partitions */
+ int free_part_entry_count; /* # free space */
+ int last_part_entry_num; /* last entry number */
+
+ uint16_t block_size; /* physical sector size */
+ uint16_t driver_count;
+ MacDeviceDriver driverlist[1 + 60]; /* 488 bytes */
+};
+
+static PedDiskType mac_disk_type;
+
+static int
+_check_signature (MacRawDisk const *raw_disk)
+{
+ if (PED_BE16_TO_CPU (raw_disk->signature) != MAC_DISK_MAGIC) {
+#ifdef DISCOVER_ONLY
+ return 0;
+#else
+ return ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Invalid signature %x for Mac disk labels."),
+ (int) PED_BE16_TO_CPU (raw_disk->signature))
+ == PED_EXCEPTION_IGNORE;
+#endif
+ }
+
+ return 1;
+}
+
+static int
+_rawpart_check_signature (MacRawPartition* raw_part)
+{
+ int sig = (int) PED_BE16_TO_CPU (raw_part->signature);
+ return sig == MAC_PARTITION_MAGIC_1 || sig == MAC_PARTITION_MAGIC_2;
+}
+
+static int
+mac_probe (const PedDevice * dev)
+{
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size < sizeof (MacRawDisk))
+ return 0;
+
+ void *label;
+ if (!ptt_read_sector (dev, 0, &label))
+ return 0;
+
+ int valid = _check_signature (label);
+
+ free (label);
+ return valid;
+}
+
+static int
+_disk_add_part_map_entry (PedDisk* disk, int warn)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ PedPartition* new_part;
+ MacPartitionData* mac_part_data;
+ PedSector part_map_size;
+ PedConstraint* constraint_any = ped_constraint_any (disk->dev);
+
+#ifndef DISCOVER_ONLY
+ if (warn && ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
+ _("Partition map has no partition map entry!"))
+ != PED_EXCEPTION_FIX)
+ goto error;
+#endif /* !DISCOVER_ONLY */
+
+ part_map_size
+ = ped_round_up_to (mac_disk_data->last_part_entry_num, 64);
+ if (part_map_size == 0)
+ part_map_size = 64;
+
+ new_part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ 1, part_map_size - 1);
+ if (!new_part)
+ goto error;
+
+ mac_part_data = new_part->disk_specific;
+ strcpy (mac_part_data->volume_name, "Apple");
+ strcpy (mac_part_data->system_name, "Apple_partition_map");
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any))
+ goto error_destroy_new_part;
+
+ mac_disk_data->part_map_entry_num = new_part->num;
+ mac_disk_data->part_map_entry_count
+ = new_part->geom.end - mac_disk_data->ghost_size;
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error_destroy_new_part:
+ ped_partition_destroy (new_part);
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+static PedDisk*
+mac_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ MacDiskData* mac_disk_data;
+
+ PED_ASSERT (dev != NULL);
+
+#ifndef DISCOVER_ONLY
+ if (dev->length < 256) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s is too small for a Mac disk label!"),
+ dev->path);
+ goto error;
+ }
+#endif
+
+ disk = _ped_disk_alloc (dev, &mac_disk_type);
+ if (!disk)
+ goto error;
+
+ mac_disk_data = (MacDiskData*) ped_malloc (sizeof (MacDiskData));
+ if (!mac_disk_data)
+ goto error_free_disk;
+ disk->disk_specific = mac_disk_data;
+ mac_disk_data->ghost_size = 1;
+ mac_disk_data->active_part_entry_count = 0;
+ mac_disk_data->free_part_entry_count = 1;
+ mac_disk_data->last_part_entry_num = 1;
+ mac_disk_data->block_size = 0;
+ mac_disk_data->driver_count = 0;
+ memset(&mac_disk_data->driverlist[0], 0, sizeof(mac_disk_data->driverlist));
+
+ if (!_disk_add_part_map_entry (disk, 0))
+ goto error_free_disk;
+ return disk;
+
+error_free_disk:
+ _ped_disk_free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk*
+mac_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ MacDiskData* new_mac_data;
+ MacDiskData* old_mac_data = (MacDiskData*) disk->disk_specific;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &mac_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ new_mac_data = (MacDiskData*) new_disk->disk_specific;
+
+ /* remove the partition map partition - it will be duplicated
+ * later.
+ */
+ PedSector first_part_map_sector = old_mac_data->ghost_size;
+ PedPartition *partition_map
+ = ped_disk_get_partition_by_sector (new_disk, first_part_map_sector);
+ PED_ASSERT (partition_map != NULL);
+
+ /* ped_disk_remove_partition may be used only to delete a "normal"
+ partition. Trying to delete at least "freespace" or "metadata"
+ partitions leads to a violation of assumptions in
+ ped_disk_remove_partition, since it calls _disk_push_update_mode,
+ which destroys all "freespace" and "metadata" partitions, and
+ depends on that destruction not freeing its PART parameter. */
+ PED_ASSERT (partition_map->type == PED_PARTITION_NORMAL);
+ ped_disk_remove_partition (new_disk, partition_map);
+
+ /* ugly, but C is ugly :p */
+ memcpy (new_mac_data, old_mac_data, sizeof (MacDiskData));
+ return new_disk;
+}
+
+static void
+mac_free (PedDisk* disk)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+
+ _ped_disk_free (disk);
+ free (mac_disk_data);
+}
+
+static int
+_rawpart_cmp_type (const MacRawPartition* raw_part, const char* type)
+{
+ return strncasecmp (raw_part->type, type, 32) == 0;
+}
+
+static int
+_rawpart_cmp_name (const MacRawPartition* raw_part, const char* name)
+{
+ return strncasecmp (raw_part->name, name, 32) == 0;
+}
+
+static int
+_rawpart_is_partition_map (const MacRawPartition* raw_part)
+{
+ return _rawpart_cmp_type (raw_part, "Apple_partition_map");
+}
+
+static int
+strncasestr (const char* haystack, const char* needle, int n)
+{
+ int needle_size = strlen (needle);
+ int i;
+
+ for (i = 0; haystack[i] && i < n - needle_size; i++) {
+ if (strncasecmp (haystack + i, needle, needle_size) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+_rawpart_is_boot (const MacRawPartition* raw_part)
+{
+ if (!strcasecmp(raw_part->type, "Apple_Bootstrap"))
+ return 1;
+
+ if (!strcasecmp(raw_part->type, "Apple_Boot"))
+ return 1;
+
+ return 0;
+}
+
+static int
+_rawpart_is_driver (const MacRawPartition* raw_part)
+{
+ if (strncmp (raw_part->type, "Apple_", 6) != 0)
+ return 0;
+ if (!strncasestr (raw_part->type, "driver", 32))
+ return 0;
+ return 1;
+}
+
+static int _GL_ATTRIBUTE_PURE
+_rawpart_has_driver (const MacRawPartition* raw_part, MacDiskData* mac_disk_data)
+{
+ MacDeviceDriver *driverlist;
+ uint16_t i;
+ uint32_t start_block, block_count;
+
+ start_block = PED_BE32_TO_CPU(raw_part->start_block);
+ block_count = PED_BE32_TO_CPU(raw_part->block_count);
+ driverlist = &mac_disk_data->driverlist[0];
+ for (i = 0; i < mac_disk_data->driver_count; i++) {
+ if (start_block == PED_BE32_TO_CPU(driverlist->block) &&
+ block_count == PED_BE16_TO_CPU(driverlist->size))
+ return 1;
+ driverlist++;
+ }
+ return 0;
+}
+
+static int
+_rawpart_is_root (MacRawPartition* raw_part)
+{
+ if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
+ return 0;
+ if (strcmp (raw_part->name, "root") != 0)
+ return 0;
+ return 1;
+}
+
+static int
+_rawpart_is_swap (MacRawPartition* raw_part)
+{
+ if (!_rawpart_cmp_type (raw_part, "Apple_UNIX_SVR2"))
+ return 0;
+ if (strcmp (raw_part->name, "swap") != 0)
+ return 0;
+ return 1;
+}
+
+static int
+_rawpart_is_lvm (MacRawPartition* raw_part)
+{
+ if (strcmp (raw_part->type, "Linux_LVM") != 0)
+ return 0;
+ return 1;
+}
+
+static int
+_rawpart_is_raid (MacRawPartition* raw_part)
+{
+ if (strcmp (raw_part->type, "Linux_RAID") != 0)
+ return 0;
+ return 1;
+}
+
+static int
+_rawpart_is_void (MacRawPartition* raw_part)
+{
+ return _rawpart_cmp_type (raw_part, "Apple_Void");
+}
+
+/* returns 1 if the raw_part represents a partition that is "unused space", or
+ * doesn't represent a partition at all. NOTE: some people make Apple_Free
+ * partitions with MacOS, because they can't select another type. So, if the
+ * name is anything other than "Extra" or "", it is treated as a "real"
+ * partition.
+ */
+static int
+_rawpart_is_active (MacRawPartition* raw_part)
+{
+ if (_rawpart_cmp_type (raw_part, "Apple_Free")
+ && (_rawpart_cmp_name (raw_part, "Extra")
+ || _rawpart_cmp_name (raw_part, "")))
+ return 0;
+ if (_rawpart_cmp_type (raw_part, "Apple_Void"))
+ return 0;
+ if (_rawpart_cmp_type (raw_part, "Apple_Scratch"))
+ return 0;
+ if (_rawpart_cmp_type (raw_part, "Apple_Extra"))
+ return 0;
+
+ return 1;
+}
+
+static PedPartition*
+_rawpart_analyse (MacRawPartition* raw_part, PedDisk* disk, int num)
+{
+ MacDiskData* mac_disk_data;
+ PedPartition* part;
+ MacPartitionData* mac_part_data;
+ PedSector start, length;
+
+ if (!_rawpart_check_signature (raw_part)) {
+#ifndef DISCOVER_ONLY
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Partition %d has an invalid signature %x."),
+ num,
+ (int) PED_BE16_TO_CPU (raw_part->signature))
+ != PED_EXCEPTION_IGNORE)
+#endif
+ goto error;
+ }
+
+ mac_disk_data = (MacDiskData*) disk->disk_specific;
+
+ start = PED_BE32_TO_CPU (raw_part->start_block);
+ length = PED_BE32_TO_CPU (raw_part->block_count);
+ if (length == 0) {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Partition %d has an invalid length of 0 bytes!"),
+ num);
+#endif
+ return NULL;
+ }
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ start, start + length - 1);
+ if (!part)
+ goto error;
+
+ mac_part_data = part->disk_specific;
+
+ strncpy (mac_part_data->volume_name, raw_part->name, 32);
+ strncpy (mac_part_data->system_name, raw_part->type, 32);
+ strncpy (mac_part_data->processor_name, raw_part->processor, 16);
+
+ mac_part_data->is_boot = _rawpart_is_boot (raw_part);
+ mac_part_data->is_driver = _rawpart_is_driver (raw_part);
+ if (mac_part_data->is_driver)
+ mac_part_data->has_driver = _rawpart_has_driver(raw_part, mac_disk_data);
+ mac_part_data->is_root = _rawpart_is_root (raw_part);
+ mac_part_data->is_swap = _rawpart_is_swap (raw_part);
+ mac_part_data->is_lvm = _rawpart_is_lvm (raw_part);
+ mac_part_data->is_raid = _rawpart_is_raid (raw_part);
+
+ /* "data" region */
+#ifndef DISCOVER_ONLY
+ if (raw_part->data_start) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The data region doesn't start at the start "
+ "of the partition."));
+ goto error_destroy_part;
+ }
+#endif /* !DISCOVER_ONLY */
+ mac_part_data->data_region_length
+ = PED_BE32_TO_CPU (raw_part->data_count);
+
+ mac_part_data->boot_region_length
+ = PED_BE32_TO_CPU (raw_part->boot_count);
+
+#ifndef DISCOVER_ONLY
+ if (mac_part_data->has_driver) {
+ if (mac_part_data->boot_region_length < part->geom.length) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The partition's boot region doesn't occupy "
+ "the entire partition."))
+ != PED_EXCEPTION_IGNORE)
+ goto error_destroy_part;
+ }
+ } else {
+ if (mac_part_data->data_region_length < part->geom.length &&
+ !mac_part_data->is_boot) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The partition's data region doesn't occupy "
+ "the entire partition."))
+ != PED_EXCEPTION_IGNORE)
+ goto error_destroy_part;
+ }
+ }
+#endif /* !DISCOVER_ONLY */
+
+ mac_part_data->boot_base_address
+ = PED_BE32_TO_CPU (raw_part->boot_load);
+ mac_part_data->boot_entry_address
+ = PED_BE32_TO_CPU (raw_part->boot_entry);
+ mac_part_data->boot_checksum
+ = PED_BE32_TO_CPU (raw_part->boot_cksum);
+
+ mac_part_data->status = PED_BE32_TO_CPU (raw_part->status);
+ mac_part_data->driver_sig = PED_BE32_TO_CPU (raw_part->driver_sig);
+
+ return part;
+
+error_destroy_part:
+ ped_partition_destroy (part);
+error:
+ return NULL;
+}
+
+/* looks at the partition map size field in a mac raw partition, and calculates
+ * what the size of the partition map should be, from it
+ */
+static int
+_rawpart_get_partmap_size (MacRawPartition* raw_part, PedDisk* disk)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ PedSector part_map_start;
+ PedSector part_map_end;
+
+ part_map_start = mac_disk_data->ghost_size;
+ part_map_end = PED_BE32_TO_CPU (raw_part->map_count);
+
+ return part_map_end - part_map_start + 1;
+}
+
+static int
+_disk_analyse_block_size (PedDisk* disk, MacRawDisk* raw_disk)
+{
+ PedSector block_size;
+
+ if (PED_BE16_TO_CPU (raw_disk->block_size) % 512) {
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Weird block size on device descriptor: %d bytes is "
+ "not divisible by 512."),
+ (int) PED_BE16_TO_CPU (raw_disk->block_size));
+#endif
+ goto error;
+ }
+
+ block_size = PED_BE16_TO_CPU (raw_disk->block_size) / 512;
+ if (block_size != disk->dev->sector_size / 512) {
+#ifndef DISCOVER_ONLY
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The driver descriptor says the physical block size "
+ "is %d bytes, but Linux says it is %d bytes."),
+ (int) block_size * 512,
+ (int) disk->dev->sector_size)
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+#endif
+ disk->dev->sector_size = block_size * 512;
+ }
+
+ return 1;
+
+error:
+ return 0;
+}
+
+/* Tries to figure out the block size used by the drivers, for the ghost
+ * partitioning scheme. Ghost partitioning works like this: the OpenFirmware
+ * (OF) sees 512 byte blocks, but some drivers use 2048 byte blocks (and,
+ * perhaps, some other number?). To remain compatible, the partition map
+ * only has "real" partition map entries on ghost-aligned block numbers (and
+ * the others are padded with Apple_Void partitions). This function tries
+ * to figure out what the "ghost-aligned" size is... (which, believe-it-or-not,
+ * doesn't always equal 2048!!!)
+ */
+static int
+_disk_analyse_ghost_size (PedDisk* disk)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+
+ void *buf = ped_malloc (disk->dev->sector_size);
+ if (!buf)
+ return 0;
+
+ int i;
+ int found = 0;
+ for (i = 1; i < 64; i *= 2) {
+ if (!ped_device_read (disk->dev, buf, i, 1))
+ break;
+ if (_rawpart_check_signature (buf)
+ && !_rawpart_is_void (buf)) {
+ mac_disk_data->ghost_size = i;
+ found = (i <= disk->dev->sector_size / 512);
+ break;
+ }
+ }
+ free (buf);
+
+#ifndef DISCOVER_ONLY
+ if (!found)
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("No valid partition map found."));
+#endif
+ return found;
+}
+
+static int
+mac_read (PedDisk* disk)
+{
+ MacDiskData* mac_disk_data;
+ PedPartition* part;
+ int num;
+ PedSector ghost_size;
+ int last_part_entry_num = 0;
+
+ PED_ASSERT (disk != NULL);
+
+ mac_disk_data = disk->disk_specific;
+ mac_disk_data->part_map_entry_num = 0; /* 0 == none */
+
+ void *buf;
+ if (!ptt_read_sector (disk->dev, 0, &buf))
+ return 0;
+
+ MacRawDisk *raw_disk = buf;
+
+ if (!_check_signature (raw_disk))
+ goto error;
+
+ /* Record the original sector size; this function may change it. */
+ PedSector ss0 = disk->dev->sector_size;
+ if (!_disk_analyse_block_size (disk, raw_disk))
+ goto error;
+
+ if (!_disk_analyse_ghost_size (disk))
+ goto error;
+ ghost_size = mac_disk_data->ghost_size;
+
+ if (!ped_disk_delete_all (disk))
+ goto error;
+
+ if (PED_BE16_TO_CPU(raw_disk->driver_count) &&
+ PED_BE16_TO_CPU(raw_disk->driver_count) < 62) {
+ memcpy(&mac_disk_data->driverlist[0], &raw_disk->driverlist[0],
+ sizeof(mac_disk_data->driverlist));
+ mac_disk_data->driver_count = PED_BE16_TO_CPU(raw_disk->driver_count);
+ mac_disk_data->block_size = PED_BE16_TO_CPU(raw_disk->block_size);
+ }
+
+ /* If _disk_analyse_block_size has increased the sector_size,
+ reallocate this buffer, so we can still read a sector into it. */
+ if (ss0 < disk->dev->sector_size) {
+ free (buf);
+ buf = ped_malloc (disk->dev->sector_size);
+ if (buf == NULL)
+ goto error;
+ }
+
+ for (num=1; num==1 || num <= last_part_entry_num; num++) {
+ void *raw_part = buf;
+ if (!ped_device_read (disk->dev, raw_part,
+ num * ghost_size, 1))
+ goto error_delete_all;
+
+ if (!_rawpart_check_signature (raw_part))
+ continue;
+
+ if (num == 1)
+ last_part_entry_num
+ = _rawpart_get_partmap_size (raw_part, disk);
+ if (_rawpart_get_partmap_size (raw_part, disk)
+ != last_part_entry_num) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Conflicting partition map entry sizes! "
+ "Entry 1 says it is %d, but entry %d says "
+ "it is %d!"),
+ last_part_entry_num,
+ _rawpart_get_partmap_size (raw_part, disk))
+ != PED_EXCEPTION_IGNORE)
+ goto error_delete_all;
+ }
+
+ if (!_rawpart_is_active (raw_part))
+ continue;
+
+ part = _rawpart_analyse (raw_part, disk, num);
+ if (!part)
+ goto error_delete_all;
+ part->num = num;
+ part->fs_type = ped_file_system_probe (&part->geom);
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ if (constraint_exact == NULL)
+ goto error_delete_all;
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok)
+ goto error_delete_all;
+
+ if (_rawpart_is_partition_map (raw_part)) {
+ if (mac_disk_data->part_map_entry_num
+ && ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Weird! There are 2 partitions "
+ "map entries!"))
+ != PED_EXCEPTION_IGNORE)
+ goto error_delete_all;
+
+ mac_disk_data->part_map_entry_num = num;
+ mac_disk_data->part_map_entry_count
+ = part->geom.end - ghost_size + 1;
+ }
+ }
+
+ if (!mac_disk_data->part_map_entry_num) {
+ if (!_disk_add_part_map_entry (disk, 1))
+ goto error_delete_all;
+ ped_disk_commit_to_dev (disk);
+ }
+ free (buf);
+ return 1;
+
+error_delete_all:
+ ped_disk_delete_all (disk);
+error:
+ free (buf);
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+/* The Ghost partition: is a blank entry, used to pad out each block (where
+ * there physical block size > 512 bytes). This is because OpenFirmware uses
+ * 512 byte blocks, but device drivers Think Different TM, with a different
+ * lbock size, so we need to do this to avoid a clash (!)
+ */
+static int
+_pad_raw_part (PedDisk* disk, int num, MacRawPartition* part_map)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ int i;
+
+ size_t ss = disk->dev->sector_size;
+ void *buf = ped_calloc (ss);
+ if (!buf)
+ return 0;
+
+ MacRawPartition *ghost_entry = buf;
+ ghost_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
+ strcpy (ghost_entry->type, "Apple_Void");
+ ghost_entry->map_count
+ = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
+
+ for (i=0; i < mac_disk_data->ghost_size - 1; i++) {
+ PedSector idx = i + (num - 1) * mac_disk_data->ghost_size;
+ memcpy ((char*)part_map + idx * ss, ghost_entry, ss);
+ }
+
+ free (buf);
+ return 1;
+}
+
+static void
+_update_driver_count (MacRawPartition* part_map_entry,
+ MacDiskData *mac_driverdata, const MacDiskData* mac_disk_data)
+{
+ uint16_t i;
+ uint32_t start_block, block_count;
+
+ start_block = PED_BE32_TO_CPU(part_map_entry->start_block);
+ block_count = PED_BE32_TO_CPU(part_map_entry->block_count);
+
+ for (i = 0; i < mac_disk_data->driver_count; i++) {
+ if (start_block == PED_BE32_TO_CPU(mac_disk_data->driverlist[i].block) &&
+ block_count == PED_BE16_TO_CPU(mac_disk_data->driverlist[i].size)) {
+ uint16_t count_cur = mac_driverdata->driver_count;
+ mac_driverdata->driverlist[count_cur].block
+ = mac_disk_data->driverlist[i].block;
+ mac_driverdata->driverlist[count_cur].size
+ = mac_disk_data->driverlist[i].size;
+ mac_driverdata->driverlist[count_cur].type
+ = mac_disk_data->driverlist[i].type;
+ mac_driverdata->driver_count++;
+ break;
+ }
+ }
+}
+
+static MacRawPartition *
+get_pme (MacRawPartition const *part_map, PedSector i, PedDisk const *disk)
+{
+ MacDiskData const *mac_disk_data = disk->disk_specific;
+ PedSector idx = i * mac_disk_data->ghost_size - 1;
+ return (MacRawPartition *) ((char*)part_map
+ + idx * disk->dev->sector_size);
+}
+
+/* Initialize the disk->dev->sector_size bytes of part_map[part->num]. */
+static int
+_generate_raw_part (PedDisk* disk, PedPartition* part,
+ MacRawPartition* part_map, MacDiskData *mac_driverdata)
+{
+ MacDiskData* mac_disk_data;
+ MacPartitionData* mac_part_data;
+
+ PED_ASSERT (part->num > 0);
+
+ mac_disk_data = disk->disk_specific;
+ mac_part_data = part->disk_specific;
+
+ MacRawPartition *part_map_entry = get_pme (part_map, part->num, disk);
+ memset (part_map_entry, 0, disk->dev->sector_size);
+
+ part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
+ part_map_entry->map_count
+ = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
+ part_map_entry->start_block = PED_CPU_TO_BE32 (part->geom.start);
+ part_map_entry->block_count = PED_CPU_TO_BE32 (part->geom.length);
+ strncpy (part_map_entry->name, mac_part_data->volume_name, 31);
+ part_map_entry->name[31] = '\0';
+ strncpy (part_map_entry->type, mac_part_data->system_name, 31);
+ part_map_entry->type[31] = '\0';
+
+ if (mac_part_data->is_driver) {
+ if (mac_part_data->has_driver)
+ _update_driver_count(part_map_entry, mac_driverdata,
+ mac_disk_data);
+ } else
+ mac_part_data->data_region_length = part->geom.length;
+ part_map_entry->data_count = PED_CPU_TO_BE32 (
+ mac_part_data->data_region_length);
+ part_map_entry->boot_count = PED_CPU_TO_BE32 (
+ mac_part_data->boot_region_length);
+ part_map_entry->status = PED_CPU_TO_BE32 (mac_part_data->status);
+ part_map_entry->driver_sig
+ = PED_CPU_TO_BE32 (mac_part_data->driver_sig);
+
+ part_map_entry->boot_load =
+ PED_CPU_TO_BE32 (mac_part_data->boot_base_address);
+ part_map_entry->boot_entry =
+ PED_CPU_TO_BE32 (mac_part_data->boot_entry_address);
+ part_map_entry->boot_cksum =
+ PED_CPU_TO_BE32 (mac_part_data->boot_checksum);
+
+ strncpy (part_map_entry->processor, mac_part_data->processor_name, 15);
+ part_map_entry->processor[15] = '\0';
+
+ if (!_pad_raw_part (disk, part->num, part_map))
+ goto error;
+
+ return 1;
+
+error:
+ return 0;
+}
+
+static int
+_generate_raw_freespace_part (PedDisk* disk, PedGeometry* geom, int num,
+ MacRawPartition* part_map)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+
+ PED_ASSERT (num > 0);
+
+ MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
+
+ part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
+ part_map_entry->map_count
+ = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
+ part_map_entry->start_block = PED_CPU_TO_BE32 (geom->start);
+ part_map_entry->block_count = PED_CPU_TO_BE32 (geom->length);
+ strcpy (part_map_entry->name, "Extra");
+ strcpy (part_map_entry->type, "Apple_Free");
+
+ part_map_entry->data_count = PED_CPU_TO_BE32 (geom->length);
+ part_map_entry->status = 0;
+ part_map_entry->driver_sig = 0;
+
+ if (!_pad_raw_part (disk, num, part_map))
+ goto error;
+
+ return 1;
+
+error:
+ return 0;
+}
+
+static int
+_generate_empty_part (PedDisk* disk, int num, MacRawPartition* part_map)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+
+ PED_ASSERT (num > 0);
+
+ MacRawPartition *part_map_entry = get_pme (part_map, num, disk);
+ part_map_entry->signature = PED_CPU_TO_BE16 (MAC_PARTITION_MAGIC_2);
+ part_map_entry->map_count
+ = PED_CPU_TO_BE32 (mac_disk_data->last_part_entry_num);
+ strcpy (part_map_entry->type, "Apple_Void");
+
+ return _pad_raw_part (disk, num, part_map);
+}
+
+/* returns the first empty entry in the partition map */
+static int _GL_ATTRIBUTE_PURE
+_get_first_empty_part_entry (PedDisk* disk, MacRawPartition* part_map)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ int i;
+
+ for (i=1; i <= mac_disk_data->last_part_entry_num; i++) {
+ MacRawPartition *part_map_entry = get_pme (part_map, i, disk);
+ if (!part_map_entry->signature)
+ return i;
+ }
+
+ return 0;
+}
+
+static int
+write_block_zero (PedDisk* disk, MacDiskData* mac_driverdata)
+{
+ PedDevice* dev = disk->dev;
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+ MacRawDisk *raw_disk = (MacRawDisk *) s0;
+
+ raw_disk->signature = PED_CPU_TO_BE16 (MAC_DISK_MAGIC);
+ raw_disk->block_size = PED_CPU_TO_BE16 (dev->sector_size);
+ raw_disk->block_count = PED_CPU_TO_BE32 (dev->length);
+
+ raw_disk->driver_count = PED_CPU_TO_BE16(mac_driverdata->driver_count);
+ memcpy(&raw_disk->driverlist[0], &mac_driverdata->driverlist[0],
+ sizeof(raw_disk->driverlist));
+
+ int write_ok = ped_device_write (dev, raw_disk, 0, 1);
+ free (s0);
+ return write_ok;
+}
+
+static int
+mac_write (PedDisk* disk)
+{
+ MacRawPartition* part_map;
+ MacDiskData* mac_disk_data;
+ MacDiskData* mac_driverdata; /* updated driver list */
+ PedPartition* part;
+ int num;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (!disk->update_mode);
+
+ mac_disk_data = disk->disk_specific;
+
+ if (!ped_disk_get_partition (disk, mac_disk_data->part_map_entry_num)) {
+ if (!_disk_add_part_map_entry (disk, 1))
+ goto error;
+ }
+
+ mac_driverdata = ped_malloc(sizeof(MacDiskData));
+ if (!mac_driverdata)
+ goto error;
+ memset (mac_driverdata, 0, sizeof(MacDiskData));
+
+ size_t pmap_bytes = (mac_disk_data->part_map_entry_count
+ * mac_disk_data->ghost_size
+ * disk->dev->sector_size);
+ part_map = (MacRawPartition*) ped_calloc (pmap_bytes);
+ if (!part_map)
+ goto error_free_driverdata;
+
+/* write (to memory) the "real" partitions */
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part)) {
+ if (!ped_partition_is_active (part))
+ continue;
+ if (!_generate_raw_part (disk, part, part_map, mac_driverdata))
+ goto error_free_part_map;
+ }
+
+/* write the "free space" partitions */
+ for (part = ped_disk_next_partition (disk, NULL); part;
+ part = ped_disk_next_partition (disk, part)) {
+ if (part->type != PED_PARTITION_FREESPACE)
+ continue;
+ num = _get_first_empty_part_entry (disk, part_map);
+ if (!_generate_raw_freespace_part (disk, &part->geom, num,
+ part_map))
+ goto error_free_part_map;
+ }
+
+/* write the "void" (empty) partitions */
+ for (num = _get_first_empty_part_entry (disk, part_map); num;
+ num = _get_first_empty_part_entry (disk, part_map))
+ _generate_empty_part (disk, num, part_map);
+
+/* write to disk */
+ if (!ped_device_write (disk->dev, part_map, 1,
+ mac_disk_data->part_map_entry_count))
+ goto error_free_part_map;
+ free (part_map);
+ int write_ok = write_block_zero (disk, mac_driverdata);
+ free (mac_driverdata);
+ return write_ok;
+
+error_free_part_map:
+ free (part_map);
+error_free_driverdata:
+ free (mac_driverdata);
+error:
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+mac_partition_new (
+ const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type, PedSector start, PedSector end)
+{
+ PedPartition* part;
+ MacPartitionData* mac_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = mac_data = ped_malloc (sizeof (MacPartitionData));
+ if (!mac_data)
+ goto error_free_part;
+
+ memset (mac_data, 0, sizeof (MacPartitionData));
+ strcpy (mac_data->volume_name, "untitled");
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return NULL;
+}
+
+static PedPartition*
+mac_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ MacPartitionData* new_mac_data;
+ MacPartitionData* old_mac_data;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_mac_data = (MacPartitionData*) part->disk_specific;
+ new_mac_data = (MacPartitionData*) new_part->disk_specific;
+
+ /* ugly, but C is ugly :p */
+ memcpy (new_mac_data, old_mac_data, sizeof (MacPartitionData));
+ return new_part;
+}
+
+static void
+mac_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part))
+ free (part->disk_specific);
+ free (part);
+}
+
+static int
+mac_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ MacPartitionData* mac_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ if (fs_type && is_linux_swap (fs_type->name))
+ ped_partition_set_flag (part, PED_PARTITION_SWAP, 1);
+
+ if (mac_data->is_boot) {
+ strcpy (mac_data->system_name, "Apple_Bootstrap");
+ mac_data->status = 0x33;
+ return 1;
+ }
+
+ if (fs_type && (!strcmp (fs_type->name, "hfs")
+ || !strcmp (fs_type->name, "hfs+"))) {
+ strcpy (mac_data->system_name, "Apple_HFS");
+ mac_data->status |= 0x7f;
+ } else if (fs_type && !strcmp (fs_type->name, "hfsx")) {
+ strcpy (mac_data->system_name, "Apple_HFSX");
+ mac_data->status |= 0x7f;
+ } else {
+ strcpy (mac_data->system_name, "Apple_UNIX_SVR2");
+ mac_data->status = 0x33;
+ }
+
+ return 1;
+}
+
+static int
+mac_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ MacPartitionData* mac_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ mac_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ mac_data->is_boot = state;
+
+ if (part->fs_type)
+ return mac_partition_set_system (part, part->fs_type);
+
+ if (state) {
+ strcpy (mac_data->system_name, "Apple_Bootstrap");
+ mac_data->status = 0x33;
+ }
+ return 1;
+
+ case PED_PARTITION_ROOT:
+ if (state) {
+ strcpy (mac_data->volume_name, "root");
+ mac_data->is_swap = 0;
+ } else {
+ if (mac_data->is_root)
+ strcpy (mac_data->volume_name, "untitled");
+ }
+ mac_data->is_root = state;
+ return 1;
+
+ case PED_PARTITION_SWAP:
+ if (state) {
+ strcpy (mac_data->volume_name, "swap");
+ mac_data->is_root = 0;
+ } else {
+ if (mac_data->is_swap)
+ strcpy (mac_data->volume_name, "untitled");
+ }
+ mac_data->is_swap = state;
+ return 1;
+
+ case PED_PARTITION_LVM:
+ if (state) {
+ strcpy (mac_data->system_name, "Linux_LVM");
+ mac_data->is_lvm = state;
+ } else {
+ if (mac_data->is_lvm)
+ mac_partition_set_system (part, part->fs_type);
+ }
+ return 1;
+
+ case PED_PARTITION_RAID:
+ if (state) {
+ strcpy (mac_data->system_name, "Linux_RAID");
+ mac_data->is_raid = state;
+ } else {
+ if (mac_data->is_raid)
+ mac_partition_set_system (part, part->fs_type);
+ }
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static int _GL_ATTRIBUTE_PURE
+mac_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ MacPartitionData* mac_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ mac_data = part->disk_specific;
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ return mac_data->is_boot;
+
+ case PED_PARTITION_ROOT:
+ return mac_data->is_root;
+
+ case PED_PARTITION_SWAP:
+ return mac_data->is_swap;
+
+ case PED_PARTITION_LVM:
+ return mac_data->is_lvm;
+
+ case PED_PARTITION_RAID:
+ return mac_data->is_raid;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+mac_partition_is_flag_available (
+ const PedPartition* part, PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_SWAP:
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_RAID:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static void
+mac_partition_set_name (PedPartition* part, const char* name)
+{
+ MacPartitionData* mac_data;
+ int i;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ mac_data = part->disk_specific;
+
+#ifndef DISCOVER_ONLY
+ if (mac_data->is_root || mac_data->is_swap) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Changing the name of a root or swap partition "
+ "will prevent Linux from recognising it as such."))
+ != PED_EXCEPTION_IGNORE)
+ return;
+ mac_data->is_root = mac_data->is_swap = 0;
+ }
+#endif
+
+ strncpy (mac_data->volume_name, name, 32);
+ mac_data->volume_name [32] = 0;
+ for (i = strlen (mac_data->volume_name) - 1;
+ mac_data->volume_name[i] == ' '; i--)
+ mac_data->volume_name [i] = 0;
+}
+
+static const char* _GL_ATTRIBUTE_PURE
+mac_partition_get_name (const PedPartition* part)
+{
+ MacPartitionData* mac_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ mac_data = part->disk_specific;
+
+ return mac_data->volume_name;
+}
+
+static PedAlignment*
+mac_get_partition_alignment(const PedDisk *disk)
+{
+ return ped_alignment_new(0, 1);
+}
+
+static PedConstraint*
+_primary_constraint (PedDisk* disk)
+{
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+
+ if (!ped_alignment_init (&start_align, 0, 1))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, 1))
+ return NULL;
+ if (!ped_geometry_init (&max_geom, disk->dev, 1, disk->dev->length - 1))
+ return NULL;
+
+ return ped_constraint_new (&start_align, &end_align, &max_geom,
+ &max_geom, 1, disk->dev->length);
+}
+
+static int
+mac_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ if (_ped_partition_attempt_align (part, constraint,
+ _primary_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+mac_partition_enumerate (PedPartition* part)
+{
+ PedDisk* disk;
+ MacDiskData* mac_disk_data;
+ int i;
+ int max_part_count;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ disk = part->disk;
+ mac_disk_data = (MacDiskData*) disk->disk_specific;
+
+ max_part_count = ped_disk_get_max_primary_partition_count (disk);
+
+ if (part->num > 0 && part->num <= mac_disk_data->part_map_entry_count)
+ return 1;
+
+ for (i = 1; i <= max_part_count; i++) {
+ if (!ped_disk_get_partition (disk, i)) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Can't add another partition -- the partition map is too "
+ "small!"));
+#endif
+
+ return 0;
+}
+
+static int
+_disk_count_partitions (PedDisk* disk)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ PedPartition* part = NULL;
+ PedPartition* last = NULL;
+
+ PED_ASSERT (disk->update_mode);
+
+ mac_disk_data->active_part_entry_count = 0;
+ mac_disk_data->free_part_entry_count = 0;
+ mac_disk_data->last_part_entry_num = 0;
+
+ /* subtle: we only care about free space after the partition map.
+ * the partition map is an "active" partition, BTW... */
+ for (part = ped_disk_next_partition (disk, part); part;
+ part = ped_disk_next_partition (disk, part)) {
+ if (!ped_partition_is_active (part))
+ continue;
+
+ mac_disk_data->active_part_entry_count++;
+ if (last && last->geom.end + 1 < part->geom.start)
+ mac_disk_data->free_part_entry_count++;
+ mac_disk_data->last_part_entry_num
+ = PED_MAX (mac_disk_data->last_part_entry_num,
+ part->num);
+
+ last = part;
+ }
+
+ if (last && last->geom.end < disk->dev->length - 1)
+ mac_disk_data->free_part_entry_count++;
+
+ mac_disk_data->last_part_entry_num
+ = PED_MAX (mac_disk_data->last_part_entry_num,
+ mac_disk_data->active_part_entry_count
+ + mac_disk_data->free_part_entry_count);
+ return 1;
+}
+
+static int
+add_metadata_part (PedDisk* disk, PedSector start, PedSector end)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = ped_constraint_any (disk->dev);
+
+ PED_ASSERT (disk != NULL);
+
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ start, end);
+ if (!new_part)
+ goto error;
+ if (!ped_disk_add_partition (disk, new_part, constraint_any))
+ goto error_destroy_new_part;
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error_destroy_new_part:
+ ped_partition_destroy (new_part);
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+static int
+mac_alloc_metadata (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ if (!add_metadata_part (disk, 0, 0))
+ return 0;
+
+ /* hack: this seems to be a good place, to update the partition map
+ * entry count, since mac_alloc_metadata() gets called during
+ * _disk_pop_update_mode()
+ */
+ return _disk_count_partitions (disk);
+}
+
+static int
+mac_get_max_primary_partition_count (const PedDisk* disk)
+{
+ MacDiskData* mac_disk_data = disk->disk_specific;
+ PedPartition* part_map_partition;
+
+ part_map_partition = ped_disk_get_partition (disk,
+ mac_disk_data->part_map_entry_num);
+
+ /* HACK: if we haven't found the partition map partition (yet),
+ * we return this.
+ */
+ if (!part_map_partition) {
+ mac_disk_data->part_map_entry_num = 0;
+ return 65536;
+ }
+
+ /* HACK: since Mac labels need an entry for free-space regions, we
+ * must allow half plus 1 entries for free-space partitions. I hate
+ * this, but things get REALLY complicated, otherwise.
+ * (I'm prepared to complicate things later, but I want to get
+ * everything working, first)
+ */
+ return mac_disk_data->part_map_entry_count / mac_disk_data->ghost_size
+ - mac_disk_data->free_part_entry_count + 1;
+}
+
+static bool
+mac_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = 65536;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (mac)
+
+static PedDiskOps mac_disk_ops = {
+ clobber: NULL,
+ /* FIXME: remove this cast, once mac_write is fixed not to
+ modify its *DISK parameter. */
+ write: NULL_IF_DISCOVER_ONLY ((int (*) (const PedDisk*)) mac_write),
+
+ partition_set_name: mac_partition_set_name,
+ partition_get_name: mac_partition_get_name,
+
+ get_partition_alignment: mac_get_partition_alignment,
+
+ PT_op_function_initializers (mac)
+};
+
+static PedDiskType mac_disk_type = {
+ next: NULL,
+ name: "mac",
+ ops: &mac_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME
+};
+
+void
+ped_disk_mac_init ()
+{
+ PED_ASSERT (sizeof (MacRawPartition) == 512);
+ PED_ASSERT (sizeof (MacRawDisk) == 512);
+
+ ped_disk_type_register (&mac_disk_type);
+}
+
+void
+ped_disk_mac_done ()
+{
+ ped_disk_type_unregister (&mac_disk_type);
+}
diff --git a/libparted/labels/misc.h b/libparted/labels/misc.h
new file mode 100644
index 0000000..7c11388
--- /dev/null
+++ b/libparted/labels/misc.h
@@ -0,0 +1,48 @@
+/* -*- Mode: c; indent-tabs-mode: nil -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2007, 2009-2014, 2019-2023 Free Software Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <inttypes.h>
+#include <uuid/uuid.h>
+
+/* hack: use the ext2 uuid library to generate a reasonably random (hopefully
+ * with /dev/random) number. Unfortunately, we can only use 4 bytes of it.
+ * We make sure to avoid returning zero which may be interpreted as no FAT
+ * serial number or no MBR signature.
+ */
+static inline uint32_t
+generate_random_uint32 (void)
+{
+ union {
+ uuid_t uuid;
+ uint32_t i;
+ } uu32;
+
+ uuid_generate (uu32.uuid);
+
+ return uu32.i > 0 ? uu32.i : 0xffffffff;
+}
+
+/* Return nonzero if FS_TYPE_NAME starts with "linux-swap".
+ This must match the NUL-terminated "linux-swap" as well
+ as "linux-swap(v0)" and "linux-swap(v1)". */
+static inline int
+is_linux_swap (char const *fs_type_name)
+{
+ char const *prefix = "linux-swap";
+ return strncmp (fs_type_name, prefix, strlen (prefix)) == 0;
+}
diff --git a/libparted/labels/pc98.c b/libparted/labels/pc98.c
new file mode 100644
index 0000000..cfa3ba4
--- /dev/null
+++ b/libparted/labels/pc98.c
@@ -0,0 +1,813 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2007-2014, 2019-2023 Free Software Foundation,
+ Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+/* hacked from Linux/98 source: fs/partitions/nec98.h
+ *
+ * See also:
+ * http://people.FreeBSD.org/~kato/pc98.html
+ * http://www.kmc.kyoto-u.ac.jp/proj/linux98/index-english.html
+ *
+ * Partition types:
+ *
+ * id0(mid):
+ * bit 7: 1=bootable, 0=not bootable
+ * # Linux uses this flag to make a distinction between ext2 and swap.
+ * bit 6--0:
+ * 00H : N88-BASIC(data)?, PC-UX(data)?
+ * 04H : PC-UX(data)
+ * 06H : N88-BASIC
+ * 10H : N88-BASIC
+ * 14H : *BSD, PC-UX
+ * 20H : DOS(data), Windows95/98/NT, Linux
+ * 21H..2FH : DOS(system#1 .. system#15)
+ * 40H : Minix
+ *
+ * id1(sid):
+ * bit 7: 1=active, 0=sleep(hidden)
+ * # PC-UX uses this flag to make a distinction between its file system
+ * # and its swap.
+ * bit 6--0:
+ * 01H: FAT12
+ * 11H: FAT16, <32MB [accessible to DOS 3.3]
+ * 21H: FAT16, >=32MB [Large Partition]
+ * 31H: NTFS
+ * 28H: Windows NT (Volume/Stripe Set?)
+ * 41H: Windows NT (Volume/Stripe Set?)
+ * 48H: Windows NT (Volume/Stripe Set?)
+ * 61H: FAT32
+ * 04H: PC-UX
+ * 06H: N88-BASIC
+ * 44H: *BSD
+ * 62H: ext2, linux-swap
+ */
+
+#define MAX_PART_COUNT 16
+#define PC9800_EXTFMT_MAGIC 0xAA55
+
+#define BIT(x) (1 << (x))
+#define GET_BIT(n,bit) (((n) & BIT(bit)) != 0)
+#define SET_BIT(n,bit,val) n = (val)? (n | BIT(bit)) : (n & ~BIT(bit))
+
+typedef struct _PC98RawPartition PC98RawPartition;
+typedef struct _PC98RawTable PC98RawTable;
+
+/* ripped from Linux/98 source */
+struct _PC98RawPartition {
+ uint8_t mid; /* 0x80 - boot */
+ uint8_t sid; /* 0x80 - active */
+ uint8_t dum1; /* dummy for padding */
+ uint8_t dum2; /* dummy for padding */
+ uint8_t ipl_sect; /* IPL sector */
+ uint8_t ipl_head; /* IPL head */
+ uint16_t ipl_cyl; /* IPL cylinder */
+ uint8_t sector; /* starting sector */
+ uint8_t head; /* starting head */
+ uint16_t cyl; /* starting cylinder */
+ uint8_t end_sector; /* end sector */
+ uint8_t end_head; /* end head */
+ uint16_t end_cyl; /* end cylinder */
+ char name[16];
+} __attribute__((packed));
+
+struct _PC98RawTable {
+ uint8_t boot_code [510];
+ uint16_t magic;
+ PC98RawPartition partitions [MAX_PART_COUNT];
+} __attribute__((packed));
+
+typedef struct {
+ PedSector ipl_sector;
+ int system;
+ int boot;
+ int hidden;
+ char name [17];
+} PC98PartitionData;
+
+/* this MBR boot code is dummy */
+static const char MBR_BOOT_CODE[] = {
+ 0xcb, /* retf */
+ 0x00, 0x00, 0x00, /* */
+ 0x49, 0x50, 0x4c, 0x31 /* "IPL1" */
+};
+
+static PedDiskType pc98_disk_type;
+
+static PedSector chs_to_sector (const PedDevice* dev, int c, int h, int s);
+static void sector_to_chs (const PedDevice* dev, PedSector sector,
+ int* c, int* h, int* s);
+
+/* magic(?) check */
+static int
+pc98_check_magic (const PC98RawTable *part_table)
+{
+ /* check "extended-format" (have partition table?) */
+ if (PED_LE16_TO_CPU(part_table->magic) != PC9800_EXTFMT_MAGIC)
+ return 0;
+
+ return 1;
+}
+
+static int
+pc98_check_ipl_signature (const PC98RawTable *part_table)
+{
+ if (memcmp (part_table->boot_code + 4, "IPL1", 4) == 0)
+ return 1;
+ else if (memcmp (part_table->boot_code + 4, "Linux 98", 8) == 0)
+ return 1;
+ else if (memcmp (part_table->boot_code + 4, "GRUB/98 ", 8) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+static int
+pc98_probe (const PedDevice *dev)
+{
+ PC98RawTable part_table;
+
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size != 512)
+ return 0;
+
+ if (!ped_device_read (dev, &part_table, 0, 2))
+ return 0;
+
+ /* check magic */
+ if (!pc98_check_magic (&part_table))
+ return 0;
+
+ /* check for boot loader signatures */
+ return pc98_check_ipl_signature (&part_table);
+}
+
+static PedDisk*
+pc98_alloc (const PedDevice* dev)
+{
+ PED_ASSERT (dev != NULL);
+
+ return _ped_disk_alloc (dev, &pc98_disk_type);
+}
+
+static PedDisk*
+pc98_duplicate (const PedDisk* disk)
+{
+ return ped_disk_new_fresh (disk->dev, &pc98_disk_type);
+}
+
+static void
+pc98_free (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+
+ _ped_disk_free (disk);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+chs_to_sector (const PedDevice* dev, int c, int h, int s)
+{
+ PED_ASSERT (dev != NULL);
+ return (c * dev->hw_geom.heads + h) * dev->hw_geom.sectors + s;
+}
+
+static void
+sector_to_chs (const PedDevice* dev, PedSector sector, int* c, int* h, int* s)
+{
+ PedSector cyl_size;
+
+ PED_ASSERT (dev != NULL);
+ PED_ASSERT (c != NULL);
+ PED_ASSERT (h != NULL);
+ PED_ASSERT (s != NULL);
+
+ cyl_size = dev->hw_geom.heads * dev->hw_geom.sectors;
+
+ *c = sector / cyl_size;
+ *h = (sector) % cyl_size / dev->hw_geom.sectors;
+ *s = (sector) % cyl_size % dev->hw_geom.sectors;
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+legacy_start (const PedDisk* disk, const PC98RawPartition* raw_part)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ return chs_to_sector (disk->dev, PED_LE16_TO_CPU(raw_part->cyl),
+ raw_part->head, raw_part->sector);
+}
+
+static PedSector _GL_ATTRIBUTE_PURE
+legacy_end (const PedDisk* disk, const PC98RawPartition* raw_part)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (raw_part != NULL);
+
+ if (raw_part->end_head == 0 && raw_part->end_sector == 0) {
+ return chs_to_sector (disk->dev,
+ PED_LE16_TO_CPU(raw_part->end_cyl),
+ disk->dev->hw_geom.heads - 1,
+ disk->dev->hw_geom.sectors - 1);
+ } else {
+ return chs_to_sector (disk->dev,
+ PED_LE16_TO_CPU(raw_part->end_cyl),
+ raw_part->end_head,
+ raw_part->end_sector);
+ }
+}
+
+static int
+is_unused_partition(const PC98RawPartition* raw_part)
+{
+ if (raw_part->mid || raw_part->sid
+ || raw_part->ipl_sect
+ || raw_part->ipl_head
+ || PED_LE16_TO_CPU(raw_part->ipl_cyl)
+ || raw_part->sector
+ || raw_part->head
+ || PED_LE16_TO_CPU(raw_part->cyl)
+ || raw_part->end_sector
+ || raw_part->end_head
+ || PED_LE16_TO_CPU(raw_part->end_cyl))
+ return 0;
+ return 1;
+}
+
+static int
+read_table (PedDisk* disk)
+{
+ int i;
+ PC98RawTable table;
+ PedConstraint* constraint_any;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ if (!ped_device_read (disk->dev, (void*) &table, 0, 2))
+ goto error;
+
+ if (!pc98_check_magic(&table)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_IGNORE_CANCEL,
+ _("Invalid partition table on %s."),
+ disk->dev->path))
+ goto error;
+ }
+
+ for (i = 0; i < MAX_PART_COUNT; i++) {
+ PC98RawPartition* raw_part;
+ PedPartition* part;
+ PC98PartitionData* pc98_data;
+ PedSector part_start;
+ PedSector part_end;
+
+ raw_part = &table.partitions [i];
+
+ if (is_unused_partition(raw_part))
+ continue;
+
+ part_start = legacy_start (disk, raw_part);
+ part_end = legacy_end (disk, raw_part);
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, part_start, part_end);
+ if (!part)
+ goto error;
+ pc98_data = part->disk_specific;
+ PED_ASSERT (pc98_data != NULL);
+
+ pc98_data->system = (raw_part->mid << 8) | raw_part->sid;
+ pc98_data->boot = GET_BIT(raw_part->mid, 7);
+ pc98_data->hidden = !GET_BIT(raw_part->sid, 7);
+
+ ped_partition_set_name (part, raw_part->name);
+
+ pc98_data->ipl_sector = chs_to_sector (
+ disk->dev,
+ PED_LE16_TO_CPU(raw_part->ipl_cyl),
+ raw_part->ipl_head,
+ raw_part->ipl_sect);
+
+ /* hack */
+ if (pc98_data->ipl_sector == part->geom.start)
+ pc98_data->ipl_sector = 0;
+
+ part->num = i + 1;
+
+ if (!ped_disk_add_partition (disk, part, constraint_any))
+ goto error;
+
+ if (part->geom.start != part_start
+ || part->geom.end != part_end) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Partition %d isn't aligned to cylinder "
+ "boundaries. This is still unsupported."),
+ part->num);
+ goto error;
+ }
+
+ part->fs_type = ped_file_system_probe (&part->geom);
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error:
+ ped_disk_delete_all (disk);
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+static int
+pc98_read (PedDisk* disk)
+{
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ ped_disk_delete_all (disk);
+ return read_table (disk);
+}
+
+#ifndef DISCOVER_ONLY
+static int
+fill_raw_part (PC98RawPartition* raw_part, const PedPartition* part)
+{
+ PC98PartitionData* pc98_data;
+ int c, h, s;
+ const char* name;
+
+ PED_ASSERT (raw_part != NULL);
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ pc98_data = part->disk_specific;
+ raw_part->mid = (pc98_data->system >> 8) & 0xFF;
+ raw_part->sid = pc98_data->system & 0xFF;
+
+ SET_BIT(raw_part->mid, 7, pc98_data->boot);
+ SET_BIT(raw_part->sid, 7, !pc98_data->hidden);
+
+ memset (raw_part->name, ' ', sizeof(raw_part->name));
+ name = ped_partition_get_name (part);
+ PED_ASSERT (name != NULL);
+ PED_ASSERT (strlen (name) <= 16);
+ if (!strlen (name) && part->fs_type)
+ name = part->fs_type->name;
+ memcpy (raw_part->name, name, strlen (name));
+
+ sector_to_chs (part->disk->dev, part->geom.start, &c, &h, &s);
+ raw_part->cyl = PED_CPU_TO_LE16(c);
+ raw_part->head = h;
+ raw_part->sector = s;
+
+ if (pc98_data->ipl_sector) {
+ sector_to_chs (part->disk->dev, pc98_data->ipl_sector,
+ &c, &h, &s);
+ raw_part->ipl_cyl = PED_CPU_TO_LE16(c);
+ raw_part->ipl_head = h;
+ raw_part->ipl_sect = s;
+ } else {
+ raw_part->ipl_cyl = raw_part->cyl;
+ raw_part->ipl_head = raw_part->head;
+ raw_part->ipl_sect = raw_part->sector;
+ }
+
+ sector_to_chs (part->disk->dev, part->geom.end, &c, &h, &s);
+ if (h != part->disk->dev->hw_geom.heads - 1
+ || s != part->disk->dev->hw_geom.sectors - 1) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Partition %d isn't aligned to cylinder "
+ "boundaries. This is still unsupported."),
+ part->num);
+ return 0;
+ }
+ raw_part->end_cyl = PED_CPU_TO_LE16(c);
+ raw_part->end_head = 0;
+ raw_part->end_sector = 0;
+
+ return 1;
+}
+
+static int
+pc98_write (const PedDisk* disk)
+{
+ PedPartition* part;
+ int i;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ void *s0;
+ if (!ptt_read_sectors (disk->dev, 0, 2, &s0))
+ return 0;
+ PC98RawTable *table = s0;
+
+ if (!pc98_check_ipl_signature (table)) {
+ memset (table->boot_code, 0, sizeof(table->boot_code));
+ memcpy (table->boot_code, MBR_BOOT_CODE, sizeof(MBR_BOOT_CODE));
+ }
+
+ memset (table->partitions, 0, sizeof (table->partitions));
+ table->magic = PED_CPU_TO_LE16(PC9800_EXTFMT_MAGIC);
+
+ for (i = 1; i <= MAX_PART_COUNT; i++) {
+ part = ped_disk_get_partition (disk, i);
+ if (!part)
+ continue;
+
+ if (!fill_raw_part (&table->partitions [i - 1], part))
+ return 0;
+ }
+
+ int write_ok = ped_device_write (disk->dev, table, 0, 2);
+ free (s0);
+ if (!write_ok)
+ return 0;
+ return ped_device_sync (disk->dev);
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+pc98_partition_new (
+ const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type, PedSector start, PedSector end)
+{
+ PedPartition* part;
+ PC98PartitionData* pc98_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = pc98_data = ped_malloc (sizeof (PC98PartitionData));
+ if (!pc98_data)
+ goto error_free_part;
+ pc98_data->ipl_sector = 0;
+ pc98_data->hidden = 0;
+ pc98_data->boot = 0;
+ strcpy (pc98_data->name, "");
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return 0;
+}
+
+static PedPartition*
+pc98_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ PC98PartitionData* new_pc98_data;
+ PC98PartitionData* old_pc98_data;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_pc98_data = (PC98PartitionData*) part->disk_specific;
+ new_pc98_data = (PC98PartitionData*) new_part->disk_specific;
+
+ /* ugly, but C is ugly :p */
+ memcpy (new_pc98_data, old_pc98_data, sizeof (PC98PartitionData));
+ return new_part;
+}
+
+static void
+pc98_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part))
+ free (part->disk_specific);
+ free (part);
+}
+
+static int
+pc98_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ PC98PartitionData* pc98_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ pc98_data->system = 0x2062;
+ if (fs_type) {
+ if (!strcmp (fs_type->name, "fat16")) {
+ if (part->geom.length * 512 >= 32 * 1024 * 1024)
+ pc98_data->system = 0x2021;
+ else
+ pc98_data->system = 0x2011;
+ } else if (!strcmp (fs_type->name, "fat32")) {
+ pc98_data->system = 0x2061;
+ } else if (!strcmp (fs_type->name, "ntfs")) {
+ pc98_data->system = 0x2031;
+ } else if (!strncmp (fs_type->name, "ufs", 3)) {
+ pc98_data->system = 0x2044;
+ } else { /* ext2, reiser, xfs, etc. */
+ /* ext2 partitions must be marked boot */
+ pc98_data->boot = 1;
+ pc98_data->system = 0xa062;
+ }
+ }
+
+ if (pc98_data->boot)
+ pc98_data->system |= 0x8000;
+ if (!pc98_data->hidden)
+ pc98_data->system |= 0x0080;
+ return 1;
+}
+
+static int
+pc98_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ PC98PartitionData* pc98_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ pc98_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ pc98_data->hidden = state;
+ return ped_partition_set_system (part, part->fs_type);
+
+ case PED_PARTITION_BOOT:
+ pc98_data->boot = state;
+ return ped_partition_set_system (part, part->fs_type);
+
+ default:
+ return 0;
+ }
+}
+
+static int _GL_ATTRIBUTE_PURE
+pc98_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ PC98PartitionData* pc98_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ pc98_data = part->disk_specific;
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ return pc98_data->hidden;
+
+ case PED_PARTITION_BOOT:
+ return pc98_data->boot;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+pc98_partition_is_flag_available (
+ const PedPartition* part, PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_BOOT:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static void
+pc98_partition_set_name (PedPartition* part, const char* name)
+{
+ PC98PartitionData* pc98_data;
+ int i;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ pc98_data = part->disk_specific;
+
+ strncpy (pc98_data->name, name, 16);
+ pc98_data->name [16] = 0;
+ for (i = strlen (pc98_data->name) - 1; pc98_data->name[i] == ' '; i--)
+ pc98_data->name [i] = 0;
+}
+
+static const char* _GL_ATTRIBUTE_PURE
+pc98_partition_get_name (const PedPartition* part)
+{
+ PC98PartitionData* pc98_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ pc98_data = part->disk_specific;
+
+ return pc98_data->name;
+}
+
+static PedAlignment*
+pc98_get_partition_alignment(const PedDisk *disk)
+{
+ PedSector cylinder_size =
+ disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
+
+ return ped_alignment_new(0, cylinder_size);
+}
+
+static PedConstraint*
+_primary_constraint (PedDisk* disk)
+{
+ PedDevice* dev = disk->dev;
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+ PedSector cylinder_size;
+
+ cylinder_size = dev->hw_geom.sectors * dev->hw_geom.heads;
+
+ if (!ped_alignment_init (&start_align, 0, cylinder_size))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, cylinder_size))
+ return NULL;
+ if (!ped_geometry_init (&max_geom, dev, cylinder_size,
+ dev->length - cylinder_size))
+ return NULL;
+
+ return ped_constraint_new (&start_align, &end_align, &max_geom,
+ &max_geom, 1, dev->length);
+}
+
+static int
+pc98_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ if (_ped_partition_attempt_align (part, constraint,
+ _primary_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+next_primary (PedDisk* disk)
+{
+ int i;
+ for (i=1; i<=MAX_PART_COUNT; i++) {
+ if (!ped_disk_get_partition (disk, i))
+ return i;
+ }
+ return 0;
+}
+
+static int
+pc98_partition_enumerate (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ /* don't re-number a partition */
+ if (part->num != -1)
+ return 1;
+
+ PED_ASSERT (ped_partition_is_active (part));
+
+ part->num = next_primary (part->disk);
+ if (!part->num) {
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Can't add another partition."));
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+pc98_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+ PedSector cyl_size;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ cyl_size = disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ 0, cyl_size - 1);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+static int
+pc98_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return MAX_PART_COUNT;
+}
+
+static bool
+pc98_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = MAX_PART_COUNT;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (pc98)
+
+static PedDiskOps pc98_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (pc98_write),
+
+ partition_set_name: pc98_partition_set_name,
+ partition_get_name: pc98_partition_get_name,
+
+ get_partition_alignment: pc98_get_partition_alignment,
+
+ PT_op_function_initializers (pc98)
+};
+
+static PedDiskType pc98_disk_type = {
+ next: NULL,
+ name: "pc98",
+ ops: &pc98_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME
+};
+
+void
+ped_disk_pc98_init ()
+{
+ PED_ASSERT (sizeof (PC98RawTable) == 512 * 2);
+ ped_disk_type_register (&pc98_disk_type);
+}
+
+void
+ped_disk_pc98_done ()
+{
+ ped_disk_type_unregister (&pc98_disk_type);
+}
diff --git a/libparted/labels/pt-common.h b/libparted/labels/pt-common.h
new file mode 100644
index 0000000..76f06e3
--- /dev/null
+++ b/libparted/labels/pt-common.h
@@ -0,0 +1,55 @@
+/* Factor some of the duplication out of *.c. */
+
+#ifdef DISCOVER_ONLY
+# define NULL_IF_DISCOVER_ONLY(val) NULL
+#else
+# define NULL_IF_DISCOVER_ONLY(val) val
+#endif
+
+#define PT_define_limit_functions(PT_type) \
+ \
+static bool \
+PT_type##_partition_check (const PedPartition *part) \
+{ \
+ return ptt_partition_max_start_len (#PT_type, part); \
+} \
+ \
+static PedSector \
+PT_type##_partition_max_start_sector (void) \
+{ \
+ PedSector max; \
+ int err = ptt_partition_max_start_sector (#PT_type, &max); \
+ PED_ASSERT (err == 0); \
+ return max; \
+} \
+ \
+static PedSector \
+PT_type##_partition_max_length (void) \
+{ \
+ PedSector max; \
+ int err = ptt_partition_max_length (#PT_type, &max); \
+ PED_ASSERT (err == 0); \
+ return max; \
+}
+
+#define PT_op_function_initializers(PT_type) \
+probe: PT_type##_probe, \
+alloc: PT_type##_alloc, \
+duplicate: PT_type##_duplicate, \
+free: PT_type##_free, \
+read: PT_type##_read, \
+partition_new: PT_type##_partition_new, \
+partition_duplicate: PT_type##_partition_duplicate, \
+partition_set_flag: PT_type##_partition_set_flag, \
+partition_get_flag: PT_type##_partition_get_flag, \
+partition_set_system: PT_type##_partition_set_system, \
+partition_is_flag_available: PT_type##_partition_is_flag_available, \
+partition_align: PT_type##_partition_align, \
+partition_destroy: PT_type##_partition_destroy, \
+partition_enumerate: PT_type##_partition_enumerate, \
+alloc_metadata: PT_type##_alloc_metadata, \
+get_max_primary_partition_count: PT_type##_get_max_primary_partition_count, \
+get_max_supported_partition_count:PT_type##_get_max_supported_partition_count,\
+partition_check: PT_type##_partition_check, \
+max_length: PT_type##_partition_max_length, \
+max_start_sector: PT_type##_partition_max_start_sector
diff --git a/libparted/labels/pt-limit.c b/libparted/labels/pt-limit.c
new file mode 100644
index 0000000..f1c7a09
--- /dev/null
+++ b/libparted/labels/pt-limit.c
@@ -0,0 +1,161 @@
+/* ANSI-C code produced by gperf version 3.1 */
+/* Command-line: gperf -C -N pt_limit_lookup -n -t -s 6 -k '*' --language=ANSI-C pt-limit.gperf */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+ && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+ && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+ && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+ && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+ && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+ && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+ && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+ && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+ && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+ && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+ && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+ && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+ && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+ && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+ && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+ && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+ && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+ && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+ && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+ && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+ && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+ && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646. */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 1 "pt-limit.gperf"
+struct partition_limit
+{
+ char const *name;
+ uint64_t max_start_sector;
+ uint64_t max_length;
+};
+
+#define TOTAL_KEYWORDS 11
+#define MIN_WORD_LENGTH 3
+#define MAX_WORD_LENGTH 5
+#define MIN_HASH_VALUE 5
+#define MAX_HASH_VALUE 55
+/* maximum key range = 51, duplicates = 0 */
+
+#ifdef __GNUC__
+__inline
+#else
+#ifdef __cplusplus
+inline
+#endif
+#endif
+static unsigned int
+hash (register const char *str, register size_t len)
+{
+ static const unsigned char asso_values[] =
+ {
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 10, 5, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 5, 40, 40,
+ 5, 56, 56, 5, 20, 0, 56, 56, 15, 0,
+ 15, 10, 0, 56, 0, 5, 0, 10, 15, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56
+ };
+ register unsigned int hval = 0;
+
+ switch (len)
+ {
+ default:
+ hval += asso_values[(unsigned char)str[4]];
+ /*FALLTHROUGH*/
+ case 4:
+ hval += asso_values[(unsigned char)str[3]];
+ /*FALLTHROUGH*/
+ case 3:
+ hval += asso_values[(unsigned char)str[2]];
+ /*FALLTHROUGH*/
+ case 2:
+ hval += asso_values[(unsigned char)str[1]];
+ /*FALLTHROUGH*/
+ case 1:
+ hval += asso_values[(unsigned char)str[0]];
+ break;
+ }
+ return hval;
+}
+
+const struct partition_limit *
+pt_limit_lookup (register const char *str, register size_t len)
+{
+ static const struct partition_limit wordlist[] =
+ {
+ {""}, {""}, {""}, {""}, {""},
+#line 10 "pt-limit.gperf"
+ {"gpt",UINT64_MAX,UINT64_MAX},
+ {""}, {""}, {""}, {""},
+#line 28 "pt-limit.gperf"
+ {"atari",INT32_MAX,INT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 27 "pt-limit.gperf"
+ {"amiga",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 8 "pt-limit.gperf"
+ {"dasd",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 12 "pt-limit.gperf"
+ {"msdos",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 18 "pt-limit.gperf"
+ {"sun",128ULL*UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 23 "pt-limit.gperf"
+ {"loop",UINT64_MAX,UINT64_MAX},
+ {""}, {""}, {""}, {""},
+#line 9 "pt-limit.gperf"
+ {"dvh",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 11 "pt-limit.gperf"
+ {"mac",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 20 "pt-limit.gperf"
+ {"bsd",UINT32_MAX,UINT32_MAX},
+ {""}, {""}, {""}, {""},
+#line 24 "pt-limit.gperf"
+ {"pc98",UINT32_MAX,UINT32_MAX}
+ };
+
+ if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+ {
+ register unsigned int key = hash (str, len);
+
+ if (key <= MAX_HASH_VALUE)
+ {
+ register const char *s = wordlist[key].name;
+
+ if (*str == *s && !strcmp (str + 1, s + 1))
+ return &wordlist[key];
+ }
+ }
+ return 0;
+}
diff --git a/libparted/labels/pt-limit.gperf b/libparted/labels/pt-limit.gperf
new file mode 100644
index 0000000..d5a580d
--- /dev/null
+++ b/libparted/labels/pt-limit.gperf
@@ -0,0 +1,28 @@
+struct partition_limit
+{
+ char const *name;
+ uint64_t max_start_sector;
+ uint64_t max_length;
+};
+%%
+dasd,UINT32_MAX,UINT32_MAX
+dvh,UINT32_MAX,UINT32_MAX
+gpt,UINT64_MAX,UINT64_MAX
+mac,UINT32_MAX,UINT32_MAX
+msdos,UINT32_MAX,UINT32_MAX
+#
+# Sun partitions are cylinder-aligned, and it looks like there are 128 sectors
+# in a cylinder. FIXME verify. Possibly compute sectors-per-cylinder, given
+# u_int16_t ntrks; /* Tracks per cylinder */
+# u_int16_t nsect; /* Sectors per track */
+sun,128ULL*UINT32_MAX,UINT32_MAX
+#
+bsd,UINT32_MAX,UINT32_MAX
+# aix,UINT32_MAX,UINT32_MAX
+# In reality, loop labels have no particular limit.
+loop,UINT64_MAX,UINT64_MAX
+pc98,UINT32_MAX,UINT32_MAX
+#
+# FIXME: not verified. looks like these are cylinder aligned, too
+amiga,UINT32_MAX,UINT32_MAX
+atari,INT32_MAX,INT32_MAX
diff --git a/libparted/labels/pt-tools.c b/libparted/labels/pt-tools.c
new file mode 100644
index 0000000..add4c45
--- /dev/null
+++ b/libparted/labels/pt-tools.c
@@ -0,0 +1,186 @@
+/* partition table tools
+ Copyright (C) 2008-2014, 2019-2023 Free Software Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+
+#include "pt-tools.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static char zero[16 * 1024];
+
+/* Write a single sector to DISK, filling the first BUFLEN
+ bytes of that sector with data from BUF, and NUL-filling
+ any remaining bytes. Return nonzero to indicate success,
+ zero otherwise. */
+int
+ptt_write_sector (PedDisk const *disk, void const *buf, size_t buflen)
+{
+ PED_ASSERT (buflen <= disk->dev->sector_size);
+ /* Allocate a big enough buffer for ped_device_write. */
+ char *s0 = ped_malloc (disk->dev->sector_size);
+ if (s0 == NULL)
+ return 0;
+ /* Copy boot_code into the first part. */
+ memcpy (s0, buf, buflen);
+ char *p = s0 + buflen;
+ /* Fill the rest with zeros. */
+ memset (p, 0, disk->dev->sector_size - buflen);
+ int write_ok = ped_device_write (disk->dev, s0, 0, 1);
+ free (s0);
+
+ return write_ok;
+}
+
+/* Read N sectors, starting with sector SECTOR_NUM (which has length
+ DEV->sector_size) into malloc'd storage. If the read fails, free
+ the memory and return zero without modifying *BUF. Otherwise, set
+ *BUF to the new buffer and return 1. */
+int
+ptt_read_sectors (PedDevice const *dev, PedSector start_sector,
+ PedSector n_sectors, void **buf)
+{
+ char *b = ped_malloc (n_sectors * dev->sector_size);
+ PED_ASSERT (b != NULL);
+ if (!ped_device_read (dev, b, start_sector, n_sectors)) {
+ free (b);
+ return 0;
+ }
+ *buf = b;
+ return 1;
+}
+
+/* Read sector, SECTOR_NUM (which has length DEV->sector_size) into malloc'd
+ storage. If the read fails, free the memory and return zero without
+ modifying *BUF. Otherwise, set *BUF to the new buffer and return 1. */
+int
+ptt_read_sector (PedDevice const *dev, PedSector sector_num, void **buf)
+{
+ return ptt_read_sectors (dev, sector_num, 1, buf);
+}
+
+/* Zero N sectors of DEV, starting with START.
+ Return nonzero to indicate success, zero otherwise. */
+int
+ptt_clear_sectors (PedDevice *dev, PedSector start, PedSector n)
+{
+ PED_ASSERT (dev->sector_size <= sizeof zero);
+ PedSector n_z_sectors = sizeof zero / dev->sector_size;
+ PedSector n_full = n / n_z_sectors;
+ PedSector i;
+ for (i = 0; i < n_full; i++)
+ {
+ if (!ped_device_write (dev, zero, start + n_z_sectors * i, n_z_sectors))
+ return 0;
+ }
+
+ PedSector rem = n - n_z_sectors * i;
+ return (rem == 0
+ ? 1 : ped_device_write (dev, zero, start + n_z_sectors * i, rem));
+}
+
+/* Zero N sectors of GEOM->dev, starting with GEOM->start + START.
+ Return nonzero to indicate success, zero otherwise. */
+int
+ptt_geom_clear_sectors (PedGeometry *geom, PedSector start, PedSector n)
+{
+ return ptt_clear_sectors (geom->dev, geom->start + start, n);
+}
+
+#define pt_limit_lookup _GL_ATTRIBUTE_PURE __pt_limit_lookup
+#include "pt-limit.c"
+
+/* Throw an exception and return 0 if PART's starting sector number or
+ its length is greater than the maximum allowed value for LABEL_TYPE.
+ Otherwise, return 1. */
+int
+ptt_partition_max_start_len (char const *pt_type, const PedPartition *part)
+{
+ struct partition_limit const *pt_lim
+ = __pt_limit_lookup (pt_type, strlen (pt_type));
+
+ /* If we don't have info on the type, return "true". */
+ if (pt_lim == NULL)
+ return 1;
+
+ /* If the length in sectors exceeds the limit, you lose. */
+ if (part->geom.length > pt_lim->max_length)
+ {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("partition length of %jd sectors exceeds"
+ " the %s-partition-table-imposed maximum"
+ " of %jd"),
+ part->geom.length,
+ pt_type,
+ pt_lim->max_length);
+ return 0;
+ }
+
+ /* If the starting sector exceeds the limit, you lose. */
+ if (part->geom.start > pt_lim->max_start_sector) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("starting sector number, %jd exceeds"
+ " the %s-partition-table-imposed maximum"
+ " of %jd"),
+ part->geom.start,
+ pt_type,
+ pt_lim->max_start_sector);
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Set *MAX to the largest representation-imposed starting sector number
+ of a partition of type PT_TYPE and return 0. If PT_TYPE is not
+ recognized, return -1. */
+int
+ptt_partition_max_start_sector (char const *pt_type, PedSector *max)
+{
+ struct partition_limit const *pt_lim
+ = __pt_limit_lookup (pt_type, strlen (pt_type));
+ if (pt_lim == NULL)
+ return -1;
+
+ *max = pt_lim->max_start_sector;
+ return 0;
+}
+
+/* Set *MAX to the maximum representable length of a partition of type
+ PT_TYPE and return 0. If PT_TYPE is not recognized, return -1. */
+int
+ptt_partition_max_length (char const *pt_type, PedSector *max)
+{
+ struct partition_limit const *pt_lim
+ = __pt_limit_lookup (pt_type, strlen (pt_type));
+ if (pt_lim == NULL)
+ return -1;
+
+ *max = pt_lim->max_length;
+ return 0;
+}
diff --git a/libparted/labels/pt-tools.h b/libparted/labels/pt-tools.h
new file mode 100644
index 0000000..34562f7
--- /dev/null
+++ b/libparted/labels/pt-tools.h
@@ -0,0 +1,31 @@
+/* libparted - a library for manipulating disk partitions
+ Copyright (C) 2008-2014, 2019-2023 Free Software Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stddef.h>
+#include <parted/disk.h>
+
+int ptt_write_sector (PedDisk const *disk, void const *buf, size_t buflen);
+int ptt_read_sector (PedDevice const *dev, PedSector sector_num, void **buf);
+int ptt_read_sectors (PedDevice const *dev, PedSector start_sector,
+ PedSector n_sectors, void **buf);
+int ptt_clear_sectors (PedDevice *dev, PedSector start, PedSector count);
+int ptt_geom_clear_sectors (PedGeometry *geom, PedSector start,
+ PedSector count);
+int ptt_partition_max_start_len (char const *label_type,
+ const PedPartition *part);
+
+int ptt_partition_max_start_sector (char const *pt_type, PedSector *max);
+int ptt_partition_max_length (char const *pt_type, PedSector *max);
diff --git a/libparted/labels/rdb.c b/libparted/labels/rdb.c
new file mode 100644
index 0000000..499d385
--- /dev/null
+++ b/libparted/labels/rdb.c
@@ -0,0 +1,1167 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ disk_amiga.c - libparted module to manipulate amiga RDB partition tables.
+ Copyright (C) 2000-2001, 2004, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Sven Luther <luther@debian.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "pt-tools.h"
+
+#ifndef MAX
+# define MAX(a,b) ((a) < (b) ? (b) : (a))
+#endif
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+
+/* String manipulation */
+static void _amiga_set_bstr (const char *cstr, char *bstr, int maxsize) {
+ int size = strlen (cstr);
+ int i;
+
+ if (size >= maxsize) return;
+ bstr[0] = size;
+ for (i = 0; i<size; i++) bstr[i+1] = cstr[i];
+}
+static const char * _amiga_get_bstr (char * bstr) {
+ char * cstr = bstr + 1;
+ int size = bstr[0];
+
+ cstr[size] = '\0';
+ return cstr;
+}
+
+#define IDNAME_RIGIDDISK (uint32_t)0x5244534B /* 'RDSK' */
+#define IDNAME_BADBLOCK (uint32_t)0x42414442 /* 'BADB' */
+#define IDNAME_PARTITION (uint32_t)0x50415254 /* 'PART' */
+#define IDNAME_FILESYSHEADER (uint32_t)0x46534844 /* 'FSHD' */
+#define IDNAME_LOADSEG (uint32_t)0x4C534547 /* 'LSEG' */
+#define IDNAME_BOOT (uint32_t)0x424f4f54 /* 'BOOT' */
+#define IDNAME_FREE (uint32_t)0xffffffff
+
+static const char *
+_amiga_block_id (uint32_t id) {
+ switch (id) {
+ case IDNAME_RIGIDDISK :
+ return "RDSK";
+ case IDNAME_BADBLOCK :
+ return "BADB";
+ case IDNAME_PARTITION :
+ return "PART";
+ case IDNAME_FILESYSHEADER :
+ return "FSHD";
+ case IDNAME_LOADSEG :
+ return "LSEG";
+ case IDNAME_BOOT :
+ return "BOOT";
+ case IDNAME_FREE :
+ return "<free>";
+ default :
+ return "<unknown>";
+ }
+}
+
+struct AmigaIds {
+ uint32_t ID;
+ struct AmigaIds *next;
+};
+
+static struct AmigaIds *
+_amiga_add_id (uint32_t id, struct AmigaIds *ids) {
+ struct AmigaIds *newid;
+
+ if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL)
+ return 0;
+ newid->ID = id;
+ newid->next = ids;
+ return newid;
+}
+
+static void
+_amiga_free_ids (struct AmigaIds *ids) {
+ struct AmigaIds *current, *next;
+
+ for (current = ids; current != NULL; current = next) {
+ next = current->next;
+ free (current);
+ }
+}
+static int _GL_ATTRIBUTE_PURE
+_amiga_id_in_list (uint32_t id, struct AmigaIds *ids) {
+ struct AmigaIds *current;
+
+ for (current = ids; current != NULL; current = current->next) {
+ if (id == current->ID)
+ return 1;
+ }
+ return 0;
+}
+
+struct AmigaBlock {
+ uint32_t amiga_ID; /* Identifier 32 bit word */
+ uint32_t amiga_SummedLongss; /* Size of the structure for checksums */
+ int32_t amiga_ChkSum; /* Checksum of the structure */
+};
+#define AMIGA(pos) ((struct AmigaBlock *)(pos))
+
+static int
+_amiga_checksum (struct AmigaBlock *blk) {
+ uint32_t *rdb = (uint32_t *) blk;
+ uint32_t sum;
+ int i, end;
+
+ sum = PED_BE32_TO_CPU (rdb[0]);
+ end = PED_BE32_TO_CPU (rdb[1]);
+
+ if (end > PED_SECTOR_SIZE_DEFAULT) end = PED_SECTOR_SIZE_DEFAULT;
+
+ for (i = 1; i < end; i++) sum += PED_BE32_TO_CPU (rdb[i]);
+
+ return sum;
+}
+
+static void
+_amiga_calculate_checksum (struct AmigaBlock *blk) {
+ blk->amiga_ChkSum = PED_CPU_TO_BE32(
+ PED_BE32_TO_CPU(blk->amiga_ChkSum) -
+ _amiga_checksum((struct AmigaBlock *) blk));
+ return;
+}
+
+static struct AmigaBlock *
+_amiga_read_block (const PedDevice *dev, struct AmigaBlock *blk,
+ PedSector block, struct AmigaIds *ids)
+{
+ if (!ped_device_read (dev, blk, block, 1))
+ return NULL;
+ if (ids && !_amiga_id_in_list(PED_BE32_TO_CPU(blk->amiga_ID), ids))
+ return NULL;
+ if (_amiga_checksum (blk) != 0) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
+ _("%s : Bad checksum on block %llu of type %s."),
+ __func__, block, _amiga_block_id(PED_BE32_TO_CPU(blk->amiga_ID))))
+ {
+ case PED_EXCEPTION_CANCEL :
+ return NULL;
+ case PED_EXCEPTION_FIX :
+ _amiga_calculate_checksum(AMIGA(blk));
+ if (!ped_device_write ((PedDevice*)dev, blk, block, 1))
+ return NULL;
+ /* FALLTHROUGH */
+ case PED_EXCEPTION_IGNORE :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return blk;
+ }
+ }
+ return blk;
+}
+
+struct RigidDiskBlock {
+ uint32_t rdb_ID; /* Identifier 32 bit word : 'RDSK' */
+ uint32_t rdb_SummedLongs; /* Size of the structure for checksums */
+ int32_t rdb_ChkSum; /* Checksum of the structure */
+ uint32_t rdb_HostID; /* SCSI Target ID of host, not really used */
+ uint32_t rdb_BlockBytes; /* Size of disk blocks */
+ uint32_t rdb_Flags; /* RDB Flags */
+ /* block list heads */
+ uint32_t rdb_BadBlockList; /* Bad block list */
+ uint32_t rdb_PartitionList; /* Partition list */
+ uint32_t rdb_FileSysHeaderList; /* File system header list */
+ uint32_t rdb_DriveInit; /* Drive specific init code */
+ uint32_t rdb_BootBlockList; /* Amiga OS 4 Boot Blocks */
+ uint32_t rdb_Reserved1[5]; /* Unused word, need to be set to $ffffffff */
+ /* physical drive characteristics */
+ uint32_t rdb_Cylinders; /* Number of the cylinders of the drive */
+ uint32_t rdb_Sectors; /* Number of sectors of the drive */
+ uint32_t rdb_Heads; /* Number of heads of the drive */
+ uint32_t rdb_Interleave; /* Interleave */
+ uint32_t rdb_Park; /* Head parking cylinder */
+ uint32_t rdb_Reserved2[3]; /* Unused word, need to be set to $ffffffff */
+ uint32_t rdb_WritePreComp; /* Starting cylinder of write precompensation */
+ uint32_t rdb_ReducedWrite; /* Starting cylinder of reduced write current */
+ uint32_t rdb_StepRate; /* Step rate of the drive */
+ uint32_t rdb_Reserved3[5]; /* Unused word, need to be set to $ffffffff */
+ /* logical drive characteristics */
+ uint32_t rdb_RDBBlocksLo; /* low block of range reserved for hardblocks */
+ uint32_t rdb_RDBBlocksHi; /* high block of range for these hardblocks */
+ uint32_t rdb_LoCylinder; /* low cylinder of partitionable disk area */
+ uint32_t rdb_HiCylinder; /* high cylinder of partitionable data area */
+ uint32_t rdb_CylBlocks; /* number of blocks available per cylinder */
+ uint32_t rdb_AutoParkSeconds; /* zero for no auto park */
+ uint32_t rdb_HighRDSKBlock; /* highest block used by RDSK */
+ /* (not including replacement bad blocks) */
+ uint32_t rdb_Reserved4;
+ /* drive identification */
+ char rdb_DiskVendor[8];
+ char rdb_DiskProduct[16];
+ char rdb_DiskRevision[4];
+ char rdb_ControllerVendor[8];
+ char rdb_ControllerProduct[16];
+ char rdb_ControllerRevision[4];
+ uint32_t rdb_Reserved5[10];
+};
+
+#define RDSK(pos) ((struct RigidDiskBlock *)(pos))
+
+#define AMIGA_RDB_NOT_FOUND ((uint32_t)0xffffffff)
+#define RDB_LOCATION_LIMIT 16
+#define AMIGA_MAX_PARTITIONS 128
+#define MAX_RDB_BLOCK (RDB_LOCATION_LIMIT + 2 * AMIGA_MAX_PARTITIONS + 2)
+
+static uint32_t
+_amiga_find_rdb (const PedDevice *dev, struct RigidDiskBlock *rdb) {
+ int i;
+ struct AmigaIds *ids;
+
+ ids = _amiga_add_id (IDNAME_RIGIDDISK, NULL);
+
+ for (i = 0; i<RDB_LOCATION_LIMIT; i++) {
+ if (!_amiga_read_block (dev, AMIGA(rdb), i, ids)) {
+ continue;
+ }
+ if (PED_BE32_TO_CPU (rdb->rdb_ID) == IDNAME_RIGIDDISK) {
+ _amiga_free_ids (ids);
+ return i;
+ }
+ }
+ _amiga_free_ids (ids);
+ return AMIGA_RDB_NOT_FOUND;
+}
+
+struct PartitionBlock {
+ uint32_t pb_ID; /* Identifier 32 bit word : 'PART' */
+ uint32_t pb_SummedLongs; /* Size of the structure for checksums */
+ int32_t pb_ChkSum; /* Checksum of the structure */
+ uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
+ uint32_t pb_Next; /* Block number of the next PartitionBlock */
+ uint32_t pb_Flags; /* Part Flags (NOMOUNT and BOOTABLE) */
+ uint32_t pb_Reserved1[2];
+ uint32_t pb_DevFlags; /* Preferred flags for OpenDevice */
+ char pb_DriveName[32]; /* Preferred DOS device name: BSTR form */
+ uint32_t pb_Reserved2[15];
+ uint32_t de_TableSize; /* Size of Environment vector */
+ /* Size of the blocks in 32 bit words, usually 128 */
+ uint32_t de_SizeBlock;
+ uint32_t de_SecOrg; /* Not used; must be 0 */
+ uint32_t de_Surfaces; /* Number of heads (surfaces) */
+ /* Disk sectors per block, used with SizeBlock, usually 1 */
+ uint32_t de_SectorPerBlock;
+ uint32_t de_BlocksPerTrack; /* Blocks per track. drive specific */
+ uint32_t de_Reserved; /* DOS reserved blocks at start of partition. */
+ uint32_t de_PreAlloc; /* DOS reserved blocks at end of partition */
+ uint32_t de_Interleave; /* Not used, usually 0 */
+ uint32_t de_LowCyl; /* First cylinder of the partition */
+ uint32_t de_HighCyl; /* Last cylinder of the partition */
+ uint32_t de_NumBuffers; /* Initial # DOS of buffers. */
+ uint32_t de_BufMemType; /* Type of mem to allocate for buffers */
+ uint32_t de_MaxTransfer; /* Max number of bytes to transfer at a time */
+ uint32_t de_Mask; /* Address Mask to block out certain memory */
+ int32_t de_BootPri; /* Boot priority for autoboot */
+ uint32_t de_DosType; /* Dostype of the file system */
+ uint32_t de_Baud; /* Baud rate for serial handler */
+ uint32_t de_Control; /* Control word for handler/filesystem */
+ uint32_t de_BootBlocks; /* Number of blocks containing boot code */
+ uint32_t pb_EReserved[12];
+};
+
+#define PART(pos) ((struct PartitionBlock *)(pos))
+
+#define PBFB_BOOTABLE 0 /* this partition is intended to be bootable */
+#define PBFF_BOOTABLE 1L /* (expected directories and files exist) */
+#define PBFB_NOMOUNT 1 /* do not mount this partition (e.g. manually */
+#define PBFF_NOMOUNT 2L /* mounted, but space reserved here) */
+#define PBFB_RAID 2 /* this partition is intended to be part of */
+#define PBFF_RAID 4L /* a RAID array */
+#define PBFB_LVM 3 /* this partition is intended to be part of */
+#define PBFF_LVM 8L /* a LVM volume group */
+
+
+struct LinkedBlock {
+ uint32_t lk_ID; /* Identifier 32 bit word */
+ uint32_t lk_SummedLongs; /* Size of the structure for checksums */
+ int32_t lk_ChkSum; /* Checksum of the structure */
+ uint32_t pb_HostID; /* SCSI Target ID of host, not really used */
+ uint32_t lk_Next; /* Block number of the next PartitionBlock */
+};
+struct Linked2Block {
+ uint32_t lk2_ID; /* Identifier 32 bit word */
+ uint32_t lk2_SummedLongs; /* Size of the structure for checksums */
+ int32_t lk2_ChkSum; /* Checksum of the structure */
+ uint32_t lk2_HostID; /* SCSI Target ID of host, not really used */
+ uint32_t lk2_Next; /* Block number of the next PartitionBlock */
+ uint32_t lk2_Reverved[13];
+ uint32_t lk2_Linked; /* Secondary linked list */
+};
+#define LINK_END (uint32_t)0xffffffff
+#define LNK(pos) ((struct LinkedBlock *)(pos))
+#define LNK2(pos) ((struct Linked2Block *)(pos))
+
+
+static PedDiskType amiga_disk_type;
+
+static int
+amiga_probe (const PedDevice *dev)
+{
+ struct RigidDiskBlock *rdb;
+ uint32_t found;
+ PED_ASSERT(dev != NULL);
+
+ if ((rdb=RDSK(ped_malloc(dev->sector_size)))==NULL)
+ return 0;
+ found = _amiga_find_rdb (dev, rdb);
+ free (rdb);
+
+ return (found == AMIGA_RDB_NOT_FOUND ? 0 : 1);
+}
+
+static PedDisk*
+amiga_alloc (const PedDevice* dev)
+{
+ PedDisk *disk;
+ struct RigidDiskBlock *rdb;
+ PedSector cyl_size;
+ int highest_cylinder, highest_block;
+
+ PED_ASSERT(dev != NULL);
+ cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
+
+ if (!(disk = _ped_disk_alloc (dev, &amiga_disk_type)))
+ return NULL;
+
+ if (!(disk->disk_specific = ped_malloc (disk->dev->sector_size))) {
+ free (disk);
+ return NULL;
+ }
+ rdb = disk->disk_specific;
+
+ /* Upon failed assertion this does leak. That's fine, because
+ if the assertion fails, you have bigger problems than this leak. */
+ PED_ASSERT(sizeof(*rdb) <= disk->dev->sector_size);
+
+ memset(rdb, 0, disk->dev->sector_size);
+
+ rdb->rdb_ID = PED_CPU_TO_BE32 (IDNAME_RIGIDDISK);
+ rdb->rdb_SummedLongs = PED_CPU_TO_BE32 (64);
+ rdb->rdb_HostID = PED_CPU_TO_BE32 (0);
+ rdb->rdb_BlockBytes = PED_CPU_TO_BE32 (disk->dev->sector_size);
+ rdb->rdb_Flags = PED_CPU_TO_BE32 (0);
+
+ /* Block lists */
+ rdb->rdb_BadBlockList = PED_CPU_TO_BE32 (LINK_END);
+ rdb->rdb_PartitionList = PED_CPU_TO_BE32 (LINK_END);
+ rdb->rdb_FileSysHeaderList = PED_CPU_TO_BE32 (LINK_END);
+ rdb->rdb_DriveInit = PED_CPU_TO_BE32 (LINK_END);
+ rdb->rdb_BootBlockList = PED_CPU_TO_BE32 (LINK_END);
+
+ /* Physical drive characteristics */
+ rdb->rdb_Cylinders = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
+ rdb->rdb_Sectors = PED_CPU_TO_BE32 (dev->hw_geom.sectors);
+ rdb->rdb_Heads = PED_CPU_TO_BE32 (dev->hw_geom.heads);
+ rdb->rdb_Interleave = PED_CPU_TO_BE32 (0);
+ rdb->rdb_Park = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
+ rdb->rdb_WritePreComp = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
+ rdb->rdb_ReducedWrite = PED_CPU_TO_BE32 (dev->hw_geom.cylinders);
+ rdb->rdb_StepRate = PED_CPU_TO_BE32 (0);
+
+ highest_cylinder = 1 + MAX_RDB_BLOCK / cyl_size;
+ highest_block = highest_cylinder * cyl_size - 1;
+
+ /* Logical driver characteristics */
+ rdb->rdb_RDBBlocksLo = PED_CPU_TO_BE32 (0);
+ rdb->rdb_RDBBlocksHi = PED_CPU_TO_BE32 (highest_block);
+ rdb->rdb_LoCylinder = PED_CPU_TO_BE32 (highest_cylinder);
+ rdb->rdb_HiCylinder = PED_CPU_TO_BE32 (dev->hw_geom.cylinders -1);
+ rdb->rdb_CylBlocks = PED_CPU_TO_BE32 (cyl_size);
+ rdb->rdb_AutoParkSeconds = PED_CPU_TO_BE32 (0);
+ /* rdb_HighRDSKBlock will only be set when writing */
+ rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32 (0);
+
+ /* Driver identification */
+ _amiga_set_bstr("", rdb->rdb_DiskVendor, 8);
+ _amiga_set_bstr(dev->model, rdb->rdb_DiskProduct, 16);
+ _amiga_set_bstr("", rdb->rdb_DiskRevision, 4);
+ _amiga_set_bstr("", rdb->rdb_ControllerVendor, 8);
+ _amiga_set_bstr("", rdb->rdb_ControllerProduct, 16);
+ _amiga_set_bstr("", rdb->rdb_ControllerRevision, 4);
+
+ /* And calculate the checksum */
+ _amiga_calculate_checksum ((struct AmigaBlock *) rdb);
+
+ return disk;
+}
+
+static PedDisk*
+amiga_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ struct RigidDiskBlock * new_rdb;
+ struct RigidDiskBlock * old_rdb;
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+ PED_ASSERT(disk->disk_specific != NULL);
+
+ old_rdb = (struct RigidDiskBlock *) disk->disk_specific;
+
+ if (!(new_disk = ped_disk_new_fresh (disk->dev, &amiga_disk_type)))
+ return NULL;
+
+ new_rdb = (struct RigidDiskBlock *) new_disk->disk_specific;
+ memcpy (new_rdb, old_rdb, 256);
+ return new_disk;
+}
+
+static void
+amiga_free (PedDisk* disk)
+{
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->disk_specific != NULL);
+
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+static int
+_amiga_loop_check (uint32_t block, uint32_t * blocklist, uint32_t max)
+{
+ uint32_t i;
+
+ for (i = 0; i < max; i++)
+ if (block == blocklist[i]) {
+ /* We are looping, let's stop. */
+ return 1;
+ }
+ blocklist[max] = block;
+ return 0;
+}
+
+/* We have already allocated a rdb, we are now reading it from the disk */
+static int
+amiga_read (PedDisk* disk)
+{
+ struct RigidDiskBlock *rdb;
+ struct PartitionBlock *partition;
+ uint32_t partblock;
+ uint32_t partlist[AMIGA_MAX_PARTITIONS];
+ PedSector cylblocks;
+ int i;
+
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+ PED_ASSERT(disk->dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0);
+ PED_ASSERT(disk->disk_specific != NULL);
+ rdb = RDSK(disk->disk_specific);
+
+ if (_amiga_find_rdb (disk->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Didn't find rdb block, should never happen."), __func__);
+ return 0;
+ }
+
+ /* Let's copy the rdb read geometry to the dev */
+ /* FIXME: should this go into disk->dev->bios_geom instead? */
+ disk->dev->hw_geom.cylinders = PED_BE32_TO_CPU (rdb->rdb_Cylinders);
+ disk->dev->hw_geom.heads = PED_BE32_TO_CPU (rdb->rdb_Heads);
+ disk->dev->hw_geom.sectors = PED_BE32_TO_CPU (rdb->rdb_Sectors);
+ cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
+ (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
+
+ /* Remove all partitions in the former in memory table */
+ ped_disk_delete_all (disk);
+
+ /* Let's allocate a partition block */
+ if (!(partition = ped_malloc (disk->dev->sector_size)))
+ return 0;
+
+ /* We initialize the hardblock free list to detect loops */
+ for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = LINK_END;
+
+ for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
+ i < AMIGA_MAX_PARTITIONS && partblock != LINK_END;
+ i++, partblock = PED_BE32_TO_CPU(partition->pb_Next))
+ {
+ PedPartition *part;
+ PedSector start, end;
+
+ /* Let's look for loops in the partition table */
+ if (_amiga_loop_check(partblock, partlist, i)) {
+ break;
+ }
+
+ /* Let's allocate and read a partition block to get its geometry*/
+ if (!_amiga_read_block (disk->dev, AMIGA(partition),
+ (PedSector)partblock, NULL)) {
+ free(partition);
+ return 0;
+ }
+
+ start = ((PedSector) PED_BE32_TO_CPU (partition->de_LowCyl))
+ * cylblocks;
+ end = (((PedSector) PED_BE32_TO_CPU (partition->de_HighCyl))
+ + 1) * cylblocks - 1;
+
+ /* We can now construct a new partition */
+ if (!(part = ped_partition_new (disk, PED_PARTITION_NORMAL,
+ NULL, start, end))) {
+ free(partition);
+ return 0;
+ }
+ /* And copy over the partition block */
+ memcpy(part->disk_specific, partition, 256);
+
+ part->num = i;
+ part->type = 0;
+ /* Let's probe what file system is present on the disk */
+ part->fs_type = ped_file_system_probe (&part->geom);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ if (constraint_exact == NULL)
+ return 0;
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok) {
+ ped_partition_destroy(part);
+ free(partition);
+ return 0;
+ }
+ }
+ free(partition);
+ return 1;
+}
+
+static int
+_amiga_find_free_blocks(const PedDisk *disk, uint32_t *table,
+ struct LinkedBlock *block, uint32_t first, uint32_t type)
+{
+ PedSector next;
+
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+
+ for (next = first; next != LINK_END; next = PED_BE32_TO_CPU(block->lk_Next)) {
+ if (table[next] != IDNAME_FREE) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_IGNORE | PED_EXCEPTION_CANCEL,
+ _("%s : Loop detected at block %d."), __func__, next))
+ {
+ case PED_EXCEPTION_CANCEL :
+ return 0;
+ case PED_EXCEPTION_FIX :
+ /* TODO : Need to add fixing code */
+ case PED_EXCEPTION_IGNORE :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return 1;
+ }
+ }
+
+ if (!_amiga_read_block (disk->dev, AMIGA(block), next, NULL)) {
+ return 0;
+ }
+ if (PED_BE32_TO_CPU(block->lk_ID) != type) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : The %s list seems bad at block %s."),
+ __func__, _amiga_block_id(PED_BE32_TO_CPU(block->lk_ID)), next))
+ {
+ /* TODO : to more subtile things here */
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return 0;
+ }
+ }
+ table[next] = type;
+ if (PED_BE32_TO_CPU(block->lk_ID) == IDNAME_FILESYSHEADER) {
+ if (_amiga_find_free_blocks(disk, table, block,
+ PED_BE32_TO_CPU(LNK2(block)->lk2_Linked),
+ IDNAME_LOADSEG) == 0) return 0;
+ }
+ }
+ return 1;
+}
+static uint32_t _GL_ATTRIBUTE_PURE
+_amiga_next_free_block(uint32_t *table, uint32_t start, uint32_t type) {
+ int i;
+
+ for (i = start; table[i] != type && table[i] != IDNAME_FREE; i++);
+ return i;
+}
+static PedPartition * _GL_ATTRIBUTE_PURE
+_amiga_next_real_partition(const PedDisk *disk, PedPartition *part) {
+ PedPartition *next;
+
+ for (next = ped_disk_next_partition (disk, part);
+ next != NULL && !ped_partition_is_active (next);
+ next = ped_disk_next_partition (disk, next));
+ return next;
+}
+#ifndef DISCOVER_ONLY
+static int
+amiga_write (const PedDisk* disk)
+{
+ struct RigidDiskBlock *rdb;
+ struct LinkedBlock *block;
+ struct PartitionBlock *partition;
+ PedPartition *part, *next_part;
+ PedSector cylblocks, first_hb, last_hb;
+ uint32_t * table;
+ uint32_t i;
+ uint32_t rdb_num, part_num, block_num, next_num;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+
+ if (!(rdb = ped_malloc (disk->dev->sector_size)))
+ return 0;
+
+ /* Let's read the rdb */
+ if ((rdb_num = _amiga_find_rdb (disk->dev, rdb)) == AMIGA_RDB_NOT_FOUND) {
+ rdb_num = 2;
+ size_t pb_size = sizeof (struct PartitionBlock);
+ /* Initialize only the part that won't be copied over
+ with a partition block in amiga_read. */
+ memset ((char *)(RDSK(disk->disk_specific)) + pb_size,
+ 0, PED_SECTOR_SIZE_DEFAULT - pb_size);
+ } else {
+ memcpy (RDSK(disk->disk_specific), rdb, disk->dev->sector_size);
+ }
+ free (rdb);
+ rdb = RDSK(disk->disk_specific);
+
+ cylblocks = (PedSector) PED_BE32_TO_CPU (rdb->rdb_Heads) *
+ (PedSector) PED_BE32_TO_CPU (rdb->rdb_Sectors);
+ first_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksLo);
+ last_hb = (PedSector) PED_BE32_TO_CPU (rdb->rdb_RDBBlocksHi);
+
+ /* Allocate a free block table and initialize it.
+ There must be room for at least RDB_NUM + 2 entries, since
+ the first RDB_NUM+1 entries get IDNAME_RIGIDDISK, and the
+ following one must have LINK_END to serve as sentinel. */
+ size_t tab_size = 2 + MAX (last_hb - first_hb, rdb_num);
+ if (!(table = ped_malloc (tab_size * sizeof *table)))
+ return 0;
+
+ for (i = 0; i <= rdb_num; i++)
+ table[i] = IDNAME_RIGIDDISK;
+ for ( ; i < tab_size; i++)
+ table[i] = LINK_END;
+
+ /* Let's allocate a partition block */
+ if (!(block = ped_malloc (disk->dev->sector_size))) {
+ free (table);
+ return 0;
+ }
+
+ /* And fill the free block table */
+ if (_amiga_find_free_blocks(disk, table, block,
+ PED_BE32_TO_CPU (rdb->rdb_BadBlockList), IDNAME_BADBLOCK) == 0)
+ {
+ ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to list bad blocks."), __func__);
+ goto error_free_table;
+ }
+ if (_amiga_find_free_blocks(disk, table, block,
+ PED_BE32_TO_CPU (rdb->rdb_PartitionList), IDNAME_PARTITION) == 0)
+ {
+ ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to list partition blocks."), __func__);
+ goto error_free_table;
+ }
+ if (_amiga_find_free_blocks(disk, table, block,
+ PED_BE32_TO_CPU (rdb->rdb_FileSysHeaderList), IDNAME_FILESYSHEADER) == 0)
+ {
+ ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to list file system blocks."), __func__);
+ goto error_free_table;
+ }
+ if (_amiga_find_free_blocks(disk, table, block,
+ PED_BE32_TO_CPU (rdb->rdb_BootBlockList), IDNAME_BOOT) == 0)
+ {
+ ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to list boot blocks."), __func__);
+ goto error_free_table;
+ }
+
+ block_num = part_num = _amiga_next_free_block(table, rdb_num+1,
+ IDNAME_PARTITION);
+ part = _amiga_next_real_partition(disk, NULL);
+ rdb->rdb_PartitionList = PED_CPU_TO_BE32(part ? part_num : LINK_END);
+ for (; part != NULL; part = next_part, block_num = next_num) {
+ PED_ASSERT(part->disk_specific != NULL);
+ PED_ASSERT(part->geom.start % cylblocks == 0);
+ PED_ASSERT((part->geom.end + 1) % cylblocks == 0);
+
+ next_part = _amiga_next_real_partition(disk, part);
+ next_num = _amiga_next_free_block(table, block_num+1, IDNAME_PARTITION);
+
+ partition = PART(part->disk_specific);
+ if (next_part == NULL)
+ partition->pb_Next = PED_CPU_TO_BE32(LINK_END);
+ else
+ partition->pb_Next = PED_CPU_TO_BE32(next_num);
+ partition->de_LowCyl = PED_CPU_TO_BE32(part->geom.start/cylblocks);
+ partition->de_HighCyl = PED_CPU_TO_BE32((part->geom.end+1)/cylblocks-1);
+ _amiga_calculate_checksum(AMIGA(partition));
+ if (!ped_device_write (disk->dev, (void*) partition, block_num, 1)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Failed to write partition block at %d."),
+ block_num);
+ goto error_free_table;
+ /* WARNING : If we fail here, we stop everything,
+ * and the partition table is lost. A better
+ * solution should be found, using the second
+ * half of the hardblocks to not overwrite the
+ * old partition table. It becomes problematic
+ * if we use more than half of the hardblocks. */
+ }
+ }
+
+ if (block_num > PED_BE32_TO_CPU (rdb->rdb_HighRDSKBlock))
+ rdb->rdb_HighRDSKBlock = PED_CPU_TO_BE32(block_num);
+
+ _amiga_calculate_checksum(AMIGA(rdb));
+ if (!ped_device_write (disk->dev, (void*) disk->disk_specific, rdb_num, 1))
+ goto error_free_table;
+
+ free (table);
+ free (block);
+ return ped_device_sync (disk->dev);
+
+error_free_table:
+ free (table);
+ free (block);
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+amiga_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition *part;
+ PedDevice *dev;
+ PedSector cyl;
+ struct PartitionBlock *partition;
+ struct RigidDiskBlock *rdb;
+
+ PED_ASSERT(disk != NULL);
+ PED_ASSERT(disk->dev != NULL);
+ PED_ASSERT(disk->disk_specific != NULL);
+ dev = disk->dev;
+ cyl = (PedSector) (dev->hw_geom.sectors * dev->hw_geom.heads);
+ rdb = RDSK(disk->disk_specific);
+
+ if (!(part = _ped_partition_alloc (disk, part_type, fs_type, start, end)))
+ return NULL;
+
+ if (ped_partition_is_active (part)) {
+ if (!(part->disk_specific = ped_malloc (disk->dev->sector_size))) {
+ free (part);
+ return NULL;
+ }
+ partition = PART(part->disk_specific);
+ memset(partition, 0, sizeof(struct PartitionBlock));
+
+ partition->pb_ID = PED_CPU_TO_BE32(IDNAME_PARTITION);
+ partition->pb_SummedLongs = PED_CPU_TO_BE32(64);
+ partition->pb_HostID = rdb->rdb_HostID;
+ partition->pb_Flags = PED_CPU_TO_BE32(0);
+ /* TODO : use a scheme including the device name and the
+ * partition number, if it is possible */
+ _amiga_set_bstr("dhx", partition->pb_DriveName, 32);
+
+ partition->de_TableSize = PED_CPU_TO_BE32(19);
+ partition->de_SizeBlock = PED_CPU_TO_BE32(128);
+ partition->de_SecOrg = PED_CPU_TO_BE32(0);
+ partition->de_Surfaces = PED_CPU_TO_BE32(dev->hw_geom.heads);
+ partition->de_SectorPerBlock = PED_CPU_TO_BE32(1);
+ partition->de_BlocksPerTrack
+ = PED_CPU_TO_BE32(dev->hw_geom.sectors);
+ partition->de_Reserved = PED_CPU_TO_BE32(2);
+ partition->de_PreAlloc = PED_CPU_TO_BE32(0);
+ partition->de_Interleave = PED_CPU_TO_BE32(0);
+ partition->de_LowCyl = PED_CPU_TO_BE32(start/cyl);
+ partition->de_HighCyl = PED_CPU_TO_BE32((end+1)/cyl-1);
+ partition->de_NumBuffers = PED_CPU_TO_BE32(30);
+ partition->de_BufMemType = PED_CPU_TO_BE32(0);
+ partition->de_MaxTransfer = PED_CPU_TO_BE32(0x7fffffff);
+ partition->de_Mask = PED_CPU_TO_BE32(0xffffffff);
+ partition->de_BootPri = PED_CPU_TO_BE32(0);
+ partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800);
+ partition->de_Baud = PED_CPU_TO_BE32(0);
+ partition->de_Control = PED_CPU_TO_BE32(0);
+ partition->de_BootBlocks = PED_CPU_TO_BE32(0);
+
+ } else {
+ part->disk_specific = NULL;
+ }
+ return part;
+}
+
+static PedPartition*
+amiga_partition_duplicate (const PedPartition* part)
+{
+ PedPartition *new_part;
+ struct PartitionBlock *new_amiga_part;
+ struct PartitionBlock *old_amiga_part;
+
+ PED_ASSERT(part != NULL);
+ PED_ASSERT(part->disk != NULL);
+ PED_ASSERT(part->disk_specific != NULL);
+ old_amiga_part = (struct PartitionBlock *) part->disk_specific;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+
+ new_amiga_part = (struct PartitionBlock *) new_part->disk_specific;
+ memcpy (new_amiga_part, old_amiga_part, 256);
+
+ return new_part;
+}
+
+static void
+amiga_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part)) {
+ PED_ASSERT (part->disk_specific != NULL);
+ free (part->disk_specific);
+ }
+ _ped_partition_free (part);
+}
+
+static int
+amiga_partition_set_system (PedPartition* part,
+ const PedFileSystemType* fs_type)
+{
+ struct PartitionBlock *partition;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ partition = PART(part->disk_specific);
+
+ part->fs_type = fs_type;
+
+ if (!fs_type)
+ partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
+ else if (!strcmp (fs_type->name, "ext2"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x4c4e5800); /* 'LNX\0' */
+ else if (!strcmp (fs_type->name, "ext3"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x45585403); /* 'EXT\3' */
+ else if (is_linux_swap (fs_type->name))
+ partition->de_DosType = PED_CPU_TO_BE32(0x53575000); /* 'SWP\0' */
+ else if (!strcmp (fs_type->name, "fat16"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x46415400); /* 'FAT\0' */
+ else if (!strcmp (fs_type->name, "fat32"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x46415401); /* 'FAT\1'*/
+ else if (!strcmp (fs_type->name, "hfs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x48465300); /* 'HFS\0' */
+ else if (!strcmp (fs_type->name, "jfs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x4a465300); /* 'JFS\0' */
+ else if (!strcmp (fs_type->name, "ntfs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x4e544653); /* 'NTFS' */
+ else if (!strcmp (fs_type->name, "reiserfs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x52465300); /* 'RFS\0' */
+ else if (!strcmp (fs_type->name, "sun-ufs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x53554653); /* 'SUFS' */
+ else if (!strcmp (fs_type->name, "hp-ufs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x48554653); /* 'HUFS' */
+ else if (!strcmp (fs_type->name, "xfs"))
+ partition->de_DosType = PED_CPU_TO_BE32(0x58465300); /* 'XFS\0' */
+ else
+ partition->de_DosType = PED_CPU_TO_BE32(0x00000000); /* unknown */
+ return 1;
+}
+
+static int
+amiga_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ struct PartitionBlock *partition;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ partition = PART(part->disk_specific);
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_BOOTABLE);
+ else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_BOOTABLE));
+ return 1;
+ case PED_PARTITION_HIDDEN:
+ if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_NOMOUNT);
+ else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_NOMOUNT));
+ return 1;
+ case PED_PARTITION_RAID:
+ if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_RAID);
+ else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_RAID));
+ return 1;
+ case PED_PARTITION_LVM:
+ if (state) partition->pb_Flags |= PED_CPU_TO_BE32(PBFF_LVM);
+ else partition->pb_Flags &= ~(PED_CPU_TO_BE32(PBFF_LVM));
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int _GL_ATTRIBUTE_PURE
+amiga_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ struct PartitionBlock *partition;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ partition = PART(part->disk_specific);
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_BOOTABLE));
+ case PED_PARTITION_HIDDEN:
+ return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_NOMOUNT));
+ case PED_PARTITION_RAID:
+ return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_RAID));
+ case PED_PARTITION_LVM:
+ return (partition->pb_Flags & PED_CPU_TO_BE32(PBFF_LVM));
+ default:
+ return 0;
+ }
+}
+
+static int
+amiga_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ case PED_PARTITION_HIDDEN:
+ case PED_PARTITION_RAID:
+ case PED_PARTITION_LVM:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void
+amiga_partition_set_name (PedPartition* part, const char* name)
+{
+ struct PartitionBlock *partition;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ partition = PART(part->disk_specific);
+ _amiga_set_bstr(name, partition->pb_DriveName, 32);
+}
+static const char*
+amiga_partition_get_name (const PedPartition* part)
+{
+ struct PartitionBlock *partition;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ partition = PART(part->disk_specific);
+
+ return _amiga_get_bstr(partition->pb_DriveName);
+}
+
+static PedAlignment*
+amiga_get_partition_alignment(const PedDisk *disk)
+{
+ PedSector cylinder_size =
+ disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
+
+ return ped_alignment_new(0, cylinder_size);
+}
+
+static PedConstraint*
+_amiga_get_constraint (const PedDisk *disk)
+{
+ PedDevice *dev = disk->dev;
+ PedAlignment start_align, end_align;
+ PedGeometry max_geom;
+ PedSector cyl_size = dev->hw_geom.sectors * dev->hw_geom.heads;
+
+ if (!ped_alignment_init(&start_align, 0, cyl_size))
+ return NULL;
+ if (!ped_alignment_init(&end_align, -1, cyl_size))
+ return NULL;
+ if (!ped_geometry_init(&max_geom, dev, MAX_RDB_BLOCK + 1,
+ dev->length - MAX_RDB_BLOCK - 1))
+ return NULL;
+
+ return ped_constraint_new (&start_align, &end_align,
+ &max_geom, &max_geom, 1, dev->length);
+}
+
+static int
+amiga_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ if (_ped_partition_attempt_align (part, constraint,
+ _amiga_get_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+amiga_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk != NULL);
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+ for (i = 1; i <= AMIGA_MAX_PARTITIONS; i++) {
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number */
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unable to allocate a partition number."));
+#endif
+ return 0;
+}
+
+static int
+amiga_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ PedConstraint* constraint_any = NULL;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* Allocate space for the RDB */
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ 0, MAX_RDB_BLOCK);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+static int
+amiga_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return AMIGA_MAX_PARTITIONS;
+}
+
+static bool
+amiga_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = AMIGA_MAX_PARTITIONS;
+ return true;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (amiga)
+
+static PedDiskOps amiga_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (amiga_write),
+
+ partition_set_name: amiga_partition_set_name,
+ partition_get_name: amiga_partition_get_name,
+
+ get_partition_alignment: amiga_get_partition_alignment,
+
+ PT_op_function_initializers (amiga)
+};
+
+static PedDiskType amiga_disk_type = {
+ next: NULL,
+ name: "amiga",
+ ops: &amiga_disk_ops,
+ features: PED_DISK_TYPE_PARTITION_NAME
+};
+
+void
+ped_disk_amiga_init ()
+{
+ PED_ASSERT (sizeof (struct AmigaBlock) != 3);
+ PED_ASSERT (sizeof (struct RigidDiskBlock) != 64);
+ PED_ASSERT (sizeof (struct PartitionBlock) != 64);
+ PED_ASSERT (sizeof (struct LinkedBlock) != 5);
+ PED_ASSERT (sizeof (struct Linked2Block) != 18);
+
+ ped_disk_type_register (&amiga_disk_type);
+}
+
+void
+ped_disk_amiga_done ()
+{
+ ped_disk_type_unregister (&amiga_disk_type);
+}
diff --git a/libparted/labels/sun.c b/libparted/labels/sun.c
new file mode 100644
index 0000000..5ed2886
--- /dev/null
+++ b/libparted/labels/sun.c
@@ -0,0 +1,910 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000-2001, 2005, 2007-2014, 2019-2023 Free Software
+ Foundation, Inc.
+
+ 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
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ Contributor: Ben Collins <bcollins@debian.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+#include <stdbool.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "misc.h"
+#include "pt-tools.h"
+#include "verify.h"
+
+/* Most of this came from util-linux's sun support, which was mostly done
+ by Jakub Jelinek. */
+
+#define SUN_DISK_MAGIC 0xDABE /* Disk magic number */
+#define SUN_DISK_MAXPARTITIONS 8
+
+#define SUN_VTOC_VERSION 1
+#define SUN_VTOC_SANITY 0x600DDEEE
+
+#define WHOLE_DISK_ID 0x05
+#define WHOLE_DISK_PART 2 /* as in 0, 1, 2 (3rd partition) */
+#define LINUX_SWAP_ID 0x82
+
+typedef struct _SunRawPartition SunRawPartition;
+typedef struct _SunPartitionInfo SunPartitionInfo;
+typedef struct _SunRawLabel SunRawLabel;
+typedef struct _SunPartitionData SunPartitionData;
+typedef struct _SunDiskData SunDiskData;
+
+struct __attribute__ ((packed)) _SunRawPartition {
+ u_int32_t start_cylinder; /* where the part starts... */
+ u_int32_t num_sectors; /* ...and it's length */
+};
+
+struct __attribute__ ((packed)) _SunPartitionInfo {
+ u_int8_t spare1;
+ u_int8_t id; /* Partition type */
+ u_int8_t spare2;
+ u_int8_t flags; /* Partition flags */
+};
+
+struct __attribute__ ((packed, aligned(2))) _SunRawLabel {
+ char info[128]; /* Informative text string */
+ u_int32_t version; /* Layout version */
+ u_int8_t volume[8]; /* Volume name */
+ u_int16_t nparts; /* Number of partitions */
+ SunPartitionInfo infos[SUN_DISK_MAXPARTITIONS];
+ u_int16_t padding; /* Alignment padding */
+ u_int32_t bootinfo[3]; /* Info needed by mboot */
+ u_int32_t sanity; /* To verify vtoc sanity */
+ u_int32_t reserved[10]; /* Free space */
+ u_int32_t timestamp[8]; /* Partition timestamp */
+ u_int32_t write_reinstruct; /* sectors to skip, writes */
+ u_int32_t read_reinstruct; /* sectors to skip, reads */
+ u_int8_t spare1[148]; /* Padding */
+ u_int16_t rspeed; /* Disk rotational speed */
+ u_int16_t pcylcount; /* Physical cylinder count */
+ u_int16_t sparecyl; /* extra sects per cylinder */
+ u_int8_t spare2[4]; /* More magic... */
+ u_int16_t ilfact; /* Interleave factor */
+ u_int16_t ncyl; /* Data cylinder count */
+ u_int16_t nacyl; /* Alt. cylinder count */
+ u_int16_t ntrks; /* Tracks per cylinder */
+ u_int16_t nsect; /* Sectors per track */
+ u_int8_t spare3[4]; /* Even more magic... */
+ SunRawPartition partitions[SUN_DISK_MAXPARTITIONS];
+ u_int16_t magic; /* Magic number */
+ u_int16_t csum; /* Label xor'd checksum */
+};
+
+struct _SunPartitionData {
+ u_int8_t type;
+ int is_boot;
+ int is_root;
+ int is_lvm;
+ int is_raid;
+};
+
+struct _SunDiskData {
+ PedSector length; /* This is based on cyl - alt-cyl */
+ SunRawLabel raw_label;
+};
+
+static PedDiskType sun_disk_type;
+
+/* Checksum computation */
+static void
+sun_compute_checksum (SunRawLabel *label)
+{
+ u_int16_t *ush = (u_int16_t *)label;
+ u_int16_t csum = 0;
+
+ while(ush < (u_int16_t *)(&label->csum))
+ csum ^= *ush++;
+ label->csum = csum;
+}
+
+/* Checksum Verification */
+static int
+sun_verify_checksum (SunRawLabel const *label)
+{
+ u_int16_t *ush = ((u_int16_t *)(label + 1)) - 1;
+ u_int16_t csum = 0;
+
+ while (ush >= (u_int16_t *)label)
+ csum ^= *ush--;
+
+ return !csum;
+}
+
+static int
+sun_probe (const PedDevice *dev)
+{
+ PED_ASSERT (dev != NULL);
+
+ void *s0;
+ if (!ptt_read_sector (dev, 0, &s0))
+ return 0;
+ SunRawLabel const *label = (void const *) s0;
+
+ int ok = 1;
+ /* check magic */
+ if (PED_BE16_TO_CPU (label->magic) != SUN_DISK_MAGIC) {
+ ok = 0;
+ } else {
+#ifndef DISCOVER_ONLY
+ if (!sun_verify_checksum(label)) {
+ ok = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Corrupted Sun disk label detected."));
+ }
+ }
+#endif
+
+ free (s0);
+ return ok;
+}
+
+static PedDisk*
+sun_alloc (const PedDevice* dev)
+{
+ PedDisk* disk;
+ SunRawLabel* label;
+ SunDiskData* sun_specific;
+ const PedCHSGeometry* bios_geom = &dev->bios_geom;
+ PedSector cyl_size = bios_geom->sectors * bios_geom->heads;
+ PED_ASSERT (cyl_size != 0);
+
+ disk = _ped_disk_alloc (dev, &sun_disk_type);
+ if (!disk)
+ goto error;
+
+ disk->disk_specific = (SunDiskData*) ped_malloc (sizeof (SunDiskData));
+ if (!disk->disk_specific)
+ goto error_free_disk;
+ sun_specific = (SunDiskData*) disk->disk_specific;
+
+ PED_ASSERT (bios_geom->cylinders == (PedSector) (dev->length / cyl_size));
+ sun_specific->length = ped_round_down_to (dev->length, cyl_size);
+
+ label = &sun_specific->raw_label;
+ memset(label, 0, sizeof(SunRawLabel));
+
+ /* #gentoo-sparc people agree that nacyl = 0 is the best option */
+ label->magic = PED_CPU_TO_BE16 (SUN_DISK_MAGIC);
+ label->nacyl = 0;
+ label->pcylcount = PED_CPU_TO_BE16 (bios_geom->cylinders);
+ label->rspeed = PED_CPU_TO_BE16 (5400);
+ label->ilfact = PED_CPU_TO_BE16 (1);
+ label->sparecyl = 0;
+ label->ntrks = PED_CPU_TO_BE16 (bios_geom->heads);
+ label->nsect = PED_CPU_TO_BE16 (bios_geom->sectors);
+ label->ncyl = PED_CPU_TO_BE16 (dev->length / cyl_size);
+
+ label->sanity = PED_CPU_TO_BE32 (SUN_VTOC_SANITY);
+ label->version = PED_CPU_TO_BE32 (SUN_VTOC_VERSION);
+ label->nparts = PED_CPU_TO_BE16 (SUN_DISK_MAXPARTITIONS);
+
+ /* Add a whole disk partition at a minimum */
+ label->infos[WHOLE_DISK_PART].id = WHOLE_DISK_ID;
+ label->partitions[WHOLE_DISK_PART].start_cylinder = 0;
+ label->partitions[WHOLE_DISK_PART].num_sectors =
+ PED_CPU_TO_BE32(sun_specific->length);
+
+ /* Now a neato string to describe this label */
+ snprintf(label->info, sizeof(label->info) - 1,
+ "GNU Parted Custom cyl %d alt %d hd %d sec %d",
+ PED_BE16_TO_CPU(label->ncyl),
+ PED_BE16_TO_CPU(label->nacyl),
+ PED_BE16_TO_CPU(label->ntrks),
+ PED_BE16_TO_CPU(label->nsect));
+
+ sun_compute_checksum(label);
+ return disk;
+
+error_free_disk:
+ _ped_disk_free (disk);
+error:
+ return NULL;
+}
+
+static PedDisk*
+sun_duplicate (const PedDisk* disk)
+{
+ PedDisk* new_disk;
+ SunDiskData* new_sun_data;
+ SunDiskData* old_sun_data = (SunDiskData*) disk->disk_specific;
+
+ new_disk = ped_disk_new_fresh (disk->dev, &sun_disk_type);
+ if (!new_disk)
+ return NULL;
+
+ new_sun_data = (SunDiskData*) new_disk->disk_specific;
+ memcpy (new_sun_data, old_sun_data, sizeof (SunDiskData));
+ return new_disk;
+}
+
+static void
+sun_free (PedDisk *disk)
+{
+ free (disk->disk_specific);
+ _ped_disk_free (disk);
+}
+
+static int
+_check_geometry_sanity (PedDisk* disk, SunRawLabel* label)
+{
+ PedDevice* dev = disk->dev;
+
+ if (PED_BE16_TO_CPU(label->nsect) == dev->hw_geom.sectors &&
+ PED_BE16_TO_CPU(label->ntrks) == dev->hw_geom.heads)
+ dev->bios_geom = dev->hw_geom;
+
+ if (!!PED_BE16_TO_CPU(label->pcylcount)
+ * !!PED_BE16_TO_CPU(label->ntrks)
+ * !!PED_BE16_TO_CPU(label->nsect) == 0)
+ return 0;
+
+ if (PED_BE16_TO_CPU(label->nsect) != dev->bios_geom.sectors ||
+ PED_BE16_TO_CPU(label->ntrks) != dev->bios_geom.heads) {
+#ifndef DISCOVER_ONLY
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The disk CHS geometry (%d,%d,%d) reported "
+ "by the operating system does not match "
+ "the geometry stored on the disk label "
+ "(%d,%d,%d)."),
+ dev->bios_geom.cylinders,
+ dev->bios_geom.heads,
+ dev->bios_geom.sectors,
+ PED_BE16_TO_CPU(label->pcylcount),
+ PED_BE16_TO_CPU(label->ntrks),
+ PED_BE16_TO_CPU(label->nsect))
+ == PED_EXCEPTION_CANCEL)
+ return 0;
+#endif
+ dev->bios_geom.sectors = PED_BE16_TO_CPU(label->nsect);
+ dev->bios_geom.heads = PED_BE16_TO_CPU(label->ntrks);
+ dev->bios_geom.cylinders = PED_BE16_TO_CPU(label->pcylcount);
+
+ if (dev->bios_geom.sectors * dev->bios_geom.heads
+ * dev->bios_geom.cylinders > dev->length) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The disk label describes a disk bigger than "
+ "%s."),
+ dev->path)
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+sun_read (PedDisk* disk)
+{
+ SunPartitionData* sun_data;
+ SunDiskData* disk_data;
+ int i;
+ PedPartition* part;
+ PedSector end, start, block;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+
+ disk_data = (SunDiskData*) disk->disk_specific;
+
+ ped_disk_delete_all (disk);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ goto error;
+
+ SunRawLabel *label = &disk_data->raw_label;
+ verify (sizeof (*label) == 512);
+ memcpy (label, s0, sizeof (*label));
+ free (s0);
+
+ if (!_check_geometry_sanity (disk, label))
+ goto error;
+
+ block = disk->dev->bios_geom.sectors * disk->dev->bios_geom.heads;
+ disk_data->length = block * disk->dev->bios_geom.cylinders;
+
+ for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
+ if (!PED_BE32_TO_CPU(label->partitions[i].num_sectors))
+ continue;
+ if (!label->infos[i].id)
+ continue;
+ if (label->infos[i].id == WHOLE_DISK_ID)
+ continue;
+
+ start = PED_BE32_TO_CPU(label->partitions[i].start_cylinder)
+ * block;
+ end = start
+ + PED_BE32_TO_CPU(label->partitions[i].num_sectors) - 1;
+
+ part = ped_partition_new (disk, PED_PARTITION_NORMAL, NULL,
+ start, end);
+ if (!part)
+ goto error;
+
+ sun_data = part->disk_specific;
+ sun_data->type = label->infos[i].id;
+ sun_data->is_boot = sun_data->type == 0x1;
+ sun_data->is_root = sun_data->type == 0x2;
+ sun_data->is_lvm = sun_data->type == 0x8e;
+ sun_data->is_raid = sun_data->type == 0xfd;
+
+ part->num = i + 1;
+ part->fs_type = ped_file_system_probe (&part->geom);
+
+ PedConstraint *constraint_exact
+ = ped_constraint_exact (&part->geom);
+ if (constraint_exact == NULL)
+ goto error;
+ bool ok = ped_disk_add_partition (disk, part, constraint_exact);
+ ped_constraint_destroy (constraint_exact);
+ if (!ok)
+ goto error;
+ }
+
+ return 1;
+
+ error:
+ return 0;
+}
+
+#ifndef DISCOVER_ONLY
+static int
+_use_old_info (const PedDisk* disk, const void *sector_0)
+{
+ SunRawLabel const *old_label = sector_0;
+
+ if (old_label->info[0]
+ && PED_BE16_TO_CPU (old_label->magic) == SUN_DISK_MAGIC) {
+ SunDiskData *sun_specific = disk->disk_specific;
+ memcpy (&sun_specific->raw_label, sector_0,
+ sizeof (sun_specific->raw_label));
+ verify (sizeof (sun_specific->raw_label) == 512);
+ }
+
+ return 1;
+}
+
+static int
+sun_write (const PedDisk* disk)
+{
+ SunRawLabel* label;
+ SunPartitionData* sun_data;
+ SunDiskData* disk_data;
+ PedPartition* part;
+ int i;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ void *s0;
+ if (!ptt_read_sector (disk->dev, 0, &s0))
+ return 0;
+
+ /* Calling _use_old_info here in sun_write
+ above seems wrong, because it modifies *DISK.
+ FIXME: maybe later. */
+ if (!_use_old_info (disk, s0)) {
+ free (s0);
+ return 0;
+ }
+
+ disk_data = (SunDiskData*) disk->disk_specific;
+ label = &disk_data->raw_label;
+
+ memset (label->partitions, 0,
+ sizeof (SunRawPartition) * SUN_DISK_MAXPARTITIONS);
+ memset (label->infos, 0,
+ sizeof (SunPartitionInfo) * SUN_DISK_MAXPARTITIONS);
+
+ for (i = 0; i < SUN_DISK_MAXPARTITIONS; i++) {
+ part = ped_disk_get_partition (disk, i + 1);
+
+ if (!part && i == WHOLE_DISK_PART) {
+ /* Ok, nothing explicitly in the whole disk
+ partition, so let's put it there for safety
+ sake. */
+
+ label->infos[i].id = WHOLE_DISK_ID;
+ label->partitions[i].start_cylinder = 0;
+ label->partitions[i].num_sectors =
+ PED_CPU_TO_BE32(disk_data->length);
+ continue;
+ }
+ if (!part)
+ continue;
+
+ sun_data = part->disk_specific;
+ label->infos[i].id = sun_data->type;
+ label->partitions[i].start_cylinder
+ = PED_CPU_TO_BE32 (part->geom.start
+ / (disk->dev->bios_geom.sectors
+ * disk->dev->bios_geom.heads));
+ label->partitions[i].num_sectors
+ = PED_CPU_TO_BE32 (part->geom.end
+ - part->geom.start + 1);
+ }
+
+ /* We assume the harddrive is always right, and that the label may
+ be wrong. I don't think this will cause any problems, since the
+ cylinder count is always enforced by our alignment, and we
+ sanity checked the sectors/heads when we detected the device. The
+ worst that could happen here is that the drive seems bigger or
+ smaller than it really is, but we'll have that problem even if we
+ don't do this. */
+
+ if (disk->dev->bios_geom.cylinders > 65536) {
+ ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("The disk has %d cylinders, which is greater than "
+ "the maximum of 65536."),
+ disk->dev->bios_geom.cylinders);
+ }
+
+ label->pcylcount = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders);
+ label->ncyl = PED_CPU_TO_BE16 (disk->dev->bios_geom.cylinders
+ - PED_BE16_TO_CPU (label->nacyl));
+
+ sun_compute_checksum (label);
+
+ verify (sizeof *label == 512);
+ memcpy (s0, label, sizeof *label);
+ int write_ok = ped_device_write (disk->dev, s0, 0, 1);
+ free (s0);
+
+ if (write_ok)
+ return ped_device_sync (disk->dev);
+
+ return 0;
+}
+#endif /* !DISCOVER_ONLY */
+
+static PedPartition*
+sun_partition_new (const PedDisk* disk, PedPartitionType part_type,
+ const PedFileSystemType* fs_type,
+ PedSector start, PedSector end)
+{
+ PedPartition* part;
+ SunPartitionData* sun_data;
+
+ part = _ped_partition_alloc (disk, part_type, fs_type, start, end);
+ if (!part)
+ goto error;
+
+ if (ped_partition_is_active (part)) {
+ part->disk_specific
+ = sun_data = ped_malloc (sizeof (SunPartitionData));
+ if (!sun_data)
+ goto error_free_part;
+ sun_data->type = 0;
+ sun_data->is_boot = 0;
+ sun_data->is_root = 0;
+ sun_data->is_lvm = 0;
+ sun_data->is_raid = 0;
+ } else {
+ part->disk_specific = NULL;
+ }
+
+ return part;
+
+error_free_part:
+ free (part);
+error:
+ return NULL;
+}
+
+static PedPartition*
+sun_partition_duplicate (const PedPartition* part)
+{
+ PedPartition* new_part;
+ SunPartitionData* new_sun_data;
+ SunPartitionData* old_sun_data;
+
+ new_part = ped_partition_new (part->disk, part->type,
+ part->fs_type, part->geom.start,
+ part->geom.end);
+ if (!new_part)
+ return NULL;
+ new_part->num = part->num;
+
+ old_sun_data = (SunPartitionData*) part->disk_specific;
+ new_sun_data = (SunPartitionData*) new_part->disk_specific;
+ new_sun_data->type = old_sun_data->type;
+ new_sun_data->is_boot = old_sun_data->is_boot;
+ new_sun_data->is_root = old_sun_data->is_root;
+ new_sun_data->is_lvm = old_sun_data->is_lvm;
+ new_sun_data->is_raid = old_sun_data->is_raid;
+ return new_part;
+}
+
+static void
+sun_partition_destroy (PedPartition* part)
+{
+ PED_ASSERT (part != NULL);
+
+ if (ped_partition_is_active (part))
+ free (part->disk_specific);
+ free (part);
+}
+
+static int
+sun_partition_set_system (PedPartition* part, const PedFileSystemType* fs_type)
+{
+ SunPartitionData* sun_data = part->disk_specific;
+
+ part->fs_type = fs_type;
+
+ if (sun_data->is_boot) {
+ sun_data->type = 0x1;
+ return 1;
+ }
+ if (sun_data->is_root) {
+ sun_data->type = 0x2;
+ return 1;
+ }
+ if (sun_data->is_lvm) {
+ sun_data->type = 0x8e;
+ return 1;
+ }
+ if (sun_data->is_raid) {
+ sun_data->type = 0xfd;
+ return 1;
+ }
+
+ sun_data->type = 0x83;
+ if (fs_type) {
+ if (is_linux_swap (fs_type->name))
+ sun_data->type = 0x82;
+ else if (!strcmp (fs_type->name, "ufs"))
+ sun_data->type = 0x6;
+ }
+
+ return 1;
+}
+
+static int
+sun_partition_set_flag (PedPartition* part, PedPartitionFlag flag, int state)
+{
+ SunPartitionData* sun_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+ PED_ASSERT (ped_partition_is_flag_available (part, flag));
+
+ sun_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ sun_data->is_boot = state;
+ if (state) {
+ sun_data->is_lvm = 0;
+ sun_data->is_raid = 0;
+ sun_data->is_root = 0;
+ }
+ return ped_partition_set_system (part, part->fs_type);
+
+ case PED_PARTITION_ROOT:
+ sun_data->is_root = state;
+ if (state) {
+ sun_data->is_boot = 0;
+ sun_data->is_lvm = 0;
+ sun_data->is_raid = 0;
+ }
+ return ped_partition_set_system (part, part->fs_type);
+
+ case PED_PARTITION_LVM:
+ sun_data->is_lvm = state;
+ if (state) {
+ sun_data->is_boot = 0;
+ sun_data->is_raid = 0;
+ sun_data->is_root = 0;
+ }
+ return ped_partition_set_system (part, part->fs_type);
+
+ case PED_PARTITION_RAID:
+ sun_data->is_raid = state;
+ if (state) {
+ sun_data->is_boot = 0;
+ sun_data->is_lvm = 0;
+ sun_data->is_root = 0;
+ }
+ return ped_partition_set_system (part, part->fs_type);
+
+ default:
+ return 0;
+ }
+}
+
+
+static int _GL_ATTRIBUTE_PURE
+sun_partition_get_flag (const PedPartition* part, PedPartitionFlag flag)
+{
+ SunPartitionData* sun_data;
+
+ PED_ASSERT (part != NULL);
+ PED_ASSERT (part->disk_specific != NULL);
+
+ sun_data = part->disk_specific;
+
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ return sun_data->is_boot;
+ case PED_PARTITION_ROOT:
+ return sun_data->is_root;
+ case PED_PARTITION_LVM:
+ return sun_data->is_lvm;
+ case PED_PARTITION_RAID:
+ return sun_data->is_raid;
+
+ default:
+ return 0;
+ }
+}
+
+
+static int
+sun_partition_is_flag_available (const PedPartition* part,
+ PedPartitionFlag flag)
+{
+ switch (flag) {
+ case PED_PARTITION_BOOT:
+ case PED_PARTITION_ROOT:
+ case PED_PARTITION_LVM:
+ case PED_PARTITION_RAID:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static bool
+sun_get_max_supported_partition_count (const PedDisk* disk, int *max_n)
+{
+ *max_n = SUN_DISK_MAXPARTITIONS;
+ return true;
+}
+
+static int
+sun_get_max_primary_partition_count (const PedDisk* disk)
+{
+ return SUN_DISK_MAXPARTITIONS;
+}
+
+static PedAlignment*
+sun_get_partition_alignment(const PedDisk *disk)
+{
+ PedSector block =
+ disk->dev->hw_geom.sectors * disk->dev->hw_geom.heads;
+
+ return ped_alignment_new(0, block);
+}
+
+static PedConstraint*
+_get_strict_constraint (PedDisk* disk)
+{
+ PedDevice* dev = disk->dev;
+ PedAlignment start_align;
+ PedAlignment end_align;
+ PedGeometry max_geom;
+ SunDiskData* disk_data = disk->disk_specific;
+ PedSector block = dev->bios_geom.sectors * dev->bios_geom.heads;
+
+ if (!ped_alignment_init (&start_align, 0, block))
+ return NULL;
+ if (!ped_alignment_init (&end_align, -1, block))
+ return NULL;
+ if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length))
+ return NULL;
+
+ return ped_constraint_new (&start_align, &end_align, &max_geom,
+ &max_geom, 1, dev->length);
+}
+
+static PedConstraint*
+_get_lax_constraint (PedDisk* disk)
+{
+ PedDevice* dev = disk->dev;
+ PedAlignment start_align;
+ PedGeometry max_geom;
+ SunDiskData* disk_data = disk->disk_specific;
+ PedSector block = dev->bios_geom.sectors * dev->bios_geom.heads;
+
+ if (!ped_alignment_init (&start_align, 0, block))
+ return NULL;
+ if (!ped_geometry_init (&max_geom, dev, 0, disk_data->length))
+ return NULL;
+
+ return ped_constraint_new (&start_align, ped_alignment_any, &max_geom,
+ &max_geom, 1, dev->length);
+}
+
+/* _get_strict_constraint() will align the partition to the end of the cylinder.
+ * This isn't required, but since partitions must start at the start of the
+ * cylinder, space between the end of a partition and the end of a cylinder
+ * is unusable, so there's no point wasting space!
+ * However, if they really insist (via constraint)... which they will
+ * if they're reading a weird table of the disk... then we allow the end to
+ * be anywhere, with _get_lax_constraint()
+ */
+static int
+sun_partition_align (PedPartition* part, const PedConstraint* constraint)
+{
+ PED_ASSERT (part != NULL);
+
+ if (_ped_partition_attempt_align (part, constraint,
+ _get_strict_constraint (part->disk)))
+ return 1;
+ if (_ped_partition_attempt_align (part, constraint,
+ _get_lax_constraint (part->disk)))
+ return 1;
+
+#ifndef DISCOVER_ONLY
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Unable to satisfy all constraints on the partition."));
+#endif
+ return 0;
+}
+
+static int
+sun_partition_enumerate (PedPartition* part)
+{
+ int i;
+ PedPartition* p;
+
+ /* never change the partition numbers */
+ if (part->num != -1)
+ return 1;
+ for (i = 1; i <= SUN_DISK_MAXPARTITIONS; i++) {
+ /* skip the Whole Disk partition for now */
+ if (i == WHOLE_DISK_PART + 1)
+ continue;
+ p = ped_disk_get_partition (part->disk, i);
+ if (!p) {
+ part->num = i;
+ return 1;
+ }
+ }
+
+#ifndef DISCOVER_ONLY
+ /* Ok, now allocate the Whole disk if it isn't already */
+ p = ped_disk_get_partition (part->disk, WHOLE_DISK_PART + 1);
+ if (!p) {
+ int j = ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The Whole Disk partition is the only "
+ "available one left. Generally, it is not a "
+ "good idea to overwrite this partition with "
+ "a real one. Solaris may not be able to "
+ "boot without it, and SILO (the sparc boot "
+ "loader) appreciates it as well."));
+ if (j == PED_EXCEPTION_IGNORE) {
+ /* bad bad bad...you will suffer your own fate */
+ part->num = WHOLE_DISK_PART + 1;
+ return 1;
+ }
+ }
+
+ /* failed to allocate a number, this means we are full */
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Sun disk label is full."));
+#endif
+ return 0;
+}
+
+static int
+sun_alloc_metadata (PedDisk* disk)
+{
+ PedPartition* new_part;
+ SunDiskData* disk_data;
+ PedConstraint* constraint_any;
+
+ PED_ASSERT (disk != NULL);
+ PED_ASSERT (disk->disk_specific != NULL);
+ PED_ASSERT (disk->dev != NULL);
+
+ constraint_any = ped_constraint_any (disk->dev);
+
+ /* Sun disk label does not need to allocate a sector. The disk
+ label is contained within the first 512 bytes, which should not
+ be overwritten by any boot loader or superblock. It is safe for
+ most partitions to start at sector 0. We do however, allocate
+ the space used by alt-cyl's, since we cannot use those. Put them
+ at the end of the disk. */
+
+ disk_data = disk->disk_specific;
+
+ if (disk->dev->length <= 0 ||
+ disk_data->length <= 0 ||
+ disk->dev->length == disk_data->length)
+ goto error;
+
+ new_part = ped_partition_new (disk, PED_PARTITION_METADATA, NULL,
+ disk_data->length, disk->dev->length - 1);
+ if (!new_part)
+ goto error;
+
+ if (!ped_disk_add_partition (disk, new_part, constraint_any)) {
+ ped_partition_destroy (new_part);
+ goto error;
+ }
+
+ ped_constraint_destroy (constraint_any);
+ return 1;
+error:
+ ped_constraint_destroy (constraint_any);
+ return 0;
+}
+
+#include "pt-common.h"
+PT_define_limit_functions (sun)
+
+static PedDiskOps sun_disk_ops = {
+ clobber: NULL,
+ write: NULL_IF_DISCOVER_ONLY (sun_write),
+
+ get_partition_alignment: sun_get_partition_alignment,
+
+ partition_set_name: NULL,
+ partition_get_name: NULL,
+
+ PT_op_function_initializers (sun)
+};
+
+static PedDiskType sun_disk_type = {
+ next: NULL,
+ name: "sun",
+ ops: &sun_disk_ops,
+ features: 0
+};
+
+void
+ped_disk_sun_init ()
+{
+ PED_ASSERT (sizeof (SunRawLabel) == 512);
+ ped_disk_type_register (&sun_disk_type);
+}
+
+void
+ped_disk_sun_done ()
+{
+ ped_disk_type_unregister (&sun_disk_type);
+}
diff --git a/libparted/labels/vtoc.c b/libparted/labels/vtoc.c
new file mode 100644
index 0000000..d467164
--- /dev/null
+++ b/libparted/labels/vtoc.c
@@ -0,0 +1,1329 @@
+#include <config.h>
+#include <parted/vtoc.h>
+
+#ifdef DEBUG_DASD
+#define PDEBUG fprintf(stderr, "%s:%d:%s\n", \
+ __FILE__, \
+ __LINE__, \
+ __PRETTY_FUNCTION__);
+#else
+#define PDEBUG
+#endif
+
+#include <parted/parted.h>
+
+#include <libintl.h>
+#if ENABLE_NLS
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static const unsigned char EBCtoASC[256] =
+{
+/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
+ 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
+ 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+/* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC
+ -ENP ->LF */
+ 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+/* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB
+ -IUS */
+ 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC
+ -INP */
+ 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
+ -SW */
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
+ 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+/* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */
+ 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+/* 0x40 SP RSP ä ---- */
+ 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+/* 0x48 . < ( + | */
+ 0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+/* 0x50 & ---- */
+ 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+/* 0x58 ß ! $ * ) ; */
+ 0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+/* 0x60 - / ---- Ä ---- ---- ---- */
+ 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+/* 0x68 ---- , % _ > ? */
+ 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+/* 0x70 --- ---- ---- ---- ---- ---- ---- */
+ 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+/* 0x78 * ` : # @ ' = " */
+ 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+/* 0x80 * a b c d e f g */
+ 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/* 0x88 h i ---- ---- ---- */
+ 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+/* 0x90 ° j k l m n o p */
+ 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+/* 0x98 q r ---- ---- */
+ 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+/* 0xA0 ~ s t u v w x */
+ 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+/* 0xA8 y z ---- ---- ---- ---- */
+ 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+/* 0xB0 ^ ---- § ---- */
+ 0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+/* 0xB8 ---- [ ] ---- ---- ---- ---- */
+ 0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+/* 0xC0 { A B C D E F G */
+ 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+/* 0xC8 H I ---- ö ---- */
+ 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+/* 0xD0 } J K L M N O P */
+ 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+/* 0xD8 Q R ---- ü */
+ 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+/* 0xE0 \ S T U V W X */
+ 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+/* 0xE8 Y Z ---- Ö ---- ---- ---- */
+ 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+/* 0xF0 0 1 2 3 4 5 6 7 */
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+/* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */
+ 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+static const unsigned char ASCtoEBC[256] =
+{
+ /*00 NL SH SX EX ET NQ AK BL */
+ 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08 BS HT LF VT FF CR SO SI */
+ 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DL D1 D2 D3 D4 NK SN EB */
+ 0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+ /*18 CN EM SB EC FS GS RS US */
+ 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
+ /*20 SP ! " # $ % & ' */
+ 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28 ( ) * + , - . / */
+ 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30 0 1 2 3 4 5 6 7 */
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38 8 9 : ; < = > ? */
+ 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40 @ A B C D E F G */
+ 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48 H I J K L M N O */
+ 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50 P Q R S T U V W */
+ 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58 X Y Z [ \ ] ^ _ */
+ 0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
+ /*60 ` a b c d e f g */
+ 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68 h i j k l m n o */
+ 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70 p q r s t u v w */
+ 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78 x y z { | } ~ DL */
+ 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+enum failure {
+ unable_to_open,
+ unable_to_seek,
+ unable_to_write,
+ unable_to_read
+};
+
+static char buffer[93];
+
+static void
+vtoc_error (enum failure why, char const *s1, char const *s2)
+{
+ PDEBUG
+ char error[8192];
+
+ switch (why) {
+ case unable_to_open:
+ sprintf(error, "VTOC: %s -- %s\n%s\n",
+ _("opening of device failed"), s1, s2);
+ break;
+ case unable_to_seek:
+ sprintf(error, "VTOC: %s -- %s\n%s\n",
+ _("seeking on device failed"), s1, s2);
+ break;
+ case unable_to_write:
+ sprintf(error, "VTOC: %s -- %s\n%s\n",
+ _("writing to device failed"), s1, s2);
+ break;
+ case unable_to_read:
+ sprintf(error, "VTOC: %s -- %s\n%s\n",
+ _("reading from device failed"), s1, s2);
+ break;
+ default:
+ sprintf(error, "VTOC: %s\n", _("Fatal error"));
+ }
+
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, error);
+}
+
+char *
+vtoc_ebcdic_enc (char const *source, char *target, int l)
+{
+ PDEBUG
+ int i;
+
+ for (i = 0; i < l; i++)
+ target[i]=ASCtoEBC[(unsigned char)(source[i])];
+
+ return target;
+}
+
+char *
+vtoc_ebcdic_dec (char const *source, char *target, int l)
+{
+ PDEBUG
+ int i;
+
+ for (i = 0; i < l; i++)
+ target[i]=EBCtoASC[(unsigned char)(source[i])];
+
+ return target;
+}
+
+void
+vtoc_set_extent (extent_t *ext, u_int8_t typeind, u_int8_t seqno,
+ cchh_t *lower, cchh_t *upper)
+{
+ PDEBUG
+ ext->typeind = typeind;
+ ext->seqno = seqno;
+ memcpy(&ext->llimit,lower,sizeof(cchh_t));
+ memcpy(&ext->ulimit,upper,sizeof(cchh_t));
+}
+
+void
+vtoc_set_cchh (cchh_t *addr, u_int32_t cc, u_int16_t hh)
+{
+ PDEBUG
+ addr->cc = (u_int16_t) cc;
+ addr->hh = cc >> 16;
+ addr->hh <<= 4;
+ addr->hh |= hh;
+}
+
+u_int32_t
+vtoc_get_cyl_from_cchh (cchh_t *addr)
+{
+ u_int32_t cyl;
+
+ /*decode cylinder for large volumes */
+ cyl = addr->hh & 0xFFF0;
+ cyl <<= 12;
+ cyl |= addr->cc;
+ return cyl;
+}
+
+u_int16_t
+vtoc_get_head_from_cchh (cchh_t *addr)
+{
+ /* decode heads for large volumes */
+ return addr->hh & 0x000F;
+}
+
+static void
+vtoc_set_ttr (ttr_t *addr, u_int16_t tt, u_int8_t r)
+{
+ PDEBUG
+ addr->tt = tt;
+ addr->r = r;
+}
+
+void
+vtoc_set_cchhb (cchhb_t *addr, u_int32_t cc, u_int16_t hh, u_int8_t b)
+{
+ PDEBUG
+ addr->cc = (u_int16_t) cc;
+ addr->hh = cc >> 16;
+ addr->hh <<= 4;
+ addr->hh |= hh;
+ addr->b = b;
+}
+
+u_int32_t
+vtoc_get_cyl_from_cchhb(cchhb_t *addr)
+{
+ u_int32_t cyl;
+
+ /* decode cylinder for large volumes */
+ cyl = addr->hh & 0xFFF0;
+ cyl <<= 12;
+ cyl |= addr->cc;
+ return cyl;
+}
+
+u_int16_t
+vtoc_get_head_from_cchhb(cchhb_t *addr)
+{
+ /* decode heads for large volumes */
+ return addr->hh & 0x000F;
+}
+
+/*
+ * some functions to convert cyl-cyl-head-head addresses to
+ * block or track numbers
+ * Note: Record zero is special, so first block on a track is
+ * in record 1!
+ */
+u_int64_t
+cchhb2blk (cchhb_t *p, struct fdasd_hd_geometry *geo)
+{
+ return (u_int64_t) vtoc_get_cyl_from_cchhb(p) *
+ geo->heads * geo->sectors +
+ vtoc_get_head_from_cchhb(p) * geo->sectors +
+ p->b;
+}
+
+u_int64_t
+cchh2blk (cchh_t *p, struct fdasd_hd_geometry *geo)
+{
+ return (u_int64_t) vtoc_get_cyl_from_cchh(p) *
+ geo->heads * geo->sectors +
+ vtoc_get_head_from_cchh(p) * geo->sectors;
+}
+
+u_int32_t
+cchh2trk (cchh_t *p, struct fdasd_hd_geometry *geo)
+{
+ return vtoc_get_cyl_from_cchh(p) * geo->heads +
+ vtoc_get_head_from_cchh(p);
+}
+
+void
+vtoc_set_date (labeldate_t * d, u_int8_t year, u_int16_t day)
+{
+ PDEBUG
+ d->year = year;
+ d->day = day;
+}
+
+/*
+ * initializes the volume label with EBCDIC spaces
+ */
+void
+vtoc_volume_label_init (volume_label_t *vlabel)
+{
+ PDEBUG
+ sprintf(buffer, "%92s", " ");
+ vtoc_ebcdic_enc(buffer, buffer, sizeof *vlabel);
+ memcpy(vlabel, buffer, sizeof *vlabel);
+}
+
+/*
+ * reads the volume label from dasd
+ */
+int
+vtoc_read_volume_label (int f, unsigned long vlabel_start,
+ volume_label_t *vlabel)
+{
+
+ char str[5];
+ unsigned long block_zero;
+ typedef struct bogus_label bogus_label_t;
+ typedef union vollabel vollabel_t;
+
+ union __attribute__((packed)) vollabel {
+ /* cdl and ldl have the same data struct */
+ volume_label_t cdl;
+ cms_volume_label_t cms;
+ };
+
+ struct __attribute__((packed)) bogus_label {
+ char overhead[512];
+ vollabel_t actual_label;
+ };
+
+ bogus_label_t mybogus;
+ bogus_label_t *bogus_ptr = &mybogus;
+ vollabel_t *union_ptr = &bogus_ptr->actual_label;
+ volume_label_t *cdl_ptr = &union_ptr->cdl;
+
+ PDEBUG
+ int rc;
+
+ if (lseek(f, vlabel_start, SEEK_SET) == -1) {
+ vtoc_error(unable_to_seek, "vtoc_read_volume_label",
+ _("Could not read volume label."));
+ return 1;
+ }
+
+ rc = read(f, vlabel, sizeof(volume_label_t));
+ if (rc != sizeof(volume_label_t)) {
+ vtoc_error(unable_to_read, "vtoc_read_volume_label",
+ _("Could not read volume label."));
+ return 1;
+ }
+
+ if (strncmp(vlabel->volkey, vtoc_ebcdic_enc("VOL1", str, 4), 4) == 0
+ || strncmp(vlabel->volkey, vtoc_ebcdic_enc("LNX1", str, 4), 4) == 0
+ || strncmp(vlabel->volkey, vtoc_ebcdic_enc("CMS1", str, 4), 4) == 0)
+ return 0;
+
+ /*
+ If we didn't find a valid volume label, there is a special case
+ we must try before we give up. For a CMS-formatted disk on FBA
+ DASD using the DIAG driver and a block size greater than 512, we
+ must read the block at offset 0, then look for a label within
+ that block at offset 512.
+ */
+
+ block_zero = 0;
+
+ if (lseek(f, block_zero, SEEK_SET) == -1) {
+ vtoc_error(unable_to_seek, "vtoc_read_volume_label",
+ _("Could not read volume label."));
+ return 1;
+ }
+
+ rc = read(f, bogus_ptr, sizeof(bogus_label_t));
+ if (rc != sizeof(bogus_label_t)) {
+ vtoc_error(unable_to_read, "vtoc_read_volume_label",
+ _("Could not read volume label."));
+ return 1;
+ }
+
+ memcpy(vlabel, cdl_ptr, sizeof *vlabel);
+ return 0;
+}
+
+/*
+ * writes the volume label to dasd
+ */
+int
+vtoc_write_volume_label (int f, unsigned long vlabel_start,
+ volume_label_t const *vlabel)
+{
+ PDEBUG
+ int rc;
+
+ if (lseek(f, vlabel_start, SEEK_SET) == -1)
+ vtoc_error(unable_to_seek, "vtoc_write_volume_label",
+ _("Could not write volume label."));
+
+ rc = write(f, vlabel, sizeof(volume_label_t));
+ if (rc != sizeof(volume_label_t))
+ vtoc_error(unable_to_write, "vtoc_write_volume_label",
+ _("Could not write volume label."));
+
+ return 0;
+}
+
+/*
+ * takes a string as input, converts it to uppercase, translates
+ * it to EBCDIC and fills it up with spaces before it copies it
+ * as volume serial to the volume label
+ */
+void
+vtoc_volume_label_set_volser (volume_label_t *vlabel, char const *volser)
+{
+ PDEBUG
+ int j, i = strlen(volser);
+ char s[VOLSER_LENGTH + 1];
+
+ strcpy(s, " ");
+ vtoc_ebcdic_enc(s, s, VOLSER_LENGTH);
+ strncpy(vlabel->volid, s, VOLSER_LENGTH);
+
+ if (i > VOLSER_LENGTH)
+ i = VOLSER_LENGTH;
+
+ strncpy(s, volser, i);
+ for (j=0; j<i; j++)
+ s[j] = toupper(s[j]);
+
+ s[VOLSER_LENGTH] = 0x00;
+ vtoc_ebcdic_enc(s, s, i);
+ strncpy(vlabel->volid, s, i);
+
+ return;
+}
+
+/*
+ * returns the volume serial number right after it is translated
+ * to ASCII
+ */
+char *
+vtoc_volume_label_get_volser (volume_label_t *vlabel, char *volser)
+{
+ PDEBUG
+ vtoc_ebcdic_dec(vlabel->volid, volser, VOLSER_LENGTH);
+
+ return volser;
+}
+
+/*
+ * sets the volume label key right after
+ * it has been translated to EBCDIC
+ */
+void
+vtoc_volume_label_set_key (volume_label_t *vlabel, char const *key)
+{
+ PDEBUG
+ char s[4];
+
+ vtoc_ebcdic_enc(key, s, 4);
+ strncpy(vlabel->volkey, s, 4);
+
+ return;
+}
+
+/*
+ * sets the volume label identifier right
+ * after it has been translated to EBCDIC
+ */
+void
+vtoc_volume_label_set_label (volume_label_t *vlabel, char const *lbl)
+{
+ PDEBUG
+ char s[4];
+
+ vtoc_ebcdic_enc(lbl, s, 4);
+ strncpy(vlabel->vollbl, s, 4);
+
+ return;
+}
+
+/*
+ * returns the volume label key = the label identifier
+ * right after it has been translated to ASCII
+ */
+char *
+vtoc_volume_label_get_label (volume_label_t *vlabel, char *lbl)
+{
+ PDEBUG
+ vtoc_ebcdic_dec(vlabel->vollbl, lbl, 4);
+
+ return lbl;
+}
+
+/*
+ * reads either a format4 label or a format1 label
+ * from the specified position
+ */
+void
+vtoc_read_label (int f, unsigned long position, format1_label_t *f1,
+ format4_label_t *f4, format5_label_t *f5, format7_label_t *f7)
+{
+ PDEBUG
+ int t;
+
+ if (lseek(f, position, SEEK_SET) == -1)
+ vtoc_error(unable_to_seek, "vtoc_read_label",
+ _("Could not read VTOC labels."));
+
+ if (f1 != NULL) {
+ t = sizeof(format1_label_t);
+ if (read(f, f1, t) != t)
+ vtoc_error(unable_to_read, "vtoc_read_label",
+ _("Could not read VTOC FMT1 DSCB."));
+ }
+
+ if (f4 != NULL) {
+ t = sizeof(format4_label_t);
+ if (read(f, f4, t) != t)
+ vtoc_error(unable_to_read, "vtoc_read_label",
+ _("Could not read VTOC FMT4 DSCB."));
+ }
+
+ if (f5 != NULL) {
+ t = sizeof(format5_label_t);
+ if (read(f, f5, t) != t)
+ vtoc_error(unable_to_read, "vtoc_read_label",
+ _("Could not read VTOC FMT5 DSCB."));
+ }
+
+ if (f7 != NULL) {
+ t = sizeof(format7_label_t);
+ if (read(f, f7, t) != t)
+ vtoc_error(unable_to_read, "vtoc_read_label",
+ _("Could not read VTOC FMT7 DSCB."));
+ }
+}
+
+/*
+ * writes either a FMT1, FMT4 or FMT5 label
+ * to the specified position
+ */
+void
+vtoc_write_label (int f, unsigned long position,
+ format1_label_t const *f1,
+ format4_label_t const *f4,
+ format5_label_t const *f5,
+ format7_label_t const *f7,
+ format9_label_t const *f9)
+{
+ PDEBUG
+ int t;
+
+ if (lseek(f, position, SEEK_SET) == -1)
+ vtoc_error(unable_to_seek, "vtoc_write_label",
+ _("Could not write VTOC labels."));
+
+ if (f1 != NULL) {
+ t = sizeof(format1_label_t);
+ if (write(f, f1, t) != t)
+ vtoc_error(unable_to_write, "vtoc_write_label",
+ _("Could not write VTOC FMT1 DSCB."));
+ }
+
+ if (f4 != NULL) {
+ t = sizeof(format4_label_t);
+ if (write(f, f4, t) != t)
+ vtoc_error(unable_to_write, "vtoc_write_label",
+ _("Could not write VTOC FMT4 DSCB."));
+ }
+
+ if (f5 != NULL) {
+ t = sizeof(format5_label_t);
+ if (write(f, f5, t) != t)
+ vtoc_error(unable_to_write, "vtoc_write_label",
+ _("Could not write VTOC FMT5 DSCB."));
+ }
+
+ if (f7 != NULL) {
+ t = sizeof(format7_label_t);
+ if (write(f, f7, t) != t)
+ vtoc_error(unable_to_write, "vtoc_write_label",
+ _("Could not write VTOC FMT7 DSCB."));
+ }
+
+ if (f9 != NULL)
+ {
+ t = sizeof(format9_label_t);
+ if (write(f, f9, t) != t)
+ {
+ close(f);
+ vtoc_error(unable_to_write, "vtoc_write_label",
+ _("Could not write VTOC FMT9 DSCB."));
+ }
+ }
+}
+
+/*
+ * initializes a format4 label
+ */
+void
+vtoc_init_format4_label (format4_label_t *f4,
+ unsigned int compat_cylinders,
+ unsigned int real_cylinders, unsigned int tracks,
+ unsigned int blocks, unsigned int blksize,
+ u_int16_t dev_type)
+{
+ PDEBUG
+ int i;
+
+ cchh_t lower = {VTOC_START_CC, VTOC_START_HH};
+ cchh_t upper = {VTOC_START_CC, VTOC_START_HH};
+
+ for (i=0; i<44; i++) f4->DS4KEYCD[i] = 0x04;
+ f4->DS4IDFMT = 0xf4;
+
+ vtoc_set_cchhb(&f4->DS4HPCHR, 0x0000, 0x0000, 0x00);
+ f4->DS4DSREC = blocks - 2;
+ /* free space starts right behind VTOC
+ vtoc_set_cchh(&f4->DS4HCCHH, VTOC_START_CC, VTOC_START_HH + 1);*/
+ vtoc_set_cchh(&f4->DS4HCCHH, 0x0000, 0x0000);
+ f4->DS4NOATK = 0x0000;
+ f4->DS4VTOCI = 0x00;
+ f4->DS4NOEXT = 0x01;
+ f4->DS4SMSFG = 0x00;
+ f4->DS4DEVAC = 0x00;
+
+ /* -- begin f4->DS4DEVCT -- */
+ f4->DS4DEVCT.DS4DSCYL = compat_cylinders;
+ f4->DS4DEVCT.DS4DSTRK = tracks;
+
+ switch (dev_type) {
+ case DASD_3380_TYPE:
+ f4->DS4DEVCT.DS4DEVTK = DASD_3380_VALUE;
+ break;
+ case DASD_3390_TYPE:
+ f4->DS4DEVCT.DS4DEVTK = DASD_3390_VALUE;
+ break;
+ case DASD_9345_TYPE:
+ f4->DS4DEVCT.DS4DEVTK = DASD_9345_VALUE;
+ break;
+ default:
+ f4->DS4DEVCT.DS4DEVTK = blocks * blksize;
+ }
+
+ f4->DS4DEVCT.DS4DEVI = 0x00;
+ f4->DS4DEVCT.DS4DEVL = 0x00;
+ f4->DS4DEVCT.DS4DEVK = 0x00;
+ f4->DS4DEVCT.DS4DEVFG = 0x30;
+ f4->DS4DEVCT.DS4DEVTL = 0x0000;
+ f4->DS4DEVCT.DS4DEVDT = blocks;
+ f4->DS4DEVCT.DS4DEVDB = 0x00;
+ /* -- end f4->DS4DEVCT -- */
+
+ bzero(f4->DS4AMTIM, sizeof(f4->DS4AMTIM));
+ bzero(f4->DS4AMCAT, sizeof(f4->DS4AMCAT));
+ bzero(f4->DS4R2TIM, sizeof(f4->DS4R2TIM));
+ bzero(f4->res1, sizeof(f4->res1));
+ bzero(f4->DS4F6PTR, sizeof(f4->DS4F6PTR));
+
+ /* -- begin f4lbl->DS4VTOCE -- */
+ vtoc_set_extent(&f4->DS4VTOCE, 0x01, 0x00, &lower, &upper);
+ /* -- end f4lbl->DS4VTOCE -- */
+
+ bzero(f4->res2, sizeof(f4->res2));
+ f4->DS4EFLVL = 0x00;
+ bzero(&f4->DS4EFPTR, sizeof(f4->DS4EFPTR));
+ bzero(&f4->res3, sizeof(f4->res3));
+ f4->DS4DCYL = real_cylinders;
+ bzero(f4->res4, sizeof(f4->res4));
+ f4->DS4DEVF2 = 0x40; /* allow format 8 and 9 labels */
+ bzero(&f4->res5, sizeof(f4->res5));
+}
+
+/*
+ * initializes a format5 label
+ */
+void
+vtoc_init_format5_label (format5_label_t *f5)
+{
+ PDEBUG
+ int i;
+
+ bzero(f5, sizeof(format5_label_t));
+ for (i=0; i<4; i++)
+ f5->DS5KEYID[i] = 0x05;
+ f5->DS5FMTID = 0xf5;
+}
+
+/*
+ * initializes a format7 label
+ */
+void
+vtoc_init_format7_label (format7_label_t *f7)
+{
+ PDEBUG
+ int i;
+
+ bzero(f7, sizeof(format7_label_t));
+ for (i=0; i<4; i++)
+ f7->DS7KEYID[i] = 0x07;
+ f7->DS7FMTID = 0xf7;
+}
+
+/*
+ * helper function that initializes a most parts of a
+ * format1 or format 8 label, all but the field DS1FMTID
+ */
+void
+vtoc_init_format_1_8_label (unsigned int blksize,
+ extent_t *part_extent, format1_label_t *f1)
+{
+ PDEBUG
+ struct tm * creatime;
+ time_t t;
+ char str[80];
+
+ /* get actual date */
+ t = time(NULL);
+ creatime = gmtime(&t);
+
+ bzero(f1->DS1DSNAM, sizeof(f1->DS1DSNAM));
+ sprintf(str, "PART .NEW ");
+ vtoc_ebcdic_enc(str, str, 44);
+ strncpy(f1->DS1DSNAM, str, 44);
+ strncpy(f1->DS1DSSN, " ", 6);
+ f1->DS1VOLSQ = 0x0001;
+
+ vtoc_set_date(&f1->DS1CREDT, (u_int8_t) creatime->tm_year,
+ (u_int16_t) creatime->tm_yday);
+ /* expires never - 99 365 */
+ vtoc_set_date(&f1->DS1EXPDT, 0x63, 0x016D);
+ f1->DS1NOEPV = 0x01;
+ f1->DS1NOBDB = 0x00;
+ f1->DS1FLAG1 = 0x00;
+ vtoc_ebcdic_enc("IBM LINUX ", str, 13);
+ strncpy(f1->DS1SYSCD, str, 13);
+ vtoc_set_date(&f1->DS1REFD, (u_int8_t) creatime->tm_year,
+ (u_int16_t) creatime->tm_yday);
+ f1->DS1SMSFG = 0x00;
+ f1->DS1SCXTF = 0x00;
+ f1->DS1SCXTV = 0x0000;
+ f1->DS1DSRG1 = 0x00;
+ f1->DS1DSRG2 = 0x00;
+ f1->DS1RECFM = 0x88;
+ f1->DS1OPTCD = 0x00;
+ f1->DS1BLKL = blksize;
+ f1->DS1LRECL = blksize;
+ f1->DS1KEYL = 0x00;
+ f1->DS1RKP = 0x0000;
+ f1->DS1DSIND = 0x80; /* last volume for this dataset */
+ f1->DS1SCAL1 = 0x80;
+ bzero(&f1->DS1SCAL3, sizeof(f1->DS1SCAL3));
+ vtoc_set_ttr(&f1->DS1LSTAR, 0x0000, 0x00);
+ f1->DS1TRBAL = 0x00;
+ bzero(&f1->res1, sizeof(f1->res1));
+ memcpy(&f1->DS1EXT1, part_extent, sizeof(extent_t));
+ bzero(&f1->DS1EXT2, sizeof(extent_t));
+ bzero(&f1->DS1EXT3, sizeof(extent_t));
+ vtoc_set_cchhb(&f1->DS1PTRDS, 0x0000, 0x0000, 0x00);
+}
+
+void
+vtoc_init_format1_label (unsigned int blksize,
+ extent_t *part_extent, format1_label_t *f1)
+{
+ vtoc_init_format_1_8_label(blksize, part_extent, f1);
+ f1->DS1FMTID = 0xf1;
+}
+
+void
+vtoc_init_format8_label (unsigned int blksize,
+ extent_t *part_extent, format1_label_t *f8)
+{
+ vtoc_init_format_1_8_label(blksize, part_extent, f8);
+ f8->DS1FMTID = 0xf8;
+}
+
+void
+vtoc_update_format8_label (cchhb_t *associated_f9, format1_label_t *f8)
+{
+ memcpy(&f8->DS1PTRDS, associated_f9, sizeof(*associated_f9));
+}
+
+void
+vtoc_init_format9_label (format9_label_t *f9)
+{
+ f9->DS9KEYID = 0x09;
+ f9->DS9SUBTY = 0x01;
+ f9->DS9NUMF9 = 1;
+ f9->DS9FMTID = 0xf9;
+}
+
+/*
+ * do some updates to the VTOC format4 label
+ */
+void
+vtoc_update_format4_label (format4_label_t *f4, cchhb_t *highest_f1,
+ u_int16_t unused_update)
+{
+ PDEBUG
+ /* update highest address of a format 1 label */
+ memcpy(&f4->DS4HPCHR, highest_f1, sizeof(cchhb_t));
+
+ /* update unused DSCB count */
+ f4->DS4DSREC = unused_update;
+}
+
+/*
+ * reorganizes all extents within a FMT5 label
+ */
+static void
+vtoc_reorganize_FMT5_extents (format5_label_t *f5)
+{
+ PDEBUG
+ ds5ext_t *ext, *last, tmp;
+ int i, j;
+
+ for (i=0; i<26; i++) {
+ if (i==0)
+ last = &f5->DS5AVEXT;
+ else if ((i > 0) && (i < 8))
+ last = &f5->DS5EXTAV[i-1];
+ else
+ last = &f5->DS5MAVET[i-8];
+
+ for (j=i; j<26; j++) {
+ if (j==0)
+ ext = &f5->DS5AVEXT;
+ else if ((j > 0) && (j < 8))
+ ext = &f5->DS5EXTAV[j-1];
+ else
+ ext = &f5->DS5MAVET[j-8];
+
+ if (((ext->t > 0) && (last->t == 0)) ||
+ ((ext->t > 0) && (ext->t < last->t)))
+ {
+ tmp.t = last->t;
+ tmp.fc = last->fc;
+ tmp.ft = last->ft;
+ last->t = ext->t;
+ last->fc = ext->fc;
+ last->ft = ext->ft;
+ ext->t = tmp.t;
+ ext->fc = tmp.fc;
+ ext->ft = tmp.ft;
+ }
+ }
+ }
+}
+
+/*
+ * add a free space extent description to the VTOC FMT5 DSCB
+ */
+void
+vtoc_update_format5_label_add (format5_label_t *f5, int verbose,
+ int trk, u_int16_t a, u_int16_t b, u_int8_t c)
+{
+ PDEBUG
+ ds5ext_t *ext = NULL, *tmp = NULL;
+ int i;
+
+ for (i=0; i<26; i++) {
+ if (i==0)
+ ext = &f5->DS5AVEXT;
+ else if ((i > 0) && (i < 8))
+ ext = &f5->DS5EXTAV[i-1];
+ else
+ ext = &f5->DS5MAVET[i-8];
+
+ if (((a < ext->t) && (a + b*trk + c > ext->t)) ||
+ ((a > ext->t) && (ext->t + ext->fc*trk + ext->ft > a)))
+ {
+ puts ("BUG: overlapping free space extents "
+ "in FMT5 DSCB!\nexiting...");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((ext->t + ext->fc + ext->ft) == 0x0000) {
+ ext->t = a;
+ ext->fc = b;
+ ext->ft = c;
+ tmp = ext;
+ if (verbose)
+ puts ("FMT5 add extent: add new extent");
+ break;
+ }
+ }
+
+ if (tmp == NULL) {
+ /* BUG: no free extent found */
+ puts ("BUG: no free FMT5 DSCB extent found!\nexiting...");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i=0; i<26; i++) {
+ if (i==0)
+ ext = &f5->DS5AVEXT;
+ else if ((i > 0) && (i < 8))
+ ext = &f5->DS5EXTAV[i-1];
+ else
+ ext = &f5->DS5MAVET[i-8];
+
+ if ((ext->t + ext->fc + ext->ft) == 0x0000)
+ continue;
+
+ if ((ext->t + ext->fc*trk + ext->ft) == tmp->t) {
+ /* this extent precedes the new one */
+ ext->fc += (tmp->fc + (tmp->ft + ext->ft)/trk);
+ ext->ft = (tmp->ft + ext->ft) % trk;
+ bzero(tmp, sizeof(ds5ext_t));
+ tmp = ext;
+
+ if (verbose)
+ puts ("FMT5 add extent: "
+ "merge with predecessor");
+
+ i = -1;
+ continue;
+ }
+
+ if ((tmp->t + tmp->fc*trk + tmp->ft) == ext->t) {
+ /* this extent succeeds the new one */
+ ext->t = tmp->t;
+ ext->fc += (tmp->fc + (tmp->ft + ext->ft)/trk);
+ ext->ft = (tmp->ft + ext->ft) % trk;
+ bzero(tmp, sizeof(ds5ext_t));
+ tmp = ext;
+
+ if (verbose)
+ puts ("FMT5 add extent: "
+ "merge with successor");
+
+ i = -1;
+ continue;
+ }
+ }
+}
+
+/*
+ * remove a free space extent description from the VTOC FMT5 DSCB
+ */
+void
+vtoc_update_format5_label_del (format5_label_t *f5, int verbose,
+ int trk, u_int16_t a, u_int16_t b, u_int8_t c)
+{
+ PDEBUG
+ ds5ext_t *ext;
+ int i, counter=0;
+
+ for (i=0; i<26; i++) {
+ if (i==0)
+ ext = &f5->DS5AVEXT;
+ else if ((i > 0) && (i < 8))
+ ext = &f5->DS5EXTAV[i-1];
+ else
+ ext = &f5->DS5MAVET[i-8];
+
+ if ((a == ext->t) && (b == ext->fc) && (c == ext->ft)) {
+ /* fills up whole free space gap */
+ bzero(ext, sizeof(ds5ext_t));
+
+ if (verbose)
+ puts ("FMT5 del extent: fills whole gap");
+
+ counter++;
+ break;
+ }
+
+ if ((a == ext->t) && ((b < ext->fc) || (c < ext->ft))) {
+ /* left-bounded in free space gap */
+ ext->t = ext->t + b*trk + c;
+
+ if (c > ext->ft) {
+ ext->fc -= (b + 1);
+ ext->ft -= (c - trk);
+ } else {
+ ext->fc -= b;
+ ext->ft -= c;
+ }
+
+ if (verbose)
+ puts ("FMT5 del extent: left bounded");
+
+ counter++;
+ break;
+ }
+
+ if ((ext->t < a)
+ && ((ext->t + ext->fc*trk + ext->ft) == (a + b*trk + c)))
+ {
+ /* right-bounded in free space gap */
+ if (c > ext->ft) {
+ ext->fc -= (b + 1);
+ ext->ft -= (c - trk);
+ } else {
+ ext->fc -= b;
+ ext->ft -= c;
+ }
+
+ if (verbose)
+ puts ("FMT5 del extent: right bounded");
+
+ counter++;
+ break;
+ }
+
+ if ((a > ext->t)
+ && ((ext->t + ext->fc*trk + ext->ft) > (a + b*trk + c)))
+ {
+ /* partition devides free space into 2 pieces */
+ u_int16_t x = a + b*trk + c;
+ u_int16_t w,y;
+ u_int8_t z;
+
+ w = (ext->t + ext->fc*trk + ext->ft) - (a + b*trk + c);
+ y = w / trk;
+ z = w % trk;
+
+ ext->fc = (a - ext->t) / trk;
+ ext->ft = (a - ext->t) % trk;
+
+ vtoc_update_format5_label_add(f5, verbose,
+ trk, x, y, z);
+
+ if (verbose)
+ puts ("FMT5 del extent: 2 pieces");
+
+ counter++;
+ break;
+ }
+
+ if ((a < ext->t) && (a + b*trk + c > ext->t)
+ && (a + b*trk + c < ext->t + ext->fc*trk + ext->ft))
+ {
+ puts ("BUG: corresponding free space extent "
+ "doesn't match free space currently shown "
+ "in FMT5 DSCB!\nexiting...");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((a > ext->t) && (a < ext->t + ext->fc*trk + ext->ft)
+ && (a + b*trk + c > ext->t + ext->fc*trk + ext->ft))
+ {
+ puts ("BUG: specified free space extent for "
+ "deleting doesn't match free space "
+ "currently shown in FMT5 DSCB!\n"
+ "exiting...");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (counter > 0)
+ return;
+
+ puts ("BUG: specified free space extent for "
+ "deleting not found in FMT5 DSCB!\n"
+ "exiting...");
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * reorganizes all extents within a FMT7 label
+ */
+static void
+vtoc_reorganize_FMT7_extents (format7_label_t *f7)
+{
+ PDEBUG
+ ds7ext_t *ext, *last, tmp;
+ int i, j;
+
+ for (i=0; i<16; i++) {
+ if (i<5)
+ last = &f7->DS7EXTNT[i];
+ else
+ last = &f7->DS7ADEXT[i-5];
+
+ for (j=i; j<16; j++) {
+ if (j<5)
+ ext = &f7->DS7EXTNT[j];
+ else
+ ext = &f7->DS7ADEXT[j-5];
+
+ if (((ext->a > 0) && (last->a == 0))
+ || ((ext->a > 0) && (ext->a < last->a)))
+ {
+ tmp.a = last->a;
+ tmp.b = last->b;
+ last->a = ext->a;
+ last->b = ext->b;
+ ext->a = tmp.a;
+ ext->b = tmp.b;
+ }
+ }
+ }
+}
+
+/*
+ * add a free space extent description to the VTOC FMT7 DSCB
+ */
+void
+vtoc_update_format7_label_add (format7_label_t *f7, int verbose,
+ u_int32_t a, u_int32_t b)
+{
+ PDEBUG
+ ds7ext_t *ext = NULL, *tmp = NULL;
+ int i;
+
+ for (i=0; i<16; i++) {
+ if (i<5)
+ ext = &f7->DS7EXTNT[i];
+ else
+ ext = &f7->DS7ADEXT[i-5];
+
+ if (((a < ext->a) && (b > ext->a) && (b < ext->b))
+ || ((a > ext->a) && (a < ext->b) && (b > ext->b)))
+ {
+ puts ("BUG: overlapping free space extents "
+ "in FMT7 DSCB!\nexiting...");
+ exit(EXIT_FAILURE);
+ }
+
+ if ((ext->a + ext->b) == 0x00000000) {
+ ext->a = a;
+ ext->b = b;
+ tmp = ext;
+
+ if (verbose)
+ puts ("FMT7 add extent: add new extent");
+
+ break;
+ }
+ }
+
+ if (tmp == NULL) {
+ /* BUG: no free extent found */
+ puts ("BUG: no free FMT7 DSCB extent found!\nexiting...");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i=0; i<16; i++) {
+ if (i<5)
+ ext = &f7->DS7EXTNT[i];
+ else
+ ext = &f7->DS7ADEXT[i-5];
+
+ if ((ext->a + ext->b) == 0x00000000)
+ continue;
+
+ if (ext->b == tmp->a) {
+ /* this extent precedes the new one */
+ ext->b = tmp->b;
+ bzero(tmp, sizeof(ds7ext_t));
+ tmp = ext;
+
+ if (verbose)
+ puts ("FMT7 add extent: "
+ "merge with predecessor");
+
+ i = -1;
+ continue;
+ }
+
+ if (ext->a == tmp->b) {
+ /* this extent succeeds the new one */
+ ext->a = tmp->a;
+ bzero(tmp, sizeof(ds7ext_t));
+ tmp = ext;
+
+ if (verbose)
+ puts ("FMT7 add extent: merge with successor");
+
+ i = -1;
+ continue;
+ }
+ }
+}
+
+/*
+ * remove a free space extent description from the VTOC FMT7 DSCB
+ */
+void
+vtoc_update_format7_label_del (format7_label_t *f7, int verbose,
+ u_int32_t a, u_int32_t b)
+{
+ PDEBUG
+ ds7ext_t *ext;
+ int i, counter=0;
+
+ for (i=0; i<16; i++) {
+ if (i<5)
+ ext = &f7->DS7EXTNT[i];
+ else
+ ext = &f7->DS7ADEXT[i-5];
+
+ if ((a == ext->a) && (b == ext->b)) {
+ /* fills up whole free space gap */
+ bzero(ext, sizeof(ds7ext_t));
+
+ if (verbose)
+ puts ("FMT7 del extent: fills whole gap");
+
+ counter++;
+ break;
+ }
+
+ if ((a == ext->a) && (b < ext->b)) {
+ /* left-bounded in free space gap */
+ ext->a = b;
+
+ if (verbose)
+ puts ("FMT7 add extent: left-bounded");
+
+ counter++;
+ break;
+ }
+
+ if ((a > ext->a) && (b == ext->b)) {
+ /* right-bounded in free space gap */
+ ext->b = a;
+
+ if (verbose)
+ puts ("FMT7 add extent: right-bounded");
+
+ counter++;
+ break;
+ }
+
+ if ((a > ext->a) && (b < ext->b)) {
+ /* partition devides free space into 2 pieces */
+ vtoc_update_format7_label_add(f7, verbose, b, ext->b);
+ ext->b = a;
+
+ if (verbose)
+ puts ("FMT7 add extent: 2 pieces");
+
+ counter++;
+ break;
+ }
+
+ if (((a < ext->a) && (b > ext->a)) || ((a < ext->b) && (b > ext->b))) {
+ puts ("BUG: specified free space extent for deleting "
+ "doesn't match free space currently shown in "
+ "FMT7 DSCB!\nexiting...");
+ printf ("%d %d %d %d\n", a, b, ext->a, ext->b);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (counter > 0)
+ return;
+
+ puts ("BUG: specified free space extent for "
+ "deleting not found in FMT7 DSCB!\n"
+ "exiting...");
+ exit(EXIT_FAILURE);
+}
+
+void
+vtoc_set_freespace(format4_label_t *f4, format5_label_t *f5,
+ format7_label_t *f7, char ch, int verbose,
+ u_int32_t start, u_int32_t stop, u_int32_t cyl,
+ u_int32_t trk)
+{
+ PDEBUG
+ if ((cyl * trk) > BIG_DISK_SIZE) {
+ if (ch == '+')
+ vtoc_update_format7_label_add(f7, verbose, start,
+ /* ds7ext RTA + 1 */
+ stop + 1);
+ else if (ch == '-')
+ vtoc_update_format7_label_del(f7, verbose, start,
+ /* ds7ext RTA + 1 */
+ stop + 1);
+ else
+ puts ("BUG: syntax error in vtoc_set_freespace call");
+
+ vtoc_reorganize_FMT7_extents (f7);
+
+ f4->DS4VTOCI = 0xa0;
+ f4->DS4EFLVL = 0x07;
+ vtoc_set_cchhb(&f4->DS4EFPTR, 0x0000, 0x0001, 0x03);
+ } else {
+ u_int16_t x,y;
+ u_int8_t z;
+
+ x = (u_int16_t) start;
+ y = (u_int16_t) ((stop - start + 1) / trk);
+ z = (u_int8_t) ((stop - start + 1) % trk);
+
+ if (ch == '+')
+ vtoc_update_format5_label_add(f5, verbose, trk, x, y, z);
+ else if (ch == '-')
+ vtoc_update_format5_label_del(f5, verbose, trk, x, y, z);
+ else
+ puts ("BUG: syntax error in vtoc_set_freespace call");
+
+ vtoc_reorganize_FMT5_extents (f5);
+ }
+}