summaryrefslogtreecommitdiffstats
path: root/libparted/fs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libparted/fs/Makefile.am123
-rw-r--r--libparted/fs/Makefile.in2532
-rw-r--r--libparted/fs/amiga/a-interface.c88
-rw-r--r--libparted/fs/amiga/affs.c292
-rw-r--r--libparted/fs/amiga/affs.h19
-rw-r--r--libparted/fs/amiga/amiga.c351
-rw-r--r--libparted/fs/amiga/amiga.h70
-rw-r--r--libparted/fs/amiga/apfs.c128
-rw-r--r--libparted/fs/amiga/apfs.h18
-rw-r--r--libparted/fs/amiga/asfs.c130
-rw-r--r--libparted/fs/amiga/asfs.h18
-rw-r--r--libparted/fs/btrfs/btrfs.c77
-rw-r--r--libparted/fs/ext2/ext2.h79
-rw-r--r--libparted/fs/ext2/ext2_fs.h329
-rw-r--r--libparted/fs/ext2/interface.c163
-rw-r--r--libparted/fs/f2fs/f2fs.c60
-rw-r--r--libparted/fs/f2fs/f2fs.h57
-rw-r--r--libparted/fs/fat/bootsector.c271
-rw-r--r--libparted/fs/fat/bootsector.h126
-rw-r--r--libparted/fs/fat/count.h46
-rw-r--r--libparted/fs/fat/fat.c162
-rw-r--r--libparted/fs/fat/fat.h163
-rw-r--r--libparted/fs/fsresize.sym13
-rw-r--r--libparted/fs/hfs/DOC92
-rw-r--r--libparted/fs/hfs/HISTORY115
-rw-r--r--libparted/fs/hfs/TODO27
-rw-r--r--libparted/fs/hfs/hfs.c92
-rw-r--r--libparted/fs/hfs/hfs.h648
-rw-r--r--libparted/fs/hfs/probe.c238
-rw-r--r--libparted/fs/hfs/probe.h44
-rw-r--r--libparted/fs/jfs/jfs.c80
-rw-r--r--libparted/fs/jfs/jfs_superblock.h144
-rw-r--r--libparted/fs/jfs/jfs_types.h527
-rw-r--r--libparted/fs/linux_swap/linux_swap.c396
-rw-r--r--libparted/fs/nilfs2/nilfs2.c155
-rw-r--r--libparted/fs/ntfs/ntfs.c73
-rw-r--r--libparted/fs/r/fat/bootsector.c441
-rw-r--r--libparted/fs/r/fat/bootsector.h130
-rw-r--r--libparted/fs/r/fat/calc.c433
-rw-r--r--libparted/fs/r/fat/calc.h77
-rw-r--r--libparted/fs/r/fat/clstdup.c423
-rw-r--r--libparted/fs/r/fat/clstdup.h28
-rw-r--r--libparted/fs/r/fat/context.c261
-rw-r--r--libparted/fs/r/fat/context.h70
-rw-r--r--libparted/fs/r/fat/count.c319
-rw-r--r--libparted/fs/r/fat/count.h46
-rw-r--r--libparted/fs/r/fat/fat.c652
-rw-r--r--libparted/fs/r/fat/fat.h159
-rw-r--r--libparted/fs/r/fat/fatio.c150
-rw-r--r--libparted/fs/r/fat/fatio.h49
-rw-r--r--libparted/fs/r/fat/resize.c876
-rw-r--r--libparted/fs/r/fat/table.c481
-rw-r--r--libparted/fs/r/fat/table.h74
-rw-r--r--libparted/fs/r/fat/traverse.c368
-rw-r--r--libparted/fs/r/fat/traverse.h75
-rw-r--r--libparted/fs/r/filesys.c320
-rw-r--r--libparted/fs/r/hfs/advfs.c332
-rw-r--r--libparted/fs/r/hfs/advfs.h49
-rw-r--r--libparted/fs/r/hfs/advfs_plus.c385
-rw-r--r--libparted/fs/r/hfs/advfs_plus.h52
-rw-r--r--libparted/fs/r/hfs/cache.c239
-rw-r--r--libparted/fs/r/hfs/cache.h118
-rw-r--r--libparted/fs/r/hfs/file.c229
-rw-r--r--libparted/fs/r/hfs/file.h42
-rw-r--r--libparted/fs/r/hfs/file_plus.c274
-rw-r--r--libparted/fs/r/hfs/file_plus.h61
-rw-r--r--libparted/fs/r/hfs/hfs.c1166
-rw-r--r--libparted/fs/r/hfs/hfs.h648
-rw-r--r--libparted/fs/r/hfs/journal.c392
-rw-r--r--libparted/fs/r/hfs/journal.h45
-rw-r--r--libparted/fs/r/hfs/probe.c99
-rw-r--r--libparted/fs/r/hfs/probe.h35
-rw-r--r--libparted/fs/r/hfs/reloc.c676
-rw-r--r--libparted/fs/r/hfs/reloc.h36
-rw-r--r--libparted/fs/r/hfs/reloc_plus.c948
-rw-r--r--libparted/fs/r/hfs/reloc_plus.h37
-rw-r--r--libparted/fs/reiserfs/reiserfs.c94
-rw-r--r--libparted/fs/reiserfs/reiserfs.h109
-rw-r--r--libparted/fs/udf/udf.c175
-rw-r--r--libparted/fs/ufs/ufs.c281
-rw-r--r--libparted/fs/xfs/platform_defs.h109
-rw-r--r--libparted/fs/xfs/xfs.c87
-rw-r--r--libparted/fs/xfs/xfs_sb.h489
-rw-r--r--libparted/fs/xfs/xfs_types.h302
84 files changed, 20887 insertions, 0 deletions
diff --git a/libparted/fs/Makefile.am b/libparted/fs/Makefile.am
new file mode 100644
index 0000000..41a60d9
--- /dev/null
+++ b/libparted/fs/Makefile.am
@@ -0,0 +1,123 @@
+# This file is part of GNU Parted
+# Copyright (C) 1999-2001, 2007, 2009-2014, 2019-2023 Free Software Foundation,
+# Inc.
+#
+# This file may be modified and/or distributed without restriction.
+
+partedincludedir = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/lib
+
+AM_CFLAGS = $(WARN_CFLAGS)
+
+noinst_LTLIBRARIES = libfs.la
+
+libfs_la_LIBADD = $(UUID_LIBS) \
+ $(INTLLIBS) \
+ $(OS_LIBS)
+
+libfs_la_SOURCES = \
+ amiga/affs.c \
+ amiga/affs.h \
+ amiga/amiga.c \
+ amiga/amiga.h \
+ amiga/apfs.c \
+ amiga/apfs.h \
+ amiga/asfs.c \
+ amiga/asfs.h \
+ amiga/a-interface.c \
+ btrfs/btrfs.c \
+ ext2/ext2.h \
+ ext2/ext2_fs.h \
+ ext2/interface.c \
+ fat/bootsector.c \
+ fat/bootsector.h \
+ fat/count.h \
+ fat/fat.c \
+ fat/fat.h \
+ f2fs/f2fs.c \
+ f2fs/f2fs.h \
+ hfs/hfs.c \
+ hfs/hfs.h \
+ hfs/probe.c \
+ hfs/probe.h \
+ jfs/jfs.c \
+ jfs/jfs_superblock.h \
+ jfs/jfs_types.h \
+ linux_swap/linux_swap.c \
+ nilfs2/nilfs2.c \
+ ntfs/ntfs.c \
+ reiserfs/reiserfs.c \
+ reiserfs/reiserfs.h \
+ udf/udf.c \
+ ufs/ufs.c \
+ xfs/platform_defs.h \
+ xfs/xfs.c \
+ xfs/xfs_sb.h \
+ xfs/xfs_types.h
+
+lib_LTLIBRARIES = libparted-fs-resize.la
+
+EXTRA_DIST = \
+ hfs/DOC \
+ hfs/HISTORY \
+ hfs/TODO
+
+# Set the shared library version, per Libtool's guidelines.
+# For details, see the "Updating library version information" section of
+# "info libtool".
+CURRENT = 0
+REVISION = 5
+AGE = 0
+
+sym_file = $(srcdir)/fsresize.sym
+libparted_fs_resize_la_LDFLAGS = \
+ -Wl,--version-script=$(sym_file) \
+ -version-info $(CURRENT):$(REVISION):$(AGE)
+EXTRA_DIST += fsresize.sym
+libparted_fs_resize_la_DEPENDENCIES = $(sym_file)
+
+libparted_fs_resize_la_SOURCES = \
+ r/filesys.c \
+ r/fat/bootsector.c \
+ r/fat/bootsector.h \
+ r/fat/calc.c \
+ r/fat/calc.h \
+ r/fat/clstdup.c \
+ r/fat/clstdup.h \
+ r/fat/context.c \
+ r/fat/context.h \
+ r/fat/count.c \
+ r/fat/count.h \
+ r/fat/fat.c \
+ r/fat/fat.h \
+ r/fat/fatio.c \
+ r/fat/fatio.h \
+ r/fat/resize.c \
+ r/fat/table.c \
+ r/fat/table.h \
+ r/fat/traverse.c \
+ r/fat/traverse.h \
+ r/hfs/advfs.c \
+ r/hfs/advfs.h \
+ r/hfs/advfs_plus.c \
+ r/hfs/advfs_plus.h \
+ r/hfs/cache.c \
+ r/hfs/cache.h \
+ r/hfs/file.c \
+ r/hfs/file.h \
+ r/hfs/file_plus.c \
+ r/hfs/file_plus.h \
+ r/hfs/hfs.c \
+ r/hfs/hfs.h \
+ r/hfs/journal.c \
+ r/hfs/journal.h \
+ r/hfs/probe.c \
+ r/hfs/probe.h \
+ r/hfs/reloc.c \
+ r/hfs/reloc.h \
+ r/hfs/reloc_plus.c \
+ r/hfs/reloc_plus.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/libparted/labels \
+ $(partedincludedir) \
+ $(INTLINCS)
diff --git a/libparted/fs/Makefile.in b/libparted/fs/Makefile.in
new file mode 100644
index 0000000..3b552b8
--- /dev/null
+++ b/libparted/fs/Makefile.in
@@ -0,0 +1,2532 @@
+# 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, 2009-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/fs
+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 =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libfs_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am__dirstamp = $(am__leading_dot)dirstamp
+am_libfs_la_OBJECTS = amiga/affs.lo amiga/amiga.lo amiga/apfs.lo \
+ amiga/asfs.lo amiga/a-interface.lo btrfs/btrfs.lo \
+ ext2/interface.lo fat/bootsector.lo fat/fat.lo f2fs/f2fs.lo \
+ hfs/hfs.lo hfs/probe.lo jfs/jfs.lo linux_swap/linux_swap.lo \
+ nilfs2/nilfs2.lo ntfs/ntfs.lo reiserfs/reiserfs.lo udf/udf.lo \
+ ufs/ufs.lo xfs/xfs.lo
+libfs_la_OBJECTS = $(am_libfs_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 =
+libparted_fs_resize_la_LIBADD =
+am_libparted_fs_resize_la_OBJECTS = r/filesys.lo r/fat/bootsector.lo \
+ r/fat/calc.lo r/fat/clstdup.lo r/fat/context.lo r/fat/count.lo \
+ r/fat/fat.lo r/fat/fatio.lo r/fat/resize.lo r/fat/table.lo \
+ r/fat/traverse.lo r/hfs/advfs.lo r/hfs/advfs_plus.lo \
+ r/hfs/cache.lo r/hfs/file.lo r/hfs/file_plus.lo r/hfs/hfs.lo \
+ r/hfs/journal.lo r/hfs/probe.lo r/hfs/reloc.lo \
+ r/hfs/reloc_plus.lo
+libparted_fs_resize_la_OBJECTS = $(am_libparted_fs_resize_la_OBJECTS)
+libparted_fs_resize_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libparted_fs_resize_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+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 = amiga/$(DEPDIR)/a-interface.Plo \
+ amiga/$(DEPDIR)/affs.Plo amiga/$(DEPDIR)/amiga.Plo \
+ amiga/$(DEPDIR)/apfs.Plo amiga/$(DEPDIR)/asfs.Plo \
+ btrfs/$(DEPDIR)/btrfs.Plo ext2/$(DEPDIR)/interface.Plo \
+ f2fs/$(DEPDIR)/f2fs.Plo fat/$(DEPDIR)/bootsector.Plo \
+ fat/$(DEPDIR)/fat.Plo hfs/$(DEPDIR)/hfs.Plo \
+ hfs/$(DEPDIR)/probe.Plo jfs/$(DEPDIR)/jfs.Plo \
+ linux_swap/$(DEPDIR)/linux_swap.Plo \
+ nilfs2/$(DEPDIR)/nilfs2.Plo ntfs/$(DEPDIR)/ntfs.Plo \
+ r/$(DEPDIR)/filesys.Plo r/fat/$(DEPDIR)/bootsector.Plo \
+ r/fat/$(DEPDIR)/calc.Plo r/fat/$(DEPDIR)/clstdup.Plo \
+ r/fat/$(DEPDIR)/context.Plo r/fat/$(DEPDIR)/count.Plo \
+ r/fat/$(DEPDIR)/fat.Plo r/fat/$(DEPDIR)/fatio.Plo \
+ r/fat/$(DEPDIR)/resize.Plo r/fat/$(DEPDIR)/table.Plo \
+ r/fat/$(DEPDIR)/traverse.Plo r/hfs/$(DEPDIR)/advfs.Plo \
+ r/hfs/$(DEPDIR)/advfs_plus.Plo r/hfs/$(DEPDIR)/cache.Plo \
+ r/hfs/$(DEPDIR)/file.Plo r/hfs/$(DEPDIR)/file_plus.Plo \
+ r/hfs/$(DEPDIR)/hfs.Plo r/hfs/$(DEPDIR)/journal.Plo \
+ r/hfs/$(DEPDIR)/probe.Plo r/hfs/$(DEPDIR)/reloc.Plo \
+ r/hfs/$(DEPDIR)/reloc_plus.Plo reiserfs/$(DEPDIR)/reiserfs.Plo \
+ udf/$(DEPDIR)/udf.Plo ufs/$(DEPDIR)/ufs.Plo \
+ xfs/$(DEPDIR)/xfs.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 = $(libfs_la_SOURCES) $(libparted_fs_resize_la_SOURCES)
+DIST_SOURCES = $(libfs_la_SOURCES) $(libparted_fs_resize_la_SOURCES)
+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@
+partedincludedir = -I$(top_builddir)/include -I$(top_srcdir)/include -I$(top_srcdir)/lib
+AM_CFLAGS = $(WARN_CFLAGS)
+noinst_LTLIBRARIES = libfs.la
+libfs_la_LIBADD = $(UUID_LIBS) \
+ $(INTLLIBS) \
+ $(OS_LIBS)
+
+libfs_la_SOURCES = \
+ amiga/affs.c \
+ amiga/affs.h \
+ amiga/amiga.c \
+ amiga/amiga.h \
+ amiga/apfs.c \
+ amiga/apfs.h \
+ amiga/asfs.c \
+ amiga/asfs.h \
+ amiga/a-interface.c \
+ btrfs/btrfs.c \
+ ext2/ext2.h \
+ ext2/ext2_fs.h \
+ ext2/interface.c \
+ fat/bootsector.c \
+ fat/bootsector.h \
+ fat/count.h \
+ fat/fat.c \
+ fat/fat.h \
+ f2fs/f2fs.c \
+ f2fs/f2fs.h \
+ hfs/hfs.c \
+ hfs/hfs.h \
+ hfs/probe.c \
+ hfs/probe.h \
+ jfs/jfs.c \
+ jfs/jfs_superblock.h \
+ jfs/jfs_types.h \
+ linux_swap/linux_swap.c \
+ nilfs2/nilfs2.c \
+ ntfs/ntfs.c \
+ reiserfs/reiserfs.c \
+ reiserfs/reiserfs.h \
+ udf/udf.c \
+ ufs/ufs.c \
+ xfs/platform_defs.h \
+ xfs/xfs.c \
+ xfs/xfs_sb.h \
+ xfs/xfs_types.h
+
+lib_LTLIBRARIES = libparted-fs-resize.la
+EXTRA_DIST = hfs/DOC hfs/HISTORY hfs/TODO fsresize.sym
+
+# Set the shared library version, per Libtool's guidelines.
+# For details, see the "Updating library version information" section of
+# "info libtool".
+CURRENT = 0
+REVISION = 5
+AGE = 0
+sym_file = $(srcdir)/fsresize.sym
+libparted_fs_resize_la_LDFLAGS = \
+ -Wl,--version-script=$(sym_file) \
+ -version-info $(CURRENT):$(REVISION):$(AGE)
+
+libparted_fs_resize_la_DEPENDENCIES = $(sym_file)
+libparted_fs_resize_la_SOURCES = \
+ r/filesys.c \
+ r/fat/bootsector.c \
+ r/fat/bootsector.h \
+ r/fat/calc.c \
+ r/fat/calc.h \
+ r/fat/clstdup.c \
+ r/fat/clstdup.h \
+ r/fat/context.c \
+ r/fat/context.h \
+ r/fat/count.c \
+ r/fat/count.h \
+ r/fat/fat.c \
+ r/fat/fat.h \
+ r/fat/fatio.c \
+ r/fat/fatio.h \
+ r/fat/resize.c \
+ r/fat/table.c \
+ r/fat/table.h \
+ r/fat/traverse.c \
+ r/fat/traverse.h \
+ r/hfs/advfs.c \
+ r/hfs/advfs.h \
+ r/hfs/advfs_plus.c \
+ r/hfs/advfs_plus.h \
+ r/hfs/cache.c \
+ r/hfs/cache.h \
+ r/hfs/file.c \
+ r/hfs/file.h \
+ r/hfs/file_plus.c \
+ r/hfs/file_plus.h \
+ r/hfs/hfs.c \
+ r/hfs/hfs.h \
+ r/hfs/journal.c \
+ r/hfs/journal.h \
+ r/hfs/probe.c \
+ r/hfs/probe.h \
+ r/hfs/reloc.c \
+ r/hfs/reloc.h \
+ r/hfs/reloc_plus.c \
+ r/hfs/reloc_plus.h
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/libparted/labels \
+ $(partedincludedir) \
+ $(INTLINCS)
+
+all: 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/fs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libparted/fs/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):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_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}; \
+ }
+
+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}; \
+ }
+amiga/$(am__dirstamp):
+ @$(MKDIR_P) amiga
+ @: > amiga/$(am__dirstamp)
+amiga/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) amiga/$(DEPDIR)
+ @: > amiga/$(DEPDIR)/$(am__dirstamp)
+amiga/affs.lo: amiga/$(am__dirstamp) amiga/$(DEPDIR)/$(am__dirstamp)
+amiga/amiga.lo: amiga/$(am__dirstamp) amiga/$(DEPDIR)/$(am__dirstamp)
+amiga/apfs.lo: amiga/$(am__dirstamp) amiga/$(DEPDIR)/$(am__dirstamp)
+amiga/asfs.lo: amiga/$(am__dirstamp) amiga/$(DEPDIR)/$(am__dirstamp)
+amiga/a-interface.lo: amiga/$(am__dirstamp) \
+ amiga/$(DEPDIR)/$(am__dirstamp)
+btrfs/$(am__dirstamp):
+ @$(MKDIR_P) btrfs
+ @: > btrfs/$(am__dirstamp)
+btrfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) btrfs/$(DEPDIR)
+ @: > btrfs/$(DEPDIR)/$(am__dirstamp)
+btrfs/btrfs.lo: btrfs/$(am__dirstamp) btrfs/$(DEPDIR)/$(am__dirstamp)
+ext2/$(am__dirstamp):
+ @$(MKDIR_P) ext2
+ @: > ext2/$(am__dirstamp)
+ext2/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ext2/$(DEPDIR)
+ @: > ext2/$(DEPDIR)/$(am__dirstamp)
+ext2/interface.lo: ext2/$(am__dirstamp) ext2/$(DEPDIR)/$(am__dirstamp)
+fat/$(am__dirstamp):
+ @$(MKDIR_P) fat
+ @: > fat/$(am__dirstamp)
+fat/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) fat/$(DEPDIR)
+ @: > fat/$(DEPDIR)/$(am__dirstamp)
+fat/bootsector.lo: fat/$(am__dirstamp) fat/$(DEPDIR)/$(am__dirstamp)
+fat/fat.lo: fat/$(am__dirstamp) fat/$(DEPDIR)/$(am__dirstamp)
+f2fs/$(am__dirstamp):
+ @$(MKDIR_P) f2fs
+ @: > f2fs/$(am__dirstamp)
+f2fs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) f2fs/$(DEPDIR)
+ @: > f2fs/$(DEPDIR)/$(am__dirstamp)
+f2fs/f2fs.lo: f2fs/$(am__dirstamp) f2fs/$(DEPDIR)/$(am__dirstamp)
+hfs/$(am__dirstamp):
+ @$(MKDIR_P) hfs
+ @: > hfs/$(am__dirstamp)
+hfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) hfs/$(DEPDIR)
+ @: > hfs/$(DEPDIR)/$(am__dirstamp)
+hfs/hfs.lo: hfs/$(am__dirstamp) hfs/$(DEPDIR)/$(am__dirstamp)
+hfs/probe.lo: hfs/$(am__dirstamp) hfs/$(DEPDIR)/$(am__dirstamp)
+jfs/$(am__dirstamp):
+ @$(MKDIR_P) jfs
+ @: > jfs/$(am__dirstamp)
+jfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) jfs/$(DEPDIR)
+ @: > jfs/$(DEPDIR)/$(am__dirstamp)
+jfs/jfs.lo: jfs/$(am__dirstamp) jfs/$(DEPDIR)/$(am__dirstamp)
+linux_swap/$(am__dirstamp):
+ @$(MKDIR_P) linux_swap
+ @: > linux_swap/$(am__dirstamp)
+linux_swap/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) linux_swap/$(DEPDIR)
+ @: > linux_swap/$(DEPDIR)/$(am__dirstamp)
+linux_swap/linux_swap.lo: linux_swap/$(am__dirstamp) \
+ linux_swap/$(DEPDIR)/$(am__dirstamp)
+nilfs2/$(am__dirstamp):
+ @$(MKDIR_P) nilfs2
+ @: > nilfs2/$(am__dirstamp)
+nilfs2/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) nilfs2/$(DEPDIR)
+ @: > nilfs2/$(DEPDIR)/$(am__dirstamp)
+nilfs2/nilfs2.lo: nilfs2/$(am__dirstamp) \
+ nilfs2/$(DEPDIR)/$(am__dirstamp)
+ntfs/$(am__dirstamp):
+ @$(MKDIR_P) ntfs
+ @: > ntfs/$(am__dirstamp)
+ntfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ntfs/$(DEPDIR)
+ @: > ntfs/$(DEPDIR)/$(am__dirstamp)
+ntfs/ntfs.lo: ntfs/$(am__dirstamp) ntfs/$(DEPDIR)/$(am__dirstamp)
+reiserfs/$(am__dirstamp):
+ @$(MKDIR_P) reiserfs
+ @: > reiserfs/$(am__dirstamp)
+reiserfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) reiserfs/$(DEPDIR)
+ @: > reiserfs/$(DEPDIR)/$(am__dirstamp)
+reiserfs/reiserfs.lo: reiserfs/$(am__dirstamp) \
+ reiserfs/$(DEPDIR)/$(am__dirstamp)
+udf/$(am__dirstamp):
+ @$(MKDIR_P) udf
+ @: > udf/$(am__dirstamp)
+udf/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) udf/$(DEPDIR)
+ @: > udf/$(DEPDIR)/$(am__dirstamp)
+udf/udf.lo: udf/$(am__dirstamp) udf/$(DEPDIR)/$(am__dirstamp)
+ufs/$(am__dirstamp):
+ @$(MKDIR_P) ufs
+ @: > ufs/$(am__dirstamp)
+ufs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ufs/$(DEPDIR)
+ @: > ufs/$(DEPDIR)/$(am__dirstamp)
+ufs/ufs.lo: ufs/$(am__dirstamp) ufs/$(DEPDIR)/$(am__dirstamp)
+xfs/$(am__dirstamp):
+ @$(MKDIR_P) xfs
+ @: > xfs/$(am__dirstamp)
+xfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) xfs/$(DEPDIR)
+ @: > xfs/$(DEPDIR)/$(am__dirstamp)
+xfs/xfs.lo: xfs/$(am__dirstamp) xfs/$(DEPDIR)/$(am__dirstamp)
+
+libfs.la: $(libfs_la_OBJECTS) $(libfs_la_DEPENDENCIES) $(EXTRA_libfs_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) $(libfs_la_OBJECTS) $(libfs_la_LIBADD) $(LIBS)
+r/$(am__dirstamp):
+ @$(MKDIR_P) r
+ @: > r/$(am__dirstamp)
+r/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) r/$(DEPDIR)
+ @: > r/$(DEPDIR)/$(am__dirstamp)
+r/filesys.lo: r/$(am__dirstamp) r/$(DEPDIR)/$(am__dirstamp)
+r/fat/$(am__dirstamp):
+ @$(MKDIR_P) r/fat
+ @: > r/fat/$(am__dirstamp)
+r/fat/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) r/fat/$(DEPDIR)
+ @: > r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/bootsector.lo: r/fat/$(am__dirstamp) \
+ r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/calc.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/clstdup.lo: r/fat/$(am__dirstamp) \
+ r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/context.lo: r/fat/$(am__dirstamp) \
+ r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/count.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/fat.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/fatio.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/resize.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/table.lo: r/fat/$(am__dirstamp) r/fat/$(DEPDIR)/$(am__dirstamp)
+r/fat/traverse.lo: r/fat/$(am__dirstamp) \
+ r/fat/$(DEPDIR)/$(am__dirstamp)
+r/hfs/$(am__dirstamp):
+ @$(MKDIR_P) r/hfs
+ @: > r/hfs/$(am__dirstamp)
+r/hfs/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) r/hfs/$(DEPDIR)
+ @: > r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/advfs.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/advfs_plus.lo: r/hfs/$(am__dirstamp) \
+ r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/cache.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/file.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/file_plus.lo: r/hfs/$(am__dirstamp) \
+ r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/hfs.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/journal.lo: r/hfs/$(am__dirstamp) \
+ r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/probe.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/reloc.lo: r/hfs/$(am__dirstamp) r/hfs/$(DEPDIR)/$(am__dirstamp)
+r/hfs/reloc_plus.lo: r/hfs/$(am__dirstamp) \
+ r/hfs/$(DEPDIR)/$(am__dirstamp)
+
+libparted-fs-resize.la: $(libparted_fs_resize_la_OBJECTS) $(libparted_fs_resize_la_DEPENDENCIES) $(EXTRA_libparted_fs_resize_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libparted_fs_resize_la_LINK) -rpath $(libdir) $(libparted_fs_resize_la_OBJECTS) $(libparted_fs_resize_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f amiga/*.$(OBJEXT)
+ -rm -f amiga/*.lo
+ -rm -f btrfs/*.$(OBJEXT)
+ -rm -f btrfs/*.lo
+ -rm -f ext2/*.$(OBJEXT)
+ -rm -f ext2/*.lo
+ -rm -f f2fs/*.$(OBJEXT)
+ -rm -f f2fs/*.lo
+ -rm -f fat/*.$(OBJEXT)
+ -rm -f fat/*.lo
+ -rm -f hfs/*.$(OBJEXT)
+ -rm -f hfs/*.lo
+ -rm -f jfs/*.$(OBJEXT)
+ -rm -f jfs/*.lo
+ -rm -f linux_swap/*.$(OBJEXT)
+ -rm -f linux_swap/*.lo
+ -rm -f nilfs2/*.$(OBJEXT)
+ -rm -f nilfs2/*.lo
+ -rm -f ntfs/*.$(OBJEXT)
+ -rm -f ntfs/*.lo
+ -rm -f r/*.$(OBJEXT)
+ -rm -f r/*.lo
+ -rm -f r/fat/*.$(OBJEXT)
+ -rm -f r/fat/*.lo
+ -rm -f r/hfs/*.$(OBJEXT)
+ -rm -f r/hfs/*.lo
+ -rm -f reiserfs/*.$(OBJEXT)
+ -rm -f reiserfs/*.lo
+ -rm -f udf/*.$(OBJEXT)
+ -rm -f udf/*.lo
+ -rm -f ufs/*.$(OBJEXT)
+ -rm -f ufs/*.lo
+ -rm -f xfs/*.$(OBJEXT)
+ -rm -f xfs/*.lo
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@amiga/$(DEPDIR)/a-interface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@amiga/$(DEPDIR)/affs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@amiga/$(DEPDIR)/amiga.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@amiga/$(DEPDIR)/apfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@amiga/$(DEPDIR)/asfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@btrfs/$(DEPDIR)/btrfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@ext2/$(DEPDIR)/interface.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@f2fs/$(DEPDIR)/f2fs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@fat/$(DEPDIR)/bootsector.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@fat/$(DEPDIR)/fat.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@hfs/$(DEPDIR)/hfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@hfs/$(DEPDIR)/probe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@jfs/$(DEPDIR)/jfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@linux_swap/$(DEPDIR)/linux_swap.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@nilfs2/$(DEPDIR)/nilfs2.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@ntfs/$(DEPDIR)/ntfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/$(DEPDIR)/filesys.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/bootsector.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/calc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/clstdup.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/context.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/count.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/fat.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/fatio.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/resize.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/table.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/fat/$(DEPDIR)/traverse.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/advfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/advfs_plus.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/cache.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/file.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/file_plus.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/hfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/journal.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/probe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/reloc.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@r/hfs/$(DEPDIR)/reloc_plus.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@reiserfs/$(DEPDIR)/reiserfs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@udf/$(DEPDIR)/udf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@ufs/$(DEPDIR)/ufs.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@xfs/$(DEPDIR)/xfs.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
+ -rm -rf amiga/.libs amiga/_libs
+ -rm -rf btrfs/.libs btrfs/_libs
+ -rm -rf ext2/.libs ext2/_libs
+ -rm -rf f2fs/.libs f2fs/_libs
+ -rm -rf fat/.libs fat/_libs
+ -rm -rf hfs/.libs hfs/_libs
+ -rm -rf jfs/.libs jfs/_libs
+ -rm -rf linux_swap/.libs linux_swap/_libs
+ -rm -rf nilfs2/.libs nilfs2/_libs
+ -rm -rf ntfs/.libs ntfs/_libs
+ -rm -rf r/.libs r/_libs
+ -rm -rf r/fat/.libs r/fat/_libs
+ -rm -rf r/hfs/.libs r/hfs/_libs
+ -rm -rf reiserfs/.libs reiserfs/_libs
+ -rm -rf udf/.libs udf/_libs
+ -rm -rf ufs/.libs ufs/_libs
+ -rm -rf xfs/.libs xfs/_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: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: 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)
+ -rm -f amiga/$(DEPDIR)/$(am__dirstamp)
+ -rm -f amiga/$(am__dirstamp)
+ -rm -f btrfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f btrfs/$(am__dirstamp)
+ -rm -f ext2/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ext2/$(am__dirstamp)
+ -rm -f f2fs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f f2fs/$(am__dirstamp)
+ -rm -f fat/$(DEPDIR)/$(am__dirstamp)
+ -rm -f fat/$(am__dirstamp)
+ -rm -f hfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f hfs/$(am__dirstamp)
+ -rm -f jfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f jfs/$(am__dirstamp)
+ -rm -f linux_swap/$(DEPDIR)/$(am__dirstamp)
+ -rm -f linux_swap/$(am__dirstamp)
+ -rm -f nilfs2/$(DEPDIR)/$(am__dirstamp)
+ -rm -f nilfs2/$(am__dirstamp)
+ -rm -f ntfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ntfs/$(am__dirstamp)
+ -rm -f r/$(DEPDIR)/$(am__dirstamp)
+ -rm -f r/$(am__dirstamp)
+ -rm -f r/fat/$(DEPDIR)/$(am__dirstamp)
+ -rm -f r/fat/$(am__dirstamp)
+ -rm -f r/hfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f r/hfs/$(am__dirstamp)
+ -rm -f reiserfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f reiserfs/$(am__dirstamp)
+ -rm -f udf/$(DEPDIR)/$(am__dirstamp)
+ -rm -f udf/$(am__dirstamp)
+ -rm -f ufs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ufs/$(am__dirstamp)
+ -rm -f xfs/$(DEPDIR)/$(am__dirstamp)
+ -rm -f xfs/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -f amiga/$(DEPDIR)/a-interface.Plo
+ -rm -f amiga/$(DEPDIR)/affs.Plo
+ -rm -f amiga/$(DEPDIR)/amiga.Plo
+ -rm -f amiga/$(DEPDIR)/apfs.Plo
+ -rm -f amiga/$(DEPDIR)/asfs.Plo
+ -rm -f btrfs/$(DEPDIR)/btrfs.Plo
+ -rm -f ext2/$(DEPDIR)/interface.Plo
+ -rm -f f2fs/$(DEPDIR)/f2fs.Plo
+ -rm -f fat/$(DEPDIR)/bootsector.Plo
+ -rm -f fat/$(DEPDIR)/fat.Plo
+ -rm -f hfs/$(DEPDIR)/hfs.Plo
+ -rm -f hfs/$(DEPDIR)/probe.Plo
+ -rm -f jfs/$(DEPDIR)/jfs.Plo
+ -rm -f linux_swap/$(DEPDIR)/linux_swap.Plo
+ -rm -f nilfs2/$(DEPDIR)/nilfs2.Plo
+ -rm -f ntfs/$(DEPDIR)/ntfs.Plo
+ -rm -f r/$(DEPDIR)/filesys.Plo
+ -rm -f r/fat/$(DEPDIR)/bootsector.Plo
+ -rm -f r/fat/$(DEPDIR)/calc.Plo
+ -rm -f r/fat/$(DEPDIR)/clstdup.Plo
+ -rm -f r/fat/$(DEPDIR)/context.Plo
+ -rm -f r/fat/$(DEPDIR)/count.Plo
+ -rm -f r/fat/$(DEPDIR)/fat.Plo
+ -rm -f r/fat/$(DEPDIR)/fatio.Plo
+ -rm -f r/fat/$(DEPDIR)/resize.Plo
+ -rm -f r/fat/$(DEPDIR)/table.Plo
+ -rm -f r/fat/$(DEPDIR)/traverse.Plo
+ -rm -f r/hfs/$(DEPDIR)/advfs.Plo
+ -rm -f r/hfs/$(DEPDIR)/advfs_plus.Plo
+ -rm -f r/hfs/$(DEPDIR)/cache.Plo
+ -rm -f r/hfs/$(DEPDIR)/file.Plo
+ -rm -f r/hfs/$(DEPDIR)/file_plus.Plo
+ -rm -f r/hfs/$(DEPDIR)/hfs.Plo
+ -rm -f r/hfs/$(DEPDIR)/journal.Plo
+ -rm -f r/hfs/$(DEPDIR)/probe.Plo
+ -rm -f r/hfs/$(DEPDIR)/reloc.Plo
+ -rm -f r/hfs/$(DEPDIR)/reloc_plus.Plo
+ -rm -f reiserfs/$(DEPDIR)/reiserfs.Plo
+ -rm -f udf/$(DEPDIR)/udf.Plo
+ -rm -f ufs/$(DEPDIR)/ufs.Plo
+ -rm -f xfs/$(DEPDIR)/xfs.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-libLTLIBRARIES
+
+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 amiga/$(DEPDIR)/a-interface.Plo
+ -rm -f amiga/$(DEPDIR)/affs.Plo
+ -rm -f amiga/$(DEPDIR)/amiga.Plo
+ -rm -f amiga/$(DEPDIR)/apfs.Plo
+ -rm -f amiga/$(DEPDIR)/asfs.Plo
+ -rm -f btrfs/$(DEPDIR)/btrfs.Plo
+ -rm -f ext2/$(DEPDIR)/interface.Plo
+ -rm -f f2fs/$(DEPDIR)/f2fs.Plo
+ -rm -f fat/$(DEPDIR)/bootsector.Plo
+ -rm -f fat/$(DEPDIR)/fat.Plo
+ -rm -f hfs/$(DEPDIR)/hfs.Plo
+ -rm -f hfs/$(DEPDIR)/probe.Plo
+ -rm -f jfs/$(DEPDIR)/jfs.Plo
+ -rm -f linux_swap/$(DEPDIR)/linux_swap.Plo
+ -rm -f nilfs2/$(DEPDIR)/nilfs2.Plo
+ -rm -f ntfs/$(DEPDIR)/ntfs.Plo
+ -rm -f r/$(DEPDIR)/filesys.Plo
+ -rm -f r/fat/$(DEPDIR)/bootsector.Plo
+ -rm -f r/fat/$(DEPDIR)/calc.Plo
+ -rm -f r/fat/$(DEPDIR)/clstdup.Plo
+ -rm -f r/fat/$(DEPDIR)/context.Plo
+ -rm -f r/fat/$(DEPDIR)/count.Plo
+ -rm -f r/fat/$(DEPDIR)/fat.Plo
+ -rm -f r/fat/$(DEPDIR)/fatio.Plo
+ -rm -f r/fat/$(DEPDIR)/resize.Plo
+ -rm -f r/fat/$(DEPDIR)/table.Plo
+ -rm -f r/fat/$(DEPDIR)/traverse.Plo
+ -rm -f r/hfs/$(DEPDIR)/advfs.Plo
+ -rm -f r/hfs/$(DEPDIR)/advfs_plus.Plo
+ -rm -f r/hfs/$(DEPDIR)/cache.Plo
+ -rm -f r/hfs/$(DEPDIR)/file.Plo
+ -rm -f r/hfs/$(DEPDIR)/file_plus.Plo
+ -rm -f r/hfs/$(DEPDIR)/hfs.Plo
+ -rm -f r/hfs/$(DEPDIR)/journal.Plo
+ -rm -f r/hfs/$(DEPDIR)/probe.Plo
+ -rm -f r/hfs/$(DEPDIR)/reloc.Plo
+ -rm -f r/hfs/$(DEPDIR)/reloc_plus.Plo
+ -rm -f reiserfs/$(DEPDIR)/reiserfs.Plo
+ -rm -f udf/$(DEPDIR)/udf.Plo
+ -rm -f ufs/$(DEPDIR)/ufs.Plo
+ -rm -f xfs/$(DEPDIR)/xfs.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: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libLTLIBRARIES 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-libLTLIBRARIES 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 uninstall-libLTLIBRARIES
+
+.PRECIOUS: Makefile
+
+
+# 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/fs/amiga/a-interface.c b/libparted/fs/amiga/a-interface.c
new file mode 100644
index 0000000..0ae84dd
--- /dev/null
+++ b/libparted/fs/amiga/a-interface.c
@@ -0,0 +1,88 @@
+/*
+ interface.c -- parted support amiga file systems
+ Copyright (C) 1998-2000, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+extern PedFileSystemType _affs0_type;
+extern PedFileSystemType _affs1_type;
+extern PedFileSystemType _affs2_type;
+extern PedFileSystemType _affs3_type;
+extern PedFileSystemType _affs4_type;
+extern PedFileSystemType _affs5_type;
+extern PedFileSystemType _affs6_type;
+extern PedFileSystemType _affs7_type;
+extern PedFileSystemType _amufs_type;
+extern PedFileSystemType _amufs0_type;
+extern PedFileSystemType _amufs1_type;
+extern PedFileSystemType _amufs2_type;
+extern PedFileSystemType _amufs3_type;
+extern PedFileSystemType _amufs4_type;
+extern PedFileSystemType _amufs5_type;
+extern PedFileSystemType _asfs_type;
+extern PedFileSystemType _apfs1_type;
+extern PedFileSystemType _apfs2_type;
+
+void ped_file_system_amiga_init ()
+{
+ ped_file_system_type_register (&_affs0_type);
+ ped_file_system_type_register (&_affs1_type);
+ ped_file_system_type_register (&_affs2_type);
+ ped_file_system_type_register (&_affs3_type);
+ ped_file_system_type_register (&_affs4_type);
+ ped_file_system_type_register (&_affs5_type);
+ ped_file_system_type_register (&_affs6_type);
+ ped_file_system_type_register (&_affs7_type);
+ ped_file_system_type_register (&_amufs_type);
+ ped_file_system_type_register (&_amufs0_type);
+ ped_file_system_type_register (&_amufs1_type);
+ ped_file_system_type_register (&_amufs2_type);
+ ped_file_system_type_register (&_amufs3_type);
+ ped_file_system_type_register (&_amufs4_type);
+ ped_file_system_type_register (&_amufs5_type);
+ ped_file_system_type_register (&_asfs_type);
+ ped_file_system_type_register (&_apfs1_type);
+ ped_file_system_type_register (&_apfs2_type);
+}
+
+void ped_file_system_amiga_done ()
+{
+ ped_file_system_type_unregister (&_affs0_type);
+ ped_file_system_type_unregister (&_affs1_type);
+ ped_file_system_type_unregister (&_affs2_type);
+ ped_file_system_type_unregister (&_affs3_type);
+ ped_file_system_type_unregister (&_affs4_type);
+ ped_file_system_type_unregister (&_affs5_type);
+ ped_file_system_type_unregister (&_affs6_type);
+ ped_file_system_type_unregister (&_affs7_type);
+ ped_file_system_type_unregister (&_amufs_type);
+ ped_file_system_type_unregister (&_amufs0_type);
+ ped_file_system_type_unregister (&_amufs1_type);
+ ped_file_system_type_unregister (&_amufs2_type);
+ ped_file_system_type_unregister (&_amufs3_type);
+ ped_file_system_type_unregister (&_amufs4_type);
+ ped_file_system_type_unregister (&_amufs5_type);
+ ped_file_system_type_unregister (&_asfs_type);
+ ped_file_system_type_unregister (&_apfs1_type);
+ ped_file_system_type_unregister (&_apfs2_type);
+}
diff --git a/libparted/fs/amiga/affs.c b/libparted/fs/amiga/affs.c
new file mode 100644
index 0000000..750eab2
--- /dev/null
+++ b/libparted/fs/amiga/affs.c
@@ -0,0 +1,292 @@
+/*
+ affs.c -- parted support for affs file systems
+ Copyright (C) 1998-2000, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "amiga.h"
+#include "affs.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static int
+_affs_probe_root (uint32_t *block, int blocksize) {
+ int i;
+ uint32_t sum;
+
+ if (PED_BE32_TO_CPU (block[0]) != 2) return 0;
+ if (PED_BE32_TO_CPU (block[128*blocksize-1]) != 1) return 0;
+ for (i = 0, sum = 0; i < 128*blocksize; i++)
+ sum += PED_BE32_TO_CPU (block[i]);
+ if (sum) return 0;
+ return 1;
+}
+
+static PedGeometry*
+_generic_affs_probe (PedGeometry* geom, uint32_t kind)
+{
+ uint32_t *block;
+ PedSector root, len, pos;
+ struct PartitionBlock * part;
+ int blocksize = 1, reserved = 2;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (geom->dev != NULL);
+ if (geom->dev->sector_size != 512)
+ return NULL;
+ /* Finds the blocksize and reserved values of the partition block */
+ if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate partition block\n"), __func__);
+ goto error_part;
+ }
+ if (amiga_find_part(geom, part) != NULL) {
+ reserved = PED_BE32_TO_CPU (part->de_Reserved);
+ reserved = reserved == 0 ? 1 : reserved;
+ blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
+ * PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
+ }
+ free (part);
+
+ /* Test boot block */
+ if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate block\n"), __func__);
+ goto error_block;
+ }
+ if (!ped_device_read (geom->dev, block, geom->start, blocksize)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read boot block %llu\n"), __func__, geom->start);
+ goto error;
+ }
+ if (PED_BE32_TO_CPU (block[0]) != kind) {
+ goto error;
+ }
+
+ /* Find and test the root block */
+ len = geom->length / blocksize - reserved;
+ pos = (len - 1) / 2;
+ root = geom->start + (pos + reserved) * blocksize;
+
+ if (!ped_device_read (geom->dev, block, root, blocksize)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read root block %llu\n"), __func__, root);
+ goto error;
+ }
+ if (_affs_probe_root(block, blocksize) == 1) {
+ free (block);
+ return ped_geometry_duplicate (geom);
+ }
+
+error:
+ free (block);
+error_block:
+error_part:
+ return NULL;
+}
+static PedGeometry*
+_affs0_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5300);
+}
+static PedGeometry*
+_affs1_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5301);
+}
+static PedGeometry*
+_affs2_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5302);
+}
+static PedGeometry*
+_affs3_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5303);
+}
+static PedGeometry*
+_affs4_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5304);
+}
+static PedGeometry*
+_affs5_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5305);
+}
+static PedGeometry*
+_affs6_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5306);
+}
+static PedGeometry*
+_affs7_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x444f5307);
+}
+static PedGeometry*
+_amufs_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754653);
+}
+static PedGeometry*
+_amufs0_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754600);
+}
+static PedGeometry*
+_amufs1_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754601);
+}
+static PedGeometry*
+_amufs2_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754602);
+}
+static PedGeometry*
+_amufs3_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754603);
+}
+static PedGeometry*
+_amufs4_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754604);
+}
+static PedGeometry*
+_amufs5_probe (PedGeometry* geom) {
+ return _generic_affs_probe (geom, 0x6d754605);
+}
+
+static PedFileSystemOps _affs0_ops = {
+ probe: _affs0_probe,
+};
+static PedFileSystemOps _affs1_ops = {
+ probe: _affs1_probe,
+};
+static PedFileSystemOps _affs2_ops = {
+ probe: _affs2_probe,
+};
+static PedFileSystemOps _affs3_ops = {
+ probe: _affs3_probe,
+};
+static PedFileSystemOps _affs4_ops = {
+ probe: _affs4_probe,
+};
+static PedFileSystemOps _affs5_ops = {
+ probe: _affs5_probe,
+};
+static PedFileSystemOps _affs6_ops = {
+ probe: _affs6_probe,
+};
+static PedFileSystemOps _affs7_ops = {
+ probe: _affs7_probe,
+};
+static PedFileSystemOps _amufs_ops = {
+ probe: _amufs_probe,
+};
+static PedFileSystemOps _amufs0_ops = {
+ probe: _amufs0_probe,
+};
+static PedFileSystemOps _amufs1_ops = {
+ probe: _amufs1_probe,
+};
+static PedFileSystemOps _amufs2_ops = {
+ probe: _amufs2_probe,
+};
+static PedFileSystemOps _amufs3_ops = {
+ probe: _amufs3_probe,
+};
+static PedFileSystemOps _amufs4_ops = {
+ probe: _amufs4_probe,
+};
+static PedFileSystemOps _amufs5_ops = {
+ probe: _amufs5_probe,
+};
+
+PedFileSystemType _affs0_type = {
+ next: NULL,
+ ops: &_affs0_ops,
+ name: "affs0",
+};
+PedFileSystemType _affs1_type = {
+ next: NULL,
+ ops: &_affs1_ops,
+ name: "affs1",
+};
+PedFileSystemType _affs2_type = {
+ next: NULL,
+ ops: &_affs2_ops,
+ name: "affs2",
+};
+PedFileSystemType _affs3_type = {
+ next: NULL,
+ ops: &_affs3_ops,
+ name: "affs3",
+};
+PedFileSystemType _affs4_type = {
+ next: NULL,
+ ops: &_affs4_ops,
+ name: "affs4",
+};
+PedFileSystemType _affs5_type = {
+ next: NULL,
+ ops: &_affs5_ops,
+ name: "affs5",
+};
+PedFileSystemType _affs6_type = {
+ next: NULL,
+ ops: &_affs6_ops,
+ name: "affs6",
+};
+PedFileSystemType _affs7_type = {
+ next: NULL,
+ ops: &_affs7_ops,
+ name: "affs7",
+};
+PedFileSystemType _amufs_type = {
+ next: NULL,
+ ops: &_amufs_ops,
+ name: "amufs",
+};
+PedFileSystemType _amufs0_type = {
+ next: NULL,
+ ops: &_amufs0_ops,
+ name: "amufs0",
+};
+PedFileSystemType _amufs1_type = {
+ next: NULL,
+ ops: &_amufs1_ops,
+ name: "amufs1",
+};
+PedFileSystemType _amufs2_type = {
+ next: NULL,
+ ops: &_amufs2_ops,
+ name: "amufs2",
+};
+PedFileSystemType _amufs3_type = {
+ next: NULL,
+ ops: &_amufs3_ops,
+ name: "amufs3",
+};
+PedFileSystemType _amufs4_type = {
+ next: NULL,
+ ops: &_amufs4_ops,
+ name: "amufs4",
+};
+PedFileSystemType _amufs5_type = {
+ next: NULL,
+ ops: &_amufs5_ops,
+ name: "amufs5",
+};
diff --git a/libparted/fs/amiga/affs.h b/libparted/fs/amiga/affs.h
new file mode 100644
index 0000000..d1650f2
--- /dev/null
+++ b/libparted/fs/amiga/affs.h
@@ -0,0 +1,19 @@
+
+/*
+ affs.h -- parted suppoer for affs filesystems header files
+ Copyright (C) 1998-2000, 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/>.
+*/
diff --git a/libparted/fs/amiga/amiga.c b/libparted/fs/amiga/amiga.c
new file mode 100644
index 0000000..1a909fc
--- /dev/null
+++ b/libparted/fs/amiga/amiga.c
@@ -0,0 +1,351 @@
+/*
+ libparted/fs_amiga - amiga file system support.
+ Copyright (C) 2000-2001, 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/>.
+
+ Contributor: Sven Luther <luther@debian.org>
+*/
+
+#include <config.h>
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "amiga.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#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 *
+_amiga_add_id (uint32_t id, struct AmigaIds *ids) {
+ struct AmigaIds *newid;
+
+ if ((newid=ped_malloc(sizeof (struct AmigaIds)))==NULL) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate id list element\n"), __func__);
+ return 0;
+ }
+ newid->ID = id;
+ newid->next = ids;
+ return newid;
+}
+
+void
+_amiga_free_ids (struct AmigaIds *ids) {
+ struct AmigaIds *current, *next;
+
+ for (current = ids; current != NULL; current = next) {
+ next = current->next;
+ free (current);
+ }
+}
+int
+_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;
+}
+
+#define AMIGA_RDB_NOT_FOUND ((uint32_t)0xffffffff)
+
+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))
+
+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 AMIGA_MAX_PARTITIONS 128
+#define RDB_LOCATION_LIMIT 16
+#define RDSK(pos) ((struct RigidDiskBlock *)(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 (PedDevice *dev, struct AmigaBlock *blk, PedSector block, struct AmigaIds *ids) {
+ if (!ped_device_read (dev, blk, block, 1)) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read block %llu\n"), __func__, block))
+ {
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ 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\n"),
+ __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 (dev, blk, block, 1)) {
+ switch (ped_exception_throw(PED_EXCEPTION_FATAL,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't write block %d\n"), __func__, block))
+ {
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return NULL;
+ }
+ }
+ /* FALLTHROUGH */
+ case PED_EXCEPTION_IGNORE :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return blk;
+ }
+ }
+ return blk;
+}
+
+static uint32_t
+_amiga_find_rdb (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;
+}
+
+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 */
+struct PartitionBlock *
+amiga_find_part (PedGeometry *geom, struct PartitionBlock *part)
+{
+ struct RigidDiskBlock *rdb;
+ uint32_t partblock;
+ uint32_t partlist[AMIGA_MAX_PARTITIONS];
+ int i;
+
+ PED_ASSERT(geom!= NULL);
+ PED_ASSERT(geom->dev!= NULL);
+
+ if (!(rdb = ped_malloc (PED_SECTOR_SIZE_DEFAULT))) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate disk_specific rdb block\n"), __func__))
+ {
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ return NULL;
+ }
+ }
+ if (_amiga_find_rdb (geom->dev, rdb) == AMIGA_RDB_NOT_FOUND) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Didn't find rdb block, should never happen\n"), __func__))
+ {
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ free(rdb);
+ return NULL;
+ }
+ }
+
+ /* We initialize the hardblock free list to detect loops */
+ for (i = 0; i < AMIGA_MAX_PARTITIONS; i++) partlist[i] = IDNAME_FREE;
+
+ for (i = 1, partblock = PED_BE32_TO_CPU(rdb->rdb_PartitionList);
+ i < AMIGA_MAX_PARTITIONS && partblock != IDNAME_FREE;
+ i++, partblock = PED_BE32_TO_CPU(part->pb_Next))
+ {
+ PedSector start, end;
+ PedSector cylblocks;
+
+ /* Let's look for loops in the partition table */
+ if (_amiga_loop_check(partblock, partlist, i)) {
+ free (rdb);
+ return NULL;
+ }
+ /* Let's read a partition block to get its geometry*/
+ if (!ped_device_read (geom->dev, part, (PedSector)partblock, 1)) {
+ switch (ped_exception_throw(PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("%s : Failed to read partition block %llu\n"),
+ __func__, (PedSector)partblock))
+ {
+ case PED_EXCEPTION_CANCEL :
+ case PED_EXCEPTION_UNHANDLED :
+ default :
+ free(rdb);
+ return NULL;
+ }
+ }
+
+ /* Current block is not a Partition Block */
+ if (part->pb_ID != IDNAME_PARTITION) {
+ free (rdb);
+ return NULL;
+ }
+
+ /* Calculate the geometry of the partition */
+ cylblocks = ((PedSector) PED_BE32_TO_CPU (part->de_Surfaces)) *
+ ((PedSector) PED_BE32_TO_CPU (part->de_BlocksPerTrack));
+ start = ((PedSector) PED_BE32_TO_CPU (part->de_LowCyl)) * cylblocks;
+ end = ((((PedSector) PED_BE32_TO_CPU (part->de_HighCyl))+1) * (cylblocks))-1;
+
+ /* And check if it is the one we are searching for */
+ if (start == geom->start && end == geom->end) {
+ free (rdb);
+ return part;
+ }
+ }
+
+ free (rdb);
+ return NULL;
+}
diff --git a/libparted/fs/amiga/amiga.h b/libparted/fs/amiga/amiga.h
new file mode 100644
index 0000000..30f5b82
--- /dev/null
+++ b/libparted/fs/amiga/amiga.h
@@ -0,0 +1,70 @@
+/*
+ util.h -- amiga partition table headers.
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+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 */
+ uint8_t pb_DriveName[32]; /* Preferred DOS device name: BSTR form */
+ uint32_t pb_Reserved2[15];
+ uint32_t de_TableSize; /* Size of Environment vector */
+ uint32_t de_SizeBlock; /* Size of the blocks in 32 bit words, usually 128 */
+ uint32_t de_SecOrg; /* Not used; must be 0 */
+ uint32_t de_Surfaces; /* Number of heads (surfaces) */
+ uint32_t de_SectorPerBlock; /* Disk sectors per block, used with SizeBlock, usually 1 */
+ 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) */
+
+struct PartitionBlock * amiga_find_part (PedGeometry *geom, struct PartitionBlock *part);
+
+struct AmigaIds {
+ uint32_t ID;
+ struct AmigaIds *next;
+};
+
+struct AmigaIds * _amiga_add_id (uint32_t id, struct AmigaIds *ids);
+void _amiga_free_ids (struct AmigaIds *ids);
+int _amiga_id_in_list (uint32_t id, struct AmigaIds *ids) _GL_ATTRIBUTE_PURE;
diff --git a/libparted/fs/amiga/apfs.c b/libparted/fs/amiga/apfs.c
new file mode 100644
index 0000000..aeaa1f3
--- /dev/null
+++ b/libparted/fs/amiga/apfs.c
@@ -0,0 +1,128 @@
+/*
+ apfs.c -- parted support for apfs file systems
+ Copyright (C) 1998-2000, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "amiga.h"
+#include "apfs.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static int
+_apfs_probe_root (uint32_t *block, uint32_t blocksize, uint32_t kind) {
+ if (PED_BE32_TO_CPU (block[0]) != kind) return 0;
+ return 1;
+}
+
+static PedGeometry*
+_generic_apfs_probe (PedGeometry* geom, uint32_t kind)
+{
+ uint32_t *block;
+ PedSector root;
+ struct PartitionBlock * part;
+ uint32_t blocksize = 1, reserved = 2;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (geom->dev != NULL);
+ if (geom->dev->sector_size != 512)
+ return NULL;
+
+ /* Finds the blocksize and reserved values of the partition block */
+ if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate partition block\n"), __func__);
+ goto error_part;
+ }
+ if (amiga_find_part(geom, part) != NULL) {
+ reserved = PED_BE32_TO_CPU (part->de_Reserved);
+ blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
+ * PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
+ }
+ free (part);
+
+ /* Test boot block */
+ if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate block\n"), __func__);
+ goto error_block;
+ }
+ if (!ped_device_read (geom->dev, block, geom->start, blocksize)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read boot block %llu\n"), __func__, geom->start);
+ goto error;
+ }
+ if (PED_BE32_TO_CPU (block[0]) != kind) {
+ goto error;
+ }
+
+ /* Find and test the root block */
+ root = geom->start+reserved*blocksize;
+ if (!ped_device_read (geom->dev, block, root, blocksize)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read root block %llu\n"), __func__, root);
+ goto error;
+ }
+ if (_apfs_probe_root(block, blocksize, kind) == 1) {
+ free(block);
+ return ped_geometry_duplicate (geom);
+ }
+
+error:
+ free (block);
+error_block:
+error_part:
+ return NULL;
+}
+
+static PedGeometry*
+_apfs1_probe (PedGeometry* geom) {
+ return _generic_apfs_probe (geom, 0x50463101);
+}
+
+static PedGeometry*
+_apfs2_probe (PedGeometry* geom) {
+ return _generic_apfs_probe (geom, 0x50463102);
+}
+
+static PedFileSystemOps _apfs1_ops = {
+ probe: _apfs1_probe,
+};
+static PedFileSystemOps _apfs2_ops = {
+ probe: _apfs2_probe,
+};
+
+PedFileSystemType _apfs1_type = {
+ next: NULL,
+ ops: &_apfs1_ops,
+ name: "apfs1",
+};
+PedFileSystemType _apfs2_type = {
+ next: NULL,
+ ops: &_apfs2_ops,
+ name: "apfs2",
+};
diff --git a/libparted/fs/amiga/apfs.h b/libparted/fs/amiga/apfs.h
new file mode 100644
index 0000000..972941b
--- /dev/null
+++ b/libparted/fs/amiga/apfs.h
@@ -0,0 +1,18 @@
+/*
+ apfs.h -- parted support for apfs file systems header files
+ Copyright (C) 1998-2000, 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/>.
+*/
diff --git a/libparted/fs/amiga/asfs.c b/libparted/fs/amiga/asfs.c
new file mode 100644
index 0000000..c4c65e5
--- /dev/null
+++ b/libparted/fs/amiga/asfs.c
@@ -0,0 +1,130 @@
+/*
+ asfs.c -- parted asfs filesystem support
+ Copyright (C) 1998-2000, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <parted/endian.h>
+
+#include "amiga.h"
+#include "asfs.h"
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static int
+_asfs_probe_root (PedGeometry *geom, uint32_t *block, int blocksize, PedSector root) {
+ int i, sum;
+ PedSector start, end;
+
+ if (PED_BE32_TO_CPU (block[0]) != 0x53465300) return 0;
+ for (i = 0, sum = 1; i < 128*blocksize; i++) sum += PED_BE32_TO_CPU (block[i]);
+ if (sum != 0) return 0;
+ if (PED_BE32_TO_CPU (block[2]) * blocksize + geom->start != root) {
+ return 0;
+ }
+ start = ((((PedSector) PED_BE32_TO_CPU (block[8])) << 32)
+ + (PedSector) PED_BE32_TO_CPU (block[9])) / 512;
+ end = (((((PedSector) PED_BE32_TO_CPU (block[10])) << 32)
+ + (PedSector) PED_BE32_TO_CPU (block[11])) / 512) - 1;
+ if (start != geom->start || end != geom->end) return 0;
+ return 1;
+}
+
+static PedGeometry*
+_asfs_probe (PedGeometry* geom)
+{
+ uint32_t *block;
+ struct PartitionBlock * part;
+ int blocksize = 1;
+ PedSector root;
+ int found = 0;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (geom->dev != NULL);
+ if (geom->dev->sector_size != 512)
+ return NULL;
+
+ /* Finds the blocksize of the partition block */
+ if (!(part = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate partition block\n"), __func__);
+ goto error_part;
+ }
+ if (amiga_find_part(geom, part) != NULL) {
+ blocksize = PED_BE32_TO_CPU (part->de_SizeBlock)
+ * PED_BE32_TO_CPU (part->de_SectorPerBlock) / 128;
+ }
+ free (part);
+
+ /* Test boot block */
+ if (!(block = ped_malloc (PED_SECTOR_SIZE_DEFAULT*blocksize))) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Failed to allocate block\n"), __func__);
+ goto error_block;
+ }
+ root = geom->start;
+ if (!ped_device_read (geom->dev, block, root, blocksize)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read root block %llu\n"), __func__, root);
+ goto error;
+ }
+ if (PED_BE32_TO_CPU (block[0]) != 0x53465300) {
+ goto error;
+ }
+
+ /* Find and test the root blocks */
+ if (_asfs_probe_root(geom, block, blocksize, root)) {
+ found++;
+ }
+ root = geom->end - blocksize - (geom->length % blocksize) + 1;
+ if (!ped_device_read (geom->dev, block, root, 1)) {
+ ped_exception_throw(PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("%s : Couldn't read root block %llu\n"), __func__, root);
+ goto error;
+ }
+ if (_asfs_probe_root(geom, block, blocksize, root)) {
+ found++;
+ }
+ if (found != 0) {
+ free (block);
+ return ped_geometry_duplicate (geom);
+ }
+
+error:
+ free (block);
+error_block:
+error_part:
+ return NULL;
+}
+
+static PedFileSystemOps _asfs_ops = {
+ probe: _asfs_probe,
+};
+
+PedFileSystemType _asfs_type = {
+ next: NULL,
+ ops: &_asfs_ops,
+ name: "asfs",
+};
diff --git a/libparted/fs/amiga/asfs.h b/libparted/fs/amiga/asfs.h
new file mode 100644
index 0000000..2b70a94
--- /dev/null
+++ b/libparted/fs/amiga/asfs.h
@@ -0,0 +1,18 @@
+/*
+ asfs.h -- parted asfs filesystem support header files
+ Copyright (C) 1998-2000, 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/>.
+*/
diff --git a/libparted/fs/btrfs/btrfs.c b/libparted/fs/btrfs/btrfs.c
new file mode 100644
index 0000000..6eded8b
--- /dev/null
+++ b/libparted/fs/btrfs/btrfs.c
@@ -0,0 +1,77 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2013-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/endian.h>
+
+/* Located 64k inside the partition (start of the first btrfs superblock) */
+#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */
+#define BTRFS_CSUM_SIZE 32
+#define BTRFS_FSID_SIZE 16
+
+
+static PedGeometry*
+btrfs_probe (PedGeometry* geom)
+{
+ union {
+ struct {
+ /* Just enough of the btrfs_super_block to get the magic */
+ uint8_t csum[BTRFS_CSUM_SIZE];
+ uint8_t fsid[BTRFS_FSID_SIZE];
+ uint64_t bytenr;
+ uint64_t flags;
+ uint64_t magic;
+ } sb;
+ int8_t sector[8192];
+ } buf;
+ PedSector offset = (64*1024)/geom->dev->sector_size;
+
+ if (geom->length < offset+1)
+ return 0;
+ if (!ped_geometry_read (geom, &buf, offset, 1))
+ return 0;
+
+ if (PED_LE64_TO_CPU(buf.sb.magic) == BTRFS_MAGIC) {
+ return ped_geometry_new (geom->dev, geom->start, geom->length);
+ }
+ return NULL;
+}
+
+static PedFileSystemOps btrfs_ops = {
+ probe: btrfs_probe,
+};
+
+static PedFileSystemType btrfs_type = {
+ next: NULL,
+ ops: &btrfs_ops,
+ name: "btrfs",
+};
+
+void
+ped_file_system_btrfs_init ()
+{
+ ped_file_system_type_register (&btrfs_type);
+}
+
+void
+ped_file_system_btrfs_done ()
+{
+ ped_file_system_type_unregister (&btrfs_type);
+}
diff --git a/libparted/fs/ext2/ext2.h b/libparted/fs/ext2/ext2.h
new file mode 100644
index 0000000..d23f63e
--- /dev/null
+++ b/libparted/fs/ext2/ext2.h
@@ -0,0 +1,79 @@
+/*
+ ext2.h -- ext2 header
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef _EXT2_H
+#define _EXT2_H
+
+#include <parted/parted.h>
+#include <parted/debug.h>
+#include <sys/types.h>
+
+#include <inttypes.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+typedef u_int32_t blk_t;
+
+#ifdef HAVE_LINUX_EXT2_FS_H__FAILS_TO_COMPILE
+#include <linux/ext2_fs.h>
+#else
+#include "ext2_fs.h"
+#endif
+
+struct ext2_fs
+{
+ struct ext2_dev_handle *devhandle;
+
+ struct ext2_super_block sb;
+ struct ext2_group_desc *gd;
+ struct ext2_buffer_cache *bc;
+ int metadirty; /* 0:all sb&gd copies clean
+ 1:all sb&gd copies dirty
+ 2:only first sb&gd copy clean */
+
+ int dynamic_version;
+ int sparse; /* sparse superblocks */
+ int has_journal; /* journal */
+ int has_internal_journal;
+
+ int blocksize;
+ int logsize;
+ blk_t adminblocks;
+ blk_t gdblocks;
+ blk_t itoffset;
+ blk_t inodeblocks;
+ int numgroups;
+ int r_frac; /* reserved % of blocks */
+
+ unsigned char *relocator_pool;
+ unsigned char *relocator_pool_end;
+
+ int opt_debug;
+ int opt_safe;
+ int opt_verbose;
+
+ void *journal;
+};
+
+#endif
diff --git a/libparted/fs/ext2/ext2_fs.h b/libparted/fs/ext2/ext2_fs.h
new file mode 100644
index 0000000..1eca7ab
--- /dev/null
+++ b/libparted/fs/ext2/ext2_fs.h
@@ -0,0 +1,329 @@
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * EXT2_*_*() convienience macros added by Andrew Clausen <clausen@gnu.org>
+ * Copyright (C) 2000, 2009-2014, 2019-2023 Free Software Foundation, Inc.
+ */
+
+#ifndef _EXT2_FS_H
+#define _EXT2_FS_H
+
+#include <parted/endian.h>
+#include <stdint.h>
+
+/*
+ * The second extended file system constants/structures
+ */
+
+#define EXT2_SUPER_MAGIC_CONST 0xEF53
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+#define EXT2_VALID_FS 0x0001
+#define EXT2_ERROR_FS 0x0002
+#define EXT2_RESERVED_INODE_COUNT 11
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Feature set definitions
+ */
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_HAS_DIR_INDEX 0x0020
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+
+/*
+ * Special inodes numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_ACL_IDX_INO 3 /* ACL inode */
+#define EXT2_ACL_DATA_INO 4 /* ACL inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+struct ext2_dir_entry_2
+{
+ uint32_t inode;
+ uint16_t rec_len;
+ uint8_t name_len;
+ uint8_t file_type;
+ char name[255];
+};
+
+struct ext2_group_desc
+{
+ uint32_t bg_block_bitmap;
+ uint32_t bg_inode_bitmap;
+ uint32_t bg_inode_table;
+ uint16_t bg_free_blocks_count;
+ uint16_t bg_free_inodes_count;
+ uint16_t bg_used_dirs_count;
+ uint16_t bg_pad;
+ uint32_t bg_reserved[3];
+};
+
+struct ext2_inode
+{
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Owner Uid */
+ uint32_t i_size; /* Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* Deletion Time */
+ uint16_t i_gid; /* Group Id */
+ uint16_t i_links_count; /* Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* File flags */
+ union {
+ struct {
+ uint32_t l_i_reserved1;
+ } linux1;
+ struct {
+ uint32_t h_i_translator;
+ } hurd1;
+ struct {
+ uint32_t m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ uint32_t i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ uint32_t i_generation; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ union {
+ struct {
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint32_t l_i_reserved2[2];
+ } linux2;
+ struct {
+ uint8_t h_i_frag; /* Fragment number */
+ uint8_t h_i_fsize; /* Fragment size */
+ uint16_t h_i_mode_high;
+ uint16_t h_i_uid_high;
+ uint16_t h_i_gid_high;
+ uint32_t h_i_author;
+ } hurd2;
+ struct {
+ uint8_t m_i_frag; /* Fragment number */
+ uint8_t m_i_fsize; /* Fragment size */
+ uint16_t m_pad1;
+ uint32_t m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+#define i_size_high i_dir_acl
+
+struct __attribute__ ((packed)) ext2_super_block
+{
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ int32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level; /* minor revision level */
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the file system.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_PREALLOC flag is on.
+ */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ uint16_t s_padding1;
+ /*
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+
+ uint32_t s_reserved[197]; /* Padding to the end of the block */
+};
+
+#define EXT2_DIRENT_INODE(dir_ent) (PED_LE32_TO_CPU((dir_ent).inode))
+#define EXT2_DIRENT_REC_LEN(dir_ent) (PED_LE16_TO_CPU((dir_ent).rec_len))
+#define EXT2_DIRENT_NAME_LEN(dir_ent) ((dir_ent).name_len)
+#define EXT2_DIRENT_FILE_TYPE(dir_ent) ((dir_ent).file_type)
+
+#define EXT2_GROUP_BLOCK_BITMAP(gd) (PED_LE32_TO_CPU((gd).bg_block_bitmap))
+#define EXT2_GROUP_INODE_BITMAP(gd) (PED_LE32_TO_CPU((gd).bg_inode_bitmap))
+#define EXT2_GROUP_INODE_TABLE(gd) (PED_LE32_TO_CPU((gd).bg_inode_table))
+#define EXT2_GROUP_FREE_BLOCKS_COUNT(gd) \
+ (PED_LE16_TO_CPU((gd).bg_free_blocks_count))
+#define EXT2_GROUP_FREE_INODES_COUNT(gd) \
+ (PED_LE16_TO_CPU((gd).bg_free_inodes_count))
+#define EXT2_GROUP_USED_DIRS_COUNT(gd) \
+ (PED_LE16_TO_CPU((gd).bg_used_dirs_count))
+
+#define EXT2_INODE_MODE(inode) (PED_LE16_TO_CPU((inode).i_mode))
+#define EXT2_INODE_UID(inode) (PED_LE16_TO_CPU((inode).i_uid))
+#define EXT2_INODE_SIZE(inode) \
+ ((uint64_t) PED_LE32_TO_CPU((inode).i_size) \
+ + ((uint64_t) PED_LE32_TO_CPU((inode).i_size_high) << 32))
+#define EXT2_INODE_ATIME(inode) (PED_LE32_TO_CPU((inode).i_atime))
+#define EXT2_INODE_CTIME(inode) (PED_LE32_TO_CPU((inode).i_ctime))
+#define EXT2_INODE_MTIME(inode) (PED_LE32_TO_CPU((inode).i_mtime))
+#define EXT2_INODE_DTIME(inode) (PED_LE32_TO_CPU((inode).i_dtime))
+#define EXT2_INODE_GID(inode) (PED_LE16_TO_CPU((inode).i_gid))
+#define EXT2_INODE_LINKS_COUNT(inode) (PED_LE16_TO_CPU((inode).i_links_count))
+#define EXT2_INODE_BLOCKS(inode) (PED_LE32_TO_CPU((inode).i_blocks))
+#define EXT2_INODE_FLAGS(inode) (PED_LE32_TO_CPU((inode).i_flags))
+#define EXT2_INODE_TRANSLATOR(inode) (PED_LE32_TO_CPU((inode).osd1.hurd1.h_i_translator))
+#define EXT2_INODE_BLOCK(inode, blk) (PED_LE32_TO_CPU((inode).i_block[blk]))
+
+#define EXT2_SUPER_INODES_COUNT(sb) (PED_LE32_TO_CPU((sb).s_inodes_count))
+#define EXT2_SUPER_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_blocks_count))
+#define EXT2_SUPER_R_BLOCKS_COUNT(sb) (PED_LE32_TO_CPU((sb).s_r_blocks_count))
+#define EXT2_SUPER_FREE_BLOCKS_COUNT(sb) \
+ (PED_LE32_TO_CPU((sb).s_free_blocks_count))
+#define EXT2_SUPER_FREE_INODES_COUNT(sb) \
+ (PED_LE32_TO_CPU((sb).s_free_inodes_count))
+#define EXT2_SUPER_FIRST_DATA_BLOCK(sb) \
+ (PED_LE32_TO_CPU((sb).s_first_data_block))
+#define EXT2_SUPER_LOG_BLOCK_SIZE(sb) (PED_LE32_TO_CPU((sb).s_log_block_size))
+#define EXT2_SUPER_LOG_FRAG_SIZE(sb) \
+ ((int32_t) PED_LE32_TO_CPU((sb).s_log_frag_size))
+#define EXT2_SUPER_BLOCKS_PER_GROUP(sb) \
+ (PED_LE32_TO_CPU((sb).s_blocks_per_group))
+#define EXT2_SUPER_FRAGS_PER_GROUP(sb) \
+ (PED_LE32_TO_CPU((sb).s_frags_per_group))
+#define EXT2_SUPER_INODES_PER_GROUP(sb) \
+ (PED_LE32_TO_CPU((sb).s_inodes_per_group))
+#define EXT2_SUPER_MTIME(sb) (PED_LE32_TO_CPU((sb).s_mtime))
+#define EXT2_SUPER_WTIME(sb) (PED_LE32_TO_CPU((sb).s_wtime))
+#define EXT2_SUPER_MNT_COUNT(sb) (PED_LE16_TO_CPU((sb).s_mnt_count))
+#define EXT2_SUPER_MAX_MNT_COUNT(sb) \
+ ((int16_t) PED_LE16_TO_CPU((sb).s_max_mnt_count))
+#define EXT2_SUPER_MAGIC(sb) (PED_LE16_TO_CPU((sb).s_magic))
+#define EXT2_SUPER_STATE(sb) (PED_LE16_TO_CPU((sb).s_state))
+#define EXT2_SUPER_ERRORS(sb) (PED_LE16_TO_CPU((sb).s_errors))
+#define EXT2_SUPER_MINOR_REV_LEVEL(sb) \
+ (PED_LE16_TO_CPU((sb).s_minor_rev_level))
+#define EXT2_SUPER_LASTCHECK(sb) (PED_LE32_TO_CPU((sb).s_lastcheck))
+#define EXT2_SUPER_CHECKINTERVAL(sb) (PED_LE32_TO_CPU((sb).s_checkinterval))
+#define EXT2_SUPER_CREATOR_OS(sb) (PED_LE32_TO_CPU((sb).s_creator_os))
+#define EXT2_SUPER_REV_LEVEL(sb) (PED_LE32_TO_CPU((sb).s_rev_level))
+#define EXT2_SUPER_DEF_RESUID(sb) (PED_LE16_TO_CPU((sb).s_def_resuid))
+#define EXT2_SUPER_DEF_RESGID(sb) (PED_LE16_TO_CPU((sb).s_def_resgid))
+
+#define EXT2_SUPER_FIRST_INO(sb) (PED_LE32_TO_CPU((sb).s_first_ino))
+#define EXT2_SUPER_INODE_SIZE(sb) (PED_LE16_TO_CPU((sb).s_inode_size))
+#define EXT2_SUPER_BLOCK_GROUP_NR(sb) (PED_LE16_TO_CPU((sb).s_block_group_nr))
+#define EXT2_SUPER_FEATURE_COMPAT(sb) (PED_LE32_TO_CPU((sb).s_feature_compat))
+#define EXT2_SUPER_FEATURE_INCOMPAT(sb) \
+ (PED_LE32_TO_CPU((sb).s_feature_incompat))
+#define EXT2_SUPER_FEATURE_RO_COMPAT(sb) \
+ (PED_LE32_TO_CPU((sb).s_feature_ro_compat))
+#define EXT2_SUPER_UUID(sb) ((sb).s_uuid)
+#define EXT2_SUPER_VOLUME_NAME(sb) ((sb).s_volume_name)
+#define EXT2_SUPER_LAST_MOUNTED(sb) ((sb).s_last_mounted)
+#define EXT2_SUPER_ALGORITHM_USAGE_BITMAP(sb) \
+ (PED_LE32_TO_CPU((sb).s_algorithm_usage_bitmap))
+
+#define EXT2_SUPER_JOURNAL_UUID(sb) ((sb).s_journal_uuid)
+#define EXT2_SUPER_JOURNAL_INUM(sb) (PED_LE32_TO_CPU((sb).s_journal_inum))
+#define EXT2_SUPER_JOURNAL_DEV(sb) (PED_LE32_TO_CPU((sb).s_journal_dev))
+#define EXT2_SUPER_LAST_ORPHAN(sb) (PED_LE32_TO_CPU((sb).s_last_orphan))
+
+#endif
diff --git a/libparted/fs/ext2/interface.c b/libparted/fs/ext2/interface.c
new file mode 100644
index 0000000..7e0b197
--- /dev/null
+++ b/libparted/fs/ext2/interface.c
@@ -0,0 +1,163 @@
+/*
+ interface.c -- parted binding glue to libext2resize
+ Copyright (C) 1998-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/>.
+*/
+
+/* VERSION: libext2resize 1.1.6 (by Lennert)
+ * merged 1.1.11 changes (by Andrew)
+ */
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include "ext2.h"
+
+static PedFileSystemType _ext2_type;
+static PedFileSystemType _ext3_type;
+
+struct ext2_dev_handle* ext2_make_dev_handle_from_parted_geometry(PedGeometry* geom);
+
+static PedGeometry*
+_ext2_generic_probe (PedGeometry* geom, int expect_ext_ver)
+{
+ struct ext2_super_block *sb;
+ const int sectors = (4096 + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ uint8_t *buf = alloca (sectors * geom->dev->sector_size);
+ if (!ped_geometry_read(geom, buf, 0, sectors))
+ return NULL;
+ sb = (struct ext2_super_block *)(buf+1024);
+
+ if (EXT2_SUPER_MAGIC(*sb) == EXT2_SUPER_MAGIC_CONST) {
+ PedSector block_size = (EXT2_MIN_BLOCK_SIZE << (EXT2_SUPER_LOG_BLOCK_SIZE(*sb))) / geom->dev->sector_size;
+ PedSector block_count = EXT2_SUPER_BLOCKS_COUNT(*sb);
+ PedSector group_blocks = EXT2_SUPER_BLOCKS_PER_GROUP(*sb);
+ PedSector group_nr = EXT2_SUPER_BLOCK_GROUP_NR(*sb);
+ PedSector first_data_block = EXT2_SUPER_FIRST_DATA_BLOCK(*sb);
+ int version = EXT2_SUPER_REV_LEVEL(*sb);
+ int is_ext3 = 0;
+ int is_ext4 = 0;
+
+ is_ext3 = (EXT2_SUPER_FEATURE_COMPAT (*sb)
+ & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0;
+ if (is_ext3) {
+ is_ext4 = ((EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
+ & EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
+ || (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
+ & EXT4_FEATURE_RO_COMPAT_GDT_CSUM)
+ || (EXT2_SUPER_FEATURE_RO_COMPAT (*sb)
+ & EXT4_FEATURE_RO_COMPAT_DIR_NLINK)
+ || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
+ & EXT4_FEATURE_INCOMPAT_EXTENTS)
+ || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
+ & EXT4_FEATURE_INCOMPAT_64BIT)
+ || (EXT2_SUPER_FEATURE_INCOMPAT (*sb)
+ & EXT4_FEATURE_INCOMPAT_FLEX_BG));
+ if (is_ext4)
+ is_ext3 = 0;
+ }
+ if (expect_ext_ver == 2 && (is_ext3 || is_ext4))
+ return NULL;
+ if (expect_ext_ver == 3 && !is_ext3)
+ return NULL;
+ else if (expect_ext_ver == 4 && !is_ext4)
+ return NULL;
+
+ if (version > 0 && group_nr > 0) {
+ PedSector start;
+ PedGeometry probe_geom;
+
+ start = geom->start
+ - group_blocks * group_nr
+ - first_data_block;
+
+ if (start < 0)
+ return NULL;
+ ped_geometry_init (&probe_geom, geom->dev,
+ start, block_count * block_size);
+ return _ext2_generic_probe (&probe_geom,
+ expect_ext_ver);
+ } else {
+ return ped_geometry_new (geom->dev, geom->start,
+ block_count * block_size);
+ }
+ }
+
+ return NULL;
+}
+
+static PedGeometry*
+_ext2_probe (PedGeometry* geom)
+{
+ return _ext2_generic_probe (geom, 2);
+}
+
+static PedGeometry*
+_ext3_probe (PedGeometry* geom)
+{
+ return _ext2_generic_probe (geom, 3);
+}
+
+static PedGeometry*
+_ext4_probe (PedGeometry* geom)
+{
+ return _ext2_generic_probe (geom, 4);
+}
+
+static PedFileSystemOps _ext2_ops = {
+ probe: _ext2_probe,
+};
+
+static PedFileSystemOps _ext3_ops = {
+ probe: _ext3_probe,
+};
+
+static PedFileSystemOps _ext4_ops = {
+ probe: _ext4_probe,
+};
+
+static PedFileSystemType _ext2_type = {
+ next: NULL,
+ ops: &_ext2_ops,
+ name: "ext2",
+};
+
+static PedFileSystemType _ext3_type = {
+ next: NULL,
+ ops: &_ext3_ops,
+ name: "ext3",
+};
+
+static PedFileSystemType _ext4_type = {
+ next: NULL,
+ ops: &_ext4_ops,
+ name: "ext4",
+};
+
+void ped_file_system_ext2_init ()
+{
+ ped_file_system_type_register (&_ext2_type);
+ ped_file_system_type_register (&_ext3_type);
+ ped_file_system_type_register (&_ext4_type);
+}
+
+void ped_file_system_ext2_done ()
+{
+ ped_file_system_type_unregister (&_ext2_type);
+ ped_file_system_type_unregister (&_ext3_type);
+ ped_file_system_type_unregister (&_ext4_type);
+}
diff --git a/libparted/fs/f2fs/f2fs.c b/libparted/fs/f2fs/f2fs.c
new file mode 100644
index 0000000..68ed092
--- /dev/null
+++ b/libparted/fs/f2fs/f2fs.c
@@ -0,0 +1,60 @@
+/*
+ libparted/fs/f2fs - Flash-Friendly File System
+ Copyright (C) 2020-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/endian.h>
+
+#include "f2fs.h"
+
+static PedGeometry*
+f2fs_probe (PedGeometry* geom)
+{
+ struct f2fs_super_block *sb = alloca(geom->dev->sector_size);
+
+ if (!ped_geometry_read (geom, sb, F2FS_SB_OFFSET, 1))
+ return NULL;
+
+ if (PED_LE32_TO_CPU(sb->magic) == F2FS_MAGIC)
+ return ped_geometry_new (geom->dev, geom->start, geom->length);
+
+ return NULL;
+}
+
+static PedFileSystemOps f2fs_ops = {
+ probe: f2fs_probe,
+};
+
+static PedFileSystemType f2fs_type = {
+ next: NULL,
+ ops: &f2fs_ops,
+ name: "f2fs",
+};
+
+void
+ped_file_system_f2fs_init ()
+{
+ ped_file_system_type_register (&f2fs_type);
+}
+
+void
+ped_file_system_f2fs_done ()
+{
+ ped_file_system_type_unregister (&f2fs_type);
+}
diff --git a/libparted/fs/f2fs/f2fs.h b/libparted/fs/f2fs/f2fs.h
new file mode 100644
index 0000000..9341337
--- /dev/null
+++ b/libparted/fs/f2fs/f2fs.h
@@ -0,0 +1,57 @@
+/*
+ libparted/fs/f2fs - Flash-Friendly File System
+ Copyright (C) 2020-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/>.
+*/
+#ifndef _F2FS_H
+#define _F2FS_H
+
+#define F2FS_MAGIC 0xF2F52010
+#define F2FS_MAX_VOLUME_NAME 512
+#define F2FS_SB_OFFSET 0x02
+
+struct f2fs_super_block {
+ uint32_t magic; /* Magic Number */
+ uint16_t major_ver; /* Major Version */
+ uint16_t minor_ver; /* Minor Version */
+ uint32_t log_sectorsize; /* log2 sector size in bytes */
+ uint32_t log_sectors_per_block; /* log2 # of sectors per block */
+ uint32_t log_blocksize; /* log2 block size in bytes */
+ uint32_t log_blocks_per_seg; /* log2 # of blocks per segment */
+ uint32_t segs_per_sec; /* # of segments per section */
+ uint32_t secs_per_zone; /* # of sections per zone */
+ uint32_t checksum_offset; /* checksum offset inside super block */
+ uint64_t block_count; /* total # of user blocks */
+ uint32_t section_count; /* total # of sections */
+ uint32_t segment_count; /* total # of segments */
+ uint32_t segment_count_ckpt; /* # of segments for checkpoint */
+ uint32_t segment_count_sit; /* # of segments for SIT */
+ uint32_t segment_count_nat; /* # of segments for NAT */
+ uint32_t segment_count_ssa; /* # of segments for SSA */
+ uint32_t segment_count_main; /* # of segments for main area */
+ uint32_t segment0_blkaddr; /* start block address of segment 0 */
+ uint32_t cp_blkaddr; /* start block address of checkpoint */
+ uint32_t sit_blkaddr; /* start block address of SIT */
+ uint32_t nat_blkaddr; /* start block address of NAT */
+ uint32_t ssa_blkaddr; /* start block address of SSA */
+ uint32_t main_blkaddr; /* start block address of main area */
+ uint32_t root_ino; /* root inode number */
+ uint32_t node_ino; /* node inode number */
+ uint32_t meta_ino; /* meta inode number */
+ uint8_t uuid[16]; /* 128-bit uuid for volume */
+ uint16_t volume_name[F2FS_MAX_VOLUME_NAME]; /* volume name */
+} __attribute__((packed));
+
+#endif
diff --git a/libparted/fs/fat/bootsector.c b/libparted/fs/fat/bootsector.c
new file mode 100644
index 0000000..f02685b
--- /dev/null
+++ b/libparted/fs/fat/bootsector.c
@@ -0,0 +1,271 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 2002, 2004, 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 <config.h>
+#include "fat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Reads in the boot sector (superblock), and does a minimum of sanity
+ * checking. The goals are:
+ * - to detect fat file systems, even if they are damaged [i.e. not
+ * return an error / throw an exception]
+ * - to fail detection if there's not enough information for
+ * fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero)
+ */
+int
+fat_boot_sector_read (FatBootSector** bsp, const PedGeometry *geom)
+{
+ PED_ASSERT (bsp != NULL);
+ PED_ASSERT (geom != NULL);
+
+ if (!ped_geometry_read_alloc (geom, (void **)bsp, 0, 1))
+ return 0;
+ FatBootSector *bs = *bsp;
+
+ if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid signature for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->sector_size
+ || PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid sector size for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->cluster_size) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid cluster size for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->reserved) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid number of reserved "
+ "sectors for a FAT file system."));
+ return 0;
+ }
+
+ if (bs->fats < 1 || bs->fats > 4) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid number of FATs."));
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ Don't trust the FAT12, FAT16 or FAT32 label string.
+ */
+FatType _GL_ATTRIBUTE_PURE
+fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
+{
+ PedSector logical_sector_size;
+ PedSector first_cluster_sector;
+ FatCluster cluster_count;
+
+ if (!PED_LE16_TO_CPU (bs->dir_entries))
+ return FAT_TYPE_FAT32;
+
+ logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
+
+ first_cluster_sector
+ = PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
+ + 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
+ + PED_LE16_TO_CPU (bs->dir_entries)
+ / (512 / sizeof (FatDirEntry));
+ cluster_count = (geom->length - first_cluster_sector)
+ / bs->cluster_size / logical_sector_size;
+ if (cluster_count > MAX_FAT12_CLUSTERS)
+ return FAT_TYPE_FAT16;
+ else
+ return FAT_TYPE_FAT12;
+}
+
+static int
+_fat_table_entry_size (FatType fat_type)
+{
+ switch (fat_type) {
+ case FAT_TYPE_FAT12:
+ return 2; /* FIXME: how? */
+
+ case FAT_TYPE_FAT16:
+ return 2;
+
+ case FAT_TYPE_FAT32:
+ return 4;
+ }
+
+ return 0;
+}
+
+/* Analyses the boot sector, and sticks appropriate numbers in
+ fs->type_specific.
+
+ Note: you need to subtract (2 * cluster_sectors) off cluster offset,
+ because the first cluster is number 2. (0 and 1 are not real clusters,
+ and referencing them is a bug)
+ */
+int
+fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int fat_entry_size;
+
+ PED_ASSERT (bs != NULL);
+
+ fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
+
+ fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
+ fs_info->heads = PED_LE16_TO_CPU (bs->heads);
+ if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
+ || fs_info->heads < 1 || fs_info->heads > 255) {
+ PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
+ int cyl_count = 0;
+
+ if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
+ cyl_count = fs->geom->dev->length / fs_info->heads
+ / fs_info->sectors_per_track;
+
+ switch (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The file system's CHS geometry is (%d, %d, %d), "
+ "which is invalid. The partition table's CHS "
+ "geometry is (%d, %d, %d)."),
+ cyl_count, fs_info->heads, fs_info->sectors_per_track,
+ bios_geom->cylinders, bios_geom->heads,
+ bios_geom->sectors)) {
+
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+
+ case PED_EXCEPTION_IGNORE:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (bs->sectors)
+ fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
+ * fs_info->logical_sector_size;
+ else
+ fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
+ * fs_info->logical_sector_size;
+
+ fs_info->fat_table_count = bs->fats;
+ fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
+ fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
+ * fs_info->logical_sector_size;
+ fs_info->cluster_sectors = bs->cluster_size
+ * fs_info->logical_sector_size;
+ fs_info->cluster_size = fs_info->cluster_sectors * 512;
+
+ if (fs_info->logical_sector_size == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says logical sector size is 0. "
+ "This is weird. "));
+ return 0;
+ }
+ if (fs_info->fat_table_count == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says there are no FAT tables. This "
+ "is weird. "));
+ return 0;
+ }
+ if (fs_info->cluster_sectors == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says clusters are 0 sectors. This "
+ "is weird. "));
+ return 0;
+ }
+
+ fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
+ if (fs_info->fat_type == FAT_TYPE_FAT12) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("File system is FAT12, which is unsupported."));
+ return 0;
+ }
+ if (fs_info->fat_type == FAT_TYPE_FAT16) {
+ fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
+ * fs_info->logical_sector_size;
+ fs_info->serial_number
+ = PED_LE32_TO_CPU (bs->u.fat16.serial_number);
+ fs_info->root_cluster = 0;
+ fs_info->root_dir_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ fs_info->root_dir_sector_count
+ = fs_info->root_dir_entry_count * sizeof (FatDirEntry)
+ / (512 * fs_info->logical_sector_size);
+ fs_info->cluster_offset
+ = fs_info->root_dir_offset
+ + fs_info->root_dir_sector_count;
+ }
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
+ * fs_info->logical_sector_size;
+ fs_info->serial_number
+ = PED_LE32_TO_CPU (bs->u.fat32.serial_number);
+ fs_info->info_sector_offset
+ = PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.info_sector)
+ * fs_info->logical_sector_size;
+ fs_info->boot_sector_backup_offset
+ = PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.backup_sector)
+ * fs_info->logical_sector_size;
+ fs_info->root_cluster
+ = PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
+ fs_info->root_dir_offset = 0;
+ fs_info->root_dir_sector_count = 0;
+ fs_info->cluster_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ }
+
+ fs_info->cluster_count
+ = (fs_info->sector_count - fs_info->cluster_offset)
+ / fs_info->cluster_sectors;
+
+ fat_entry_size = _fat_table_entry_size (fs_info->fat_type);
+ if (fs_info->cluster_count + 2
+ > fs_info->fat_sectors * 512 / fat_entry_size)
+ fs_info->cluster_count
+ = fs_info->fat_sectors * 512 / fat_entry_size - 2;
+
+ fs_info->dir_entries_per_cluster
+ = fs_info->cluster_size / sizeof (FatDirEntry);
+ return 1;
+}
diff --git a/libparted/fs/fat/bootsector.h b/libparted/fs/fat/bootsector.h
new file mode 100644
index 0000000..328ba2f
--- /dev/null
+++ b/libparted/fs/fat/bootsector.h
@@ -0,0 +1,126 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef PED_FAT_BOOTSECTOR_H
+#define PED_FAT_BOOTSECTOR_H
+
+typedef struct _FatBootSector FatBootSector;
+typedef struct _FatInfoSector FatInfoSector;
+
+#include "fat.h"
+
+#define FAT32_INFO_MAGIC1 0x41615252
+#define FAT32_INFO_MAGIC2 0x61417272
+#define FAT32_INFO_MAGIC3 0xaa55
+
+/* stolen from mkdosfs, by Dave Hudson */
+
+#define FAT_BOOT_MESSAGE \
+"This partition does not have an operating system loader installed on it.\n\r"\
+"Press a key to reboot..."
+
+#define FAT_BOOT_JUMP "\xeb\x58\x90" /* jmp +5a */
+
+#define FAT_BOOT_CODE "\x0e" /* push cs */ \
+ "\x1f" /* pop ds */ \
+ "\xbe\x74\x7e" /* mov si, offset message */ \
+ /* write_msg_loop: */ \
+ "\xac" /* lodsb */ \
+ "\x22\xc0" /* and al, al */ \
+ "\x74\x06" /* jz done (+8) */ \
+ "\xb4\x0e" /* mov ah, 0x0e */ \
+ "\xcd\x10" /* int 0x10 */ \
+ "\xeb\xf5" /* jmp write_msg_loop */ \
+ /* done: */ \
+ "\xb4\x00" /* mov ah, 0x00 */ \
+ "\xcd\x16" /* int 0x16 */ \
+ "\xb4\x00" /* mov ah, 0x00 */ \
+ "\xcd\x19" /* int 0x19 */ \
+ "\xeb\xfe" /* jmp +0 - in case int 0x19 */ \
+ /* doesn't work */ \
+ /* message: */ \
+ FAT_BOOT_MESSAGE
+
+#define FAT_BOOT_CODE_LENGTH 128
+
+struct __attribute__ ((packed)) _FatBootSector {
+ uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */
+ uint8_t system_id[8]; /* 03: system name */
+ uint16_t sector_size; /* 0b: bytes per logical sector */
+ uint8_t cluster_size; /* 0d: sectors/cluster */
+ uint16_t reserved; /* 0e: reserved sectors */
+ uint8_t fats; /* 10: number of FATs */
+ uint16_t dir_entries; /* 11: number of root directory entries */
+ uint16_t sectors; /* 13: if 0, total_sect supersedes */
+ uint8_t media; /* 15: media code */
+ uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */
+ uint16_t secs_track; /* 18: sectors per track */
+ uint16_t heads; /* 1a: number of heads */
+ uint32_t hidden; /* 1c: hidden sectors (partition start) */
+ uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */
+
+ union __attribute__ ((packed)) {
+ /* FAT16 fields */
+ struct __attribute__ ((packed)) {
+ uint8_t drive_num; /* 24: */
+ uint8_t empty_1; /* 25: */
+ uint8_t ext_signature; /* 26: always 0x29 */
+ uint32_t serial_number; /* 27: */
+ uint8_t volume_name [11]; /* 2b: */
+ uint8_t fat_name [8]; /* 36: */
+ uint8_t boot_code[448]; /* 3f: Boot code (or message) */
+ } fat16;
+ /* FAT32 fields */
+ struct __attribute__ ((packed)) {
+ uint32_t fat_length; /* 24: size of FAT in sectors */
+ uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */
+ uint16_t version; /* 2a: minor * 256 + major */
+ uint32_t root_dir_cluster; /* 2c: */
+ uint16_t info_sector; /* 30: */
+ uint16_t backup_sector; /* 32: */
+ uint8_t empty_1 [12]; /* 34: */
+ uint16_t drive_num; /* 40: */
+ uint8_t ext_signature; /* 42: always 0x29 */
+ uint32_t serial_number; /* 43: */
+ uint8_t volume_name [11]; /* 47: */
+ uint8_t fat_name [8]; /* 52: */
+ uint8_t boot_code[420]; /* 5a: Boot code (or message) */
+ } fat32;
+ } u;
+
+ uint16_t boot_sign; /* 1fe: always 0xAA55 */
+};
+
+struct __attribute__ ((packed)) _FatInfoSector {
+ uint32_t signature_1; /* should be 0x41615252 */
+ uint8_t unused [480];
+ uint32_t signature_2; /* should be 0x61417272 */
+ uint32_t free_clusters;
+ uint32_t next_cluster; /* most recently allocated cluster */
+ uint8_t unused2 [0xe];
+ uint16_t signature_3; /* should be 0xaa55 */
+};
+
+int fat_boot_sector_read (FatBootSector** bs, const PedGeometry* geom);
+FatType fat_boot_sector_probe_type (const FatBootSector* bs,
+ const PedGeometry* geom);
+int fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs);
+
+
+#endif /* PED_FAT_BOOTSECTOR_H */
diff --git a/libparted/fs/fat/count.h b/libparted/fs/fat/count.h
new file mode 100644
index 0000000..bb7d6af
--- /dev/null
+++ b/libparted/fs/fat/count.h
@@ -0,0 +1,46 @@
+/*
+ libparted
+ 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/>.
+*/
+
+#ifndef COUNT_H_INCLUDED
+#define COUNT_H_INCLUDED
+
+typedef enum _FatClusterFlag FatClusterFlag;
+typedef struct _FatClusterInfo FatClusterInfo;
+
+enum _FatClusterFlag {
+ FAT_FLAG_FREE=0,
+ FAT_FLAG_FILE=1,
+ FAT_FLAG_DIRECTORY=2,
+ FAT_FLAG_BAD=3
+};
+
+struct __attribute__ ((packed)) _FatClusterInfo {
+ unsigned int units_used:6; /* 1 unit = cluster_size / 64 */
+ FatClusterFlag flag:2;
+};
+
+extern int fat_collect_cluster_info (PedFileSystem *fs);
+extern FatClusterFlag fat_get_cluster_flag (PedFileSystem* fs,
+ FatCluster cluster);
+extern PedSector fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster);
+extern FatClusterFlag fat_get_fragment_flag (PedFileSystem* fs,
+ FatFragment frag);
+extern int fat_is_fragment_active (PedFileSystem* fs, FatFragment frag);
+
+#endif /* COUNT_H_INCLUDED */
diff --git a/libparted/fs/fat/fat.c b/libparted/fs/fat/fat.c
new file mode 100644
index 0000000..c04f178
--- /dev/null
+++ b/libparted/fs/fat/fat.c
@@ -0,0 +1,162 @@
+/*
+ libparted
+ Copyright (C) 1998-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 <string.h>
+#include <uuid/uuid.h>
+
+#include "fat.h"
+
+PedFileSystem*
+fat_alloc (const PedGeometry* geom)
+{
+ PedFileSystem* fs;
+
+ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
+ if (!fs)
+ goto error;
+
+ fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
+ if (!fs->type_specific)
+ goto error_free_fs;
+ FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
+ fs_info->boot_sector = NULL;
+ fs_info->info_sector = NULL;
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom)
+ goto error_free_type_specific;
+
+ fs->checked = 0;
+ return fs;
+
+error_free_type_specific:
+ free (fs->type_specific);
+error_free_fs:
+ free (fs);
+error:
+ return NULL;
+}
+
+void
+fat_free (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
+ free (fs_info->boot_sector);
+ ped_geometry_destroy (fs->geom);
+ free (fs->type_specific);
+ free (fs);
+}
+
+PedGeometry*
+fat_probe (PedGeometry* geom, FatType* fat_type)
+{
+ PedFileSystem* fs;
+ FatSpecific* fs_info;
+ PedGeometry* result;
+
+ fs = fat_alloc (geom);
+ if (!fs)
+ goto error;
+ fs_info = (FatSpecific*) fs->type_specific;
+
+ if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
+ goto error_free_fs;
+ if (!fat_boot_sector_analyse (fs_info->boot_sector, fs))
+ goto error_free_fs;
+
+ *fat_type = fs_info->fat_type;
+ result = ped_geometry_new (geom->dev, geom->start,
+ fs_info->sector_count);
+
+ fat_free (fs);
+ return result;
+
+error_free_fs:
+ fat_free (fs);
+error:
+ return NULL;
+}
+
+PedGeometry*
+fat_probe_fat16 (PedGeometry* geom)
+{
+ FatType fat_type;
+ PedGeometry* probed_geom = fat_probe (geom, &fat_type);
+
+ if (probed_geom) {
+ if (fat_type == FAT_TYPE_FAT16)
+ return probed_geom;
+ ped_geometry_destroy (probed_geom);
+ }
+ return NULL;
+}
+
+PedGeometry*
+fat_probe_fat32 (PedGeometry* geom)
+{
+ FatType fat_type;
+ PedGeometry* probed_geom = fat_probe (geom, &fat_type);
+
+ if (probed_geom) {
+ if (fat_type == FAT_TYPE_FAT32)
+ return probed_geom;
+ ped_geometry_destroy (probed_geom);
+ }
+ return NULL;
+}
+
+static PedFileSystemOps fat16_ops = {
+ probe: fat_probe_fat16,
+};
+
+static PedFileSystemOps fat32_ops = {
+ probe: fat_probe_fat32,
+};
+
+PedFileSystemType fat16_type = {
+ next: NULL,
+ ops: &fat16_ops,
+ name: "fat16",
+};
+
+PedFileSystemType fat32_type = {
+ next: NULL,
+ ops: &fat32_ops,
+ name: "fat32",
+};
+
+void
+ped_file_system_fat_init ()
+{
+ if (sizeof (FatBootSector) != 512) {
+ ped_exception_throw (PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
+ _("GNU Parted was miscompiled: the FAT boot sector "
+ "should be 512 bytes. FAT support will be disabled."));
+ } else {
+ ped_file_system_type_register (&fat16_type);
+ ped_file_system_type_register (&fat32_type);
+ }
+}
+
+void
+ped_file_system_fat_done ()
+{
+ ped_file_system_type_unregister (&fat16_type);
+ ped_file_system_type_unregister (&fat32_type);
+}
diff --git a/libparted/fs/fat/fat.h b/libparted/fs/fat/fat.h
new file mode 100644
index 0000000..f5302d9
--- /dev/null
+++ b/libparted/fs/fat/fat.h
@@ -0,0 +1,163 @@
+/*
+ libparted
+ Copyright (C) 1998-2001, 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/>.
+*/
+
+#ifndef FAT_H_INCLUDED
+#define FAT_H_INCLUDED
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define BUFFER_SIZE 1024 /* buffer size in sectors (512 bytes) */
+
+typedef uint32_t FatCluster;
+typedef int32_t FatFragment;
+
+enum _FatType {
+ FAT_TYPE_FAT12,
+ FAT_TYPE_FAT16,
+ FAT_TYPE_FAT32
+};
+typedef enum _FatType FatType;
+
+typedef struct _FatSpecific FatSpecific;
+typedef struct _FatDirEntry FatDirEntry;
+
+#include "bootsector.h"
+#include "count.h"
+
+struct _FatTable {
+ void* table;
+ FatCluster size;
+ int raw_size;
+
+ FatType fat_type;
+ FatCluster cluster_count;
+ FatCluster free_cluster_count;
+ FatCluster bad_cluster_count;
+
+ FatCluster last_alloc;
+};
+typedef struct _FatTable FatTable;
+
+struct __attribute__ ((packed)) _FatDirEntry {
+ char name[8];
+ uint8_t extension[3];
+ uint8_t attributes;
+ uint8_t is_upper_case_name;
+ uint8_t creation_time_low; /* milliseconds */
+ uint16_t creation_time_high;
+ uint16_t creation_date;
+ uint16_t access_date;
+ uint16_t first_cluster_high; /* for FAT32 */
+ uint16_t time;
+ uint16_t date;
+ uint16_t first_cluster;
+ uint32_t length;
+};
+
+struct _FatSpecific {
+ FatBootSector *boot_sector; /* structure of boot sector */
+ FatInfoSector *info_sector; /* fat32-only information sector */
+
+ int logical_sector_size; /* illogical sector size :-) */
+ PedSector sector_count;
+
+ int sectors_per_track; /* BIOS CHS stuff (S) */
+ int heads; /* BIOS CHS stuff (H) */
+
+ int cluster_size;
+ PedSector cluster_sectors;
+ FatCluster cluster_count;
+ int dir_entries_per_cluster;
+
+ FatType fat_type;
+ int fat_table_count;
+ PedSector fat_sectors;
+
+ uint32_t serial_number;
+
+ PedSector info_sector_offset; /* FAT32 only */
+ PedSector fat_offset;
+ PedSector root_dir_offset; /* non-FAT32 */
+ PedSector cluster_offset;
+ PedSector boot_sector_backup_offset;
+
+ FatCluster root_cluster; /* FAT32 only */
+ int root_dir_entry_count; /* non-FAT32 */
+ PedSector root_dir_sector_count; /* non-FAT32 */
+ FatCluster total_dir_clusters;
+
+ FatTable* fat;
+ FatClusterInfo* cluster_info;
+
+ PedSector buffer_sectors;
+ char* buffer;
+
+ int frag_size;
+ PedSector frag_sectors;
+ FatFragment frag_count;
+ FatFragment buffer_frags;
+ FatFragment cluster_frags;
+};
+
+#define FAT_SPECIFIC(fs) ((FatSpecific*) fs->type_specific)
+
+#define FAT_ROOT 0
+
+#define DELETED_FLAG 0xe5
+
+#define READONLY_ATTR 0x01
+#define HIDDEN_ATTR 0x02
+#define SYSTEM_ATTR 0x04
+#define VOLUME_LABEL_ATTR 0x08
+#define VFAT_ATTR 0x0f
+#define DIRECTORY_ATTR 0x10
+#define ARCH_ATTR 0x20
+
+#define MAX_FAT12_CLUSTERS 4086
+#define MAX_FAT16_CLUSTERS 65526
+#define MAX_FAT32_CLUSTERS 2000000
+
+#define FAT_ROOT_DIR_ENTRY_COUNT 512
+
+extern PedFileSystemType fat16_type;
+extern PedFileSystemType fat32_type;
+
+extern void fat_print (const PedFileSystem* fs);
+
+extern PedFileSystem* fat_alloc (const PedGeometry* geom);
+extern void fat_free (PedFileSystem* fs);
+extern int fat_alloc_buffers (PedFileSystem* fs);
+
+extern int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer);
+
+#endif /* FAT_H_INCLUDED */
diff --git a/libparted/fs/fsresize.sym b/libparted/fs/fsresize.sym
new file mode 100644
index 0000000..86829d1
--- /dev/null
+++ b/libparted/fs/fsresize.sym
@@ -0,0 +1,13 @@
+# This is an LD linker script.
+# Expose only the functions named below.
+
+LIBPARTED_FS_RESIZE_0.0.0 {
+ global:
+ ped_file_system_close;
+ ped_file_system_get_resize_constraint;
+ ped_file_system_open;
+ ped_file_system_resize;
+
+ local:
+ *;
+};
diff --git a/libparted/fs/hfs/DOC b/libparted/fs/hfs/DOC
new file mode 100644
index 0000000..9ee8b4d
--- /dev/null
+++ b/libparted/fs/hfs/DOC
@@ -0,0 +1,92 @@
+WARNING : Both HFS and HFS+ implementations of Linux 2.4 are buggy, at
+least when used before or after this implementation. Some workarounds
+are used in this implementation, but there can still be incompatibilities.
+Try Linux 2.6 if you want to play with HFS(+) resizing (though some bugs
+might also be there in 2.6, there is of course no warranty)
+
+---
+
+ Technical doc about Apple HFS and HFS+ file systems is available at :
+ * For HFS, section "Data Organization on Volumes",
+ "Chapter 2 - File Manager"
+ of the book "Inside Macintosh: Files"
+ http://developer.apple.com/documentation/mac/Files/Files-99.html
+ * For HFS+, "Technical Note TN1150", "HFS Plus Volume Format"
+ http://developer.apple.com/technotes/tn/tn1150.html
+
+ Some useful HFS precisions concerning alignement, bit ordering, and
+ order of fields for extent key comparaisons are only in the HFS+ TN
+
+ These Apple Creator Codes are reserved for us :
+ Shnk traP GP16 GnuP PH+x Xpnd Resz GP17 GP18 GP19 GP20
+
+---
+
+* Cache design *
+
+Versions before HFS Patch 15 were very slow when data relocation was needed,
+because every extent to relocate involved scanning the whole file system,
+looking for a reference to its physical position on the volume (this was a
+dummy algorithm, I know :)
+
+HFS Patch 16 introduced a cache that allows to efficiently retrieve the place
+of the reference in the file system given the physical position of an extent.
+The cache is designed for : - efficiency
+ - scaling
+ - simplicity
+ - avoiding memory allocation while resizing
+
+This cache involves quite big worst case memory consumption, but without it
+the time needed to complete the operation in the worst case would be huge
+anyway (maybe several years...) so this isn't really an issue. The cache size
+is nearly proportional to the number of files you have, or if you have very few
+files, to the size of your volume, so worst cases situations occure when you
+fill a drive with millions of < 4 ko files :p For this very special usage you
+will just need a very special amount of RAM (on typical systems about
+(FS size) / 256 )... On a more "normal" volume it's about
+(# of files) * 20 bytes. With very few files it's about (FS Size) / 1024 / 256.
+
+At the beginning of the resize process, the cache is filed by scanning the FS.
+The position of each extent is cut into 2 parts : high order is used as
+an index into a table of pointer to a linked list which contains :
+- the next ptr (sizeof struct *)
+- the extent start (4 bytes)
+- the extent size (4 bytes)
+- number of BTree block or 0 if in prim (4 bytes)
+- offset of the extent start reference
+ from the block beginning (2 bytes)
+- sectors by BTree block, or
+ 1 for VH/MDB (1 byte)
+- FS special file / primary structure
+ where the extent reference is stored (1 byte)
+ (3 bits for the extent index, 5 for
+ the actual ref)
+
+ 0 : dont exists --- reserved
+ 1 : mdb / vh : catalog ---
+ 2 : mdb / vh : extent ---
+ 3 : vh : attributes X+-
+ 4 : vh : allocation X+-
+ 5 : vh : startup X+-
+ 6 : catalog ---
+ 7 : attributes X+-
+ 8 : extent (nothing to update) ---
+ 9 : extent (update catalog) ---
+ 10 : extent (update extent !?!) --- should not exist
+ 11 : extent (update attributes) X+-
+ 12 : extent (update allocation) X+-
+ 13 : extent (update startup) X+- reserved
+ 14 : vh : journal info block X+J
+ 15 : jib: journal X+J
+ 16 - 31 : ---
+
+mdb : Master Directory Block
+vh : Volume Header
+X+ : HFSX or HFS+ only
+J : Journaled only
+
+Large amount of memory is allocated at once (first enough memory to fit
+every files if there isn't any fragmentation +6.25%, then this value / 4,
+if this wasn't enough). On a typical FS, the first allocation should be enough.
+
+---
diff --git a/libparted/fs/hfs/HISTORY b/libparted/fs/hfs/HISTORY
new file mode 100644
index 0000000..5e138a6
--- /dev/null
+++ b/libparted/fs/hfs/HISTORY
@@ -0,0 +1,115 @@
+## modifications dd-mm-yyyy
+---------------------- PATCH FOR PARTED 1.6.5 ----------------------------
+ 1 initial revision 07-04-2003
+ 2 one pass resizing, removal of debug info 08-04-2003
+ 3 safe abort if resize failed, code cleanups, timer, 10-04-2003
+ source file split, won't resize if not unmounted,
+ only relocate data if needed, minimize disk operations
+ 4 memory leaks removal, code cleanups, resize hfs+ code, 17-04-2003
+ more checks, minor hfs resize bugfix, probe code
+ returns real geometry
+ 5 hfs+ resize bugfixes : 19-04-2003
+ * fragmented fs could be corrupted
+ * VH wasn't written on error during alloc map writing
+ * attributes file could be corrupted
+ 6 Use PedSector to be able to use 2To+ HD 23-04-2003
+ Minor probe bugfix, Cleanups, HFS+ Timer tuning,
+ 7 80 columns indentation 23-04-2003
+ 8 Bugfix free blocks calculation in wrapper
+ (makes Mac OS boot !) 28-04-2003
+---------------------- PATCH FOR PARTED 1.6.6 ----------------------------
+ 9 Don't destroy the file being worked on in case of
+ interruption of Parted 28-10-2003
+---------------------- PATCH FOR PARTED 1.6.10 ---------------------------
+10 Regression tests, URL correction, In effect_move_extent :
+ corrected memory leak & corrected a bug in precondition checks
+ Added error messages, Check ped_alloc results
+ Use macro for test / set / clear in the allocation bitmap
+ Light probe correction, Check return value of get_empty_end
+ Moved dynamic memory allocation out of effect_move_extent
+ Check HFS+ version, Set implementation creator code
+ Check journal absence, Corrected a bug in HFS+ block number
+ calculation 24-04-2004
+--------------------- PATCH FOR PARTED 1.6.11 ----------------------------
+11-Some pointer dereference moved after non nul assertion
+ -Error messages for HFS(+) file IO
+ -Memory leak correction in hfs(plus)_read_bad_blocks
+ -Mark out of volume blocks as used
+ (improve compatibility with broken HFS+ Linux
+ implementation)
+ WARNING : this fix is not 100% tn1150 compatible :
+ "The allocation file may be larger than the minimum
+ number of bits required for the given volume size.
+ Any unused bits in the bitmap must be set to _zero_."
+ Anyway neither is the Linux implementation, nor was my
+ previous implementations
+ Maybe I should ask Apple to change the specifications
+ -HISTORY, DOC and TODO files 29-04-2004
+12 Corrected a bug in hfsplus_volume_resize : size of alloc
+ bitmap could be miscalculated 29-04-2004
+--------------------- PATCH FOR PARTED 1.6.12 ----------------------------
+13-Finally partial rewrite of *_search_move_*
+ Easier to maintain and prepare for extent search and
+ relocation algorithm changes for better ones.
+ -"An extent has not been relocated!" message now only when
+ relocation requested
+ -Slightly better and simpler relocation algorithm
+ -Update of Makefile.in and Makefile.am in fs_hfs
+ -Sign correction for some 8bits HFS integers
+ -Added the option --enable-hfs-extract-fs in 'configure'
+ -Added every ped_geometry_sync where needed
+ -Bugfix : "A root node does not need to exist
+ (if the tree is empty)."
+ - now handled correctly in btree_search
+ -Bugfix : failure wasn't detected in some cases
+ during 2 pass relocation (*_search_move_*)
+ -Bugfix : The extent key comparaison was done in a wrong order
+ and a pad field was used during the comparaison
+ -Bugfix : in hfs_file_find_sector and hfsplus_file_find_sector
+ the absolute position of a file sector could be
+ miscalculated in case of fragmentation, resulting
+ in potential data corruption, or various errors
+ -Bugfix : The end of the HFS bitmap compatibility block was
+ miscalculated ( (1<<16)/8 instead of (1<<16) )
+ in hfs_resize
+ 07-09-2004
+--------------------- PATCH FOR PARTED 1.6.14 ----------------------------
+14 Port of Patch 13 for Parted 1.6.14 (update timestamps)
+ 08-09-2004
+--------------------- PATCH FOR PARTED 1.6.15 ----------------------------
+15-hfsplus_open : added a warning message if the "attributes"
+ special file exists
+ -hfsplus_open : added a test to check if the "allocation"
+ special file has been correctly opened
+ -optimisation of hfs+ block access : don't recalculate
+ the address of each sector, and avoid checking the cache if
+ obviously not useful
+ ( hfsplus_file_read && hfsplus_file_write
+ && hfsplus_file_find_extent && hfs_file_find_sector)
+ -cut the "hfs.c" file in several parts
+ -Bugfix: in hfsplus_do_move_primary, hfs_effect_move_extent
+ was called instead of hfsplus_effect_move_extent !!!
+ This could not produce data corruption, because of a welcome
+ ASSERT in *_effect_move_extent that would detect the bug :)
+ -Bugfix: in hfs_effect_move_extent, do
+ PED_ASSERT(*ptr_to_fblock <= *ptr_fblock, return -1);
+ instead of
+ PED_ASSERT(*ptr_to_fblock < *ptr_fblock, return -1);
+ and added that assertion to hfsplus_effect_move_extent
+ -Bugfix: bugs introduced in rewrite of hfsplus_file_read
+ && hfsplus_file_write : last sector was incorrectly detected
+ as out of file.
+ -Cache the extent references (speed improvement ?)
+ 23-09-2004
+16-Bugfix: in hfsplus_do_move (reloc_plus.c), case CR_BTREE_EXT_ATTR
+ incorrectly updated the cached part of priv_data->catalog_file
+ instead of priv_data->attributes_file
+ -Bugfix: in hfs_read_bad_blocks && hfsplus_read_bad_blocks,
+ now generate an error if file_ID or type mismatch after the
+ first pass
+ Also check return value of ped_malloc
+ -Bugfix: in hfsplus_btree_search, check return value of ped_malloc
+ 29-09-2004
+---------------- INTEGRATION IN PARTED 1.6.22 (cvs) ----------------------
+Futur changes will be described in ../../ChangeLog
+ 02-02-2005
diff --git a/libparted/fs/hfs/TODO b/libparted/fs/hfs/TODO
new file mode 100644
index 0000000..6e408e3
--- /dev/null
+++ b/libparted/fs/hfs/TODO
@@ -0,0 +1,27 @@
+--- TODO ---
+
+ * Continue to write regressions tests and try on 2.6 kernel -- (high)
+ * Fix timer progression calculation, according to the new
+ caching code -- (high)
+ * write doc, website, ... -- (high)
+ * Check block allocation in linux 2.4 and remove
+ compatibility code if possible -- (high)
+
+ * In hfs(plus)_btree_search , use a static variable to detect
+ illegal recursion and abort in that case. (find the right
+ number of recursion before reporting bug) -- easy -- (medium)
+ * Finish the HFS Extractor -- (medium)
+ (add mdb & vh extraction, and maybe journal)
+
+ * Write code to allow enlarging and moving HFS[+x] -- (low)
+ * Use a bitmap to internaly store the bad blocks -- (low)
+ * Less bitmap saves ? -- (low)
+ * Continue to change the relocation algorithm
+ for a better one :) -- (low)
+
+--- NOT todo ---
+
+ * debug HFS(+) Linux implementation (block allocation for HFS+,
+ hard and sym links for HFS+, filename length for HFS, ...) -- (dont)
+ /// Linux 2.6 contains HFS(+) implementations with less bugs
+ /// Linux 2.4 should not be used anymore to access HFS(+)
diff --git a/libparted/fs/hfs/hfs.c b/libparted/fs/hfs/hfs.c
new file mode 100644
index 0000000..3684646
--- /dev/null
+++ b/libparted/fs/hfs/hfs.c
@@ -0,0 +1,92 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 2003-2005, 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/>.
+*/
+
+/*
+ Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
+ Report bug to <bug-parted@gnu.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "probe.h"
+
+uint8_t* hfs_block = NULL;
+uint8_t* hfsp_block = NULL;
+unsigned hfs_block_count;
+unsigned hfsp_block_count;
+
+static PedFileSystemOps hfs_ops = {
+ probe: hfs_probe,
+};
+
+static PedFileSystemOps hfsplus_ops = {
+ probe: hfsplus_probe,
+};
+
+static PedFileSystemOps hfsx_ops = {
+ probe: hfsx_probe,
+};
+
+
+static PedFileSystemType hfs_type = {
+ next: NULL,
+ ops: &hfs_ops,
+ name: "hfs",
+};
+
+static PedFileSystemType hfsplus_type = {
+ next: NULL,
+ ops: &hfsplus_ops,
+ name: "hfs+",
+};
+
+static PedFileSystemType hfsx_type = {
+ next: NULL,
+ ops: &hfsx_ops,
+ name: "hfsx",
+};
+
+void
+ped_file_system_hfs_init ()
+{
+ ped_file_system_type_register (&hfs_type);
+ ped_file_system_type_register (&hfsplus_type);
+ ped_file_system_type_register (&hfsx_type);
+}
+
+void
+ped_file_system_hfs_done ()
+{
+ ped_file_system_type_unregister (&hfs_type);
+ ped_file_system_type_unregister (&hfsplus_type);
+ ped_file_system_type_unregister (&hfsx_type);
+}
diff --git a/libparted/fs/hfs/hfs.h b/libparted/fs/hfs/hfs.h
new file mode 100644
index 0000000..5b9138c
--- /dev/null
+++ b/libparted/fs/hfs/hfs.h
@@ -0,0 +1,648 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2003-2005, 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/>.
+*/
+
+#ifndef _HFS_H
+#define _HFS_H
+
+/* WARNING : bn is used 2 times in theses macro */
+/* so _never_ use side effect operators when using them */
+#define TST_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) & (1<<(7-((bn)&7))))
+#define SET_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) |= (1<<(7-((bn)&7))))
+#define CLR_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) &= ~(1<<(7-((bn)&7))))
+
+/* Maximum number of blocks for the copy buffers */
+#define BLOCK_MAX_BUFF 256
+/* Maximum size of the copy buffers, in bytes */
+#define BYTES_MAX_BUFF 8388608
+
+/* Apple Creator Codes follow */
+#define HFSP_IMPL_Shnk 0x53686e6b /* in use */
+#define HFSP_IMPL_Xpnd 0x58706e64 /* reserved */
+#define HFSP_IMPL_Resz 0x5265737a /* reserved */
+#define HFSP_IMPL_PHpx 0x50482b78 /* reserved */
+#define HFSP_IMPL_traP 0x74726150 /* reserved */
+#define HFSP_IMPL_GnuP 0x476e7550 /* reserved */
+
+#define HFS_SIGNATURE 0x4244 /* 'BD' */
+#define HFSP_SIGNATURE 0x482B /* 'H+' */
+#define HFSX_SIGNATURE 0x4858 /* 'HX' */
+
+#define HFSP_VERSION 4
+#define HFSX_VERSION 5
+
+#define HFS_HARD_LOCK 7
+#define HFS_UNMOUNTED 8
+#define HFS_BAD_SPARED 9
+#define HFS_SOFT_LOCK 15
+#define HFSP_NO_CACHE 10
+#define HFSP_INCONSISTENT 11
+#define HFSP_REUSE_CNID 12
+#define HFSP_JOURNALED 13
+
+#define HFS_IDX_NODE 0x00
+#define HFS_HDR_NODE 0x01
+#define HFS_MAP_NODE 0x02
+#define HFS_LEAF_NODE 0xFF
+
+#define HFS_FIRST_REC 0x0E
+#define HFS_NSD_HD_REC 0x78
+#define HFS_MAP_REC 0xF8
+
+#define HFS_DATA_FORK 0x00
+#define HFS_RES_FORK 0xFF
+
+#define HFS_CAT_DIR 0x01
+#define HFS_CAT_FILE 0x02
+#define HFS_CAT_DIR_TH 0x03
+#define HFS_CAT_FILE_TH 0x04
+
+#define HFSP_ATTR_INLINE 0x10
+#define HFSP_ATTR_FORK 0x20
+#define HFSP_ATTR_EXTENTS 0x30
+
+#define HFS_ROOT_PAR_ID 0x01
+#define HFS_ROOT_DIR_ID 0x02
+#define HFS_XTENT_ID 0x03
+#define HFS_CATALOG_ID 0x04
+#define HFS_BAD_BLOCK_ID 0x05
+#define HFSP_ALLOC_ID 0x06
+#define HFSP_STARTUP_ID 0x07
+#define HFSP_ATTRIB_ID 0x08
+#define HFSP_BOGUS_ID 0x0F
+#define HFSP_FIRST_AV_ID 0x10
+
+#define HFSJ_JOURN_IN_FS 0x00
+#define HFSJ_JOURN_OTHER_DEV 0x01
+#define HFSJ_JOURN_NEED_INIT 0x02
+
+#define HFSJ_HEADER_MAGIC 0x4a4e4c78
+#define HFSJ_ENDIAN_MAGIC 0x12345678
+
+#define HFSX_CASE_FOLDING 0xCF /* case insensitive HFSX */
+#define HFSX_BINARY_COMPARE 0xBC /* case sensitive HFSX */
+
+#define HFS_EXT_NB 3
+#define HFSP_EXT_NB 8
+
+/* Define the filenames used by the FS extractor */
+#ifdef HFS_EXTRACT_FS
+
+#define HFS_MDB_FILENAME "mdb.hfs"
+#define HFS_CATALOG_FILENAME "catalog.hfs"
+#define HFS_EXTENTS_FILENAME "extents.hfs"
+#define HFS_BITMAP_FILENAME "bitmap.hfs"
+
+#define HFSP_VH_FILENAME "vh.hfsplus"
+#define HFSP_CATALOG_FILENAME "catalog.hfsplus"
+#define HFSP_EXTENTS_FILENAME "extents.hfsplus"
+#define HFSP_BITMAP_FILENAME "bitmap.hfsplus"
+#define HFSP_ATTRIB_FILENAME "attributes.hfsplus"
+#define HFSP_STARTUP_FILENAME "startup.hfsplus"
+
+#endif /* HFS_EXTRACT_FS */
+
+
+
+/* ----------------------------------- */
+/* -- HFS DATA STRUCTURES -- */
+/* ----------------------------------- */
+
+/* Extent descriptor */
+struct __attribute__ ((packed)) _HfsExtDescriptor {
+ uint16_t start_block;
+ uint16_t block_count;
+};
+typedef struct _HfsExtDescriptor HfsExtDescriptor;
+typedef HfsExtDescriptor HfsExtDataRec[HFS_EXT_NB];
+
+/* Volume header */
+struct __attribute__ ((packed)) _HfsMasterDirectoryBlock {
+ uint16_t signature;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint16_t volume_attributes;
+ uint16_t files_in_root;
+ uint16_t volume_bitmap_block; /* in sectors */
+ uint16_t next_allocation;
+ uint16_t total_blocks;
+ uint32_t block_size; /* in bytes */
+ uint32_t def_clump_size; /* in bytes */
+ uint16_t start_block; /* in sectors */
+ uint32_t next_free_node;
+ uint16_t free_blocks;
+ uint8_t name_length;
+ char name[27];
+ uint32_t backup_date;
+ uint16_t backup_number;
+ uint32_t write_count;
+ uint32_t extents_clump;
+ uint32_t catalog_clump;
+ uint16_t dirs_in_root;
+ uint32_t file_count;
+ uint32_t dir_count;
+ uint32_t finder_info[8];
+ union __attribute__ ((packed)) {
+ struct __attribute__ ((packed)) {
+ uint16_t volume_cache_size; /* in blocks */
+ uint16_t bitmap_cache_size; /* in blocks */
+ uint16_t common_cache_size; /* in blocks */
+ } legacy;
+ struct __attribute__ ((packed)) {
+ uint16_t signature;
+ HfsExtDescriptor location;
+ } embedded;
+ } old_new;
+ uint32_t extents_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec extents_file_rec;
+ uint32_t catalog_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec catalog_file_rec;
+};
+typedef struct _HfsMasterDirectoryBlock HfsMasterDirectoryBlock;
+
+/* B*-Tree Node Descriptor */
+struct __attribute__ ((packed)) _HfsNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsNodeDescriptor HfsNodeDescriptor;
+
+/* Header record of a whole B*-Tree */
+struct __attribute__ ((packed)) _HfsHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes;
+ int8_t reserved[76];
+};
+typedef struct _HfsHeaderRecord HfsHeaderRecord;
+
+/* Catalog key for B*-Tree lookup in the catalog file */
+struct __attribute__ ((packed)) _HfsCatalogKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t reserved;
+ uint32_t parent_ID;
+ uint8_t name_length;
+ char name[31]; /* in fact physicaly 1 upto 31 */
+};
+typedef struct _HfsCatalogKey HfsCatalogKey;
+
+/* Extents overflow key for B*-Tree lookup */
+struct __attribute__ ((packed)) _HfsExtentKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t type; /* data or ressource fork */
+ uint32_t file_ID;
+ uint16_t start;
+};
+typedef struct _HfsExtentKey HfsExtentKey;
+
+/* Catalog subdata case directory */
+struct __attribute__ ((packed)) _HfsDir {
+ uint16_t flags;
+ uint16_t valence; /* number of files in this directory */
+ uint32_t dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t reserved[4];
+};
+typedef struct _HfsDir HfsDir;
+
+/* Catalog subdata case file */
+struct __attribute__ ((packed)) _HfsFile {
+ int8_t flags;
+ int8_t type; /* should be 0 */
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t file_ID;
+ uint16_t data_start_block;
+ uint32_t data_sz_byte;
+ uint32_t data_sz_block;
+ uint16_t res_start_block;
+ uint32_t res_sz_byte;
+ uint32_t res_sz_block;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint16_t clump_size;
+ HfsExtDataRec extents_data;
+ HfsExtDataRec extents_res;
+ uint32_t reserved;
+};
+typedef struct _HfsFile HfsFile;
+
+/* Catalog subdata case directory thread */
+struct __attribute__ ((packed)) _HfsDirTh {
+ uint32_t reserved[2];
+ uint32_t parent_ID;
+ int8_t name_length;
+ char name[31];
+};
+typedef struct _HfsDirTh HfsDirTh;
+
+/* Catalog subdata case file thread */
+typedef struct _HfsDirTh HfsFileTh; /* same as directory thread */
+
+/* Catalog data */
+struct __attribute__ ((packed)) _HfsCatalog {
+ int8_t type;
+ int8_t reserved;
+ union {
+ HfsDir dir;
+ HfsFile file;
+ HfsDirTh dir_th;
+ HfsFileTh file_th;
+ } sel;
+};
+typedef struct _HfsCatalog HfsCatalog;
+
+
+
+/* ------------------------------------ */
+/* -- HFS+ DATA STRUCTURES -- */
+/* ------------------------------------ */
+
+/* documented since 2004 in tn1150 */
+struct __attribute__ ((packed)) _HfsPPerms {
+ uint32_t owner_ID;
+ uint32_t group_ID;
+ uint32_t permissions;
+ uint32_t special_devices;
+};
+typedef struct _HfsPPerms HfsPPerms;
+
+/* HFS+ extent descriptor*/
+struct __attribute__ ((packed)) _HfsPExtDescriptor {
+ uint32_t start_block;
+ uint32_t block_count;
+};
+typedef struct _HfsPExtDescriptor HfsPExtDescriptor;
+typedef HfsPExtDescriptor HfsPExtDataRec[HFSP_EXT_NB];
+
+/* HFS+ fork data structure */
+struct __attribute__ ((packed)) _HfsPForkData {
+ uint64_t logical_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ HfsPExtDataRec extents;
+};
+typedef struct _HfsPForkData HfsPForkData;
+
+/* HFS+ catalog node ID */
+typedef uint32_t HfsPNodeID;
+
+/* HFS+ file names */
+typedef uint16_t unichar;
+struct __attribute__ ((packed)) _HfsPUniStr255 {
+ uint16_t length;
+ unichar unicode[255]; /* 1 upto 255 */
+};
+typedef struct _HfsPUniStr255 HfsPUniStr255;
+
+/* HFS+ volume header */
+struct __attribute__ ((packed)) _HfsPVolumeHeader {
+ uint16_t signature;
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mounted_version;
+ uint32_t journal_info_block;
+
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+
+ uint32_t file_count;
+ uint32_t dir_count;
+
+ uint32_t block_size;
+ uint32_t total_blocks;
+ uint32_t free_blocks;
+
+ uint32_t next_allocation;
+ uint32_t res_clump_size;
+ uint32_t data_clump_size;
+ HfsPNodeID next_catalog_ID;
+
+ uint32_t write_count;
+ uint64_t encodings_bitmap;
+
+ uint8_t finder_info[32];
+
+ HfsPForkData allocation_file;
+ HfsPForkData extents_file;
+ HfsPForkData catalog_file;
+ HfsPForkData attributes_file;
+ HfsPForkData startup_file;
+};
+typedef struct _HfsPVolumeHeader HfsPVolumeHeader;
+
+/* HFS+ B-Tree Node Descriptor. Same as HFS btree. */
+struct __attribute__ ((packed)) _HfsPNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsPNodeDescriptor HfsPNodeDescriptor;
+
+/* Header record of a whole HFS+ B-Tree. */
+struct __attribute__ ((packed)) _HfsPHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes; /* same as hfs btree until here */
+ uint16_t reserved1;
+
+ uint32_t clump_size;
+ uint8_t btree_type; /* must be 0 for HFS+ B-Tree */
+ uint8_t key_compare_type; /* hfsx => 0xCF = case folding */
+ /* 0xBC = binary compare */
+ /* otherwise, reserved */
+ uint32_t attributes;
+ uint32_t reserved3[16];
+};
+typedef struct _HfsPHeaderRecord HfsPHeaderRecord;
+
+/* Catalog key for B-Tree lookup in the HFS+ catalog file */
+struct __attribute__ ((packed)) _HfsPCatalogKey {
+ uint16_t key_length;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPCatalogKey HfsPCatalogKey;
+
+/* HFS+ catalog subdata case dir */
+struct __attribute__ ((packed)) _HfsPDir {
+ uint16_t flags;
+ uint32_t valence;
+ HfsPNodeID dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved;
+};
+typedef struct _HfsPDir HfsPDir;
+
+/* HFS+ catalog subdata case file */
+struct __attribute__ ((packed)) _HfsPFile {
+ uint16_t flags;
+ uint32_t reserved1;
+ HfsPNodeID file_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved2;
+
+ HfsPForkData data_fork;
+ HfsPForkData res_fork;
+};
+typedef struct _HfsPFile HfsPFile;
+
+/* HFS+ catalog subdata case thread */
+struct __attribute__ ((packed)) _HfsPThread {
+ int16_t reserved;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPThread HfsPDirTh;
+typedef struct _HfsPThread HfsPFileTh;
+
+/* HFS+ Catalog leaf data */
+struct __attribute__ ((packed)) _HfsPCatalog {
+ int16_t type;
+ union {
+ HfsPDir dir;
+ HfsPFile file;
+ HfsPDirTh dir_th;
+ HfsPFileTh file_th;
+ } sel;
+};
+typedef struct _HfsPCatalog HfsPCatalog;
+
+/* HFS+ extents file key */
+struct __attribute__ ((packed)) _HfsPExtentKey {
+ uint16_t key_length;
+ uint8_t type;
+ uint8_t pad;
+ HfsPNodeID file_ID;
+ uint32_t start;
+};
+typedef struct _HfsPExtentKey HfsPExtentKey;
+
+/* extent file data is HfsPExtDataRec */
+
+/* Fork data attribute file */
+struct __attribute__ ((packed)) _HfsPForkDataAttr {
+ uint32_t record_type;
+ uint32_t reserved;
+ union __attribute__ ((packed)) {
+ HfsPForkData fork;
+ HfsPExtDataRec extents;
+ } fork_res;
+};
+typedef struct _HfsPForkDataAttr HfsPForkDataAttr;
+
+
+/* ----------- Journal data structures ----------- */
+
+/* Info block : stored in a block # defined in the VH */
+struct __attribute__ ((packed)) _HfsJJournalInfoBlock {
+ uint32_t flags;
+ uint32_t device_signature[8];
+ uint64_t offset;
+ uint64_t size;
+ uint32_t reserved[32];
+};
+typedef struct _HfsJJournalInfoBlock HfsJJournalInfoBlock;
+
+struct __attribute__ ((packed)) _HfsJJournalHeader {
+ uint32_t magic;
+ uint32_t endian;
+ uint64_t start;
+ uint64_t end;
+ uint64_t size;
+ uint32_t blhdr_size;
+ uint32_t checksum;
+ uint32_t jhdr_size;
+};
+typedef struct _HfsJJournalHeader HfsJJournalHeader;
+
+struct __attribute__ ((packed)) _HfsJBlockInfo {
+ uint64_t bnum; /* sector number */
+ uint32_t bsize; /* size in bytes */
+ uint32_t next;
+};
+typedef struct _HfsJBlockInfo HfsJBlockInfo;
+
+struct __attribute__ ((packed)) _HfsJBlockListHeader {
+ uint16_t max_blocks; /* reserved */
+ uint16_t num_blocks;
+ uint32_t bytes_used;
+ uint32_t checksum;
+ uint32_t pad;
+ HfsJBlockInfo binfo[];
+};
+typedef struct _HfsJBlockListHeader HfsJBlockListHeader;
+
+
+
+/* ---------------------------------------- */
+/* -- INTERNAL DATA STRUCTURES -- */
+/* ---------------------------------------- */
+
+/* Data of an opened HFS file */
+struct _HfsPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ uint32_t CNID; /* disk order (BE) */
+ HfsExtDataRec first; /* disk order (BE) */
+ HfsExtDataRec cache; /* disk order (BE) */
+ uint16_t start_cache; /* CPU order */
+};
+typedef struct _HfsPrivateFile HfsPrivateFile;
+
+/* To store bad block list */
+struct _HfsPrivateLinkExtent {
+ HfsExtDescriptor extent;
+ struct _HfsPrivateLinkExtent* next;
+};
+typedef struct _HfsPrivateLinkExtent HfsPrivateLinkExtent;
+
+/* HFS Filesystem specific data */
+struct _HfsPrivateFSData {
+ uint8_t alloc_map[(1<<16) / 8];
+ HfsMasterDirectoryBlock* mdb;
+ HfsPrivateFile* extent_file;
+ HfsPrivateFile* catalog_file;
+ HfsPrivateLinkExtent* bad_blocks_xtent_list;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+};
+typedef struct _HfsPrivateFSData HfsPrivateFSData;
+
+/* Generic btree key */
+struct __attribute__ ((packed)) _HfsPrivateGenericKey {
+ uint8_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPrivateGenericKey HfsPrivateGenericKey;
+
+/* ----- HFS+ ----- */
+
+/* Data of an opened HFS file */
+struct _HfsPPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ HfsPNodeID CNID; /* disk order (BE) */
+ HfsPExtDataRec first; /* disk order (BE) */
+ HfsPExtDataRec cache; /* disk order (BE) */
+ uint32_t start_cache; /* CPU order */
+};
+typedef struct _HfsPPrivateFile HfsPPrivateFile;
+
+struct _HfsPPrivateExtent {
+ PedSector start_sector;
+ PedSector sector_count;
+};
+typedef struct _HfsPPrivateExtent HfsPPrivateExtent;
+
+/* To store bad block list */
+struct _HfsPPrivateLinkExtent {
+ HfsPExtDescriptor extent;
+ struct _HfsPPrivateLinkExtent* next;
+};
+typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
+
+/* HFS+ file system specific data */
+struct _HfsPPrivateFSData {
+ PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
+ PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
+ uint8_t* alloc_map;
+ uint8_t* dirty_alloc_map;
+ HfsPVolumeHeader* vh;
+ HfsPPrivateFile* extents_file;
+ HfsPPrivateFile* catalog_file;
+ HfsPPrivateFile* attributes_file;
+ HfsPPrivateFile* allocation_file;
+ HfsPPrivateLinkExtent* bad_blocks_xtent_list;
+ uint32_t jib_start_block;
+ uint32_t jl_start_block;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+ char free_geom; /* 1 = plus_geom must be freed */
+};
+typedef struct _HfsPPrivateFSData HfsPPrivateFSData;
+
+/* Generic + btree key */
+struct __attribute__ ((packed)) _HfsPPrivateGenericKey {
+ uint16_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPPrivateGenericKey HfsPPrivateGenericKey;
+
+/* ---- common ---- */
+
+/* node and lead record reference for a BTree search */
+struct _HfsCPrivateLeafRec {
+ unsigned int node_size; /* in sectors */
+ unsigned int node_number;
+ unsigned int record_pos;
+ unsigned int record_number;
+};
+typedef struct _HfsCPrivateLeafRec HfsCPrivateLeafRec;
+
+extern uint8_t* hfs_block;
+extern uint8_t* hfsp_block;
+extern unsigned hfs_block_count;
+extern unsigned hfsp_block_count;
+
+#endif /* _HFS_H */
diff --git a/libparted/fs/hfs/probe.c b/libparted/fs/hfs/probe.c
new file mode 100644
index 0000000..d02ca28
--- /dev/null
+++ b/libparted/fs/hfs/probe.c
@@ -0,0 +1,238 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+
+#include "probe.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom)
+{
+ PedDevice* dev;
+
+ dev = geom->dev;
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Parted can't use HFS file systems on disks "
+ "with a sector size not equal to %d bytes."),
+ (int)PED_SECTOR_SIZE_DEFAULT );
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Probe an HFS volume, detecting it even if
+it is in fact a wrapper to an HFS+ volume */
+/* Used by hfsplus_probe and hfs_probe */
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom)
+{
+ HfsMasterDirectoryBlock *mdb;
+ PedGeometry* geom_ret;
+ PedSector search, max;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (hfsc_can_use_geom (geom));
+
+ const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ char * buf = alloca (sectors * geom->dev->sector_size);
+
+ mdb = (HfsMasterDirectoryBlock *)(buf+1024);
+
+ /* is 5 an intelligent value ? */
+ if ((geom->length < 5)
+ || (!ped_geometry_read (geom, buf, 0, sectors))
+ || (mdb->signature != PED_CPU_TO_BE16 (HFS_SIGNATURE)) )
+ return NULL;
+
+ search = ((PedSector) PED_BE16_TO_CPU (mdb->start_block)
+ + ((PedSector) PED_BE16_TO_CPU (mdb->total_blocks)
+ * (PED_BE32_TO_CPU (mdb->block_size) / geom->dev->sector_size)));
+ max = search + (PED_BE32_TO_CPU (mdb->block_size) / geom->dev->sector_size);
+ if ((search < 0)
+ || !(geom_ret = ped_geometry_new (geom->dev, geom->start, search + 2)))
+ return NULL;
+
+ for (; search < max; search++) {
+ if (!ped_geometry_set (geom_ret, geom_ret->start, search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1))
+ break;
+ if (mdb->signature == PED_CPU_TO_BE16 (HFS_SIGNATURE))
+ return geom_ret;
+ }
+
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+}
+
+PedGeometry*
+hfsplus_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_ret;
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ if ((geom_ret = hfs_and_wrapper_probe(geom))) {
+ /* HFS+ is embedded in an HFS volume ? */
+ HfsMasterDirectoryBlock *mdb;
+ mdb = (HfsMasterDirectoryBlock *) buf;
+
+ if (!ped_geometry_read (geom, buf, 2, 1)
+ || (mdb->old_new.embedded.signature
+ != PED_CPU_TO_BE16 (HFSP_SIGNATURE))) {
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+ } else
+ return geom_ret;
+ } else {
+ /* This is a standalone HFS+ volume ? */
+ PedSector search, max;
+ HfsPVolumeHeader *vh;
+ vh = (HfsPVolumeHeader *) buf;
+
+ if ((geom->length < 5)
+ || !ped_geometry_read (geom, buf, 2, 1)
+ || (vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)))
+ return NULL;
+
+ /* Correct range is indeed [ blocks*sz-2;(blocs+1)*sz-2 ( */
+ /* But previous versions of my implementation used to */
+ /* assume range is [(blocks-1)*sz-1;(blocks*sz) ( */
+ /* (blocks-1)*sz-1 has to be scanned last, because */
+ /* it can belong to a regular file */
+ max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 2;
+ search = max - 2 * ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT ) + 2;
+ if ((search < 0)
+ || !(geom_ret = ped_geometry_new (geom->dev, geom->start,
+ search + 2)))
+ return NULL;
+
+ for (; search < max; search++) {
+ if (!ped_geometry_set (geom_ret, geom_ret->start,
+ search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1))
+ break;
+ if (vh->signature == PED_CPU_TO_BE16 (HFSP_SIGNATURE))
+ return geom_ret;
+ }
+ search = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) - 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 1;
+ if ((search < 0)
+ || !ped_geometry_set (geom_ret, geom_ret->start,
+ search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1)
+ || vh->signature != PED_CPU_TO_BE16 (HFSP_SIGNATURE)) {
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+ } else
+ return geom_ret;
+ }
+}
+
+PedGeometry*
+hfs_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_base;
+ PedGeometry* geom_plus = NULL;
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ if ((geom_base = hfs_and_wrapper_probe(geom))
+ && (!(geom_plus = hfsplus_probe(geom_base))))
+ return geom_base;
+ else {
+ if (geom_base) ped_geometry_destroy (geom_base);
+ if (geom_plus) ped_geometry_destroy (geom_plus);
+ return NULL;
+ }
+}
+
+PedGeometry*
+hfsx_probe (PedGeometry* geom)
+{
+ PedGeometry* geom_ret;
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedSector search, max;
+ HfsPVolumeHeader *vh = (HfsPVolumeHeader *) buf;
+
+ PED_ASSERT (geom != NULL);
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ if ((geom->length < 5)
+ || !ped_geometry_read (geom, buf, 2, 1)
+ || (vh->signature != PED_CPU_TO_BE16 (HFSX_SIGNATURE)))
+ return NULL;
+
+ /* unlike the hfs+ code, which should be kept compatible
+ with my old previous implementations, we only care here
+ about legal alternate VH positions, like TN1150 describes them */
+ max = ((PedSector) PED_BE32_TO_CPU (vh->total_blocks) + 1)
+ * ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT )
+ - 2;
+ search = max - ( PED_BE32_TO_CPU (vh->block_size) / PED_SECTOR_SIZE_DEFAULT );
+ if ((search < 0)
+ || !(geom_ret = ped_geometry_new (geom->dev, geom->start,
+ search + 2)))
+ return NULL;
+ for (; search < max; search++) {
+ if (!ped_geometry_set (geom_ret, geom_ret->start,
+ search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1))
+ break;
+ if (vh->signature == PED_CPU_TO_BE16 (HFSX_SIGNATURE))
+ return geom_ret;
+ }
+
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+}
diff --git a/libparted/fs/hfs/probe.h b/libparted/fs/hfs/probe.h
new file mode 100644
index 0000000..29ce880
--- /dev/null
+++ b/libparted/fs/hfs/probe.h
@@ -0,0 +1,44 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef _PROBE_H
+#define _PROBE_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom);
+
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom);
+
+PedGeometry*
+hfsplus_probe (PedGeometry* geom);
+
+PedGeometry*
+hfs_probe (PedGeometry* geom);
+
+PedGeometry*
+hfsx_probe (PedGeometry* geom);
+
+#endif /* _PROBE_H */
diff --git a/libparted/fs/jfs/jfs.c b/libparted/fs/jfs/jfs.c
new file mode 100644
index 0000000..f00bd9f
--- /dev/null
+++ b/libparted/fs/jfs/jfs.c
@@ -0,0 +1,80 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2001, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+
+#define _JFS_UTILITY
+#include "jfs_types.h"
+#include "jfs_superblock.h"
+
+#define JFS_SUPER_OFFSET 32768
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+static PedGeometry*
+jfs_probe (PedGeometry* geom)
+{
+ struct superblock *sb = alloca (geom->dev->sector_size);
+
+ if (geom->length * geom->dev->sector_size < JFS_SUPER_OFFSET)
+ return NULL;
+ if (!ped_geometry_read (geom, sb, JFS_SUPER_OFFSET / geom->dev->sector_size, 1))
+ return NULL;
+
+ if (strncmp (sb->s_magic, JFS_MAGIC, 4) == 0) {
+ PedSector block_size = PED_LE32_TO_CPU (sb->s_pbsize);
+ PedSector block_count = PED_LE64_TO_CPU (sb->s_size);
+ /* apparently jfs is retarded and always claims 512 byte
+ sectors, with the block count as a multiple of that */
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count / geom->dev->sector_size);
+ } else {
+ return NULL;
+ }
+}
+
+static PedFileSystemOps jfs_ops = {
+ probe: jfs_probe,
+};
+
+static PedFileSystemType jfs_type = {
+ next: NULL,
+ ops: &jfs_ops,
+ name: "jfs",
+};
+
+void
+ped_file_system_jfs_init ()
+{
+ ped_file_system_type_register (&jfs_type);
+}
+
+void
+ped_file_system_jfs_done ()
+{
+ ped_file_system_type_unregister (&jfs_type);
+}
diff --git a/libparted/fs/jfs/jfs_superblock.h b/libparted/fs/jfs/jfs_superblock.h
new file mode 100644
index 0000000..ea13dfb
--- /dev/null
+++ b/libparted/fs/jfs/jfs_superblock.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000
+ *
+ * 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 _H_JFS_SUPERBLOCK
+#define _H_JFS_SUPERBLOCK
+/*
+ * jfs_superblock.h
+ */
+
+/*
+ * make the magic number something a human could read
+ */
+#define JFS_MAGIC "JFS1" /* Magic word: Version 1 */
+
+#define JFS_VERSION 1 /* Version number: Version 1 */
+
+#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
+
+/*
+ * aggregate superblock
+ *
+ * The name superblock is too close to super_block, so the name has been
+ * changed to jfs_superblock. The utilities are still using the old name.
+ */
+#ifdef _JFS_UTILITY
+struct superblock
+#else
+struct jfs_superblock
+#endif
+{
+ char s_magic[4]; /* 4: magic number */
+ u32 s_version; /* 4: version number */
+
+ s64 s_size; /* 8: aggregate size in hardware/LVM blocks;
+ * VFS: number of blocks
+ */
+ s32 s_bsize; /* 4: aggregate block size in bytes;
+ * VFS: fragment size
+ */
+ s16 s_l2bsize; /* 2: log2 of s_bsize */
+ s16 s_l2bfactor; /* 2: log2(s_bsize/hardware block size) */
+ s32 s_pbsize; /* 4: hardware/LVM block size in bytes */
+ s16 s_l2pbsize; /* 2: log2 of s_pbsize */
+ s16 pad; /* 2: padding necessary for alignment */
+
+ u32 s_agsize; /* 4: allocation group size in aggr. blocks */
+
+ u32 s_flag; /* 4: aggregate attributes:
+ * see jfs_filsys.h
+ */
+ u32 s_state; /* 4: mount/unmount/recovery state:
+ * see jfs_filsys.h
+ */
+ s32 s_compress; /* 4: > 0 if data compression */
+
+ pxd_t s_ait2; /* 8: first extent of secondary
+ * aggregate inode table
+ */
+
+ pxd_t s_aim2; /* 8: first extent of secondary
+ * aggregate inode map
+ */
+ u32 s_logdev; /* 4: device address of log */
+ s32 s_logserial; /* 4: log serial number at aggregate mount */
+ pxd_t s_logpxd; /* 8: inline log extent */
+
+ pxd_t s_fsckpxd; /* 8: inline fsck work space extent */
+
+ struct timestruc_t s_time; /* 8: time last updated */
+
+ s32 s_fsckloglen; /* 4: Number of file system blocks reserved for
+ * the fsck service log.
+ * N.B. These blocks are divided among the
+ * versions kept. This is not a per
+ * version size.
+ * N.B. These blocks are included in the
+ * length field of s_fsckpxd.
+ */
+ s8 s_fscklog; /* 1: which fsck service log is most recent
+ * 0 => no service log data yet
+ * 1 => the first one
+ * 2 => the 2nd one
+ */
+ char s_fpack[11]; /* 11: file system volume name
+ * N.B. This must be 11 bytes to
+ * conform with the OS/2 BootSector
+ * requirements
+ */
+
+ /* extendfs() parameter under s_state & FM_EXTENDFS */
+ s64 s_xsize; /* 8: extendfs s_size */
+ pxd_t s_xfsckpxd; /* 8: extendfs fsckpxd */
+ pxd_t s_xlogpxd; /* 8: extendfs logpxd */
+ /* - 128 byte boundary - */
+
+ /*
+ * DFS VFS support (preliminary)
+ */
+ char s_attach; /* 1: VFS: flag: set when aggregate is attached
+ */
+ u8 rsrvd4[7]; /* 7: reserved - set to 0 */
+
+ u64 totalUsable; /* 8: VFS: total of 1K blocks which are
+ * available to "normal" (non-root) users.
+ */
+ u64 minFree; /* 8: VFS: # of 1K blocks held in reserve for
+ * exclusive use of root. This value can be 0,
+ * and if it is then totalUsable will be equal
+ * to # of blocks in aggregate. I believe this
+ * means that minFree + totalUsable = # blocks.
+ * In that case, we don't need to store both
+ * totalUsable and minFree since we can compute
+ * one from the other. I would guess minFree
+ * would be the one we should store, and
+ * totalUsable would be the one we should
+ * compute. (Just a guess...)
+ */
+
+ u64 realFree; /* 8: VFS: # of free 1K blocks can be used by
+ * "normal" users. It may be this is something
+ * we should compute when asked for instead of
+ * storing in the superblock. I don't know how
+ * often this information is needed.
+ */
+ /*
+ * graffiti area
+ */
+};
+
+#endif /*_H_JFS_SUPERBLOCK */
diff --git a/libparted/fs/jfs/jfs_types.h b/libparted/fs/jfs/jfs_types.h
new file mode 100644
index 0000000..0366ebd
--- /dev/null
+++ b/libparted/fs/jfs/jfs_types.h
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) International Business Machines Corp., 2000
+ *
+ * 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 _H_JFS_TYPES
+#define _H_JFS_TYPES
+
+/*
+ * jfs_types.h:
+ *
+ * basic type/utility definitions
+ *
+ * note: this header file must be the 1st include file
+ * of JFS include list in all JFS .c file.
+ */
+
+#ifdef _JFS_UTILITY
+/* this is defined in asm/byteorder.h for i386, but
+ * is NOT defined in asm/byteorder.h for ppc (non-kernel).
+ * Until that is changed, we'll define it here. */
+#define __BYTEORDER_HAS_U64__
+
+#include <sys/types.h>
+//#include <asm/byteorder.h>
+typedef unsigned short UniChar;
+#else
+#include <linux/types.h>
+#include <linux/jfs_fs.h>
+#include <linux/nls.h>
+
+#ifndef _ULS_UNICHAR_DEFINED
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0))
+typedef wchar_t UniChar;
+#else
+typedef unsigned short UniChar;
+#endif
+#define _ULS_UNICHAR_DEFINED
+#endif
+#endif
+/* #include "endian24.h" */
+
+/*
+ * primitive types
+ */
+#ifdef _JFS_UTILITY
+typedef int8_t s8;
+typedef uint8_t u8;
+typedef int16_t s16;
+typedef uint16_t u16;
+typedef int32_t s32;
+typedef uint32_t u32;
+typedef int64_t s64;
+typedef uint64_t u64;
+
+#ifndef _UINT_TYPES
+ /* unicode includes also define these */
+typedef u16 uint16;
+typedef u32 uint32;
+#define _UINT_TYPES
+#endif
+
+typedef s8 int8;
+typedef u8 uint8;
+typedef s16 int16;
+typedef s32 int32;
+typedef s64 int64;
+typedef u64 uint64;
+
+#endif /* _JFS_UTILITY */
+/*
+ * Holdovers from OS/2. Try to get away from using these altogether.
+ */
+typedef unsigned long ULONG;
+typedef unsigned short USHORT;
+typedef unsigned char UCHAR;
+typedef void *PVOID;
+#define MAXPATHLEN 255
+
+
+/*
+ * Almost identical to Linux's timespec, but not quite
+ */
+struct timestruc_t {
+ u32 tv_sec;
+ u32 tv_nsec;
+};
+
+/*
+ * handy
+ */
+#undef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#undef MAX
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#undef ROUNDUP
+#define ROUNDUP(x, y) ( ((x) + ((y) - 1)) & ~((y) - 1) )
+
+#define LEFTMOSTONE 0x80000000
+#define HIGHORDER 0x80000000u /* high order bit on */
+#define ONES 0xffffffffu /* all bit on */
+
+typedef int boolean_t;
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * logical xd (lxd)
+ */
+typedef struct {
+ unsigned len:24;
+ unsigned off1:8;
+ u32 off2;
+} lxd_t;
+
+/* lxd_t field construction */
+#define LXDlength(lxd, length32) ( (lxd)->len = length32 )
+#define LXDoffset(lxd, offset64)\
+{\
+ (lxd)->off1 = ((s64)offset64) >> 32;\
+ (lxd)->off2 = (offset64) & 0xffffffff;\
+}
+
+/* lxd_t field extraction */
+#define lengthLXD(lxd) ( (lxd)->len )
+#define offsetLXD(lxd)\
+ ( ((s64)((lxd)->off1)) << 32 | (lxd)->off2 )
+
+/* lxd list */
+typedef struct {
+ s16 maxnlxd;
+ s16 nlxd;
+ lxd_t *lxd;
+} lxdlist_t;
+
+/*
+ * physical xd (pxd)
+ */
+typedef struct {
+ unsigned len:24;
+ unsigned addr1:8;
+ u32 addr2;
+} pxd_t;
+
+/* xd_t field construction */
+
+#define PXDlength(pxd, length32) ((pxd)->len = __cpu_to_le24(length32))
+#define PXDaddress(pxd, address64)\
+{\
+ (pxd)->addr1 = ((s64)address64) >> 32;\
+ (pxd)->addr2 = __cpu_to_le32((address64) & 0xffffffff);\
+}
+
+/* xd_t field extraction */
+#define lengthPXD(pxd) __le24_to_cpu((pxd)->len)
+#define addressPXD(pxd)\
+ ( ((s64)((pxd)->addr1)) << 32 | __le32_to_cpu((pxd)->addr2))
+
+/* pxd list */
+typedef struct {
+ s16 maxnpxd;
+ s16 npxd;
+ pxd_t pxd[8];
+} pxdlist_t;
+
+
+/*
+ * data extent descriptor (dxd)
+ */
+typedef struct {
+ unsigned flag:8; /* 1: flags */
+ unsigned rsrvd:24; /* 3: */
+ u32 size; /* 4: size in byte */
+ unsigned len:24; /* 3: length in unit of fsblksize */
+ unsigned addr1:8; /* 1: address in unit of fsblksize */
+ u32 addr2; /* 4: address in unit of fsblksize */
+} dxd_t; /* - 16 - */
+
+/* dxd_t flags */
+#define DXD_INDEX 0x80 /* B+-tree index */
+#define DXD_INLINE 0x40 /* in-line data extent */
+#define DXD_EXTENT 0x20 /* out-of-line single extent */
+#define DXD_FILE 0x10 /* out-of-line file (inode) */
+#define DXD_CORRUPT 0x08 /* Inconsistency detected */
+
+/* dxd_t field construction
+ * Conveniently, the PXD macros work for DXD
+ */
+#define DXDlength PXDlength
+#define DXDaddress PXDaddress
+#define lengthDXD lengthPXD
+#define addressDXD addressPXD
+
+/*
+ * directory entry argument
+ */
+typedef struct component_name {
+ int namlen;
+ UniChar *name;
+} component_t;
+
+
+/*
+ * DASD limit information - stored in directory inode
+ */
+typedef struct dasd {
+ u8 thresh; /* Alert Threshold (in percent) */
+ u8 delta; /* Alert Threshold delta (in percent) */
+ u8 rsrvd1;
+ u8 limit_hi; /* DASD limit (in logical blocks) */
+ u32 limit_lo; /* DASD limit (in logical blocks) */
+ u8 rsrvd2[3];
+ u8 used_hi; /* DASD usage (in logical blocks) */
+ u32 used_lo; /* DASD usage (in logical blocks) */
+} dasd_t;
+
+#define DASDLIMIT(dasdp) \
+ (((u64)((dasdp)->limit_hi) << 32) + __le32_to_cpu((dasdp)->limit_lo))
+#define setDASDLIMIT(dasdp, limit)\
+{\
+ (dasdp)->limit_hi = ((u64)limit) >> 32;\
+ (dasdp)->limit_lo = __cpu_to_le32(limit);\
+}
+#define DASDUSED(dasdp) \
+ (((u64)((dasdp)->used_hi) << 32) + __le32_to_cpu((dasdp)->used_lo))
+#define setDASDUSED(dasdp, used)\
+{\
+ (dasdp)->used_hi = ((u64)used) >> 32;\
+ (dasdp)->used_lo = __cpu_to_le32(used);\
+}
+
+/*
+ * circular doubly-linked list (cdll)
+ *
+ * A circular doubly-linked list (cdll) is anchored by a pair of pointers,
+ * one to the head of the list and the other to the tail of the list.
+ * The elements are doubly linked so that an arbitrary element can be
+ * removed without a need to traverse the list.
+ * New elements can be added to the list before or after an existing element,
+ * at the head of the list, or at the tail of the list.
+ * A circle queue may be traversed in either direction.
+ *
+ * +----------+ +-------------------------------------+
+ * | | | |
+ * +->+-----+ | +->+-----+ +->+-----+ +->+-----+ |
+ * | | h +-+ | | h +--+ | n +----+ | n +--+
+ * | +-----+ | +-----+ | +-----+ | +-----+
+ * | | t +-+ +-----+ t | | | p +--+ | | p +--+
+ * | +-----+ | | | +-----+ | +-----+ | | +-----+ |
+ * +----------+ | +-----------------------+ | |
+ * | | | |
+ * | +-------------------------+
+ * | |
+ * +----------------------------+
+ */
+/*
+ * define header
+ *
+ * list header field definition in header element:
+ *
+ * type - type of list element struct embedding the link field
+ */
+#define CDLL_HEADER(type)\
+struct {\
+ struct type *head;\
+ struct type *tail;\
+}
+
+struct cdll_header {
+ struct cdll_header *head;
+ struct cdll_header *tail;
+};
+
+/*
+ * define link
+ *
+ * list link field definition in list element:
+ *
+ * type - type of parent list element struct embedding the link field
+ */
+#define CDLL_ENTRY(type)\
+struct {\
+ struct type *next;\
+ struct type *prev;\
+}
+
+struct cdll_entry {
+ struct cdll_entry *next;
+ struct cdll_entry *prev;
+};
+
+/*
+ * initialize header
+ *
+ * header - ptr to the header field in the header element
+ */
+#define CDLL_INIT(header) {\
+ (header)->head = (void *)(header);\
+ (header)->tail = (void *)(header);\
+}
+
+/*
+ * scan list
+ *
+ * header - ptr to the header field in the header element
+ * elm - ptr to the element to be inserted
+ * field - name of the link field in the list element
+ *
+ * struct header_container *container;
+ * struct header_type *header;
+ * struct element_type *elm;
+ *
+ * header = &container->header_field;
+ * for (elm = header->head; elm != (void *)header; elm = elm->field.next)
+ */
+
+/*
+ * insert <elm> at head of list anchored at <header>
+ *
+ * header - ptr to the header field in the header element
+ * elm - ptr to the list element to be inserted
+ * field - name of the link field in the list element
+ */
+#define CDLL_INSERT_HEAD(header, elm, field) {\
+ (elm)->field.next = (header)->head;\
+ (elm)->field.prev = (void *)(header);\
+ if ((header)->tail == (void *)(header))\
+ (header)->tail = (elm);\
+ else\
+ (header)->head->field.prev = (elm);\
+ (header)->head = (elm);\
+}
+
+/*
+ * insert <elm> at tail of list anchored at <header>
+ *
+ * header - ptr to the header field in the header element
+ * elm - ptr to the list element to be inserted
+ * field - name of the link field in the list element
+ */
+#define CDLL_INSERT_TAIL(header, elm, field) {\
+ (elm)->field.next = (void *)(header);\
+ (elm)->field.prev = (header)->tail;\
+ if ((header)->head == (void *)(header))\
+ (header)->head = (elm);\
+ else\
+ (header)->tail->field.next = (elm);\
+ (header)->tail = (elm);\
+}
+
+/*
+ * insert <elm> after <listelm> of list anchored at <header>
+ *
+ * header - ptr to the header field in the header element
+ * listelm - ptr to the list element at insertion point
+ * elm - ptr to the list element to be inserted
+ * field - name of the link field in the list element
+ */
+#define CDLL_INSERT_AFTER(header, listelm, elm, field) {\
+ (elm)->field.next = (listelm)->field.next;\
+ (elm)->field.prev = (listelm);\
+ if ((listelm)->field.next == (void *)(header))\
+ (header)->tail = (elm);\
+ else\
+ (listelm)->field.next->field.prev = (elm);\
+ (listelm)->field.next = (elm);\
+}
+
+/*
+ * insert <elm> before <listelm> of list anchored at <header>
+ *
+ * header - ptr to the header field in the header element
+ * listelm - ptr to list element at insertion point
+ * elm - ptr to the element to be inserted
+ * field - name of the link field in the list element
+ */
+#define CDLL_INSERT_BEFORE(header, listelm, elm, field) {\
+ (elm)->field.next = (listelm);\
+ (elm)->field.prev = (listelm)->field.prev;\
+ if ((listelm)->field.prev == (void *)(header))\
+ (header)->head = (elm);\
+ else\
+ (listelm)->field.prev->field.next = (elm);\
+ (listelm)->field.prev = (elm);\
+}
+
+/*
+ * remove <elm> from list anchored at <header>
+ *
+ * header - ptr to the header field in the header element
+ * elm - ptr to the list element to be removed
+ * field - name of the link field in the list element
+ */
+#define CDLL_REMOVE(header, elm, field) {\
+ if ((elm)->field.next == (void *)(header))\
+ (header)->tail = (elm)->field.prev;\
+ else\
+ (elm)->field.next->field.prev = (elm)->field.prev;\
+ if ((elm)->field.prev == (void *)(header))\
+ (header)->head = (elm)->field.next;\
+ else\
+ (elm)->field.prev->field.next = (elm)->field.next;\
+}
+
+#define CDLL_MOVE_TO_HEAD(header, elm, field) {\
+ if ((elm)->field.prev != (void *)(header))\
+ {\
+ if ((elm)->field.next == (void *)(header))\
+ (header)->tail = (elm)->field.prev;\
+ else\
+ (elm)->field.next->field.prev = (elm)->field.prev;\
+ (elm)->field.prev->field.next = (elm)->field.next;\
+ (elm)->field.next = (header)->head;\
+ (elm)->field.prev = (void *)(header);\
+ (header)->head->field.prev = (elm);\
+ (header)->head = (elm);\
+ }\
+}
+
+#define CDLL_MOVE_TO_TAIL(header, elm, field) {\
+ if ((elm)->field.next != (void *)(header))\
+ {\
+ (elm)->field.next->field.prev = (elm)->field.prev;\
+ if ((elm)->field.prev == (void *)(header))\
+ (header)->head = (elm)->field.next;\
+ else\
+ (elm)->field.prev->field.next = (elm)->field.next;\
+ (elm)->field.next = (void *)(header);\
+ (elm)->field.prev = (header)->tail;\
+ (header)->tail->field.next = (elm);\
+ (header)->tail = (elm);\
+ }\
+}
+
+/*
+ * orphan list element
+ */
+#define CDLL_SELF(elm, field)\
+ (elm)->field.next = (elm)->field.prev = (elm);
+
+
+/*
+ * single head doubly-linked list
+ *
+ * A list is headed by a single head pointer.
+ * The elements are doubly linked so that an arbitrary element can be
+ * removed without a need to traverse the list.
+ * New elements can be added to the list at the head of the list, or
+ * after an existing element (NO insert at tail).
+ * A list may only be traversed in the forward direction.
+ * (note: the list is NULL terminated in next field.)
+ *
+ * +-----+ +->+-----+ +->+-----+ +->+-----+
+ * | NULL| | | h +--+ | n +----+ | NULL|
+ * +-----+ | +-----+ | +-----+ +-----+
+ * | | | p +--+ | p +--+
+ * | | +-----+ | +-----+ |
+ * +-----------------------+ |
+ * | |
+ * +-------------------------+
+ */
+#define LIST_HEADER(type)\
+struct {\
+ struct type *head;\
+}
+
+#define LIST_ENTRY(type)\
+struct {\
+ struct type *next;\
+ struct type **prev;\
+}
+
+#define LIST_INIT(header) { (header)->head = NULL; }
+
+/*
+ * scan list
+ *
+ * header - ptr to the header (field in header element)
+ * elm - ptr to the element to be inserted
+ * field - name of the link field in list element
+ *
+ * struct header_container *container;
+ * struct header_type *header;
+ * struct element_type *elm;
+ *
+ * header = &container->header_field;
+ * for (elm = header->head; elm; elm = elm->field.next)
+ */
+
+#define LIST_INSERT_HEAD(header, elm, field) {\
+ if (((elm)->field.next = (header)->head) != NULL)\
+ (header)->head->field.prev = &(elm)->field.next;\
+ (header)->head = (elm);\
+ (elm)->field.prev = &(header)->head;\
+}
+
+#define LIST_INSERT_AFTER(listelm, elm, field) {\
+ if (((elm)->field.next = (listelm)->field.next) != NULL)\
+ (listelm)->field.next->field.prev = &(elm)->field.next;\
+ (listelm)->field.next = (elm);\
+ (elm)->field.prev = &(listelm)->field.next;\
+}
+
+#define LIST_REMOVE(elm, field) {\
+ if ((elm)->field.next != NULL)\
+ (elm)->field.next->field.prev = (elm)->field.prev;\
+ *(elm)->field.prev = (elm)->field.next;\
+}
+
+#define LIST_SELF(elm, field) {\
+ (elm)->field.next = NULL;\
+ (elm)->field.prev = &(elm)->field.next;\
+}
+
+#endif /* !_H_JFS_TYPES */
diff --git a/libparted/fs/linux_swap/linux_swap.c b/libparted/fs/linux_swap/linux_swap.c
new file mode 100644
index 0000000..60100b0
--- /dev/null
+++ b/libparted/fs/linux_swap/linux_swap.c
@@ -0,0 +1,396 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 1999-2000, 2002, 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/>.
+*/
+
+/* It's a bit silly calling a swap partition a file system. Oh well... */
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <unistd.h>
+#include <uuid/uuid.h>
+
+#define SWAP_SPECIFIC(fs) ((SwapSpecific*) (fs->type_specific))
+#define BUFFER_SIZE 128
+
+#define LINUXSWAP_BLOCK_SIZES ((int[2]){512, 0})
+
+typedef struct {
+ char page_map[1];
+} SwapOldHeader;
+
+/* ripped from mkswap */
+typedef struct {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ uint32_t version;
+ uint32_t last_page;
+ uint32_t nr_badpages;
+ unsigned char sws_uuid[16];
+ unsigned char sws_volume[16];
+ uint32_t padding[117];
+ uint32_t badpages[1];
+} SwapNewHeader;
+
+typedef struct {
+ union {
+ SwapNewHeader new;
+ SwapOldHeader old;
+ }* header;
+
+ void* buffer;
+ int buffer_size;
+
+ PedSector page_sectors;
+ unsigned int page_count;
+ unsigned int version;
+ unsigned int max_bad_pages;
+} SwapSpecific;
+
+static PedFileSystemType _swap_v0_type;
+static PedFileSystemType _swap_v1_type;
+static PedFileSystemType _swap_swsusp_type;
+
+static PedFileSystem* _swap_v0_open (PedGeometry* geom);
+static PedFileSystem* _swap_v1_open (PedGeometry* geom);
+static PedFileSystem* _swap_swsusp_open (PedGeometry* geom);
+static int swap_close (PedFileSystem* fs);
+
+static PedGeometry*
+_generic_swap_probe (PedGeometry* geom, int kind)
+{
+ PedFileSystem* fs;
+ SwapSpecific* fs_info;
+ PedGeometry* probed_geom;
+ PedSector length;
+
+ switch (kind) {
+ /* Check for old style swap partitions. */
+ case 0:
+ fs = _swap_v0_open(geom);
+ break;
+ /* Check for new style swap partitions. */
+ case 1:
+ fs = _swap_v1_open(geom);
+ break;
+ /* Check for swap partitions containing swsusp data. */
+ case -1:
+ fs = _swap_swsusp_open(geom);
+ break;
+ /* Not reached. */
+ default:
+ goto error;
+ }
+
+ if (!fs)
+ goto error;
+ fs_info = SWAP_SPECIFIC (fs);
+
+ if (fs_info->version)
+ length = fs_info->page_sectors * fs_info->page_count;
+ else
+ length = geom->length;
+
+ probed_geom = ped_geometry_new (geom->dev, geom->start, length);
+ if (!probed_geom)
+ goto error_close_fs;
+ swap_close (fs);
+ return probed_geom;
+
+error_close_fs:
+ swap_close (fs);
+error:
+ return NULL;
+}
+
+
+static int
+swap_init (PedFileSystem* fs)
+{
+ SwapSpecific* fs_info = SWAP_SPECIFIC (fs);
+
+ fs_info->page_sectors = getpagesize () / fs->geom->dev->sector_size;
+ fs_info->page_count = fs->geom->length / fs_info->page_sectors;
+ fs_info->version = 1;
+ fs_info->max_bad_pages = (getpagesize()
+ - sizeof (SwapNewHeader)) / 4;
+
+ return ped_geometry_read (fs->geom, fs_info->header,
+ 0, fs_info->page_sectors);
+}
+
+
+static PedFileSystem*
+swap_alloc (PedGeometry* geom)
+{
+ PedFileSystem* fs;
+ SwapSpecific* fs_info;
+
+ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
+ if (!fs)
+ goto error;
+
+ fs->type_specific = (SwapSpecific*) ped_malloc (sizeof (SwapSpecific));
+ if (!fs->type_specific)
+ goto error_free_fs;
+
+ fs_info = SWAP_SPECIFIC (fs);
+ fs_info->header = ped_malloc (PED_MAX(getpagesize(), geom->dev->sector_size));
+ if (!fs_info->header)
+ goto error_free_type_specific;
+
+ fs_info = SWAP_SPECIFIC (fs);
+ fs_info->buffer_size = getpagesize() * BUFFER_SIZE;
+ fs_info->buffer = ped_malloc (fs_info->buffer_size);
+ if (!fs_info->buffer)
+ goto error_free_header;
+
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom)
+ goto error_free_buffer;
+ fs->type = &_swap_v1_type;
+ return fs;
+
+error_free_buffer:
+ free (fs_info->buffer);
+error_free_header:
+ free (fs_info->header);
+error_free_type_specific:
+ free (fs->type_specific);
+error_free_fs:
+ free (fs);
+error:
+ return NULL;
+}
+
+static void
+swap_free (PedFileSystem* fs)
+{
+ SwapSpecific* fs_info = SWAP_SPECIFIC (fs);
+
+ free (fs_info->buffer);
+ free (fs_info->header);
+ free (fs->type_specific);
+
+ ped_geometry_destroy (fs->geom);
+ free (fs);
+}
+
+static PedFileSystem*
+_swap_v0_open (PedGeometry* geom)
+{
+ PedFileSystem* fs;
+ SwapSpecific* fs_info;
+ const char* sig;
+
+ fs = swap_alloc (geom);
+ if (!fs)
+ goto error;
+ swap_init (fs);
+
+ fs_info = SWAP_SPECIFIC (fs);
+ if (!ped_geometry_read (fs->geom, fs_info->header, 0,
+ fs_info->page_sectors))
+ goto error_free_fs;
+
+ sig = ((char*) fs_info->header) + getpagesize() - 10;
+ if (strncmp (sig, "SWAP-SPACE", 10) == 0) {
+ fs_info->version = 0;
+ fs_info->page_count
+ = PED_MIN (fs->geom->length / fs_info->page_sectors,
+ 8 * (getpagesize() - 10));
+ } else {
+ char _sig [11];
+
+ memcpy (_sig, sig, 10);
+ _sig [10] = 0;
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unrecognised old style linux swap signature '%10s'."), _sig);
+ goto error_free_fs;
+ }
+
+ fs->checked = 1;
+ return fs;
+
+error_free_fs:
+ swap_free (fs);
+error:
+ return NULL;
+}
+
+static PedFileSystem*
+_swap_v1_open (PedGeometry* geom)
+{
+ PedFileSystem* fs;
+ SwapSpecific* fs_info;
+ const char* sig;
+
+ fs = swap_alloc (geom);
+ if (!fs)
+ goto error;
+ if (!swap_init(fs))
+ goto error_free_fs;
+
+ fs_info = SWAP_SPECIFIC (fs);
+
+ sig = ((char*) fs_info->header) + getpagesize() - 10;
+ if (strncmp (sig, "SWAPSPACE2", 10) == 0) {
+ fs_info->version = 1;
+ fs_info->page_count = fs_info->header->new.last_page;
+ } else {
+ char _sig [11];
+
+ memcpy (_sig, sig, 10);
+ _sig [10] = 0;
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unrecognised new style linux swap signature '%10s'."), _sig);
+ goto error_free_fs;
+ }
+
+ fs->checked = 1;
+ return fs;
+
+error_free_fs:
+ swap_free (fs);
+error:
+ return NULL;
+}
+
+static PedFileSystem*
+_swap_swsusp_open (PedGeometry* geom)
+{
+ PedFileSystem* fs;
+ SwapSpecific* fs_info;
+ const char* sig;
+
+ fs = swap_alloc (geom);
+ if (!fs)
+ goto error;
+ fs->type = &_swap_swsusp_type;
+ swap_init (fs);
+
+ fs_info = SWAP_SPECIFIC (fs);
+ if (!ped_geometry_read (fs->geom, fs_info->header, 0,
+ fs_info->page_sectors))
+ goto error_free_fs;
+
+ sig = ((char*) fs_info->header) + getpagesize() - 10;
+ if (strncmp (sig, "S1SUSPEND", 9) == 0) {
+ fs_info->version = -1;
+ } else {
+ char _sig [10];
+
+ memcpy (_sig, sig, 9);
+ _sig [9] = 0;
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Unrecognised swsusp linux swap signature '%9s'."), _sig);
+ goto error_free_fs;
+ }
+
+ fs->checked = 1;
+ return fs;
+
+error_free_fs:
+ swap_free (fs);
+error:
+ return NULL;
+}
+
+static int
+swap_close (PedFileSystem* fs)
+{
+ swap_free (fs);
+ return 1;
+}
+
+static PedGeometry*
+_swap_v0_probe (PedGeometry* geom) {
+ return _generic_swap_probe (geom, 0);
+}
+
+static PedGeometry*
+_swap_v1_probe (PedGeometry* geom) {
+ return _generic_swap_probe (geom, 1);
+}
+
+static PedGeometry*
+_swap_swsusp_probe (PedGeometry* geom) {
+ return _generic_swap_probe (geom, -1);
+}
+
+static PedFileSystemOps _swap_v0_ops = {
+ probe: _swap_v0_probe,
+};
+
+static PedFileSystemOps _swap_v1_ops = {
+ probe: _swap_v1_probe,
+};
+
+static PedFileSystemOps _swap_swsusp_ops = {
+ probe: _swap_swsusp_probe,
+};
+
+static PedFileSystemType _swap_v0_type = {
+ next: NULL,
+ ops: &_swap_v0_ops,
+ name: "linux-swap(v0)",
+};
+
+static PedFileSystemType _swap_v1_type = {
+ next: NULL,
+ ops: &_swap_v1_ops,
+ name: "linux-swap(v1)",
+};
+
+static PedFileSystemType _swap_swsusp_type = {
+ next: NULL,
+ ops: &_swap_swsusp_ops,
+ name: "swsusp",
+};
+
+void
+ped_file_system_linux_swap_init ()
+{
+ ped_file_system_type_register (&_swap_v0_type);
+ ped_file_system_type_register (&_swap_v1_type);
+ ped_file_system_type_register (&_swap_swsusp_type);
+
+ ped_file_system_alias_register (&_swap_v0_type, "linux-swap(old)", 1);
+ ped_file_system_alias_register (&_swap_v1_type, "linux-swap(new)", 1);
+ ped_file_system_alias_register (&_swap_v1_type, "linux-swap", 0);
+}
+
+void
+ped_file_system_linux_swap_done ()
+{
+ ped_file_system_alias_unregister (&_swap_v0_type, "linux-swap(old)");
+ ped_file_system_alias_unregister (&_swap_v1_type, "linux-swap(new)");
+ ped_file_system_alias_unregister (&_swap_v1_type, "linux-swap");
+
+ ped_file_system_type_unregister (&_swap_v0_type);
+ ped_file_system_type_unregister (&_swap_v1_type);
+ ped_file_system_type_unregister (&_swap_swsusp_type);
+}
diff --git a/libparted/fs/nilfs2/nilfs2.c b/libparted/fs/nilfs2/nilfs2.c
new file mode 100644
index 0000000..6204542
--- /dev/null
+++ b/libparted/fs/nilfs2/nilfs2.c
@@ -0,0 +1,155 @@
+/*
+ * nilfs2.c - New Implementation of Log filesystem
+ *
+ * Written by Jiro SEKIBA <jir@unicus.jp>
+ *
+ * Copyright (C) 2011-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/crc32.h>
+#include <parted/endian.h>
+
+/* Magic value for nilfs2 superblock. */
+#define NILFS2_SUPER_MAGIC 0x3434
+
+/* primariy superblock offset in 512bytes blocks. */
+#define NILFS_SB_OFFSET 2
+
+/* secondary superblock offset in 512byte blocks. */
+#define NILFS_SB2_OFFSET(devsize) ((((devsize)>>3) - 1) << 3)
+
+struct __attribute__ ((packed)) nilfs2_super_block {
+ uint32_t s_rev_level;
+ uint16_t s_minor_rev_level;
+ uint16_t s_magic;
+ uint16_t s_bytes;
+ uint16_t s_flags;
+ uint32_t s_crc_seed;
+ uint32_t s_sum;
+ uint32_t s_log_block_size;
+ uint64_t s_nsegments;
+ uint64_t s_dev_size;
+ uint64_t s_first_data_block;
+ uint32_t s_blocks_per_segment;
+ uint32_t s_r_segments_percentage;
+ uint64_t s_last_cno;
+ uint64_t s_last_pseg;
+ uint64_t s_last_seq;
+ uint64_t s_free_blocks_count;
+ uint64_t s_ctime;
+ uint64_t s_mtime;
+ uint64_t s_wtime;
+ uint16_t s_mnt_count;
+ uint16_t s_max_mnt_count;
+ uint16_t s_state;
+ uint16_t s_errors;
+ uint64_t s_lastcheck;
+ uint32_t s_checkinterval;
+ uint32_t s_creator_os;
+ uint16_t s_def_resuid;
+ uint16_t s_def_resgid;
+ uint32_t s_first_ino;
+ uint16_t s_inode_size;
+ uint16_t s_dat_entry_size;
+ uint16_t s_checkpoint_size;
+ uint16_t s_segment_usage_size;
+ uint8_t s_uuid[16];
+ char s_volume_name[80];
+ uint32_t s_c_interval;
+ uint32_t s_c_block_max;
+ uint32_t s_reserved[192];
+};
+
+static int
+is_valid_nilfs_sb(struct nilfs2_super_block *sb)
+{
+ static unsigned char sum[4];
+ const int sumoff = offsetof (struct nilfs2_super_block, s_sum);
+ size_t bytes;
+ uint32_t crc;
+
+ if (PED_LE16_TO_CPU(sb->s_magic) != NILFS2_SUPER_MAGIC)
+ return 0;
+
+ bytes = PED_LE16_TO_CPU(sb->s_bytes);
+ if (bytes > 1024 || bytes < sumoff - 4)
+ return 0;
+
+ crc = __efi_crc32(sb, sumoff, PED_LE32_TO_CPU(sb->s_crc_seed));
+ crc = __efi_crc32(sum, 4, crc);
+ crc = __efi_crc32((unsigned char *)sb + sumoff + 4,
+ bytes - sumoff - 4, crc);
+
+ return crc == PED_LE32_TO_CPU(sb->s_sum);
+}
+
+PedGeometry*
+nilfs2_probe (PedGeometry* geom)
+{
+ struct nilfs2_super_block *sb = NULL;
+ struct nilfs2_super_block *sb2 = NULL;
+ PedSector length = geom->length * (geom->dev->sector_size / 512);
+
+ PedSector sb2off = NILFS_SB2_OFFSET(length) / (geom->dev->sector_size / 512);
+ if (sb2off <= 2)
+ return NULL;
+ const int sectors = (4096 + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ uint8_t *buf = alloca (sectors * geom->dev->sector_size);
+ const int sectors2 = (1024 + geom->dev->sector_size -1 ) /
+ geom->dev->sector_size;
+ void *buff2 = alloca (sectors2 * geom->dev->sector_size);
+
+ if (ped_geometry_read(geom, buf, 0, sectors))
+ sb = (struct nilfs2_super_block*)(buf + 1024);
+ if (ped_geometry_read(geom, buff2, sb2off, sectors2))
+ sb2 = (struct nilfs2_super_block*)buff2;
+
+ if ((!sb || !is_valid_nilfs_sb(sb)) &&
+ (!sb2 || !is_valid_nilfs_sb(sb2)))
+ return NULL;
+
+ /* reserve 4k bytes for secondary superblock */
+ length = sb2off + ((4096 + geom->dev->sector_size - 1) /
+ geom->dev->sector_size);
+
+ return ped_geometry_new(geom->dev, geom->start, length);
+}
+
+static PedFileSystemOps nilfs2_ops = {
+ probe: nilfs2_probe,
+};
+
+static PedFileSystemType nilfs2_type = {
+ next: NULL,
+ ops: &nilfs2_ops,
+ name: "nilfs2",
+};
+
+void
+ped_file_system_nilfs2_init ()
+{
+ ped_file_system_type_register (&nilfs2_type);
+}
+
+void
+ped_file_system_nilfs2_done ()
+{
+ ped_file_system_type_unregister (&nilfs2_type);
+}
diff --git a/libparted/fs/ntfs/ntfs.c b/libparted/fs/ntfs/ntfs.c
new file mode 100644
index 0000000..9829f39
--- /dev/null
+++ b/libparted/fs/ntfs/ntfs.c
@@ -0,0 +1,73 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <unistd.h>
+
+#define NTFS_SIGNATURE "NTFS"
+
+PedGeometry*
+ntfs_probe (PedGeometry* geom)
+{
+ uint8_t *buf = alloca(geom->dev->sector_size);
+ PedGeometry *newg = NULL;
+
+ if (!ped_geometry_read(geom, buf, 0, 1))
+ return 0;
+
+ if (strncmp (NTFS_SIGNATURE, ((char *)buf + 3), strlen (NTFS_SIGNATURE)) == 0) {
+ uint64_t length;
+ memcpy(&length, buf + 0x28, sizeof(uint64_t));
+ newg = ped_geometry_new (geom->dev, geom->start, length);
+ }
+ return newg;
+}
+
+static PedFileSystemOps ntfs_ops = {
+ probe: ntfs_probe,
+};
+
+static PedFileSystemType ntfs_type = {
+ next: NULL,
+ ops: &ntfs_ops,
+ name: "ntfs",
+};
+
+void
+ped_file_system_ntfs_init ()
+{
+ ped_file_system_type_register (&ntfs_type);
+}
+
+void
+ped_file_system_ntfs_done ()
+{
+ ped_file_system_type_unregister (&ntfs_type);
+}
diff --git a/libparted/fs/r/fat/bootsector.c b/libparted/fs/r/fat/bootsector.c
new file mode 100644
index 0000000..85ccc0f
--- /dev/null
+++ b/libparted/fs/r/fat/bootsector.c
@@ -0,0 +1,441 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 2002, 2004, 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 <config.h>
+#include "fat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* Reads in the boot sector (superblock), and does a minimum of sanity
+ * checking. The goals are:
+ * - to detect fat file systems, even if they are damaged [i.e. not
+ * return an error / throw an exception]
+ * - to fail detection if there's not enough information for
+ * fat_boot_sector_probe_type() to work (or possibly crash on a divide-by-zero)
+ */
+int
+fat_boot_sector_read (FatBootSector** bsp, const PedGeometry *geom)
+{
+ PED_ASSERT (bsp != NULL);
+ PED_ASSERT (geom != NULL);
+
+ if (!ped_geometry_read_alloc (geom, (void **)bsp, 0, 1))
+ return 0;
+ FatBootSector *bs = *bsp;
+ if (PED_LE16_TO_CPU (bs->boot_sign) != 0xAA55) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid signature for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->sector_size
+ || PED_LE16_TO_CPU (bs->sector_size) % PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid sector size for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->cluster_size) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid cluster size for a FAT "
+ "file system."));
+ return 0;
+ }
+
+ if (!bs->reserved) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid number of reserved "
+ "sectors for a FAT file system."));
+ return 0;
+ }
+
+ if (bs->fats < 1 || bs->fats > 4) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("File system has an invalid number of FATs."));
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ Don't trust the FAT12, FAT16 or FAT32 label string.
+ */
+FatType _GL_ATTRIBUTE_PURE
+fat_boot_sector_probe_type (const FatBootSector* bs, const PedGeometry* geom)
+{
+ PedSector logical_sector_size;
+ PedSector first_cluster_sector;
+ FatCluster cluster_count;
+
+ if (!PED_LE16_TO_CPU (bs->dir_entries))
+ return FAT_TYPE_FAT32;
+
+ logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
+
+ first_cluster_sector
+ = PED_LE16_TO_CPU (bs->reserved) * logical_sector_size
+ + 2 * PED_LE16_TO_CPU (bs->fat_length) * logical_sector_size
+ + PED_LE16_TO_CPU (bs->dir_entries)
+ / (512 / sizeof (FatDirEntry));
+ cluster_count = (geom->length - first_cluster_sector)
+ / bs->cluster_size / logical_sector_size;
+ if (cluster_count > MAX_FAT12_CLUSTERS)
+ return FAT_TYPE_FAT16;
+ else
+ return FAT_TYPE_FAT12;
+}
+
+/* Analyses the boot sector, and sticks appropriate numbers in
+ fs->type_specific.
+
+ Note: you need to subtract (2 * cluster_sectors) off cluster offset,
+ because the first cluster is number 2. (0 and 1 are not real clusters,
+ and referencing them is a bug)
+ */
+int
+fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int fat_entry_size;
+
+ PED_ASSERT (bs != NULL);
+
+ fs_info->logical_sector_size = PED_LE16_TO_CPU (bs->sector_size) / 512;
+
+ fs_info->sectors_per_track = PED_LE16_TO_CPU (bs->secs_track);
+ fs_info->heads = PED_LE16_TO_CPU (bs->heads);
+ if (fs_info->sectors_per_track < 1 || fs_info->sectors_per_track > 63
+ || fs_info->heads < 1 || fs_info->heads > 255) {
+ PedCHSGeometry* bios_geom = &fs->geom->dev->bios_geom;
+ int cyl_count = 0;
+
+ if (fs_info->heads > 0 && fs_info->sectors_per_track > 0)
+ cyl_count = fs->geom->dev->length / fs_info->heads
+ / fs_info->sectors_per_track;
+
+ switch (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_FIX + PED_EXCEPTION_IGNORE
+ + PED_EXCEPTION_CANCEL,
+ _("The file system's CHS geometry is (%d, %d, %d), "
+ "which is invalid. The partition table's CHS "
+ "geometry is (%d, %d, %d). If you select Ignore, "
+ "the file system's CHS geometry will be left "
+ "unchanged. If you select Fix, the file system's "
+ "CHS geometry will be set to match the partition "
+ "table's CHS geometry."),
+ cyl_count, fs_info->heads, fs_info->sectors_per_track,
+ bios_geom->cylinders, bios_geom->heads,
+ bios_geom->sectors)) {
+
+ case PED_EXCEPTION_FIX:
+ fs_info->sectors_per_track = bios_geom->sectors;
+ fs_info->heads = bios_geom->heads;
+ bs->secs_track
+ = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
+ bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
+ if (!fat_boot_sector_write (bs, fs))
+ return 0;
+ break;
+
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+
+ case PED_EXCEPTION_IGNORE:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (bs->sectors)
+ fs_info->sector_count = PED_LE16_TO_CPU (bs->sectors)
+ * fs_info->logical_sector_size;
+ else
+ fs_info->sector_count = PED_LE32_TO_CPU (bs->sector_count)
+ * fs_info->logical_sector_size;
+
+ fs_info->fat_table_count = bs->fats;
+ fs_info->root_dir_entry_count = PED_LE16_TO_CPU (bs->dir_entries);
+ fs_info->fat_offset = PED_LE16_TO_CPU (bs->reserved)
+ * fs_info->logical_sector_size;
+ fs_info->cluster_sectors = bs->cluster_size
+ * fs_info->logical_sector_size;
+ fs_info->cluster_size = fs_info->cluster_sectors * 512;
+
+ if (fs_info->logical_sector_size == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says logical sector size is 0. "
+ "This is weird. "));
+ return 0;
+ }
+ if (fs_info->fat_table_count == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says there are no FAT tables. This "
+ "is weird. "));
+ return 0;
+ }
+ if (fs_info->cluster_sectors == 0) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("FAT boot sector says clusters are 0 sectors. This "
+ "is weird. "));
+ return 0;
+ }
+
+ fs_info->fat_type = fat_boot_sector_probe_type (bs, fs->geom);
+ if (fs_info->fat_type == FAT_TYPE_FAT12) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("File system is FAT12, which is unsupported."));
+ return 0;
+ }
+ if (fs_info->fat_type == FAT_TYPE_FAT16) {
+ fs_info->fat_sectors = PED_LE16_TO_CPU (bs->fat_length)
+ * fs_info->logical_sector_size;
+ fs_info->serial_number
+ = PED_LE32_TO_CPU (bs->u.fat16.serial_number);
+ fs_info->root_cluster = 0;
+ fs_info->root_dir_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ fs_info->root_dir_sector_count
+ = fs_info->root_dir_entry_count * sizeof (FatDirEntry)
+ / (512 * fs_info->logical_sector_size);
+ fs_info->cluster_offset
+ = fs_info->root_dir_offset
+ + fs_info->root_dir_sector_count;
+ }
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
+ * fs_info->logical_sector_size;
+ fs_info->serial_number
+ = PED_LE32_TO_CPU (bs->u.fat32.serial_number);
+ fs_info->info_sector_offset
+ = PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.info_sector)
+ * fs_info->logical_sector_size;
+ fs_info->boot_sector_backup_offset
+ = PED_LE16_TO_CPU (fs_info->boot_sector->u.fat32.backup_sector)
+ * fs_info->logical_sector_size;
+ fs_info->root_cluster
+ = PED_LE32_TO_CPU (bs->u.fat32.root_dir_cluster);
+ fs_info->root_dir_offset = 0;
+ fs_info->root_dir_sector_count = 0;
+ fs_info->cluster_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ }
+
+ fs_info->cluster_count
+ = (fs_info->sector_count - fs_info->cluster_offset)
+ / fs_info->cluster_sectors;
+
+ fat_entry_size = fat_table_entry_size (fs_info->fat_type);
+ if (fs_info->cluster_count + 2
+ > fs_info->fat_sectors * 512 / fat_entry_size)
+ fs_info->cluster_count
+ = fs_info->fat_sectors * 512 / fat_entry_size - 2;
+
+ fs_info->dir_entries_per_cluster
+ = fs_info->cluster_size / sizeof (FatDirEntry);
+ return 1;
+}
+
+#ifndef DISCOVER_ONLY
+int
+fat_boot_sector_set_boot_code (FatBootSector** bsp, const PedFileSystem* fs)
+{
+ PED_ASSERT (bsp != NULL);
+ *bsp = ped_malloc (fs->geom->dev->sector_size);
+ FatBootSector *bs = *bsp;
+ PED_ASSERT (bs != NULL);
+
+ memset (bs, 0, 512);
+ memcpy (bs->boot_jump, FAT_BOOT_JUMP, 3);
+ PED_ASSERT (sizeof(FAT_BOOT_CODE) < sizeof(bs->u.fat32.boot_code));
+ strcpy (bs->u.fat32.boot_code, FAT_BOOT_CODE);
+ return 1;
+}
+
+int
+fat_boot_sector_generate (FatBootSector** bsp, const PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (bsp != NULL);
+ FatBootSector *bs = *bsp;
+ PED_ASSERT (bs != NULL);
+
+ memcpy (bs->system_id, "MSWIN4.1", 8);
+ bs->sector_size = PED_CPU_TO_LE16 (fs_info->logical_sector_size * 512);
+ bs->cluster_size = fs_info->cluster_sectors
+ / fs_info->logical_sector_size;
+ bs->reserved = PED_CPU_TO_LE16 (fs_info->fat_offset
+ / fs_info->logical_sector_size);
+ bs->fats = fs_info->fat_table_count;
+
+ bs->dir_entries = (fs_info->fat_type == FAT_TYPE_FAT16)
+ ? PED_CPU_TO_LE16 (fs_info->root_dir_entry_count)
+ : 0;
+
+ if (fs_info->sector_count / fs_info->logical_sector_size > 0xffff
+ || fs_info->fat_type == FAT_TYPE_FAT32) {
+ bs->sectors = 0;
+ bs->sector_count = PED_CPU_TO_LE32 (fs_info->sector_count
+ / fs_info->logical_sector_size);
+ } else {
+ bs->sectors = PED_CPU_TO_LE16 (fs_info->sector_count
+ / fs_info->logical_sector_size);
+ bs->sector_count = 0;
+ }
+
+ bs->media = 0xf8;
+
+ bs->secs_track = PED_CPU_TO_LE16 (fs_info->sectors_per_track);
+ bs->heads = PED_CPU_TO_LE16 (fs_info->heads);
+ bs->hidden = PED_CPU_TO_LE32 (fs->geom->start);
+
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ bs->fat_length = 0;
+ bs->u.fat32.fat_length = PED_CPU_TO_LE32 (fs_info->fat_sectors
+ / fs_info->logical_sector_size);
+ bs->u.fat32.flags = 0; /* FIXME: what the hell are these? */
+ bs->u.fat32.version = 0; /* must be 0, for Win98 bootstrap */
+ bs->u.fat32.root_dir_cluster
+ = PED_CPU_TO_LE32 (fs_info->root_cluster);
+ bs->u.fat32.info_sector
+ = PED_CPU_TO_LE16 (fs_info->info_sector_offset
+ / fs_info->logical_sector_size);
+ bs->u.fat32.backup_sector
+ = PED_CPU_TO_LE16 (fs_info->boot_sector_backup_offset
+ / fs_info->logical_sector_size);
+
+ bs->u.fat32.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
+
+ memset (bs->u.fat32.empty_1, 0, 12);
+
+ bs->u.fat32.ext_signature = 0x29;
+ bs->u.fat32.serial_number
+ = PED_CPU_TO_LE32 (fs_info->serial_number);
+ memcpy (bs->u.fat32.volume_name, "NO NAME ", 11);
+ memcpy (bs->u.fat32.fat_name, "FAT32 ", 8);
+ } else {
+ bs->fat_length
+ = PED_CPU_TO_LE16 (fs_info->fat_sectors
+ / fs_info->logical_sector_size);
+
+ bs->u.fat16.drive_num = 0x80; /* _ALWAYS_ 0x80. silly DOS */
+
+ bs->u.fat16.ext_signature = 0x29;
+ bs->u.fat16.serial_number
+ = PED_CPU_TO_LE32 (fs_info->serial_number);
+ memcpy (bs->u.fat16.volume_name, "NO NAME ", 11);
+ memcpy (bs->u.fat16.fat_name, "FAT16 ", 8);
+ }
+
+ bs->boot_sign = PED_CPU_TO_LE16 (0xaa55);
+
+ return 1;
+}
+
+int
+fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (bs != NULL);
+
+ if (!ped_geometry_write (fs->geom, bs, 0, 1))
+ return 0;
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ if (!ped_geometry_write (fs->geom, bs,
+ fs_info->boot_sector_backup_offset, 1))
+ return 0;
+ }
+ return ped_geometry_sync (fs->geom);
+}
+
+int
+fat_info_sector_read (FatInfoSector** isp, const PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int status;
+
+ PED_ASSERT (isp != NULL);
+
+ if (!ped_geometry_read_alloc (fs->geom, (void **)isp, fs_info->info_sector_offset, 1))
+ return 0;
+ FatInfoSector *is = *isp;
+ if (PED_LE32_TO_CPU (is->signature_2) != FAT32_INFO_MAGIC2) {
+ status = ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The information sector has the wrong "
+ "signature (%x). Select cancel for now, "
+ "and send in a bug report. If you're "
+ "desperate, it's probably safe to ignore."),
+ PED_LE32_TO_CPU (is->signature_2));
+ if (status == PED_EXCEPTION_CANCEL) return 0;
+ }
+ return 1;
+}
+
+int
+fat_info_sector_generate (FatInfoSector** isp, const PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (isp != NULL);
+ *isp = ped_malloc (fs->geom->dev->sector_size);
+ FatInfoSector *is = *isp;
+
+ fat_table_count_stats (fs_info->fat);
+
+ memset (is, 0, 512);
+
+ is->signature_1 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC1);
+ is->signature_2 = PED_CPU_TO_LE32 (FAT32_INFO_MAGIC2);
+ is->free_clusters = PED_CPU_TO_LE32 (fs_info->fat->free_cluster_count);
+ is->next_cluster = PED_CPU_TO_LE32 (fs_info->fat->last_alloc);
+ is->signature_3 = PED_CPU_TO_LE16 (FAT32_INFO_MAGIC3);
+
+ return 1;
+}
+
+int
+fat_info_sector_write (const FatInfoSector* is, PedFileSystem *fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (is != NULL);
+
+ if (!ped_geometry_write (fs->geom, is, fs_info->info_sector_offset, 1))
+ return 0;
+ return ped_geometry_sync (fs->geom);
+}
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/bootsector.h b/libparted/fs/r/fat/bootsector.h
new file mode 100644
index 0000000..699d6cf
--- /dev/null
+++ b/libparted/fs/r/fat/bootsector.h
@@ -0,0 +1,130 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef PED_FAT_BOOTSECTOR_H
+#define PED_FAT_BOOTSECTOR_H
+
+typedef struct _FatBootSector FatBootSector;
+typedef struct _FatInfoSector FatInfoSector;
+
+#include "fat.h"
+
+#define FAT32_INFO_MAGIC1 0x41615252
+#define FAT32_INFO_MAGIC2 0x61417272
+#define FAT32_INFO_MAGIC3 0xaa55
+
+/* stolen from mkdosfs, by Dave Hudson */
+
+#define FAT_BOOT_MESSAGE \
+"This partition does not have an operating system loader installed on it.\n\r"\
+"Press a key to reboot..."
+
+#define FAT_BOOT_JUMP "\xeb\x58\x90" /* jmp +5a */
+
+#define FAT_BOOT_CODE "\x0e" /* push cs */ \
+ "\x1f" /* pop ds */ \
+ "\xbe\x74\x7e" /* mov si, offset message */ \
+ /* write_msg_loop: */ \
+ "\xac" /* lodsb */ \
+ "\x22\xc0" /* and al, al */ \
+ "\x74\x06" /* jz done (+8) */ \
+ "\xb4\x0e" /* mov ah, 0x0e */ \
+ "\xcd\x10" /* int 0x10 */ \
+ "\xeb\xf5" /* jmp write_msg_loop */ \
+ /* done: */ \
+ "\xb4\x00" /* mov ah, 0x00 */ \
+ "\xcd\x16" /* int 0x16 */ \
+ "\xb4\x00" /* mov ah, 0x00 */ \
+ "\xcd\x19" /* int 0x19 */ \
+ "\xeb\xfe" /* jmp +0 - in case int 0x19 */ \
+ /* doesn't work */ \
+ /* message: */ \
+ FAT_BOOT_MESSAGE
+
+struct __attribute__ ((packed)) _FatBootSector {
+ uint8_t boot_jump[3]; /* 00: Boot strap short or near jump */
+ uint8_t system_id[8]; /* 03: system name */
+ uint16_t sector_size; /* 0b: bytes per logical sector */
+ uint8_t cluster_size; /* 0d: sectors/cluster */
+ uint16_t reserved; /* 0e: reserved sectors */
+ uint8_t fats; /* 10: number of FATs */
+ uint16_t dir_entries; /* 11: number of root directory entries */
+ uint16_t sectors; /* 13: if 0, total_sect supersedes */
+ uint8_t media; /* 15: media code */
+ uint16_t fat_length; /* 16: sectors/FAT for FAT12/16 */
+ uint16_t secs_track; /* 18: sectors per track */
+ uint16_t heads; /* 1a: number of heads */
+ uint32_t hidden; /* 1c: hidden sectors (partition start) */
+ uint32_t sector_count; /* 20: no. of sectors (if sectors == 0) */
+
+ union __attribute__ ((packed)) {
+ /* FAT16 fields */
+ struct __attribute__ ((packed)) {
+ uint8_t drive_num; /* 24: */
+ uint8_t empty_1; /* 25: */
+ uint8_t ext_signature; /* 26: always 0x29 */
+ uint32_t serial_number; /* 27: */
+ uint8_t volume_name [11]; /* 2b: */
+ uint8_t fat_name [8]; /* 36: */
+ uint8_t boot_code[448]; /* 3f: Boot code (or message) */
+ } fat16;
+ /* FAT32 fields */
+ struct __attribute__ ((packed)) {
+ uint32_t fat_length; /* 24: size of FAT in sectors */
+ uint16_t flags; /* 28: bit8: fat mirroring, low4: active fat */
+ uint16_t version; /* 2a: minor * 256 + major */
+ uint32_t root_dir_cluster; /* 2c: */
+ uint16_t info_sector; /* 30: */
+ uint16_t backup_sector; /* 32: */
+ uint8_t empty_1 [12]; /* 34: */
+ uint16_t drive_num; /* 40: */
+ uint8_t ext_signature; /* 42: always 0x29 */
+ uint32_t serial_number; /* 43: */
+ uint8_t volume_name [11]; /* 47: */
+ uint8_t fat_name [8]; /* 52: */
+ uint8_t boot_code[420]; /* 5a: Boot code (or message) */
+ } fat32;
+ } u;
+
+ uint16_t boot_sign; /* 1fe: always 0xAA55 */
+};
+
+struct __attribute__ ((packed)) _FatInfoSector {
+ uint32_t signature_1; /* should be 0x41615252 */
+ uint8_t unused [480];
+ uint32_t signature_2; /* should be 0x61417272 */
+ uint32_t free_clusters;
+ uint32_t next_cluster; /* most recently allocated cluster */
+ uint8_t unused2 [0xe];
+ uint16_t signature_3; /* should be 0xaa55 */
+};
+
+int fat_boot_sector_read (FatBootSector** bs, const PedGeometry* geom);
+FatType fat_boot_sector_probe_type (const FatBootSector* bs,
+ const PedGeometry* geom);
+int fat_boot_sector_analyse (FatBootSector* bs, PedFileSystem* fs);
+int fat_boot_sector_set_boot_code (FatBootSector** bs, const PedFileSystem* fs);
+int fat_boot_sector_generate (FatBootSector** bs, const PedFileSystem* fs);
+int fat_boot_sector_write (const FatBootSector* bs, PedFileSystem* fs);
+
+int fat_info_sector_read (FatInfoSector** is, const PedFileSystem* fs);
+int fat_info_sector_generate (FatInfoSector** is, const PedFileSystem* fs);
+int fat_info_sector_write (const FatInfoSector* is, PedFileSystem* fs);
+
+#endif /* PED_FAT_BOOTSECTOR_H */
diff --git a/libparted/fs/r/fat/calc.c b/libparted/fs/r/fat/calc.c
new file mode 100644
index 0000000..4ba1030
--- /dev/null
+++ b/libparted/fs/r/fat/calc.c
@@ -0,0 +1,433 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 2002, 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 <config.h>
+#include "fat.h"
+
+#ifndef DISCOVER_ONLY
+
+/* returns the minimum size of clusters for a given file system type */
+PedSector _GL_ATTRIBUTE_CONST
+fat_min_cluster_size (FatType fat_type) {
+ switch (fat_type) {
+ case FAT_TYPE_FAT12: return 1;
+ case FAT_TYPE_FAT16: return 1024/512;
+ case FAT_TYPE_FAT32: return 4096/512;
+ }
+ return 0;
+}
+
+static PedSector _GL_ATTRIBUTE_CONST
+_smallest_power2_over (PedSector ceiling)
+{
+ PedSector result = 1;
+
+ while (result < ceiling)
+ result *= 2;
+
+ return result;
+}
+
+/* returns the minimum size of clusters for a given file system type */
+PedSector _GL_ATTRIBUTE_CONST
+fat_recommend_min_cluster_size (FatType fat_type, PedSector size) {
+ switch (fat_type) {
+ case FAT_TYPE_FAT12: return 1;
+ case FAT_TYPE_FAT16: return fat_min_cluster_size(fat_type);
+ case FAT_TYPE_FAT32:
+ return PED_MAX(_smallest_power2_over(size
+ / MAX_FAT32_CLUSTERS),
+ fat_min_cluster_size (fat_type));
+ }
+ return 0;
+}
+
+/* returns the maxmimum size of clusters for a given file system type */
+PedSector _GL_ATTRIBUTE_CONST
+fat_max_cluster_size (FatType fat_type) {
+ switch (fat_type) {
+ case FAT_TYPE_FAT12: return 1; /* dunno... who cares? */
+ case FAT_TYPE_FAT16: return 65536/512;
+ case FAT_TYPE_FAT32: return 65536/512;
+ }
+ return 0;
+}
+
+/* returns the minimum number of clusters for a given file system type */
+FatCluster _GL_ATTRIBUTE_CONST
+fat_min_cluster_count (FatType fat_type) {
+ switch (fat_type) {
+ case FAT_TYPE_FAT12:
+ case FAT_TYPE_FAT16:
+ return fat_max_cluster_count (fat_type) / 2;
+
+ case FAT_TYPE_FAT32: return 0xfff0;
+ }
+ return 0;
+}
+
+/* returns the maximum number of clusters for a given file system type */
+FatCluster _GL_ATTRIBUTE_CONST
+fat_max_cluster_count (FatType fat_type) {
+ switch (fat_type) {
+ case FAT_TYPE_FAT12: return 0xff0;
+ case FAT_TYPE_FAT16: return 0xfff0;
+ case FAT_TYPE_FAT32: return 0x0ffffff0;
+ }
+ return 0;
+}
+
+/* what is this supposed to be? What drugs are M$ on? (Can I have some? :-) */
+PedSector _GL_ATTRIBUTE_CONST
+fat_min_reserved_sector_count (FatType fat_type)
+{
+ return (fat_type == FAT_TYPE_FAT32) ? 32 : 1;
+}
+
+int
+fat_check_resize_geometry (const PedFileSystem* fs,
+ const PedGeometry* geom,
+ PedSector new_cluster_sectors,
+ FatCluster new_cluster_count)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector free_space;
+ PedSector min_free_space;
+ PedSector total_space;
+ PedSector new_total_space;
+ PedSector dir_space;
+
+ PED_ASSERT (geom != NULL);
+
+ dir_space = fs_info->total_dir_clusters * fs_info->cluster_sectors;
+ free_space = fs_info->fat->free_cluster_count
+ * fs_info->cluster_sectors;
+ total_space = fs_info->fat->cluster_count * fs_info->cluster_sectors;
+ new_total_space = new_cluster_count * new_cluster_sectors;
+ min_free_space = total_space - new_total_space + dir_space;
+
+ PED_ASSERT (new_cluster_count
+ <= fat_max_cluster_count (FAT_TYPE_FAT32));
+
+ if (free_space < min_free_space) {
+ char* needed = ped_unit_format (geom->dev, min_free_space);
+ char* have = ped_unit_format (geom->dev, free_space);
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("You need %s of free disk space to shrink this "
+ "partition to this size. Currently, only %s is "
+ "free."),
+ needed, have);
+ free (needed);
+ free (have);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/******************************************************************************/
+
+/* DO NOT EDIT THIS ALGORITHM!
+ * As far as I can tell, this is the same algorithm used by Microsoft to
+ * calculate the size of the file allocaion tables, and the number of clusters.
+ * I have not verified this by dissassembling Microsoft code - I came to this
+ * conclusion by empirical analysis (i.e. trial and error - this was HORRIBLE).
+ *
+ * If you think this code makes no sense, then you are right. I will restrain
+ * the urge to inflict serious bodily harm on Microsoft people.
+ */
+
+static int
+entries_per_sector (FatType fat_type)
+{
+ switch (fat_type) {
+ case FAT_TYPE_FAT12:
+ return 512 * 3 / 2;
+ case FAT_TYPE_FAT16:
+ return 512 / 2;
+ case FAT_TYPE_FAT32:
+ return 512 / 4;
+ }
+ return 0;
+}
+
+static int
+calc_sizes (PedSector size, PedSector align, FatType fat_type,
+ PedSector root_dir_sectors, PedSector cluster_sectors,
+ FatCluster* out_cluster_count, PedSector* out_fat_size)
+{
+ PedSector data_fat_space; /* space available to clusters + FAT */
+ PedSector fat_space; /* space taken by each FAT */
+ PedSector cluster_space; /* space taken by clusters */
+ FatCluster cluster_count;
+ int i;
+
+ PED_ASSERT (out_cluster_count != NULL);
+ PED_ASSERT (out_fat_size != NULL);
+
+ data_fat_space = size - fat_min_reserved_sector_count (fat_type)
+ - align;
+ if (fat_type == FAT_TYPE_FAT16)
+ data_fat_space -= root_dir_sectors;
+
+ fat_space = 0;
+ for (i = 0; i < 2; i++) {
+ if (fat_type == FAT_TYPE_FAT32)
+ cluster_space = data_fat_space - fat_space;
+ else
+ cluster_space = data_fat_space - 2 * fat_space;
+
+ cluster_count = cluster_space / cluster_sectors;
+ fat_space = ped_div_round_up (cluster_count + 2,
+ entries_per_sector (fat_type));
+ }
+
+ cluster_space = data_fat_space - 2 * fat_space;
+ cluster_count = cluster_space / cluster_sectors;
+
+ /* looks like this should be part of the loop condition?
+ * Need to build the Big Table TM again to check
+ */
+ if (fat_space < ped_div_round_up (cluster_count + 2,
+ entries_per_sector (fat_type))) {
+ fat_space = ped_div_round_up (cluster_count + 2,
+ entries_per_sector (fat_type));
+ }
+
+ if (cluster_count > fat_max_cluster_count (fat_type)
+ || cluster_count < fat_min_cluster_count (fat_type))
+ return 0;
+
+ *out_cluster_count = cluster_count;
+ *out_fat_size = fat_space;
+
+ return 1;
+}
+
+/****************************************************************************/
+
+int
+fat_calc_sizes (PedSector size, PedSector align, FatType fat_type,
+ PedSector root_dir_sectors,
+ PedSector* out_cluster_sectors, FatCluster* out_cluster_count,
+ PedSector* out_fat_size)
+{
+ PedSector cluster_sectors;
+
+ PED_ASSERT (out_cluster_sectors != NULL);
+ PED_ASSERT (out_cluster_count != NULL);
+ PED_ASSERT (out_fat_size != NULL);
+
+ for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
+ cluster_sectors <= fat_max_cluster_size (fat_type);
+ cluster_sectors *= 2) {
+ if (calc_sizes (size, align, fat_type, root_dir_sectors,
+ cluster_sectors,
+ out_cluster_count, out_fat_size)) {
+ *out_cluster_sectors = cluster_sectors;
+ return 1;
+ }
+ }
+
+ for (cluster_sectors = fat_recommend_min_cluster_size (fat_type, size);
+ cluster_sectors >= fat_min_cluster_size (fat_type);
+ cluster_sectors /= 2) {
+ if (calc_sizes (size, align, fat_type, root_dir_sectors,
+ cluster_sectors,
+ out_cluster_count, out_fat_size)) {
+ *out_cluster_sectors = cluster_sectors;
+ return 1;
+ }
+ }
+
+ /* only make the cluster size really small (<4k) if a bigger one is
+ * isn't possible. Windows never makes FS's like this, but it
+ * seems to work... (do more tests!)
+ */
+ for (cluster_sectors = 4; cluster_sectors > 0; cluster_sectors /= 2) {
+ if (calc_sizes (size, align, fat_type, root_dir_sectors,
+ cluster_sectors,
+ out_cluster_count, out_fat_size)) {
+ *out_cluster_sectors = cluster_sectors;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/* Same as fat_calc_sizes, except it only attempts to match a particular
+ * cluster size. This is useful, because the FAT resizer can only shrink the
+ * cluster size.
+ */
+int
+fat_calc_resize_sizes (
+ const PedGeometry* geom,
+ PedSector align,
+ FatType fat_type,
+ PedSector root_dir_sectors,
+ PedSector cluster_sectors,
+ PedSector* out_cluster_sectors,
+ FatCluster* out_cluster_count,
+ PedSector* out_fat_size)
+{
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (out_cluster_sectors != NULL);
+ PED_ASSERT (out_cluster_count != NULL);
+ PED_ASSERT (out_fat_size != NULL);
+
+/* libparted can only reduce the cluster size at this point */
+ for (*out_cluster_sectors = cluster_sectors;
+ *out_cluster_sectors >= fat_min_cluster_size (fat_type);
+ *out_cluster_sectors /= 2) {
+ if (calc_sizes (geom->length, align, fat_type, root_dir_sectors,
+ *out_cluster_sectors,
+ out_cluster_count, out_fat_size))
+ return 1;
+ }
+ return 0;
+}
+
+/* Calculates the number of sectors needed to be added to cluster_offset,
+ to make the cluster on the new file system match up with the ones
+ on the old file system.
+ However, some space is reserved by fat_calc_resize_sizes() and
+ friends, to allow room for this space. If too much of this space is left
+ over, everyone will complain, so we have to be greedy, and use it all up...
+ */
+PedSector _GL_ATTRIBUTE_PURE
+fat_calc_align_sectors (const PedFileSystem* new_fs,
+ const PedFileSystem* old_fs)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
+ PedSector raw_old_meta_data_end;
+ PedSector new_meta_data_size;
+ PedSector min_new_meta_data_end;
+ PedSector new_data_size;
+ PedSector new_clusters_size;
+ PedSector align;
+
+ new_meta_data_size
+ = fat_min_reserved_sector_count (new_fs_info->fat_type)
+ + new_fs_info->fat_sectors * 2;
+
+ if (new_fs_info->fat_type == FAT_TYPE_FAT16)
+ new_meta_data_size += new_fs_info->root_dir_sector_count;
+
+ raw_old_meta_data_end = old_fs->geom->start
+ + old_fs_info->cluster_offset;
+
+ min_new_meta_data_end = new_fs->geom->start + new_meta_data_size;
+
+ if (raw_old_meta_data_end > min_new_meta_data_end)
+ align = (raw_old_meta_data_end - min_new_meta_data_end)
+ % new_fs_info->cluster_sectors;
+ else
+ align = (new_fs_info->cluster_sectors
+ - ( (min_new_meta_data_end - raw_old_meta_data_end)
+ % new_fs_info->cluster_sectors ))
+ % new_fs_info->cluster_sectors;
+
+ new_data_size = new_fs->geom->length - new_meta_data_size;
+ new_clusters_size = new_fs_info->cluster_count
+ * new_fs_info->cluster_sectors;
+
+ while (new_clusters_size + align + new_fs_info->cluster_sectors
+ <= new_data_size)
+ align += new_fs_info->cluster_sectors;
+
+ return align;
+}
+
+int _GL_ATTRIBUTE_PURE
+fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ return sector >= fs_info->cluster_offset
+ && sector < fs_info->cluster_offset
+ + fs_info->cluster_sectors * fs_info->cluster_count;
+}
+
+FatFragment _GL_ATTRIBUTE_PURE
+fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
+
+ return (cluster - 2) * fs_info->cluster_frags;
+}
+
+FatCluster _GL_ATTRIBUTE_PURE
+fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
+
+ return frag / fs_info->cluster_frags + 2;
+}
+
+PedSector _GL_ATTRIBUTE_PURE
+fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
+
+ return frag * fs_info->frag_sectors + fs_info->cluster_offset;
+}
+
+FatFragment _GL_ATTRIBUTE_PURE
+fat_sector_to_frag (const PedFileSystem* fs, PedSector sector)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (sector >= fs_info->cluster_offset);
+
+ return (sector - fs_info->cluster_offset) / fs_info->frag_sectors;
+}
+
+PedSector _GL_ATTRIBUTE_PURE
+fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
+
+ return (cluster - 2) * fs_info->cluster_sectors
+ + fs_info->cluster_offset;
+}
+
+FatCluster _GL_ATTRIBUTE_PURE
+fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (sector >= fs_info->cluster_offset);
+
+ return (sector - fs_info->cluster_offset) / fs_info->cluster_sectors
+ + 2;
+}
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/calc.h b/libparted/fs/r/fat/calc.h
new file mode 100644
index 0000000..d4884c1
--- /dev/null
+++ b/libparted/fs/r/fat/calc.h
@@ -0,0 +1,77 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef PED_FAT_CALC_H
+#define PED_FAT_CALC_H
+
+extern PedSector fat_min_cluster_size (FatType fat_type);
+extern PedSector fat_max_cluster_size (FatType fat_type);
+extern FatCluster fat_min_cluster_count (FatType fat_type);
+extern FatCluster fat_max_cluster_count (FatType fat_type);
+
+extern PedSector fat_min_reserved_sector_count (FatType fat_type);
+
+extern int fat_check_resize_geometry (const PedFileSystem* fs,
+ const PedGeometry* geom,
+ PedSector new_cluster_sectors,
+ FatCluster new_cluster_count);
+
+extern int fat_calc_sizes (PedSector size,
+ PedSector align,
+ FatType fat_type,
+ PedSector root_dir_sectors,
+ PedSector* out_cluster_sectors,
+ FatCluster* out_cluster_count,
+ PedSector* out_fat_size);
+
+extern int fat_calc_resize_sizes (const PedGeometry* geom,
+ PedSector align,
+ FatType fat_type,
+ PedSector root_dir_sectors,
+ PedSector cluster_sectors,
+ PedSector* out_cluster_sectors,
+ FatCluster* out_cluster_count,
+ PedSector* out_fat_size);
+
+extern PedSector
+fat_calc_align_sectors (const PedFileSystem* new_fs,
+ const PedFileSystem* old_fs);
+
+extern int
+fat_is_sector_in_clusters (const PedFileSystem* fs, PedSector sector);
+
+extern FatFragment
+fat_cluster_to_frag (const PedFileSystem* fs, FatCluster cluster);
+
+extern FatCluster
+fat_frag_to_cluster (const PedFileSystem* fs, FatFragment frag);
+
+extern PedSector
+fat_frag_to_sector (const PedFileSystem* fs, FatFragment frag);
+
+extern FatFragment
+fat_sector_to_frag (const PedFileSystem* fs, PedSector sector);
+
+extern PedSector
+fat_cluster_to_sector (const PedFileSystem* fs, FatCluster cluster);
+
+extern FatCluster
+fat_sector_to_cluster (const PedFileSystem* fs, PedSector sector);
+
+#endif /* PED_FAT_CALC_H */
diff --git a/libparted/fs/r/fat/clstdup.c b/libparted/fs/r/fat/clstdup.c
new file mode 100644
index 0000000..6a3054f
--- /dev/null
+++ b/libparted/fs/r/fat/clstdup.c
@@ -0,0 +1,423 @@
+/*
+ libparted
+ Copyright (C) 1998-2001, 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 <config.h>
+#include <string.h>
+
+#include "fat.h"
+
+#ifndef DISCOVER_ONLY
+
+static int
+needs_duplicating (const FatOpContext* ctx, FatFragment frag)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatCluster cluster = fat_frag_to_cluster (ctx->old_fs, frag);
+ FatClusterFlag flag;
+
+ PED_ASSERT (cluster >= 2 && cluster < old_fs_info->cluster_count + 2);
+
+ flag = fat_get_fragment_flag (ctx->old_fs, frag);
+ switch (flag) {
+ case FAT_FLAG_FREE:
+ return 0;
+
+ case FAT_FLAG_DIRECTORY:
+ return 1;
+
+ case FAT_FLAG_FILE:
+ return fat_op_context_map_static_fragment (ctx, frag) == -1;
+
+ case FAT_FLAG_BAD:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int
+search_next_fragment (FatOpContext* ctx)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
+
+ for (; ctx->buffer_offset < fs_info->frag_count; ctx->buffer_offset++) {
+ if (needs_duplicating (ctx, ctx->buffer_offset))
+ return 1;
+ }
+ return 0; /* all done! */
+}
+
+static int
+read_marked_fragments (FatOpContext* ctx, FatFragment length)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
+ int status;
+ FatFragment i;
+
+ ped_exception_fetch_all ();
+ status = fat_read_fragments (ctx->old_fs, fs_info->buffer,
+ ctx->buffer_offset, length);
+ ped_exception_leave_all ();
+ if (status)
+ return 1;
+
+ ped_exception_catch ();
+
+/* something bad happened, so read fragments one by one. (The error may
+ have occurred on an unused fragment: who cares) */
+ for (i = 0; i < length; i++) {
+ if (ctx->buffer_map [i]) {
+ if (!fat_read_fragment (ctx->old_fs,
+ fs_info->buffer + i * fs_info->frag_size,
+ ctx->buffer_offset + i))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+fetch_fragments (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatFragment fetch_length = 0;
+ FatFragment frag;
+
+ for (frag = 0; frag < ctx->buffer_frags; frag++)
+ ctx->buffer_map [frag] = -1;
+
+ for (frag = 0;
+ frag < ctx->buffer_frags
+ && ctx->buffer_offset + frag < old_fs_info->frag_count;
+ frag++) {
+ if (needs_duplicating (ctx, ctx->buffer_offset + frag)) {
+ ctx->buffer_map [frag] = 1;
+ fetch_length = frag + 1;
+ }
+ }
+
+ if (!read_marked_fragments (ctx, fetch_length))
+ return 0;
+
+ return 1;
+}
+
+/*****************************************************************************
+ * here starts the write code. All assumes that ctx->buffer_map [first] and
+ * ctx->buffer_map [last] are occupied by fragments that need to be duplicated.
+ *****************************************************************************/
+
+/* finds the first fragment that is not going to get overwritten (that needs to
+ get read in) */
+static FatFragment _GL_ATTRIBUTE_PURE
+get_first_underlay (const FatOpContext* ctx, int first, int last)
+{
+ int old;
+ FatFragment new;
+
+ PED_ASSERT (first <= last);
+
+ new = ctx->buffer_map [first];
+ for (old = first + 1; old <= last; old++) {
+ if (ctx->buffer_map [old] == -1)
+ continue;
+ new++;
+ if (ctx->buffer_map [old] != new)
+ return new;
+ }
+ return -1;
+}
+
+/* finds the last fragment that is not going to get overwritten (that needs to
+ get read in) */
+static FatFragment _GL_ATTRIBUTE_PURE
+get_last_underlay (const FatOpContext* ctx, int first, int last)
+{
+ int old;
+ FatFragment new;
+
+ PED_ASSERT (first <= last);
+
+ new = ctx->buffer_map [last];
+ for (old = last - 1; old >= first; old--) {
+ if (ctx->buffer_map [old] == -1)
+ continue;
+ new--;
+ if (ctx->buffer_map [old] != new)
+ return new;
+ }
+ return -1;
+}
+
+/* "underlay" refers to the "static" fragments, that remain unchanged.
+ * when writing large chunks at a time, we don't want to clobber these,
+ * so we read them in, and write them back again. MUCH quicker that way.
+ */
+static int
+quick_group_write_read_underlay (FatOpContext* ctx, int first, int last)
+{
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatFragment first_underlay;
+ FatFragment last_underlay;
+ FatFragment underlay_length;
+
+ PED_ASSERT (first <= last);
+
+ first_underlay = get_first_underlay (ctx, first, last);
+ if (first_underlay == -1)
+ return 1;
+ last_underlay = get_last_underlay (ctx, first, last);
+
+ PED_ASSERT (first_underlay <= last_underlay);
+
+ underlay_length = last_underlay - first_underlay + 1;
+ if (!fat_read_fragments (ctx->new_fs,
+ new_fs_info->buffer
+ + (first_underlay - ctx->buffer_map [first])
+ * new_fs_info->frag_size,
+ first_underlay,
+ underlay_length))
+ return 0;
+ return 1;
+}
+
+/* quick_group_write() makes no attempt to recover from errors - just
+ * does things fast. If there is an error, slow_group_write() is
+ * called.
+ * Note: we do syncing writes, to make sure there isn't any
+ * error writing out. It's rather difficult recovering from errors
+ * further on.
+ */
+static int
+quick_group_write (FatOpContext* ctx, int first, int last)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ int active_length;
+ int i;
+ int offset;
+
+ PED_ASSERT (first <= last);
+
+ ped_exception_fetch_all ();
+ if (!quick_group_write_read_underlay (ctx, first, last))
+ goto error;
+
+ for (i = first; i <= last; i++) {
+ if (ctx->buffer_map [i] == -1)
+ continue;
+
+ offset = ctx->buffer_map [i] - ctx->buffer_map [first];
+ memcpy (new_fs_info->buffer + offset * new_fs_info->frag_size,
+ old_fs_info->buffer + i * new_fs_info->frag_size,
+ new_fs_info->frag_size);
+ }
+
+ active_length = ctx->buffer_map [last] - ctx->buffer_map [first] + 1;
+ if (!fat_write_sync_fragments (ctx->new_fs, new_fs_info->buffer,
+ ctx->buffer_map [first], active_length))
+ goto error;
+
+ ped_exception_leave_all ();
+ return 1;
+
+error:
+ ped_exception_catch ();
+ ped_exception_leave_all ();
+ return 0;
+}
+
+/* Writes fragments out, one at a time, avoiding errors on redundant writes
+ * on damaged parts of the disk we already know about. If there's an error
+ * on one of the required fragments, it gets marked as bad, and a replacement
+ * is found.
+ */
+static int
+slow_group_write (FatOpContext* ctx, int first, int last)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ int i;
+
+ PED_ASSERT (first <= last);
+
+ for (i = first; i <= last; i++) {
+ if (ctx->buffer_map [i] == -1)
+ continue;
+
+ while (!fat_write_sync_fragment (ctx->new_fs,
+ old_fs_info->buffer + i * old_fs_info->frag_size,
+ ctx->buffer_map [i])) {
+ fat_table_set_bad (new_fs_info->fat,
+ ctx->buffer_map [i]);
+ ctx->buffer_map [i] = fat_table_alloc_cluster
+ (new_fs_info->fat);
+ if (ctx->buffer_map [i] == 0)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+update_remap (FatOpContext* ctx, int first, int last)
+{
+ int i;
+
+ PED_ASSERT (first <= last);
+
+ for (i = first; i <= last; i++) {
+ if (ctx->buffer_map [i] == -1)
+ continue;
+ ctx->remap [ctx->buffer_offset + i] = ctx->buffer_map [i];
+ }
+
+ return 1;
+}
+
+static int
+group_write (FatOpContext* ctx, int first, int last)
+{
+ PED_ASSERT (first <= last);
+
+ if (!quick_group_write (ctx, first, last)) {
+ if (!slow_group_write (ctx, first, last))
+ return 0;
+ }
+ if (!update_remap (ctx, first, last))
+ return 0;
+ return 1;
+}
+
+/* assumes fragment size and new_fs's cluster size are equal */
+static int
+write_fragments (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ int group_start;
+ int group_end = -1; /* shut gcc up! */
+ FatFragment mapped_length;
+ FatFragment i;
+ FatCluster new_cluster;
+
+ PED_ASSERT (ctx->buffer_offset < old_fs_info->frag_count);
+
+ group_start = -1;
+ for (i = 0; i < ctx->buffer_frags; i++) {
+ if (ctx->buffer_map [i] == -1)
+ continue;
+
+ ctx->frags_duped++;
+
+ new_cluster = fat_table_alloc_cluster (new_fs_info->fat);
+ if (!new_cluster)
+ return 0;
+ fat_table_set_eof (new_fs_info->fat, new_cluster);
+ ctx->buffer_map [i] = fat_cluster_to_frag (ctx->new_fs,
+ new_cluster);
+
+ if (group_start == -1)
+ group_start = group_end = i;
+
+ PED_ASSERT (ctx->buffer_map [i]
+ >= ctx->buffer_map [group_start]);
+
+ mapped_length = ctx->buffer_map [i]
+ - ctx->buffer_map [group_start] + 1;
+ if (mapped_length <= ctx->buffer_frags) {
+ group_end = i;
+ } else {
+ /* ran out of room in the buffer, so write this group,
+ * and start a new one...
+ */
+ if (!group_write (ctx, group_start, group_end))
+ return 0;
+ group_start = group_end = i;
+ }
+ }
+
+ PED_ASSERT (group_start != -1);
+
+ if (!group_write (ctx, group_start, group_end))
+ return 0;
+ return 1;
+}
+
+/* default all fragments to unmoved
+ */
+static void
+init_remap (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatFragment i;
+
+ for (i = 0; i < old_fs_info->frag_count; i++)
+ ctx->remap[i] = fat_op_context_map_static_fragment (ctx, i);
+}
+
+static FatFragment
+count_frags_to_dup (FatOpContext* ctx)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatFragment i;
+ FatFragment total;
+
+ total = 0;
+
+ for (i = 0; i < fs_info->frag_count; i++) {
+ if (needs_duplicating (ctx, i))
+ total++;
+ }
+
+ return total;
+}
+
+/* duplicates unreachable file clusters, and all directory clusters
+ */
+int
+fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer)
+{
+ FatFragment total_frags_to_dup;
+
+ init_remap (ctx);
+ total_frags_to_dup = count_frags_to_dup (ctx);
+
+ ped_timer_reset (timer);
+ ped_timer_set_state_name (timer, "moving data");
+
+ ctx->buffer_offset = 0;
+ ctx->frags_duped = 0;
+ while (search_next_fragment (ctx)) {
+ ped_timer_update (
+ timer, 1.0 * ctx->frags_duped / total_frags_to_dup);
+
+ if (!fetch_fragments (ctx))
+ return 0;
+ if (!write_fragments (ctx))
+ return 0;
+ ctx->buffer_offset += ctx->buffer_frags;
+ }
+
+ ped_timer_update (timer, 1.0);
+ return 1;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/clstdup.h b/libparted/fs/r/fat/clstdup.h
new file mode 100644
index 0000000..23e51b4
--- /dev/null
+++ b/libparted/fs/r/fat/clstdup.h
@@ -0,0 +1,28 @@
+/*
+ libparted
+ Copyright (C) 1999, 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/>.
+*/
+
+#ifndef PED_FAT_CLSTDUP_H_INCLUDED
+#define PED_FAT_CLSTDUP_H_INCLUDED
+
+#include "context.h"
+
+/* the big important one :-) */
+extern int fat_duplicate_clusters (FatOpContext* ctx, PedTimer* timer);
+
+#endif /* PED_FAT_CLSTDUP_H_INCLUDED */
diff --git a/libparted/fs/r/fat/context.c b/libparted/fs/r/fat/context.c
new file mode 100644
index 0000000..c782323
--- /dev/null
+++ b/libparted/fs/r/fat/context.c
@@ -0,0 +1,261 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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 <config.h>
+#include <string.h>
+
+#include "fat.h"
+
+#ifndef DISCOVER_ONLY
+
+/* Note: this deals with file system start and end sectors, even if the physical
+ * devices are different (eg for fat_copy()) Perhaps this is a hack, but it
+ * works ;-)
+ */
+static int
+calc_deltas (FatOpContext* ctx)
+{
+ PedFileSystem* old_fs = ctx->old_fs;
+ PedFileSystem* new_fs = ctx->new_fs;
+ FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
+ PedSector old_cluster_ofs;
+ PedSector new_cluster_ofs;
+ PedSector sector_delta;
+
+ old_cluster_ofs = old_fs->geom->start + old_fs_info->cluster_offset;
+ new_cluster_ofs = new_fs->geom->start + new_fs_info->cluster_offset;
+
+ if (new_cluster_ofs > old_cluster_ofs) {
+ ctx->start_move_dir = FAT_DIR_FORWARD;
+ sector_delta = new_cluster_ofs - old_cluster_ofs;
+ } else {
+ ctx->start_move_dir = FAT_DIR_BACKWARD;
+ sector_delta = old_cluster_ofs - new_cluster_ofs;
+ }
+
+ if (sector_delta % new_fs_info->cluster_sectors) {
+ ped_exception_throw (
+ PED_EXCEPTION_BUG, PED_EXCEPTION_CANCEL,
+ _("Cluster start delta = %d, which is not a multiple "
+ "of the cluster size %d."),
+ (int) sector_delta,
+ (int) new_fs_info->cluster_sectors);
+ return 0;
+ }
+
+ ctx->start_move_delta = sector_delta / ctx->frag_sectors;
+
+#ifdef PED_VERBOSE
+ printf ("Start move delta is: %d %s.\n",
+ (int) ctx->start_move_delta,
+ (ctx->start_move_dir == FAT_DIR_FORWARD)?
+ "forwards" : "backwards");
+#endif
+
+ return 1;
+}
+
+FatOpContext*
+fat_op_context_new (PedFileSystem* new_fs, PedFileSystem* old_fs)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (new_fs);
+ FatOpContext* ctx;
+
+ ctx = (FatOpContext*) ped_malloc (sizeof (FatOpContext));
+ if (!ctx)
+ goto error;
+
+ ctx->frag_sectors = PED_MIN (old_fs_info->cluster_sectors,
+ new_fs_info->cluster_sectors);
+ if (!fat_set_frag_sectors (new_fs, ctx->frag_sectors))
+ goto error;
+ if (!fat_set_frag_sectors (old_fs, ctx->frag_sectors))
+ goto error;
+
+ ctx->buffer_frags = old_fs_info->buffer_sectors / ctx->frag_sectors;
+ ctx->buffer_map = (FatFragment*) ped_malloc (sizeof (FatFragment)
+ * ctx->buffer_frags);
+ if (!ctx->buffer_map)
+ goto error_free_ctx;
+
+ ctx->remap = (FatFragment*) ped_malloc (sizeof (FatFragment)
+ * old_fs_info->frag_count);
+ if (!ctx->remap)
+ goto error_free_buffer_map;
+
+ ctx->new_fs = new_fs;
+ ctx->old_fs = old_fs;
+ if (!calc_deltas (ctx))
+ goto error_free_buffer_map;
+
+ return ctx;
+
+error_free_buffer_map:
+ free (ctx->buffer_map);
+error_free_ctx:
+ free (ctx);
+error:
+ return NULL;
+}
+
+void
+fat_op_context_destroy (FatOpContext* ctx)
+{
+ free (ctx->buffer_map);
+ free (ctx->remap);
+ free (ctx);
+}
+
+FatFragment _GL_ATTRIBUTE_PURE
+fat_op_context_map_static_fragment (const FatOpContext* ctx, FatFragment frag)
+{
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatFragment result;
+
+ if (ctx->new_fs->geom->dev != ctx->old_fs->geom->dev)
+ return -1;
+
+ if (ctx->start_move_dir == FAT_DIR_FORWARD) {
+ if (frag < ctx->start_move_delta)
+ return -1;
+ result = frag - ctx->start_move_delta;
+ } else {
+ result = frag + ctx->start_move_delta;
+ }
+
+ if (result >= new_fs_info->frag_count)
+ return -1;
+
+ return result;
+}
+
+FatCluster
+fat_op_context_map_static_cluster (const FatOpContext* ctx, FatCluster clst)
+{
+ FatFragment mapped_frag;
+
+ mapped_frag = fat_op_context_map_static_fragment (ctx,
+ fat_cluster_to_frag (ctx->old_fs, clst));
+ if (mapped_frag != -1)
+ return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
+ else
+ return 0;
+}
+
+FatFragment _GL_ATTRIBUTE_PURE
+fat_op_context_map_fragment (const FatOpContext* ctx, FatFragment frag)
+{
+ return ctx->remap [frag];
+}
+
+FatCluster
+fat_op_context_map_cluster (const FatOpContext* ctx, FatCluster clst)
+{
+ FatFragment mapped_frag;
+
+ mapped_frag = fat_op_context_map_fragment (ctx,
+ fat_cluster_to_frag (ctx->old_fs, clst));
+ if (mapped_frag != -1)
+ return fat_frag_to_cluster (ctx->new_fs, mapped_frag);
+ else
+ return 0;
+}
+
+/* This function sets the initial fat for the new resized file system.
+ This is in *NO WAY* a proper FAT table - all it does is:
+ a) mark bad clusters as bad.
+ b) mark used clusters (that is, clusters from the original FS that are
+ reachable from the resized one). Marks as EOF (i.e. used, end of
+ file chain).
+ c) mark original file system metadata as EOF (i.e. used), to prevent
+ it from being clobbered. This will leave the original file system
+ intact, until the partition table is modified, if the start of
+ the partition is moved.
+
+ The FATs are rebuilt *properly* after cluster relocation. This here is
+ only to mark clusters as used, so when cluster relocation occurs, clusters
+ aren't relocated on top of ones marked in a, b or c.
+*/
+int
+fat_op_context_create_initial_fat (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatCluster clst;
+ FatCluster new_clst;
+ PedSector sect;
+ PedSector new_sect;
+ FatFragment frag;
+ FatFragment new_frag;
+ FatClusterFlag frag_flag;
+
+ new_fs_info->fat = fat_table_new (
+ new_fs_info->fat_type,
+ new_fs_info->fat_sectors * 512
+ / fat_table_entry_size (new_fs_info->fat_type));
+ if (!new_fs_info->fat)
+ return 0;
+
+ if (!fat_table_set_cluster_count (new_fs_info->fat,
+ new_fs_info->cluster_count))
+ return 0;
+
+/* mark bad and used clusters */
+ for (frag = 0; frag < old_fs_info->frag_count; frag++) {
+ frag_flag = fat_get_fragment_flag (ctx->old_fs, frag);
+ if (frag_flag == FAT_FLAG_FREE)
+ continue;
+
+ new_frag = fat_op_context_map_static_fragment (ctx, frag);
+ if (new_frag == -1)
+ continue;
+
+ new_clst = fat_frag_to_cluster (ctx->new_fs, new_frag);
+ PED_ASSERT (new_clst != 0);
+
+ if (frag_flag == FAT_FLAG_BAD) {
+ if (!fat_table_set_bad (new_fs_info->fat, new_clst))
+ return 0;
+ } else {
+ if (!fat_table_set_eof (new_fs_info->fat, new_clst))
+ return 0;
+ }
+ }
+
+/* mark metadata regions that map to clusters on the new FS */
+ for (sect = 0; sect < old_fs_info->cluster_offset; sect++) {
+ new_sect = ped_geometry_map (ctx->new_fs->geom,
+ ctx->old_fs->geom, sect);
+ if (new_sect == -1
+ || !fat_is_sector_in_clusters (ctx->new_fs, new_sect))
+ continue;
+
+ clst = fat_sector_to_cluster (ctx->new_fs, new_sect);
+ PED_ASSERT (clst != 0);
+
+ if (!fat_table_set_eof (new_fs_info->fat, clst))
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/context.h b/libparted/fs/r/fat/context.h
new file mode 100644
index 0000000..9a76a47
--- /dev/null
+++ b/libparted/fs/r/fat/context.h
@@ -0,0 +1,70 @@
+/*
+ libparted
+ Copyright (C) 1999-2000, 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/>.
+*/
+
+#ifndef PED_FAT_CONTEXT_H_INCLUDED
+#define PED_FAT_CONTEXT_H_INCLUDED
+
+#include "count.h"
+
+enum _FatDirection {
+ FAT_DIR_FORWARD,
+ FAT_DIR_BACKWARD
+};
+typedef enum _FatDirection FatDirection;
+
+struct _FatOpContext {
+ PedFileSystem* old_fs;
+ PedFileSystem* new_fs;
+
+ PedSector frag_sectors; /* should equal old_fs and
+ new_fs's frag_sectors */
+
+ FatDirection start_move_dir;
+ FatFragment start_move_delta;
+
+ FatFragment buffer_offset;
+ FatFragment buffer_frags;
+ FatFragment* buffer_map;
+
+ FatFragment frags_duped;
+
+ FatFragment* remap;
+
+ FatCluster new_root_dir [32];
+};
+typedef struct _FatOpContext FatOpContext;
+
+extern FatOpContext* fat_op_context_new (PedFileSystem* new_fs,
+ PedFileSystem* old_fs);
+
+extern void fat_op_context_destroy (FatOpContext* ctx);
+
+extern FatFragment fat_op_context_map_static_fragment (const FatOpContext* ctx,
+ FatFragment frag);
+extern FatCluster fat_op_context_map_static_cluster (const FatOpContext* ctx,
+ FatCluster clst);
+
+extern FatFragment fat_op_context_map_fragment (const FatOpContext* ctx,
+ FatFragment frag);
+extern FatCluster fat_op_context_map_cluster (const FatOpContext* ctx,
+ FatCluster clst);
+
+extern int fat_op_context_create_initial_fat (FatOpContext* ctx);
+
+#endif /* PED_FAT_CONTEXT_H_INCLUDED */
diff --git a/libparted/fs/r/fat/count.c b/libparted/fs/r/fat/count.c
new file mode 100644
index 0000000..e23404b
--- /dev/null
+++ b/libparted/fs/r/fat/count.c
@@ -0,0 +1,319 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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 <config.h>
+#include "fat.h"
+#include "traverse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DISCOVER_ONLY
+
+/*
+ prints out the sequence of clusters for a given file chain, beginning
+ at start_cluster.
+*/
+#ifdef PED_VERBOSE
+static void
+print_chain (PedFileSystem* fs, FatCluster start)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster clst;
+ int this_row;
+
+ this_row = 0;
+ for (clst = start; !fat_table_is_eof (fs_info->fat, clst);
+ clst = fat_table_get (fs_info->fat, clst)) {
+ printf (" %d", (int) clst);
+ if (++this_row == 7) {
+ putchar ('\n');
+ this_row = 0;
+ }
+ }
+ putchar ('\n');
+}
+#endif /* PED_VERBOSE */
+
+static PedSector
+remainder_round_up (PedSector a, PedSector b)
+{
+ PedSector result;
+
+ result = a % b;
+ if (!result)
+ result = b;
+ return result;
+}
+
+/*
+ traverse the FAT for a file/directory, marking each entry's flag
+ to "flag".
+*/
+static int
+flag_traverse_fat (PedFileSystem* fs, const char* chain_name, FatCluster start,
+ FatClusterFlag flag, PedSector size)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster clst;
+ FatCluster prev_clst;
+ int last_cluster_usage;
+ FatCluster chain_length = 0;
+
+ if (fat_table_is_eof (fs_info->fat, start)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Bad directory entry for %s: first cluster is the "
+ "end of file marker."),
+ chain_name)
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+
+ for (prev_clst = clst = start; !fat_table_is_eof (fs_info->fat, clst);
+ prev_clst = clst, clst = fat_table_get (fs_info->fat, clst)) {
+ chain_length++;
+ if (!clst) {
+ ped_exception_throw (PED_EXCEPTION_FATAL,
+ PED_EXCEPTION_CANCEL,
+ _("Bad FAT: unterminated chain for %s. You "
+ "should run dosfsck or scandisk."),
+ chain_name);
+ return 0;
+ }
+
+ if (clst >= fs_info->fat->cluster_count + 2) {
+ ped_exception_throw (PED_EXCEPTION_FATAL,
+ PED_EXCEPTION_CANCEL,
+ _("Bad FAT: cluster %d outside file system "
+ "in chain for %s. You should run dosfsck "
+ "or scandisk."),
+ (int) clst, chain_name);
+ return 0;
+ }
+
+ if (fs_info->cluster_info [clst].flag != FAT_FLAG_FREE ) {
+ ped_exception_throw (PED_EXCEPTION_FATAL,
+ PED_EXCEPTION_CANCEL,
+ _("Bad FAT: cluster %d is cross-linked for "
+ "%s. You should run dosfsck or scandisk."),
+ (int) clst, chain_name);
+ return 0;
+ }
+
+ if (flag == FAT_FLAG_DIRECTORY)
+ fs_info->total_dir_clusters++;
+
+ fs_info->cluster_info [clst].flag = flag;
+ fs_info->cluster_info [clst].units_used = 0; /* 0 == 64 */
+ }
+
+ if (size
+ && chain_length
+ != ped_div_round_up (size, fs_info->cluster_sectors)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("%s is %dk, but it has %d clusters (%dk)."),
+ chain_name,
+ (int) size / 2,
+ (int) chain_length,
+ (int) chain_length * fs_info->cluster_sectors / 2)
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+
+ last_cluster_usage
+ = ped_div_round_up (64 * remainder_round_up (size,
+ fs_info->cluster_sectors),
+ fs_info->cluster_sectors);
+
+ fs_info->cluster_info [prev_clst].units_used = last_cluster_usage;
+
+ return 1;
+}
+
+/*
+ recursively traverses a directory, flagging all clusters in the process.
+ It frees the traverse_info structure before returning.
+*/
+static int
+flag_traverse_dir (FatTraverseInfo* trav_info) {
+ PedFileSystem* fs = trav_info->fs;
+ FatDirEntry* this_entry;
+ FatTraverseInfo* subdir_trav_info;
+ char file_name [4096];
+ char* file_name_start;
+ FatCluster first_cluster;
+ PedSector size;
+
+ PED_ASSERT (trav_info != NULL);
+
+ strcpy (file_name, trav_info->dir_name);
+ file_name_start = file_name + strlen (file_name);
+
+ while ( (this_entry = fat_traverse_next_dir_entry (trav_info)) ) {
+ if (fat_dir_entry_is_null_term (this_entry))
+ break;
+ if (!fat_dir_entry_has_first_cluster (this_entry, fs))
+ continue;
+ if (this_entry->name [0] == '.')
+ continue; /* skip . and .. entries */
+
+ fat_dir_entry_get_name (this_entry, file_name_start);
+ first_cluster = fat_dir_entry_get_first_cluster(this_entry, fs);
+ size = ped_div_round_up (fat_dir_entry_get_length (this_entry),
+ 512);
+
+#ifdef PED_VERBOSE
+ printf ("%s: ", file_name);
+ print_chain (fs, first_cluster);
+#endif
+
+ if (fat_dir_entry_is_directory (this_entry)) {
+ if (!flag_traverse_fat (fs, file_name, first_cluster,
+ FAT_FLAG_DIRECTORY, size))
+ return 0;
+
+ subdir_trav_info = fat_traverse_directory (trav_info,
+ this_entry);
+ if (!subdir_trav_info)
+ return 0;
+ if (!flag_traverse_dir (subdir_trav_info))
+ return 0;
+ } else if (fat_dir_entry_is_file (this_entry)) {
+ if (!flag_traverse_fat (fs, file_name, first_cluster,
+ FAT_FLAG_FILE, size))
+ return 0;
+ }
+ }
+
+ fat_traverse_complete (trav_info);
+ return 1;
+}
+
+static void
+_mark_bad_clusters (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster cluster;
+
+ for (cluster = 2; cluster < fs_info->cluster_count + 2; cluster++) {
+ if (fat_table_is_bad (fs_info->fat, cluster))
+ fs_info->cluster_info [cluster].flag = FAT_FLAG_BAD;
+ }
+}
+
+/*
+ fills in cluster_info. Each FAT entry (= cluster) is flagged as either
+ FAT_FLAG_FREE, FAT_FLAG_FILE or FAT_FLAG_DIRECTORY.
+
+ Also, the fraction of each cluster (x/64) is recorded
+*/
+int
+fat_collect_cluster_info (PedFileSystem* fs) {
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatTraverseInfo* trav_info;
+
+ /* set all clusters to unused as a default */
+ memset (fs_info->cluster_info, 0, fs_info->fat->cluster_count + 2);
+ fs_info->total_dir_clusters = 0;
+
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ trav_info = fat_traverse_begin (fs, fs_info->root_cluster,
+ "\\");
+ if (!flag_traverse_dir (trav_info))
+ return 0;
+ if (!flag_traverse_fat (fs, "\\", fs_info->root_cluster,
+ FAT_FLAG_DIRECTORY, 0))
+ return 0;
+ } else {
+ trav_info = fat_traverse_begin (fs, FAT_ROOT, "\\");
+ if (!flag_traverse_dir (trav_info))
+ return 0;
+ }
+
+ _mark_bad_clusters (fs);
+ return 1;
+}
+
+FatClusterFlag _GL_ATTRIBUTE_PURE
+fat_get_cluster_flag (PedFileSystem* fs, FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ return fs_info->cluster_info [cluster].flag;
+}
+
+PedSector _GL_ATTRIBUTE_PURE
+fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int fraction;
+
+ if (fs_info->cluster_info [cluster].flag == FAT_FLAG_FREE)
+ return 0;
+
+ fraction = fs_info->cluster_info [cluster].units_used;
+ if (fraction == 0)
+ fraction = 64;
+
+ return fraction * fs_info->cluster_sectors / 64;
+}
+
+FatClusterFlag
+fat_get_fragment_flag (PedFileSystem* fs, FatFragment frag)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster cluster = fat_frag_to_cluster (fs, frag);
+ FatFragment offset = frag % fs_info->cluster_frags;
+ FatFragment last_frag_used;
+ FatClusterFlag flag;
+
+ PED_ASSERT (cluster >= 2 && cluster < fs_info->cluster_count + 2);
+
+ flag = fat_get_cluster_flag (fs, cluster);
+ if (flag != FAT_FLAG_FILE && flag != FAT_FLAG_DIRECTORY)
+ return flag;
+ last_frag_used = (fat_get_cluster_usage (fs, cluster) - 1)
+ / fs_info->frag_sectors;
+ if (offset > last_frag_used)
+ return FAT_FLAG_FREE;
+ else
+ return flag;
+}
+
+int
+fat_is_fragment_active (PedFileSystem* fs, FatFragment frag)
+{
+ switch (fat_get_fragment_flag (fs, frag)) {
+ case FAT_FLAG_FREE:
+ case FAT_FLAG_BAD:
+ return 0;
+
+ case FAT_FLAG_FILE:
+ case FAT_FLAG_DIRECTORY:
+ return 1;
+ }
+ return 0;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/count.h b/libparted/fs/r/fat/count.h
new file mode 100644
index 0000000..bb7d6af
--- /dev/null
+++ b/libparted/fs/r/fat/count.h
@@ -0,0 +1,46 @@
+/*
+ libparted
+ 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/>.
+*/
+
+#ifndef COUNT_H_INCLUDED
+#define COUNT_H_INCLUDED
+
+typedef enum _FatClusterFlag FatClusterFlag;
+typedef struct _FatClusterInfo FatClusterInfo;
+
+enum _FatClusterFlag {
+ FAT_FLAG_FREE=0,
+ FAT_FLAG_FILE=1,
+ FAT_FLAG_DIRECTORY=2,
+ FAT_FLAG_BAD=3
+};
+
+struct __attribute__ ((packed)) _FatClusterInfo {
+ unsigned int units_used:6; /* 1 unit = cluster_size / 64 */
+ FatClusterFlag flag:2;
+};
+
+extern int fat_collect_cluster_info (PedFileSystem *fs);
+extern FatClusterFlag fat_get_cluster_flag (PedFileSystem* fs,
+ FatCluster cluster);
+extern PedSector fat_get_cluster_usage (PedFileSystem* fs, FatCluster cluster);
+extern FatClusterFlag fat_get_fragment_flag (PedFileSystem* fs,
+ FatFragment frag);
+extern int fat_is_fragment_active (PedFileSystem* fs, FatFragment frag);
+
+#endif /* COUNT_H_INCLUDED */
diff --git a/libparted/fs/r/fat/fat.c b/libparted/fs/r/fat/fat.c
new file mode 100644
index 0000000..6583b5b
--- /dev/null
+++ b/libparted/fs/r/fat/fat.c
@@ -0,0 +1,652 @@
+/*
+ libparted
+ Copyright (C) 1998-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 <string.h>
+
+#include "fat.h"
+#include "calc.h"
+#include "../../../labels/misc.h"
+
+PedFileSystem*
+fat_alloc (const PedGeometry* geom)
+{
+ PedFileSystem* fs;
+
+ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
+ if (!fs)
+ goto error;
+
+ fs->type_specific = (FatSpecific*) ped_malloc (sizeof (FatSpecific));
+ if (!fs->type_specific)
+ goto error_free_fs;
+ FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
+ fs_info->boot_sector = NULL;
+ fs_info->info_sector = NULL;
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom)
+ goto error_free_type_specific;
+
+ fs->checked = 0;
+ return fs;
+
+error_free_type_specific:
+ free (fs->type_specific);
+error_free_fs:
+ free (fs);
+error:
+ return NULL;
+}
+
+/* Requires the boot sector to be analysed */
+int
+fat_alloc_buffers (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ fs_info->buffer_sectors = BUFFER_SIZE;
+ fs_info->buffer = ped_malloc (fs_info->buffer_sectors * 512);
+ if (!fs_info->buffer)
+ goto error;
+
+ fs_info->cluster_info = ped_malloc (fs_info->cluster_count + 2);
+ if (!fs_info->cluster_info)
+ goto error_free_buffer;
+
+ return 1;
+
+error_free_buffer:
+ free (fs_info->buffer);
+error:
+ return 0;
+};
+
+void
+fat_free_buffers (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ free (fs_info->cluster_info);
+ free (fs_info->buffer);
+}
+
+void
+fat_free (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = (FatSpecific*) fs->type_specific;
+ free (fs_info->boot_sector);
+ ped_geometry_destroy (fs->geom);
+ free (fs->type_specific);
+ free (fs);
+}
+
+int
+fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (fs_info->cluster_sectors % frag_sectors == 0
+ && frag_sectors <= fs_info->cluster_sectors);
+
+ fs_info->frag_size = frag_sectors * 512;
+ fs_info->frag_sectors = frag_sectors;
+ fs_info->buffer_frags = fs_info->buffer_sectors / frag_sectors;
+ fs_info->cluster_frags = fs_info->cluster_sectors / frag_sectors;
+ fs_info->frag_count = fs_info->cluster_count * fs_info->cluster_frags;
+
+ return 1;
+}
+
+#ifndef DISCOVER_ONLY
+int
+fat_clobber (PedGeometry* geom)
+{
+ FatBootSector *boot_sector;
+ int ok;
+
+ if (!fat_boot_sector_read (&boot_sector, geom))
+ return 1;
+
+ boot_sector->system_id[0] = 0;
+ boot_sector->boot_sign = 0;
+ if (boot_sector->u.fat16.fat_name[0] == 'F')
+ boot_sector->u.fat16.fat_name[0] = 0;
+ if (boot_sector->u.fat32.fat_name[0] == 'F')
+ boot_sector->u.fat32.fat_name[0] = 0;
+
+ ok = ped_geometry_write (geom, boot_sector, 0, 1);
+ free (boot_sector);
+ return ok;
+}
+
+static int
+_init_fats (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster table_size;
+
+ table_size = fs_info->fat_sectors * 512
+ / fat_table_entry_size (fs_info->fat_type);
+ fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
+ if (!fs_info->fat)
+ goto error;
+
+ if (!fat_table_read (fs_info->fat, fs, 0))
+ goto error_free_fat;
+
+ return 1;
+
+error_free_fat:
+ fat_table_destroy (fs_info->fat);
+error:
+ return 0;
+}
+
+PedFileSystem*
+fat_open (PedGeometry* geom)
+{
+ PedFileSystem* fs;
+ FatSpecific* fs_info;
+
+ fs = fat_alloc (geom);
+ if (!fs)
+ goto error;
+ fs_info = (FatSpecific*) fs->type_specific;
+
+ if (!fat_boot_sector_read (&fs_info->boot_sector, geom))
+ goto error_free_fs;
+ if (!fat_boot_sector_analyse (fs_info->boot_sector, fs))
+ goto error_free_fs;
+ fs->type = (fs_info->fat_type == FAT_TYPE_FAT16)
+ ? &fat16_type
+ : &fat32_type;
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ if (!fat_info_sector_read (&fs_info->info_sector, fs))
+ goto error_free_fs;
+ }
+
+ if (!_init_fats (fs))
+ goto error_free_fs;
+ if (!fat_alloc_buffers (fs))
+ goto error_free_fat_table;
+ if (!fat_collect_cluster_info (fs))
+ goto error_free_buffers;
+
+ return fs;
+
+error_free_buffers:
+ fat_free_buffers (fs);
+error_free_fat_table:
+ fat_table_destroy (fs_info->fat);
+error_free_fs:
+ fat_free (fs);
+error:
+ return NULL;
+}
+
+static int
+fat_root_dir_clear (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ memset (fs_info->buffer, 0, 512 * fs_info->root_dir_sector_count);
+ return ped_geometry_write (fs->geom, fs_info->buffer,
+ fs_info->root_dir_offset,
+ fs_info->root_dir_sector_count);
+}
+
+PedFileSystem*
+fat_create (PedGeometry* geom, FatType fat_type, PedTimer* timer)
+{
+ PedFileSystem* fs;
+ FatSpecific* fs_info;
+ FatCluster table_size;
+
+ fs = fat_alloc (geom);
+ if (!fs)
+ goto error;
+ fs_info = (FatSpecific*) fs->type_specific;
+
+ fs_info->logical_sector_size = 1;
+ fs_info->sectors_per_track = geom->dev->bios_geom.sectors;
+ fs_info->heads = geom->dev->bios_geom.heads;
+ fs_info->sector_count = fs->geom->length;
+ fs_info->fat_table_count = 2;
+/* some initial values, to be changed later */
+ fs_info->root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
+ / (512 / sizeof (FatDirEntry));
+ fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
+
+ fs_info->fat_type = fat_type;
+ if (!fat_calc_sizes (fs->geom->length, 0,
+ fs_info->fat_type,
+ fs_info->root_dir_sector_count,
+ &fs_info->cluster_sectors,
+ &fs_info->cluster_count,
+ &fs_info->fat_sectors)) {
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Partition too big/small for a %s file system."),
+ (fat_type == FAT_TYPE_FAT16)
+ ? fat16_type.name
+ : fat32_type.name);
+ goto error_free_fs;
+ }
+
+ fs_info->cluster_size = fs_info->cluster_sectors * 512;
+
+ fs_info->fat_offset = fat_min_reserved_sector_count (fs_info->fat_type);
+ fs_info->dir_entries_per_cluster
+ = fs_info->cluster_size / sizeof (FatDirEntry);
+
+ if (fs_info->fat_type == FAT_TYPE_FAT16) {
+ /* FAT16 */
+ fs->type = &fat16_type;
+
+ if (fs_info->cluster_count
+ > fat_max_cluster_count (fs_info->fat_type)) {
+ fs_info->cluster_count
+ = fat_max_cluster_count (fs_info->fat_type);
+ }
+
+ fs_info->root_dir_sector_count
+ = FAT_ROOT_DIR_ENTRY_COUNT
+ / (512 / sizeof (FatDirEntry));
+ fs_info->root_dir_entry_count = FAT_ROOT_DIR_ENTRY_COUNT;
+ fs_info->root_dir_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ fs_info->cluster_offset
+ = fs_info->root_dir_offset
+ + fs_info->root_dir_sector_count;
+ } else {
+ /* FAT32 */
+ fs->type = &fat32_type;
+
+ fs_info->info_sector_offset = 1;
+ fs_info->boot_sector_backup_offset = 6;
+
+ fs_info->root_dir_sector_count = 0;
+ fs_info->root_dir_entry_count = 0;
+ fs_info->root_dir_offset = 0;
+
+ fs_info->cluster_offset
+ = fs_info->fat_offset
+ + fs_info->fat_sectors * fs_info->fat_table_count;
+ }
+
+ table_size = fs_info->fat_sectors * 512
+ / fat_table_entry_size (fs_info->fat_type);
+ fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
+ if (!fs_info->fat)
+ goto error_free_fs;
+ fat_table_set_cluster_count (fs_info->fat, fs_info->cluster_count);
+ if (!fat_alloc_buffers (fs))
+ goto error_free_fat_table;
+
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ fs_info->root_cluster
+ = fat_table_alloc_cluster (fs_info->fat);
+ fat_table_set_eof (fs_info->fat, fs_info->root_cluster);
+ memset (fs_info->buffer, 0, fs_info->cluster_size);
+ if (!fat_write_cluster (fs, fs_info->buffer,
+ fs_info->root_cluster))
+ goto error_free_buffers;
+ }
+
+ fs_info->serial_number = generate_random_uint32 ();
+
+ if (!fat_boot_sector_set_boot_code (&fs_info->boot_sector, fs))
+ goto error_free_buffers;
+ if (!fat_boot_sector_generate (&fs_info->boot_sector, fs))
+ goto error_free_buffers;
+ if (!fat_boot_sector_write (fs_info->boot_sector, fs))
+ goto error_free_buffers;
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ if (!fat_info_sector_generate (&fs_info->info_sector, fs))
+ goto error_free_buffers;
+ if (!fat_info_sector_write (fs_info->info_sector, fs))
+ goto error_free_buffers;
+ }
+
+ if (!fat_table_write_all (fs_info->fat, fs))
+ goto error_free_buffers;
+
+ if (fs_info->fat_type == FAT_TYPE_FAT16) {
+ if (!fat_root_dir_clear (fs))
+ goto error_free_buffers;
+ }
+
+ return fs;
+
+error_free_buffers:
+ fat_free_buffers (fs);
+error_free_fat_table:
+ fat_table_destroy (fs_info->fat);
+error_free_fs:
+ fat_free (fs);
+error:
+ return NULL;
+}
+
+PedFileSystem*
+fat_create_fat16 (PedGeometry* geom, PedTimer* timer)
+{
+ return fat_create (geom, FAT_TYPE_FAT16, timer);
+}
+
+PedFileSystem*
+fat_create_fat32 (PedGeometry* geom, PedTimer* timer)
+{
+ return fat_create (geom, FAT_TYPE_FAT32, timer);
+}
+
+int
+fat_close (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ fat_free_buffers (fs);
+ fat_table_destroy (fs_info->fat);
+ fat_free (fs);
+ return 1;
+}
+
+/* Hack: just resize the file system outside of its boundaries! */
+PedFileSystem*
+fat_copy (const PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
+{
+ PedFileSystem* new_fs;
+
+ new_fs = ped_file_system_open (fs->geom);
+ if (!new_fs)
+ goto error;
+ if (!ped_file_system_resize (new_fs, geom, timer))
+ goto error_close_new_fs;
+ return new_fs;
+
+error_close_new_fs:
+ ped_file_system_close (new_fs);
+error:
+ return 0;
+}
+
+static int
+_compare_fats (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatTable* table_copy;
+ FatCluster table_size;
+ int i;
+
+ table_size = fs_info->fat_sectors * 512
+ / fat_table_entry_size (fs_info->fat_type);
+
+ table_copy = fat_table_new (fs_info->fat_type, table_size);
+ if (!table_copy)
+ goto error;
+
+ for (i = 1; i < fs_info->fat_table_count; i++) {
+ if (!fat_table_read (table_copy, fs, i))
+ goto error_free_table_copy;
+ if (!fat_table_compare (fs_info->fat, table_copy)) {
+ if (ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The FATs don't match. If you don't know "
+ "what this means, then select cancel, run "
+ "scandisk on the file system, and then come "
+ "back."))
+ != PED_EXCEPTION_IGNORE)
+ goto error_free_table_copy;
+ }
+ }
+
+ fat_table_destroy (table_copy);
+ return 1;
+
+error_free_table_copy:
+ fat_table_destroy (table_copy);
+error:
+ return 0;
+}
+
+int
+fat_check (PedFileSystem* fs, PedTimer* timer)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector cluster_sectors;
+ FatCluster cluster_count;
+ PedSector fat_sectors;
+ PedSector align_sectors;
+ FatCluster info_free_clusters;
+
+ align_sectors = fs_info->fat_offset
+ - fat_min_reserved_sector_count (fs_info->fat_type);
+
+ if (!fat_calc_sizes (fs->geom->length,
+ align_sectors,
+ fs_info->fat_type,
+ fs_info->root_dir_sector_count,
+ &cluster_sectors,
+ &cluster_count,
+ &fat_sectors)) {
+ if (ped_exception_throw (PED_EXCEPTION_BUG,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("There are no possible configurations for this FAT "
+ "type."))
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+ }
+
+ if (fs_info->fat_type == FAT_TYPE_FAT16) {
+ if (cluster_sectors != fs_info->cluster_sectors
+ || cluster_count != fs_info->cluster_count
+ || fat_sectors != fs_info->fat_sectors) {
+ if (ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("File system doesn't have expected sizes for "
+ "Windows to like it. "
+ "Cluster size is %dk (%dk expected); "
+ "number of clusters is %d (%d expected); "
+ "size of FATs is %d sectors (%d expected)."),
+ (int) fs_info->cluster_sectors / 2,
+ (int) cluster_sectors / 2,
+ (int) fs_info->cluster_count,
+ (int) cluster_count,
+ (int) fs_info->fat_sectors,
+ (int) fat_sectors)
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+ }
+ }
+
+ if (fs_info->fat_type == FAT_TYPE_FAT32) {
+ info_free_clusters
+ = PED_LE32_TO_CPU (fs_info->info_sector->free_clusters);
+ if (info_free_clusters != (FatCluster) -1
+ && info_free_clusters != fs_info->fat->free_cluster_count) {
+ if (ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("File system is reporting the free space as "
+ "%d clusters, not %d clusters."),
+ info_free_clusters,
+ fs_info->fat->free_cluster_count)
+ != PED_EXCEPTION_IGNORE)
+ goto error;
+ }
+ }
+
+ if (!_compare_fats (fs))
+ goto error;
+
+ fs->checked = 1;
+ return 1; /* existence of fs implies consistency ;-) */
+
+error:
+ return 0;
+}
+
+/* Calculates how much space there will be in clusters in:
+ * old_fs intersect the-new-fs
+ */
+static PedSector
+_calc_resize_data_size (
+ const PedFileSystem* old_fs,
+ PedSector new_cluster_sectors,
+ FatCluster new_cluster_count,
+ PedSector new_fat_size)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (old_fs);
+ PedSector fat_size_delta;
+
+ fat_size_delta = old_fs_info->fat_sectors - new_fat_size;
+ return new_cluster_sectors * new_cluster_count - fat_size_delta * 2;
+}
+
+static int
+_test_resize_size (const PedFileSystem* fs,
+ PedSector length, PedSector min_data_size)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedGeometry geom;
+ PedSector _cluster_sectors;
+ FatCluster _cluster_count;
+ PedSector _fat_size;
+
+ ped_geometry_init (&geom, fs->geom->dev, fs->geom->start, length);
+
+ if (fat_calc_resize_sizes (
+ &geom,
+ fs_info->cluster_sectors,
+ FAT_TYPE_FAT16,
+ fs_info->root_dir_sector_count,
+ fs_info->cluster_sectors,
+ &_cluster_sectors,
+ &_cluster_count,
+ &_fat_size)
+ && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
+ _fat_size)
+ >= min_data_size)
+ return 1;
+
+ if (fat_calc_resize_sizes (
+ &geom,
+ fs_info->cluster_sectors,
+ FAT_TYPE_FAT32,
+ 0,
+ fs_info->cluster_sectors,
+ &_cluster_sectors,
+ &_cluster_count,
+ &_fat_size)
+ && _calc_resize_data_size (fs, _cluster_sectors, _cluster_count,
+ _fat_size)
+ >= min_data_size)
+ return 1;
+
+ return 0;
+}
+
+/* does a binary search (!) for the mininum size. Too hard to compute directly
+ * (see calc_sizes() for why!)
+ */
+static PedSector
+_get_min_resize_size (const PedFileSystem* fs, PedSector min_data_size)
+{
+ PedSector min_length = 0;
+ PedSector max_length = fs->geom->length;
+ PedSector length;
+
+ while (min_length < max_length - 1) {
+ length = (min_length + max_length) / 2;
+ if (_test_resize_size (fs, length, min_data_size))
+ max_length = length;
+ else
+ min_length = length;
+ }
+
+/* adds a bit of leeway (64 sectors), for resolving extra issues, like root
+ * directory allocation, that aren't covered here.
+ */
+ return max_length + 64;
+}
+
+PedConstraint*
+fat_get_copy_constraint (const PedFileSystem* fs, const PedDevice* dev)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedGeometry full_dev;
+ PedSector min_cluster_count;
+ FatCluster used_clusters;
+ PedSector min_data_size;
+
+ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
+ return NULL;
+
+ used_clusters = fs_info->fat->cluster_count
+ - fs_info->fat->free_cluster_count;
+ min_cluster_count = used_clusters + fs_info->total_dir_clusters;
+ min_data_size = min_cluster_count * fs_info->cluster_sectors;
+
+ return ped_constraint_new (ped_alignment_any, ped_alignment_any,
+ &full_dev, &full_dev,
+ _get_min_resize_size (fs, min_data_size),
+ dev->length);
+}
+
+PedConstraint*
+fat_get_resize_constraint (const PedFileSystem* fs)
+{
+ return fat_get_copy_constraint (fs, fs->geom->dev);
+}
+
+PedConstraint*
+fat_get_create_constraint_fat16 (const PedDevice* dev)
+{
+ PedGeometry full_dev;
+ PedSector min_size;
+ PedSector max_size;
+
+ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
+ return NULL;
+
+ min_size = 65794;
+ max_size = 2097153;
+
+ return ped_constraint_new (
+ ped_alignment_any, ped_alignment_any,
+ &full_dev, &full_dev,
+ min_size, max_size);
+}
+
+PedConstraint*
+fat_get_create_constraint_fat32 (const PedDevice* dev)
+{
+ PedGeometry full_dev;
+ PedSector min_size;
+
+ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
+ return NULL;
+
+ min_size = 525224;
+
+ return ped_constraint_new (
+ ped_alignment_any, ped_alignment_any,
+ &full_dev, &full_dev,
+ min_size, dev->length);
+}
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/fat.h b/libparted/fs/r/fat/fat.h
new file mode 100644
index 0000000..54f0669
--- /dev/null
+++ b/libparted/fs/r/fat/fat.h
@@ -0,0 +1,159 @@
+/*
+ libparted
+ Copyright (C) 1998-2001, 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/>.
+*/
+
+#ifndef FAT_H_INCLUDED
+#define FAT_H_INCLUDED
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define BUFFER_SIZE 1024 /* buffer size in sectors (512 bytes) */
+
+typedef uint32_t FatCluster;
+typedef int32_t FatFragment;
+
+enum _FatType {
+ FAT_TYPE_FAT12,
+ FAT_TYPE_FAT16,
+ FAT_TYPE_FAT32
+};
+typedef enum _FatType FatType;
+
+typedef struct _FatSpecific FatSpecific;
+typedef struct _FatDirEntry FatDirEntry;
+
+/* FIXME: YUCKY */
+#include "table.h"
+#include "bootsector.h"
+#include "context.h"
+#include "fatio.h"
+#include "traverse.h"
+#include "calc.h"
+#include "count.h"
+#include "clstdup.h"
+
+struct __attribute__ ((packed)) _FatDirEntry {
+ char name[8];
+ uint8_t extension[3];
+ uint8_t attributes;
+ uint8_t is_upper_case_name;
+ uint8_t creation_time_low; /* milliseconds */
+ uint16_t creation_time_high;
+ uint16_t creation_date;
+ uint16_t access_date;
+ uint16_t first_cluster_high; /* for FAT32 */
+ uint16_t time;
+ uint16_t date;
+ uint16_t first_cluster;
+ uint32_t length;
+};
+
+struct _FatSpecific {
+ FatBootSector *boot_sector; /* structure of boot sector */
+ FatInfoSector *info_sector; /* fat32-only information sector */
+
+ int logical_sector_size; /* illogical sector size :-) */
+ PedSector sector_count;
+
+ int sectors_per_track; /* BIOS CHS stuff (S) */
+ int heads; /* BIOS CHS stuff (H) */
+
+ int cluster_size;
+ PedSector cluster_sectors;
+ FatCluster cluster_count;
+ int dir_entries_per_cluster;
+
+ FatType fat_type;
+ int fat_table_count;
+ PedSector fat_sectors;
+
+ uint32_t serial_number;
+
+ PedSector info_sector_offset; /* FAT32 only */
+ PedSector fat_offset;
+ PedSector root_dir_offset; /* non-FAT32 */
+ PedSector cluster_offset;
+ PedSector boot_sector_backup_offset;
+
+ FatCluster root_cluster; /* FAT32 only */
+ int root_dir_entry_count; /* non-FAT32 */
+ PedSector root_dir_sector_count; /* non-FAT32 */
+ FatCluster total_dir_clusters;
+
+ FatTable* fat;
+ FatClusterInfo* cluster_info;
+
+ PedSector buffer_sectors;
+ char* buffer;
+
+ int frag_size;
+ PedSector frag_sectors;
+ FatFragment frag_count;
+ FatFragment buffer_frags;
+ FatFragment cluster_frags;
+};
+
+#define FAT_SPECIFIC(fs) ((FatSpecific*) fs->type_specific)
+
+#define FAT_ROOT 0
+
+#define DELETED_FLAG 0xe5
+
+#define READONLY_ATTR 0x01
+#define HIDDEN_ATTR 0x02
+#define SYSTEM_ATTR 0x04
+#define VOLUME_LABEL_ATTR 0x08
+#define VFAT_ATTR 0x0f
+#define DIRECTORY_ATTR 0x10
+#define ARCH_ATTR 0x20
+
+#define MAX_FAT12_CLUSTERS 4086
+#define MAX_FAT16_CLUSTERS 65526
+#define MAX_FAT32_CLUSTERS 2000000
+
+#define FAT_ROOT_DIR_ENTRY_COUNT 512
+
+extern PedFileSystemType fat16_type;
+extern PedFileSystemType fat32_type;
+
+extern void fat_print (const PedFileSystem* fs);
+
+extern PedFileSystem* fat_alloc (const PedGeometry* geom);
+extern void fat_free (PedFileSystem* fs);
+extern int fat_alloc_buffers (PedFileSystem* fs);
+extern void fat_free_buffers (PedFileSystem* fs);
+
+extern int fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer);
+
+extern int fat_set_frag_sectors (PedFileSystem* fs, PedSector frag_sectors);
+
+#endif /* FAT_H_INCLUDED */
diff --git a/libparted/fs/r/fat/fatio.c b/libparted/fs/r/fat/fatio.c
new file mode 100644
index 0000000..3a947ff
--- /dev/null
+++ b/libparted/fs/r/fat/fatio.c
@@ -0,0 +1,150 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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 <config.h>
+#include "fat.h"
+#include "fatio.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifndef DISCOVER_ONLY
+
+int
+fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
+ FatFragment count)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector sector = fat_frag_to_sector (fs, frag);
+ PedSector sector_count = count * fs_info->frag_sectors;
+
+ PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
+
+ return ped_geometry_read (fs->geom, buf, sector, sector_count);
+}
+
+int
+fat_read_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
+{
+ return fat_read_fragments (fs, buf, frag, 1);
+}
+
+int
+fat_write_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
+ FatFragment count)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector sector = fat_frag_to_sector (fs, frag);
+ PedSector sector_count = count * fs_info->frag_sectors;
+
+ PED_ASSERT (frag >= 0 && frag < fs_info->frag_count);
+
+ return ped_geometry_write (fs->geom, buf, sector, sector_count);
+}
+
+int
+fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
+{
+ return fat_write_fragments (fs, buf, frag, 1);
+}
+
+int
+fat_write_sync_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
+ FatFragment count)
+{
+ if (!fat_write_fragments (fs, buf, frag, count))
+ return 0;
+ if (!ped_geometry_sync (fs->geom))
+ return 0;
+ return 1;
+}
+
+int
+fat_write_sync_fragment (PedFileSystem* fs, char* buf, FatFragment frag)
+{
+ return fat_write_sync_fragments (fs, buf, frag, 1);
+}
+
+int
+fat_read_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
+ FatCluster count)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector sector = fat_cluster_to_sector (fs, cluster);
+ PedSector sector_count = count * fs_info->cluster_sectors;
+
+ PED_ASSERT (cluster >= 2
+ && cluster + count - 1 < fs_info->cluster_count + 2);
+
+ return ped_geometry_read (fs->geom, buf, sector, sector_count);
+}
+
+int
+fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
+{
+ return fat_read_clusters (fs, buf, cluster, 1);
+}
+
+int
+fat_write_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
+ FatCluster count)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector sector = fat_cluster_to_sector (fs, cluster);
+ PedSector sector_count = count * fs_info->cluster_sectors;
+
+ PED_ASSERT (cluster >= 2
+ && cluster + count - 1 < fs_info->cluster_count + 2);
+
+ return ped_geometry_write (fs->geom, buf, sector, sector_count);
+}
+
+int
+fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
+{
+ return fat_write_clusters (fs, buf, cluster, 1);
+}
+
+int
+fat_write_sync_clusters (PedFileSystem* fs, char *buf, FatCluster cluster,
+ FatCluster count)
+{
+ if (!fat_write_clusters (fs, buf, cluster, count))
+ return 0;
+ if (!ped_geometry_sync (fs->geom))
+ return 0;
+ return 1;
+}
+
+int
+fat_write_sync_cluster (PedFileSystem* fs, char *buf, FatCluster cluster)
+{
+ if (!fat_write_cluster (fs, buf, cluster))
+ return 0;
+ if (!ped_geometry_sync (fs->geom))
+ return 0;
+ return 1;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/fatio.h b/libparted/fs/r/fat/fatio.h
new file mode 100644
index 0000000..53ebed7
--- /dev/null
+++ b/libparted/fs/r/fat/fatio.h
@@ -0,0 +1,49 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef FATIO_H_INCLUDED
+#define FATIO_H_INCLUDED
+
+#include "fat.h"
+
+extern int fat_read_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
+ FatFragment count);
+extern int fat_write_fragments (PedFileSystem* fs, char* buf, FatFragment frag,
+ FatFragment count);
+extern int fat_write_sync_fragments (PedFileSystem* fs, char* buf,
+ FatFragment frag, FatFragment count);
+
+extern int fat_read_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
+extern int fat_write_fragment (PedFileSystem* fs, char* buf, FatFragment frag);
+extern int fat_write_sync_fragment (PedFileSystem* fs, char* buf,
+ FatFragment frag);
+
+extern int fat_read_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
+ FatCluster count);
+extern int fat_write_clusters (PedFileSystem* fs, char* buf, FatCluster cluster,
+ FatCluster count);
+extern int fat_write_sync_clusters (PedFileSystem* fs, char* buf,
+ FatCluster cluster, FatCluster count);
+
+extern int fat_read_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
+extern int fat_write_cluster (PedFileSystem* fs, char *buf, FatCluster cluster);
+extern int fat_write_sync_cluster (PedFileSystem* fs, char *buf,
+ FatCluster cluster);
+
+#endif /* FATIO_H_INCLUDED */
diff --git a/libparted/fs/r/fat/resize.c b/libparted/fs/r/fat/resize.c
new file mode 100644
index 0000000..78dede4
--- /dev/null
+++ b/libparted/fs/r/fat/resize.c
@@ -0,0 +1,876 @@
+/*
+ libparted
+ Copyright (C) 1998-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 "fat.h"
+#include "traverse.h"
+#include "count.h"
+#include "fatio.h"
+#include "calc.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifndef DISCOVER_ONLY
+
+/* Recursively builds (i.e. makes consistent) the duplicated directory tree
+ * (leaving the original directory tree in tact)
+ */
+static int
+fat_construct_directory (FatOpContext* ctx, FatTraverseInfo* trav_info)
+{
+ FatTraverseInfo* sub_dir_info;
+ FatDirEntry* dir_entry;
+ FatCluster old_first_cluster;
+
+ while ( (dir_entry = fat_traverse_next_dir_entry (trav_info)) ) {
+ if (fat_dir_entry_is_null_term (dir_entry))
+ break;
+ if (!fat_dir_entry_has_first_cluster (dir_entry, ctx->old_fs))
+ continue;
+
+ fat_traverse_mark_dirty (trav_info);
+
+ old_first_cluster = fat_dir_entry_get_first_cluster (dir_entry,
+ ctx->old_fs);
+ fat_dir_entry_set_first_cluster (dir_entry, ctx->new_fs,
+ fat_op_context_map_cluster (ctx, old_first_cluster));
+
+ if (fat_dir_entry_is_directory (dir_entry)
+ && dir_entry->name [0] != '.') {
+ sub_dir_info
+ = fat_traverse_directory (trav_info, dir_entry);
+ if (!sub_dir_info)
+ return 0;
+ if (!fat_construct_directory (ctx, sub_dir_info))
+ return 0;
+ }
+ }
+ /* remove "stale" entries at the end */
+ while ((dir_entry = fat_traverse_next_dir_entry (trav_info))) {
+ memset (dir_entry, 0, sizeof (FatDirEntry));
+ fat_traverse_mark_dirty (trav_info);
+ }
+ fat_traverse_complete (trav_info);
+ return 1;
+}
+
+static int
+duplicate_legacy_root_dir (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+
+ PED_ASSERT (old_fs_info->root_dir_sector_count
+ == new_fs_info->root_dir_sector_count);
+
+ if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
+ old_fs_info->root_dir_offset,
+ old_fs_info->root_dir_sector_count))
+ return 0;
+
+ if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
+ new_fs_info->root_dir_offset,
+ new_fs_info->root_dir_sector_count))
+ return 0;
+
+ return 1;
+}
+
+/*
+ Constructs the new directory tree for legacy (FAT16) file systems.
+*/
+static int
+fat_construct_legacy_root (FatOpContext* ctx)
+{
+ FatTraverseInfo* trav_info;
+
+ if (!duplicate_legacy_root_dir (ctx))
+ return 0;
+ trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT, "\\");
+ return fat_construct_directory (ctx, trav_info);
+}
+
+/*
+ Constructs the new directory tree for new (FAT32) file systems.
+*/
+static int
+fat_construct_root (FatOpContext* ctx)
+{
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatTraverseInfo* trav_info;
+
+ trav_info = fat_traverse_begin (ctx->new_fs, new_fs_info->root_cluster,
+ "\\");
+ fat_construct_directory (ctx, trav_info);
+ return 1;
+}
+
+/* Converts the root directory between FAT16 and FAT32. NOTE: this code
+ * can also do no conversion. I'm leaving fat_construct_directory(), because
+ * it's really pretty :-) It also leaves a higher chance of deleted file
+ * recovery, because it doesn't remove redundant entries. (We do this here,
+ * because brain-damaged FAT16 has an arbitary limit on root directory entries,
+ * so we save room)
+ */
+static int
+fat_convert_directory (FatOpContext* ctx, FatTraverseInfo* old_trav,
+ FatTraverseInfo* new_trav)
+{
+ FatTraverseInfo* sub_old_dir_trav;
+ FatTraverseInfo* sub_new_dir_trav;
+ FatDirEntry* new_dir_entry;
+ FatDirEntry* old_dir_entry;
+ FatCluster old_first_cluster;
+
+ while ( (old_dir_entry = fat_traverse_next_dir_entry (old_trav)) ) {
+ if (fat_dir_entry_is_null_term (old_dir_entry))
+ break;
+ if (!fat_dir_entry_is_active (old_dir_entry))
+ continue;
+
+ new_dir_entry = fat_traverse_next_dir_entry (new_trav);
+ if (!new_dir_entry) {
+ return ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("There's not enough room in the root "
+ "directory for all of the files. Either "
+ "cancel, or ignore to lose the files."))
+ == PED_EXCEPTION_IGNORE;
+ }
+
+ *new_dir_entry = *old_dir_entry;
+ fat_traverse_mark_dirty (new_trav);
+
+ if (!fat_dir_entry_has_first_cluster (old_dir_entry,
+ ctx->old_fs))
+ continue;
+
+ old_first_cluster = fat_dir_entry_get_first_cluster (
+ old_dir_entry, ctx->old_fs);
+ fat_dir_entry_set_first_cluster (new_dir_entry, ctx->new_fs,
+ fat_op_context_map_cluster (ctx, old_first_cluster));
+
+ if (fat_dir_entry_is_directory (old_dir_entry)
+ && old_dir_entry->name [0] != '.') {
+ sub_old_dir_trav
+ = fat_traverse_directory (old_trav, old_dir_entry);
+ if (!sub_old_dir_trav) return 0;
+ sub_new_dir_trav
+ = fat_traverse_directory (new_trav, new_dir_entry);
+ if (!sub_new_dir_trav) {
+ fat_traverse_complete (sub_old_dir_trav);
+ return 0;
+ }
+
+ if (!fat_convert_directory (ctx, sub_old_dir_trav,
+ sub_new_dir_trav))
+ return 0;
+ }
+ }
+
+ /* remove "stale" entries at the end, just in case there is some
+ * overlap
+ */
+ while ((new_dir_entry = fat_traverse_next_dir_entry (new_trav))) {
+ memset (new_dir_entry, 0, sizeof (FatDirEntry));
+ fat_traverse_mark_dirty (new_trav);
+ }
+
+ fat_traverse_complete (old_trav);
+ fat_traverse_complete (new_trav);
+ return 1;
+}
+
+static void
+clear_cluster (PedFileSystem* fs, FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ memset (fs_info->buffer, 0, fs_info->cluster_size);
+ fat_write_cluster (fs, fs_info->buffer, cluster);
+}
+
+/* This MUST be called BEFORE the fat_construct_new_fat(), because cluster
+ * allocation depend on the old FAT. The reason is, old clusters may
+ * still be needed during the resize, (particularly clusters in the directory
+ * tree) even if they will be discarded later.
+ */
+static int
+alloc_root_dir (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatCluster i;
+ FatCluster cluster;
+ FatCluster cluster_count;
+
+ PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT32);
+
+ cluster_count = ped_div_round_up (
+ PED_MAX (16, old_fs_info->root_dir_sector_count),
+ new_fs_info->cluster_sectors);
+
+ for (i = 0; i < cluster_count; i++) {
+ cluster = fat_table_alloc_check_cluster (new_fs_info->fat,
+ ctx->new_fs);
+ if (!cluster)
+ return 0;
+ ctx->new_root_dir [i] = cluster;
+ clear_cluster (ctx->new_fs, cluster);
+ }
+ ctx->new_root_dir [i] = 0;
+ new_fs_info->root_cluster = ctx->new_root_dir [0];
+ return 1;
+}
+
+/* when converting FAT32 -> FAT16
+ * fat_duplicate clusters() duplicated the root directory unnecessarily.
+ * Let's free it.
+ *
+ * This must be called AFTER fat_construct_new_fat(). (otherwise, our
+ * changes just get overwritten)
+ */
+static int
+free_root_dir (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatCluster old_cluster;
+ FatFragment i;
+
+ PED_ASSERT (old_fs_info->fat_type == FAT_TYPE_FAT32);
+ PED_ASSERT (new_fs_info->fat_type == FAT_TYPE_FAT16);
+
+ for (old_cluster = old_fs_info->root_cluster;
+ !fat_table_is_eof (old_fs_info->fat, old_cluster);
+ old_cluster = fat_table_get (old_fs_info->fat, old_cluster)) {
+ FatFragment old_frag;
+ old_frag = fat_cluster_to_frag (ctx->old_fs, old_cluster);
+ for (i = 0; i < new_fs_info->cluster_frags; i++) {
+ FatFragment new_frag;
+ FatCluster new_clst;
+ new_frag = fat_op_context_map_fragment (ctx,
+ old_frag + i);
+ new_clst = fat_frag_to_cluster (ctx->old_fs, new_frag);
+ if (!fat_table_set_avail (new_fs_info->fat, new_clst))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int
+fat_clear_root_dir (PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int i;
+
+ PED_ASSERT (fs_info->fat_type == FAT_TYPE_FAT16);
+ PED_ASSERT (fs_info->root_dir_sector_count);
+
+ memset (fs_info->buffer, 0, 512);
+
+ for (i = 0; i < fs_info->root_dir_sector_count; i++) {
+ if (!ped_geometry_write (fs->geom, fs_info->buffer,
+ fs_info->root_dir_offset + i, 1)) {
+ if (ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Error writing to the root directory."))
+ == PED_EXCEPTION_CANCEL)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+fat_construct_converted_tree (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatTraverseInfo* old_trav_info;
+ FatTraverseInfo* new_trav_info;
+
+ if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ new_trav_info = fat_traverse_begin (ctx->new_fs,
+ new_fs_info->root_cluster, "\\");
+ if (!new_trav_info) return 0;
+ old_trav_info = fat_traverse_begin (ctx->old_fs, FAT_ROOT,
+ "\\");
+ } else {
+ fat_clear_root_dir (ctx->new_fs);
+ new_trav_info = fat_traverse_begin (ctx->new_fs, FAT_ROOT,
+ "\\");
+ if (!new_trav_info) return 0;
+ old_trav_info = fat_traverse_begin (ctx->old_fs,
+ old_fs_info->root_cluster, "\\");
+ }
+ if (!old_trav_info) {
+ fat_traverse_complete (new_trav_info);
+ return 0;
+ }
+ if (!fat_convert_directory (ctx, old_trav_info, new_trav_info))
+ return 0;
+ return 1;
+}
+
+/*
+ Constructs the new directory tree to match the new file locations.
+*/
+static int
+fat_construct_dir_tree (FatOpContext* ctx)
+{
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+
+ if (new_fs_info->fat_type == old_fs_info->fat_type) {
+ switch (old_fs_info->fat_type) {
+ case FAT_TYPE_FAT12:
+ PED_ASSERT (0);
+ break;
+
+ case FAT_TYPE_FAT16:
+ return fat_construct_legacy_root (ctx);
+
+ case FAT_TYPE_FAT32:
+ return fat_construct_root (ctx);
+ }
+ } else {
+ return fat_construct_converted_tree (ctx);
+ }
+
+ return 0;
+}
+
+static FatFragment
+_get_next_old_frag (FatOpContext* ctx, FatFragment frag)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatCluster cluster;
+ FatCluster next_cluster;
+
+ if ((frag + 1) % old_fs_info->cluster_frags != 0) {
+ if (fat_is_fragment_active (ctx->old_fs, frag + 1))
+ return frag + 1;
+ else
+ return -1;
+ } else {
+ cluster = fat_frag_to_cluster (ctx->old_fs, frag);
+ next_cluster = fat_table_get (old_fs_info->fat, cluster);
+
+ if (fat_table_is_eof (old_fs_info->fat, next_cluster))
+ return -1;
+ else
+ return fat_cluster_to_frag (ctx->old_fs, next_cluster);
+ }
+}
+
+/*
+ Constructs the new fat for the resized file system.
+*/
+static int
+fat_construct_new_fat (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ FatFragment old_frag;
+ FatCluster new_cluster;
+ FatFragment new_frag;
+ FatFragment old_next_frag;
+ FatFragment new_next_frag;
+ FatCluster new_next_cluster;
+ FatClusterFlag flag;
+ int i;
+
+ fat_table_clear (new_fs_info->fat);
+ if (!fat_table_set_cluster_count (new_fs_info->fat,
+ new_fs_info->cluster_count))
+ return 0;
+
+ for (old_frag = 0; old_frag < old_fs_info->frag_count; old_frag++) {
+ flag = fat_get_fragment_flag (ctx->old_fs, old_frag);
+ if (flag == FAT_FLAG_FREE)
+ continue;
+ if (flag == FAT_FLAG_BAD) {
+ new_frag = fat_op_context_map_static_fragment (
+ ctx, old_frag);
+ if (new_frag == -1)
+ continue;
+ new_cluster = fat_frag_to_cluster (ctx->new_fs,
+ new_frag);
+ fat_table_set_bad (new_fs_info->fat, new_cluster);
+ continue;
+ }
+
+ new_frag = fat_op_context_map_fragment (ctx, old_frag);
+ new_cluster = fat_frag_to_cluster (ctx->new_fs, new_frag);
+
+ old_next_frag = _get_next_old_frag (ctx, old_frag);
+ if (old_next_frag == -1) {
+ fat_table_set_eof (new_fs_info->fat, new_cluster);
+ continue;
+ }
+
+ new_next_frag = fat_op_context_map_fragment (ctx,
+ old_next_frag);
+ PED_ASSERT (new_next_frag != -1);
+
+ new_next_cluster = fat_frag_to_cluster (ctx->new_fs,
+ new_next_frag);
+ PED_ASSERT (new_next_cluster != new_cluster);
+
+ fat_table_set (new_fs_info->fat, new_cluster, new_next_cluster);
+ }
+
+ if (old_fs_info->fat_type == FAT_TYPE_FAT32
+ && new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ new_fs_info->root_cluster
+ = fat_op_context_map_cluster (ctx,
+ old_fs_info->root_cluster);
+ }
+
+ if (old_fs_info->fat_type == FAT_TYPE_FAT16
+ && new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ for (i=0; ctx->new_root_dir[i+1]; i++) {
+ fat_table_set (new_fs_info->fat,
+ ctx->new_root_dir[i],
+ ctx->new_root_dir[i+1]);
+ }
+ fat_table_set_eof (new_fs_info->fat, ctx->new_root_dir[i]);
+ }
+
+ return 1;
+}
+
+static int
+ask_type (PedFileSystem* fs, int fat16_ok, int fat32_ok, FatType* out_fat_type)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedExceptionOption status;
+ const char* fat16_msg;
+ const char* fat32_msg;
+
+ if (fs_info->fat_type == FAT_TYPE_FAT16)
+ fat16_msg = _("If you leave your file system as FAT16, "
+ "then you will have no problems.");
+ else
+ fat16_msg = _("If you convert to FAT16, and MS Windows "
+ "is installed on this partition, then "
+ "you must re-install the MS Windows boot "
+ "loader. If you want to do this, you "
+ "should consult the Parted manual (or "
+ "your distribution's manual).");
+
+ if (fs_info->fat_type == FAT_TYPE_FAT32)
+ fat32_msg = _("If you leave your file system as FAT32, "
+ "then you will not introduce any new "
+ "problems.");
+ else
+ fat32_msg = _("If you convert to FAT32, and MS Windows "
+ "is installed on this partition, then "
+ "you must re-install the MS Windows boot "
+ "loader. If you want to do this, you "
+ "should consult the Parted manual (or "
+ "your distribution's manual). Also, "
+ "converting to FAT32 will make the file "
+ "system unreadable by MS DOS, MS Windows "
+ "95a, and MS Windows NT.");
+
+ if (fat16_ok && fat32_ok) {
+ status = ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_YES_NO_CANCEL,
+ _("%s %s %s"),
+ _("Would you like to use FAT32?"),
+ fat16_msg,
+ fat32_msg);
+
+ switch (status) {
+ case PED_EXCEPTION_YES:
+ *out_fat_type = FAT_TYPE_FAT32;
+ return 1;
+
+ case PED_EXCEPTION_NO:
+ *out_fat_type = FAT_TYPE_FAT16;
+ return 1;
+
+ case PED_EXCEPTION_UNHANDLED:
+ *out_fat_type = fs_info->fat_type;
+ return 1;
+
+ case PED_EXCEPTION_CANCEL:
+ return 0;
+
+ default:
+ PED_ASSERT (0);
+ break;
+ }
+ }
+
+ if (fat16_ok) {
+ if (fs_info->fat_type != FAT_TYPE_FAT16) {
+ status = ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_OK_CANCEL,
+ _("%s %s"),
+ _("The file system can only be resized to this "
+ "size by converting to FAT16."),
+ fat16_msg);
+ if (status == PED_EXCEPTION_CANCEL)
+ return 0;
+ }
+ *out_fat_type = FAT_TYPE_FAT16;
+ return 1;
+ }
+
+ if (fat32_ok) {
+ if (fs_info->fat_type != FAT_TYPE_FAT32) {
+ status = ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_OK_CANCEL,
+ _("%s %s"),
+ _("The file system can only be resized to this "
+ "size by converting to FAT32."),
+ fat32_msg);
+ if (status == PED_EXCEPTION_CANCEL)
+ return 0;
+ }
+ *out_fat_type = FAT_TYPE_FAT32;
+ return 1;
+ }
+
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("GNU Parted cannot resize this partition to this size. "
+ "We're working on it!"));
+
+ return 0;
+}
+
+/* For resize operations: determine if the file system must be FAT16 or FAT32,
+ * or either. If the new file system must be FAT32, then query for
+ * confirmation. If either file system can be used, query for which one.
+ */
+static int
+get_fat_type (PedFileSystem* fs, const PedGeometry* new_geom,
+ FatType* out_fat_type)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ PedSector fat16_cluster_sectors;
+ PedSector fat32_cluster_sectors;
+ FatCluster dummy_cluster_count;
+ PedSector dummy_fat_sectors;
+ int fat16_ok;
+ int fat32_ok;
+
+ fat16_ok = fat_calc_resize_sizes (
+ new_geom,
+ fs_info->cluster_sectors,
+ FAT_TYPE_FAT16,
+ fs_info->root_dir_sector_count,
+ fs_info->cluster_sectors,
+ &fat16_cluster_sectors,
+ &dummy_cluster_count,
+ &dummy_fat_sectors);
+
+ fat32_ok = fat_calc_resize_sizes (
+ new_geom,
+ fs_info->cluster_sectors,
+ FAT_TYPE_FAT32,
+ fs_info->root_dir_sector_count,
+ fs_info->cluster_sectors,
+ &fat32_cluster_sectors,
+ &dummy_cluster_count,
+ &dummy_fat_sectors);
+
+ return ask_type (fs, fat16_ok, fat32_ok, out_fat_type);
+}
+
+/* Creates the PedFileSystem struct for the new resized file system, and
+ sticks it in a FatOpContext. At the end of the process, the original
+ (ctx->old_fs) is destroyed, and replaced with the new one (ctx->new_fs).
+ */
+static FatOpContext*
+create_resize_context (PedFileSystem* fs, const PedGeometry* new_geom)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatSpecific* new_fs_info;
+ PedFileSystem* new_fs;
+ PedSector new_cluster_sectors;
+ FatCluster new_cluster_count;
+ PedSector new_fat_sectors;
+ FatType new_fat_type;
+ PedSector root_dir_sector_count;
+ FatOpContext* context;
+
+ /* hypothetical number of root dir sectors, if we end up using
+ * FAT16
+ */
+ if (fs_info->root_dir_sector_count)
+ root_dir_sector_count = fs_info->root_dir_sector_count;
+ else
+ root_dir_sector_count = FAT_ROOT_DIR_ENTRY_COUNT
+ * sizeof (FatDirEntry) / 512;
+
+ if (!get_fat_type (fs, new_geom, &new_fat_type))
+ return 0;
+
+ fat_calc_resize_sizes (new_geom, fs_info->cluster_sectors, new_fat_type,
+ root_dir_sector_count, fs_info->cluster_sectors,
+ &new_cluster_sectors, &new_cluster_count, &new_fat_sectors);
+
+ if (!fat_check_resize_geometry (fs, new_geom, new_cluster_sectors,
+ new_cluster_count))
+ goto error;
+
+ new_fs = fat_alloc (new_geom);
+ if (!new_fs)
+ goto error;
+
+ new_fs_info = FAT_SPECIFIC (new_fs);
+ if (!new_fs_info)
+ goto error_free_new_fs;
+
+/* preserve boot code, etc. */
+ new_fs_info->boot_sector = ped_malloc (new_geom->dev->sector_size);
+ memcpy (new_fs_info->boot_sector, fs_info->boot_sector,
+ new_geom->dev->sector_size);
+ new_fs_info->info_sector = NULL;
+ if (fs_info->fat_type == FAT_TYPE_FAT32)
+ {
+ PED_ASSERT (fs_info->info_sector != NULL);
+ new_fs_info->info_sector =
+ ped_malloc (new_geom->dev->sector_size);
+ memcpy (new_fs_info->info_sector, fs_info->info_sector,
+ new_geom->dev->sector_size);
+ }
+
+ new_fs_info->logical_sector_size = fs_info->logical_sector_size;
+ new_fs_info->sector_count = new_geom->length;
+
+ new_fs_info->sectors_per_track = fs_info->sectors_per_track;
+ new_fs_info->heads = fs_info->heads;
+
+ new_fs_info->cluster_size = new_cluster_sectors * 512;
+ new_fs_info->cluster_sectors = new_cluster_sectors;
+ new_fs_info->cluster_count = new_cluster_count;
+ new_fs_info->dir_entries_per_cluster = fs_info->dir_entries_per_cluster;
+
+ new_fs_info->fat_type = new_fat_type;
+ new_fs_info->fat_table_count = 2;
+ new_fs_info->fat_sectors = new_fat_sectors;
+
+ /* what about copying? */
+ new_fs_info->serial_number = fs_info->serial_number;
+
+ if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ new_fs_info->info_sector_offset = 1;
+ new_fs_info->boot_sector_backup_offset = 6;
+
+ new_fs_info->root_dir_offset = 0;
+ new_fs_info->root_dir_entry_count = 0;
+ new_fs_info->root_dir_sector_count = 0;
+
+ /* we add calc_align_sectors to push the cluster_offset
+ forward, to keep the clusters aligned between the new
+ and old file systems
+ */
+ new_fs_info->fat_offset
+ = fat_min_reserved_sector_count (FAT_TYPE_FAT32)
+ + fat_calc_align_sectors (new_fs, fs);
+
+ new_fs_info->cluster_offset
+ = new_fs_info->fat_offset
+ + 2 * new_fs_info->fat_sectors;
+ } else {
+ new_fs_info->root_dir_sector_count = root_dir_sector_count;
+ new_fs_info->root_dir_entry_count
+ = root_dir_sector_count * 512 / sizeof (FatDirEntry);
+
+ new_fs_info->fat_offset
+ = fat_min_reserved_sector_count (FAT_TYPE_FAT16)
+ + fat_calc_align_sectors (new_fs, fs);
+
+ new_fs_info->root_dir_offset = new_fs_info->fat_offset
+ + 2 * new_fs_info->fat_sectors;
+
+ new_fs_info->cluster_offset = new_fs_info->root_dir_offset
+ + new_fs_info->root_dir_sector_count;
+ }
+
+ new_fs_info->total_dir_clusters = fs_info->total_dir_clusters;
+
+ context = fat_op_context_new (new_fs, fs);
+ if (!context)
+ goto error_free_new_fs_info;
+
+ if (!fat_op_context_create_initial_fat (context))
+ goto error_free_context;
+
+ if (!fat_alloc_buffers (new_fs))
+ goto error_free_fat;
+
+ return context;
+
+error_free_fat:
+ fat_table_destroy (new_fs_info->fat);
+error_free_context:
+ free (context);
+error_free_new_fs_info:
+ free (new_fs_info);
+error_free_new_fs:
+ free (new_fs);
+error:
+ return NULL;
+}
+
+static int
+resize_context_assimilate (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+
+ fat_free_buffers (ctx->old_fs);
+ fat_table_destroy (old_fs_info->fat);
+ free (old_fs_info);
+ ped_geometry_destroy (ctx->old_fs->geom);
+
+ ctx->old_fs->type_specific = ctx->new_fs->type_specific;
+ ctx->old_fs->geom = ctx->new_fs->geom;
+ ctx->old_fs->type = (new_fs_info->fat_type == FAT_TYPE_FAT16)
+ ? &fat16_type
+ : &fat32_type;
+
+ free (ctx->new_fs);
+
+ fat_op_context_destroy (ctx);
+
+ return 1;
+}
+
+static int
+resize_context_abort (FatOpContext* ctx)
+{
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+
+ fat_free_buffers (ctx->new_fs);
+ fat_table_destroy (new_fs_info->fat);
+ free (new_fs_info);
+ ped_geometry_destroy (ctx->new_fs->geom);
+ free (ctx->new_fs);
+
+ fat_op_context_destroy (ctx);
+
+ return 1;
+}
+
+/* copies the "hidden" sectors, between the boot sector and the FAT. Required,
+ * for the Windows 98 FAT32 boot loader
+ */
+int
+_copy_hidden_sectors (FatOpContext* ctx)
+{
+ FatSpecific* old_fs_info = FAT_SPECIFIC (ctx->old_fs);
+ FatSpecific* new_fs_info = FAT_SPECIFIC (ctx->new_fs);
+ PedSector first = 1;
+ PedSector last;
+ PedSector count;
+
+ /* nothing to copy for FAT16 */
+ if (old_fs_info->fat_type == FAT_TYPE_FAT16
+ || new_fs_info->fat_type == FAT_TYPE_FAT16)
+ return 1;
+
+ last = PED_MIN (old_fs_info->fat_offset, new_fs_info->fat_offset) - 1;
+ count = last - first + 1;
+
+ PED_ASSERT (count < BUFFER_SIZE);
+
+ if (!ped_geometry_read (ctx->old_fs->geom, old_fs_info->buffer,
+ first, count))
+ return 0;
+ if (!ped_geometry_write (ctx->new_fs->geom, old_fs_info->buffer,
+ first, count))
+ return 0;
+ return 1;
+}
+
+int
+fat_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatSpecific* new_fs_info;
+ FatOpContext* ctx;
+ PedFileSystem* new_fs;
+
+ ctx = create_resize_context (fs, geom);
+ if (!ctx)
+ goto error;
+ new_fs = ctx->new_fs;
+ new_fs_info = FAT_SPECIFIC (new_fs);
+
+ if (!fat_duplicate_clusters (ctx, timer))
+ goto error_abort_ctx;
+ if (fs_info->fat_type == FAT_TYPE_FAT16
+ && new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ if (!alloc_root_dir (ctx))
+ goto error_abort_ctx;
+ }
+ if (!fat_construct_new_fat (ctx))
+ goto error_abort_ctx;
+ if (fs_info->fat_type == FAT_TYPE_FAT32
+ && new_fs_info->fat_type == FAT_TYPE_FAT16) {
+ if (!free_root_dir (ctx))
+ goto error_abort_ctx;
+ }
+ if (!fat_construct_dir_tree (ctx))
+ goto error_abort_ctx;
+ if (!fat_table_write_all (new_fs_info->fat, new_fs))
+ goto error_abort_ctx;
+
+ _copy_hidden_sectors (ctx);
+ fat_boot_sector_generate (&new_fs_info->boot_sector, new_fs);
+ fat_boot_sector_write (new_fs_info->boot_sector, new_fs);
+ if (new_fs_info->fat_type == FAT_TYPE_FAT32) {
+ fat_info_sector_generate (&new_fs_info->info_sector, new_fs);
+ fat_info_sector_write (new_fs_info->info_sector, new_fs);
+ }
+
+ if (!resize_context_assimilate (ctx))
+ goto error;
+
+ return 1;
+
+error_abort_ctx:
+ resize_context_abort (ctx);
+error:
+ return 0;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/table.c b/libparted/fs/r/fat/table.c
new file mode 100644
index 0000000..ec0907f
--- /dev/null
+++ b/libparted/fs/r/fat/table.c
@@ -0,0 +1,481 @@
+/*
+ libparted
+ Copyright (C) 1998-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/endian.h>
+#include "fat.h"
+
+#ifndef DISCOVER_ONLY
+
+FatTable*
+fat_table_new (FatType fat_type, FatCluster size)
+{
+ FatTable* ft;
+ int entry_size = fat_table_entry_size (fat_type);
+
+ ft = (FatTable*) ped_malloc (sizeof (FatTable));
+ if (!ft) return NULL;
+
+ ft->cluster_count = ft->free_cluster_count = size - 2;
+
+/* ensure there's some free room on the end, to finish off the sector */
+ ft->size = ped_div_round_up (size * entry_size, 512) * 512 / entry_size;
+ ft->fat_type = fat_type;
+ ft->raw_size = ft->size * entry_size;
+
+ ft->table = ped_malloc (ft->raw_size);
+ if (!ft->table) {
+ free (ft);
+ return NULL;
+ }
+
+ fat_table_clear (ft);
+ return ft;
+}
+
+void
+fat_table_destroy (FatTable* ft)
+{
+ free (ft->table);
+ free (ft);
+}
+
+FatTable*
+fat_table_duplicate (const FatTable* ft)
+{
+ FatTable* dup_ft;
+
+ dup_ft = fat_table_new (ft->fat_type, ft->size);
+ if (!dup_ft) return NULL;
+
+ dup_ft->cluster_count = ft->cluster_count;
+ dup_ft->free_cluster_count = ft->free_cluster_count;
+ dup_ft->bad_cluster_count = ft->bad_cluster_count;
+ dup_ft->last_alloc = ft->last_alloc;
+
+ memcpy (dup_ft->table, ft->table, ft->raw_size);
+
+ return dup_ft;
+}
+
+void
+fat_table_clear (FatTable* ft)
+{
+ memset (ft->table, 0, ft->raw_size);
+
+ fat_table_set (ft, 0, 0x0ffffff8);
+ fat_table_set (ft, 1, 0x0fffffff);
+
+ ft->free_cluster_count = ft->cluster_count;
+ ft->bad_cluster_count = 0;
+ ft->last_alloc = 1;
+}
+
+int
+fat_table_set_cluster_count (FatTable* ft, FatCluster new_cluster_count)
+{
+ PED_ASSERT (new_cluster_count + 2 <= ft->size);
+
+ ft->cluster_count = new_cluster_count;
+ return fat_table_count_stats (ft);
+}
+
+int
+fat_table_count_stats (FatTable* ft)
+{
+ FatCluster i;
+
+ PED_ASSERT (ft->cluster_count + 2 <= ft->size);
+
+ ft->free_cluster_count = 0;
+ ft->bad_cluster_count = 0;
+
+ for (i=2; i < ft->cluster_count + 2; i++) {
+ if (fat_table_is_available (ft, i))
+ ft->free_cluster_count++;
+ if (fat_table_is_bad (ft, i))
+ ft->bad_cluster_count++;
+ }
+ return 1;
+}
+
+int
+fat_table_read (FatTable* ft, const PedFileSystem* fs, int table_num)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
+
+ memset (ft->table, 0, ft->raw_size);
+
+ if (!ped_geometry_read (fs->geom, (void *) ft->table,
+ fs_info->fat_offset
+ + table_num * fs_info->fat_sectors,
+ fs_info->fat_sectors))
+ return 0;
+
+ if ( *((unsigned char*) ft->table) != fs_info->boot_sector->media) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("FAT %d media %x doesn't match the boot sector's "
+ "media %x. You should probably run scandisk."),
+ (int) table_num + 1,
+ (int) *((unsigned char*) ft->table),
+ (int) fs_info->boot_sector->media)
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ }
+
+ ft->cluster_count = fs_info->cluster_count;
+
+ fat_table_count_stats (ft);
+
+ return 1;
+}
+
+int
+fat_table_write (const FatTable* ft, PedFileSystem* fs, int table_num)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
+
+ if (!ped_geometry_write (fs->geom, (void *) ft->table,
+ fs_info->fat_offset
+ + table_num * fs_info->fat_sectors,
+ fs_info->fat_sectors))
+ return 0;
+ if (!ped_geometry_sync (fs->geom))
+ return 0;
+
+ return 1;
+}
+
+int
+fat_table_write_all (const FatTable* ft, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ int i;
+
+ for (i = 0; i < fs_info->fat_table_count; i++) {
+ if (!fat_table_write (ft, fs, i))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+fat_table_compare (const FatTable* a, const FatTable* b)
+{
+ FatCluster i;
+
+ if (a->cluster_count != b->cluster_count)
+ return 0;
+
+ for (i = 0; i < a->cluster_count + 2; i++) {
+ if (fat_table_get (a, i) != fat_table_get (b, i))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+_test_code_available (const FatTable* ft, FatCluster code)
+{
+ return code == 0;
+}
+
+static int
+_test_code_bad (const FatTable* ft, FatCluster code)
+{
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ if (code == 0xff7) return 1;
+ break;
+
+ case FAT_TYPE_FAT16:
+ if (code == 0xfff7) return 1;
+ break;
+
+ case FAT_TYPE_FAT32:
+ if (code == 0x0ffffff7) return 1;
+ break;
+ }
+ return 0;
+}
+
+static int
+_test_code_eof (const FatTable* ft, FatCluster code)
+{
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ if (code >= 0xff7) return 1;
+ break;
+
+ case FAT_TYPE_FAT16:
+ if (code >= 0xfff7) return 1;
+ break;
+
+ case FAT_TYPE_FAT32:
+ if (code >= 0x0ffffff7) return 1;
+ break;
+ }
+ return 0;
+}
+
+void
+_update_stats (FatTable* ft, FatCluster cluster, FatCluster value)
+{
+ if (_test_code_available (ft, value)
+ && !fat_table_is_available (ft, cluster)) {
+ ft->free_cluster_count++;
+ if (fat_table_is_bad (ft, cluster))
+ ft->bad_cluster_count--;
+ }
+
+ if (!_test_code_available (ft, value)
+ && fat_table_is_available (ft, cluster)) {
+ ft->free_cluster_count--;
+ if (_test_code_bad (ft, cluster))
+ ft->bad_cluster_count--;
+ }
+}
+
+int
+fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value)
+{
+ if (cluster >= ft->cluster_count + 2) {
+ ped_exception_throw (PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("fat_table_set: cluster %ld outside "
+ "file system"),
+ (long) cluster);
+ return 0;
+ }
+
+ _update_stats (ft, cluster, value);
+
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ PED_ASSERT (0);
+ break;
+
+ case FAT_TYPE_FAT16:
+ ((unsigned short *) ft->table) [cluster]
+ = PED_CPU_TO_LE16 (value);
+ break;
+
+ case FAT_TYPE_FAT32:
+ ((unsigned int *) ft->table) [cluster]
+ = PED_CPU_TO_LE32 (value);
+ break;
+ }
+ return 1;
+}
+
+FatCluster
+fat_table_get (const FatTable* ft, FatCluster cluster)
+{
+ if (cluster >= ft->cluster_count + 2) {
+ ped_exception_throw (PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("fat_table_get: cluster %ld outside "
+ "file system"),
+ (long) cluster);
+ exit (EXIT_FAILURE); /* FIXME */
+ }
+
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ PED_ASSERT (0);
+ break;
+
+ case FAT_TYPE_FAT16:
+ return PED_LE16_TO_CPU
+ (((unsigned short *) ft->table) [cluster]);
+
+ case FAT_TYPE_FAT32:
+ return PED_LE32_TO_CPU
+ (((unsigned int *) ft->table) [cluster]);
+ }
+
+ return 0;
+}
+
+FatCluster
+fat_table_alloc_cluster (FatTable* ft)
+{
+ FatCluster i;
+ FatCluster cluster;
+
+/* hack: assumes the first two FAT entries are marked as used (which they
+ * always should be)
+ */
+ for (i=1; i < ft->cluster_count + 1; i++) {
+ cluster = (i + ft->last_alloc) % ft->cluster_count;
+ if (fat_table_is_available (ft, cluster)) {
+ ft->last_alloc = cluster;
+ return cluster;
+ }
+ }
+
+ ped_exception_throw (PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("fat_table_alloc_cluster: no free clusters"));
+ return 0;
+}
+
+FatCluster
+fat_table_alloc_check_cluster (FatTable* ft, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster result;
+
+ while (1) {
+ result = fat_table_alloc_cluster (ft);
+ if (!result)
+ return 0;
+ if (fat_read_cluster (fs, fs_info->buffer, result))
+ return result;
+ fat_table_set_bad (ft, result);
+ }
+}
+
+/*
+ returns true if <cluster> is marked as bad
+*/
+int
+fat_table_is_bad (const FatTable* ft, FatCluster cluster)
+{
+ return _test_code_bad (ft, fat_table_get (ft, cluster));
+}
+
+/*
+ returns true if <cluster> represents an EOF marker
+*/
+int _GL_ATTRIBUTE_PURE
+fat_table_is_eof (const FatTable* ft, FatCluster cluster)
+{
+ return _test_code_eof (ft, cluster);
+}
+
+/*
+ returns true if <cluster> is available.
+*/
+int
+fat_table_is_available (const FatTable* ft, FatCluster cluster)
+{
+ return _test_code_available (ft, fat_table_get (ft, cluster));
+}
+
+/*
+ returns true if <cluster> is empty. Note that this includes bad clusters.
+*/
+int
+fat_table_is_empty (const FatTable* ft, FatCluster cluster)
+{
+ return fat_table_is_available (ft, cluster)
+ || fat_table_is_bad (ft, cluster);
+}
+
+/*
+ returns true if <cluster> is being used for something constructive.
+*/
+int
+fat_table_is_active (const FatTable* ft, FatCluster cluster)
+{
+ return !fat_table_is_bad (ft, cluster)
+ && !fat_table_is_available (ft, cluster);
+}
+
+/*
+ marks <cluster> as the last cluster in the chain
+*/
+int
+fat_table_set_eof (FatTable* ft, FatCluster cluster)
+{
+
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ PED_ASSERT (0);
+ break;
+
+ case FAT_TYPE_FAT16:
+ return fat_table_set (ft, cluster, 0xfff8);
+
+ case FAT_TYPE_FAT32:
+ return fat_table_set (ft, cluster, 0x0fffffff);
+ }
+
+ return 0;
+}
+
+/*
+ Marks a clusters as unusable, due to physical disk damage.
+*/
+int
+fat_table_set_bad (FatTable* ft, FatCluster cluster)
+{
+ if (!fat_table_is_bad (ft, cluster))
+ ft->bad_cluster_count++;
+
+ switch (ft->fat_type) {
+ case FAT_TYPE_FAT12:
+ return fat_table_set (ft, cluster, 0xff7);
+
+ case FAT_TYPE_FAT16:
+ return fat_table_set (ft, cluster, 0xfff7);
+
+ case FAT_TYPE_FAT32:
+ return fat_table_set (ft, cluster, 0x0ffffff7);
+ }
+
+ return 0;
+}
+
+/*
+ marks <cluster> as unused/free/available
+*/
+int
+fat_table_set_avail (FatTable* ft, FatCluster cluster)
+{
+ return fat_table_set (ft, cluster, 0);
+}
+
+#endif /* !DISCOVER_ONLY */
+
+int _GL_ATTRIBUTE_CONST
+fat_table_entry_size (FatType fat_type)
+{
+ switch (fat_type) {
+ case FAT_TYPE_FAT12:
+ return 2; /* FIXME: how? */
+
+ case FAT_TYPE_FAT16:
+ return 2;
+
+ case FAT_TYPE_FAT32:
+ return 4;
+ }
+
+ return 0;
+}
diff --git a/libparted/fs/r/fat/table.h b/libparted/fs/r/fat/table.h
new file mode 100644
index 0000000..a70241b
--- /dev/null
+++ b/libparted/fs/r/fat/table.h
@@ -0,0 +1,74 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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/>.
+*/
+
+#ifndef PED_FAT_TABLE_H_INCLUDED
+#define PED_FAT_TABLE_H_INCLUDED
+
+typedef struct _FatTable FatTable;
+
+#include "fat.h"
+
+struct _FatTable {
+ void* table;
+ FatCluster size;
+ int raw_size;
+
+ FatType fat_type;
+ FatCluster cluster_count;
+ FatCluster free_cluster_count;
+ FatCluster bad_cluster_count;
+
+ FatCluster last_alloc;
+};
+
+extern FatTable* fat_table_new (FatType fat_type, FatCluster size);
+extern FatTable* fat_table_duplicate (const FatTable* ft);
+extern void fat_table_destroy (FatTable* ft);
+extern void fat_table_clear (FatTable* ft);
+extern int fat_table_set_cluster_count (FatTable* ft,
+ FatCluster new_cluster_count);
+
+extern int fat_table_read (FatTable* ft, const PedFileSystem* fs,
+ int table_num);
+extern int fat_table_write (const FatTable* ft, PedFileSystem* fs,
+ int table_num);
+extern int fat_table_write_all (const FatTable* ft, PedFileSystem* fs);
+extern int fat_table_compare (const FatTable* a, const FatTable* b);
+extern int fat_table_count_stats (FatTable* ft);
+
+extern FatCluster fat_table_get (const FatTable* ft, FatCluster cluster);
+extern int fat_table_set (FatTable* ft, FatCluster cluster, FatCluster value);
+
+extern FatCluster fat_table_alloc_cluster (FatTable* ft);
+extern FatCluster fat_table_alloc_check_cluster (FatTable* ft,
+ PedFileSystem* fs);
+
+extern int fat_table_is_bad (const FatTable* ft, FatCluster cluster);
+extern int fat_table_is_eof (const FatTable* ft, FatCluster cluster);
+extern int fat_table_is_empty (const FatTable* ft, FatCluster cluster);
+extern int fat_table_is_available (const FatTable* ft, FatCluster cluster);
+extern int fat_table_is_active (const FatTable* ft, FatCluster cluster);
+
+extern int fat_table_set_eof (FatTable* ft, FatCluster cluster);
+extern int fat_table_set_avail (FatTable* ft, FatCluster cluster);
+extern int fat_table_set_bad (FatTable* ft, FatCluster cluster);
+
+extern int fat_table_entry_size (FatType fat_type);
+
+#endif /* PED_FAT_TABLE_H_INCLUDED */
diff --git a/libparted/fs/r/fat/traverse.c b/libparted/fs/r/fat/traverse.c
new file mode 100644
index 0000000..42eeff9
--- /dev/null
+++ b/libparted/fs/r/fat/traverse.c
@@ -0,0 +1,368 @@
+/*
+ libparted
+ Copyright (C) 1998-2000, 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 "fat.h"
+#include "traverse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DISCOVER_ONLY
+
+#define NO_CLUSTER -1
+
+static char tmp_buffer [4096];
+
+int _GL_ATTRIBUTE_PURE
+fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info)
+{
+ return trav_info->buffer_size / sizeof (FatDirEntry);
+}
+
+/* returns 1 if there are no more directory entries in the directory being
+ * traversed, 0 otherwise.
+ */
+static int
+is_last_buffer (FatTraverseInfo* trav_info) {
+ FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
+
+ if (trav_info->is_legacy_root_dir)
+ return 1;
+ else
+ return fat_table_is_eof (fs_info->fat, trav_info->next_buffer);
+}
+
+static int
+write_root_dir (FatTraverseInfo* trav_info)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
+
+ if (!ped_geometry_write (trav_info->fs->geom, trav_info->dir_entries,
+ fs_info->root_dir_offset,
+ fs_info->root_dir_sector_count))
+ return 0;
+ if (!ped_geometry_sync (trav_info->fs->geom))
+ return 0;
+ trav_info->dirty = 0;
+ return 1;
+}
+
+static int
+write_dir_cluster (FatTraverseInfo* trav_info)
+{
+ if (!fat_write_sync_cluster (trav_info->fs,
+ (void*) trav_info->dir_entries,
+ trav_info->this_buffer))
+ return 0;
+ trav_info->dirty = 0;
+ return 1;
+}
+
+static int
+write_dir_buffer (FatTraverseInfo* trav_info)
+{
+ if (trav_info->is_legacy_root_dir)
+ return write_root_dir (trav_info);
+ else
+ return write_dir_cluster (trav_info);
+}
+
+static int
+read_next_dir_buffer (FatTraverseInfo* trav_info)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (trav_info->fs);
+
+ PED_ASSERT (!trav_info->is_legacy_root_dir);
+
+ trav_info->this_buffer = trav_info->next_buffer;
+
+ if (trav_info->this_buffer < 2
+ || trav_info->this_buffer >= fs_info->cluster_count + 2) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ "Cluster %ld in directory %s is outside file system!",
+ (long) trav_info->this_buffer,
+ trav_info->dir_name);
+ return 0;
+ }
+
+ trav_info->next_buffer
+ = fat_table_get (fs_info->fat, trav_info->this_buffer);
+
+ return fat_read_cluster (trav_info->fs, (void *) trav_info->dir_entries,
+ trav_info->this_buffer);
+}
+
+/* FIXME: put into fat_dir_entry_* operations */
+void
+fat_traverse_mark_dirty (FatTraverseInfo* trav_info)
+{
+ trav_info->dirty = 1;
+}
+
+FatTraverseInfo*
+fat_traverse_begin (PedFileSystem* fs, FatCluster start_cluster,
+ const char* dir_name)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatTraverseInfo* trav_info;
+
+ trav_info = (FatTraverseInfo*) ped_malloc (sizeof (FatTraverseInfo));
+ if (!trav_info)
+ goto error;
+
+ trav_info->dir_name = strdup (dir_name);
+ if (!trav_info->dir_name)
+ goto error_free_trav_info;
+
+ trav_info->fs = fs;
+ trav_info->is_legacy_root_dir
+ = (fs_info->fat_type == FAT_TYPE_FAT16) && (start_cluster == 0);
+ trav_info->dirty = 0;
+ trav_info->eof = 0;
+ trav_info->current_entry = -1;
+
+ if (trav_info->is_legacy_root_dir) {
+ trav_info->buffer_size = 512 * fs_info->root_dir_sector_count;
+ } else {
+ trav_info->next_buffer = start_cluster;
+ trav_info->buffer_size = fs_info->cluster_size;
+ }
+
+ trav_info->dir_entries
+ = (FatDirEntry*) ped_malloc (trav_info->buffer_size);
+ if (!trav_info->dir_entries)
+ goto error_free_dir_name;
+
+ if (trav_info->is_legacy_root_dir) {
+ if (!ped_geometry_read (fs->geom, trav_info->dir_entries,
+ fs_info->root_dir_offset,
+ fs_info->root_dir_sector_count))
+ goto error_free_dir_entries;
+ } else {
+ if (!read_next_dir_buffer (trav_info))
+ goto error_free_dir_entries;
+ }
+
+ return trav_info;
+
+error_free_dir_entries:
+ free (trav_info->dir_entries);
+error_free_dir_name:
+ free (trav_info->dir_name);
+error_free_trav_info:
+ free (trav_info);
+error:
+ return NULL;
+}
+
+int
+fat_traverse_complete (FatTraverseInfo* trav_info)
+{
+ if (trav_info->dirty) {
+ if (!write_dir_buffer (trav_info))
+ return 0;
+ }
+ free (trav_info->dir_entries);
+ free (trav_info->dir_name);
+ free (trav_info);
+ return 1;
+}
+
+FatTraverseInfo*
+fat_traverse_directory (FatTraverseInfo *trav_info, FatDirEntry* parent)
+{
+ strcpy (tmp_buffer, trav_info->dir_name);
+ fat_dir_entry_get_name (parent,
+ tmp_buffer + strlen (trav_info->dir_name));
+ strcat (tmp_buffer, "\\");
+
+ return fat_traverse_begin (trav_info->fs,
+ fat_dir_entry_get_first_cluster (parent, trav_info->fs),
+ tmp_buffer);
+}
+
+FatDirEntry*
+fat_traverse_next_dir_entry (FatTraverseInfo *trav_info)
+{
+ if (trav_info->eof)
+ return NULL;
+
+ trav_info->current_entry++;
+ if (trav_info->current_entry
+ >= fat_traverse_entries_per_buffer (trav_info)) {
+ if (trav_info->dirty) {
+ if (!write_dir_buffer (trav_info))
+ return NULL;
+ }
+
+ trav_info->current_entry = 0;
+ if (is_last_buffer (trav_info)) {
+ trav_info->eof = 1;
+ return NULL;
+ }
+ if (!read_next_dir_buffer (trav_info))
+ return NULL;
+ }
+ return trav_info->dir_entries + trav_info->current_entry;
+}
+
+FatCluster _GL_ATTRIBUTE_PURE
+fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry, PedFileSystem *fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ switch (fs_info->fat_type) {
+ case FAT_TYPE_FAT12:
+ case FAT_TYPE_FAT16:
+ return PED_LE16_TO_CPU (dir_entry->first_cluster);
+
+ case FAT_TYPE_FAT32:
+ return PED_LE16_TO_CPU (dir_entry->first_cluster_high)
+ * 65536L
+ + PED_LE16_TO_CPU (dir_entry->first_cluster);
+ }
+
+ return 0;
+}
+
+void
+fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs,
+ FatCluster cluster)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+
+ switch (fs_info->fat_type) {
+ case FAT_TYPE_FAT12:
+ PED_ASSERT (0);
+ break;
+
+ case FAT_TYPE_FAT16:
+ dir_entry->first_cluster = PED_CPU_TO_LE16 (cluster);
+ break;
+
+ case FAT_TYPE_FAT32:
+ dir_entry->first_cluster
+ = PED_CPU_TO_LE16 (cluster & 0xffff);
+ dir_entry->first_cluster_high
+ = PED_CPU_TO_LE16 (cluster / 0x10000);
+ break;
+ }
+}
+
+uint32_t _GL_ATTRIBUTE_PURE
+fat_dir_entry_get_length (FatDirEntry* dir_entry)
+{
+ return PED_LE32_TO_CPU (dir_entry->length);
+}
+
+int
+fat_dir_entry_is_null_term (const FatDirEntry* dir_entry)
+{
+ FatDirEntry null_entry;
+
+ memset (&null_entry, 0, sizeof (null_entry));
+ return memcmp (&null_entry, dir_entry, sizeof (null_entry)) == 0;
+}
+
+int _GL_ATTRIBUTE_PURE
+fat_dir_entry_is_active (FatDirEntry* dir_entry)
+{
+ if ((unsigned char) dir_entry->name[0] == DELETED_FLAG) return 0;
+ if ((unsigned char) dir_entry->name[0] == 0) return 0;
+ if ((unsigned char) dir_entry->name[0] == 0xF6) return 0;
+ return 1;
+}
+
+int _GL_ATTRIBUTE_PURE
+fat_dir_entry_is_file (FatDirEntry* dir_entry) {
+ if (dir_entry->attributes == VFAT_ATTR) return 0;
+ if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
+ if (!fat_dir_entry_is_active (dir_entry)) return 0;
+ if ((dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR) return 0;
+ return 1;
+}
+
+int _GL_ATTRIBUTE_PURE
+fat_dir_entry_is_system_file (FatDirEntry* dir_entry)
+{
+ if (!fat_dir_entry_is_file (dir_entry)) return 0;
+ return (dir_entry->attributes & SYSTEM_ATTR)
+ || (dir_entry->attributes & HIDDEN_ATTR);
+}
+
+int _GL_ATTRIBUTE_PURE
+fat_dir_entry_is_directory (FatDirEntry* dir_entry)
+{
+ if (dir_entry->attributes == VFAT_ATTR) return 0;
+ if (dir_entry->attributes & VOLUME_LABEL_ATTR) return 0;
+ if (!fat_dir_entry_is_active (dir_entry)) return 0;
+ return (dir_entry->attributes & DIRECTORY_ATTR) == DIRECTORY_ATTR;
+}
+
+int
+fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry, PedFileSystem* fs)
+{
+ FatSpecific* fs_info = FAT_SPECIFIC (fs);
+ FatCluster first_cluster;
+
+ if (!fat_dir_entry_is_file (dir_entry)
+ && !fat_dir_entry_is_directory (dir_entry))
+ return 0;
+
+ first_cluster = fat_dir_entry_get_first_cluster (dir_entry, fs);
+ if (first_cluster == 0
+ || fat_table_is_eof (fs_info->fat, first_cluster))
+ return 0;
+
+ return 1;
+}
+
+/*
+ decrypts silly DOS names to FILENAME.EXT
+*/
+void
+fat_dir_entry_get_name (const FatDirEntry *dir_entry, char *result) {
+ size_t i;
+ const char *src;
+ const char *ext;
+
+ src = dir_entry->name;
+
+ for (i=0; i < sizeof dir_entry->name; i++) {
+ if (src[i] == ' ' || src[i] == 0) break;
+ *result++ = src[i];
+ }
+
+ ext = (const char *) dir_entry->extension;
+ if (ext[0] != ' ' && ext[0] != 0) {
+ *result++ = '.';
+ for (i=0; i < sizeof dir_entry->extension; i++) {
+ if (ext[i] == ' ' || ext[i] == 0) break;
+ *result++ = ext[i];
+ }
+ }
+
+ *result = 0;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/fat/traverse.h b/libparted/fs/r/fat/traverse.h
new file mode 100644
index 0000000..02318ba
--- /dev/null
+++ b/libparted/fs/r/fat/traverse.h
@@ -0,0 +1,75 @@
+/*
+ libparted
+ Copyright (C) 1998-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/>.
+*/
+
+#ifndef TRAVERSE_H_INCLUDED
+#define TRAVERSE_H_INCLUDED
+
+#include "fatio.h"
+
+typedef struct _FatTraverseInfo FatTraverseInfo;
+
+struct _FatTraverseInfo {
+ PedFileSystem* fs;
+ char* dir_name;
+
+ int is_legacy_root_dir;
+ int dirty;
+ int eof;
+
+ FatDirEntry* dir_entries;
+ int current_entry;
+ FatCluster this_buffer, next_buffer;
+ int buffer_size;
+};
+
+extern int fat_traverse_entries_per_buffer (FatTraverseInfo* trav_info);
+
+/* starts traversal at an arbitary cluster. if start_cluster==0, then uses
+ root directory */
+extern FatTraverseInfo* fat_traverse_begin (PedFileSystem* fs,
+ FatCluster start_cluster,
+ const char* dir_name);
+
+extern int fat_traverse_complete (FatTraverseInfo* trav_info);
+
+extern FatTraverseInfo* fat_traverse_directory (FatTraverseInfo* trav_info,
+ FatDirEntry* parent);
+
+extern void fat_traverse_mark_dirty (FatTraverseInfo* trav_info);
+
+extern FatDirEntry* fat_traverse_next_dir_entry (FatTraverseInfo* trav_info);
+
+extern FatCluster fat_dir_entry_get_first_cluster (FatDirEntry* dir_entry,
+ PedFileSystem* fs);
+
+extern void fat_dir_entry_set_first_cluster (FatDirEntry* dir_entry,
+ PedFileSystem* fs, FatCluster cluster);
+
+extern uint32_t fat_dir_entry_get_length (FatDirEntry* dir_entry);
+
+extern int fat_dir_entry_is_null_term (const FatDirEntry* dir_entry);
+extern int fat_dir_entry_is_file (FatDirEntry* dir_entry);
+extern int fat_dir_entry_is_system_file (FatDirEntry* dir_entry);
+extern int fat_dir_entry_is_directory (FatDirEntry* dir_entry);
+extern void fat_dir_entry_get_name (const FatDirEntry* dir_entry, char* result);
+extern int fat_dir_entry_is_active (FatDirEntry* dir_entry);
+extern int fat_dir_entry_has_first_cluster (FatDirEntry* dir_entry,
+ PedFileSystem* fs);
+
+#endif /* TRAVERSE_H_INCLUDED */
diff --git a/libparted/fs/r/filesys.c b/libparted/fs/r/filesys.c
new file mode 100644
index 0000000..856238c
--- /dev/null
+++ b/libparted/fs/r/filesys.c
@@ -0,0 +1,320 @@
+/* libparted - a library for manipulating disk partitions
+ Copyright (C) 1999-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/>.
+*/
+
+/** \file filesys.c */
+
+/**
+ * \addtogroup PedFileSystem
+ *
+ * \note File systems exist on a PedGeometry - NOT a PedPartition.
+ *
+ * @{
+ */
+
+#include <config.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 */
+
+#define STREQ(a, b) (strcmp (a, b) == 0)
+
+#ifndef MIN
+# define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+typedef PedFileSystem * (*open_fn_t) (PedGeometry *);
+extern PedFileSystem *hfsplus_open (PedGeometry *);
+extern PedFileSystem *hfs_open (PedGeometry *);
+extern PedFileSystem *fat_open (PedGeometry *);
+
+typedef int (*close_fn_t) (PedFileSystem *);
+extern int hfsplus_close (PedFileSystem *);
+extern int hfs_close (PedFileSystem *);
+extern int fat_close (PedFileSystem *);
+
+typedef int (*resize_fn_t) (PedFileSystem *fs, PedGeometry *geom,
+ PedTimer *timer);
+extern int hfsplus_resize (PedFileSystem *fs, PedGeometry *geom,
+ PedTimer *timer);
+extern int hfs_resize (PedFileSystem *fs, PedGeometry *geom,
+ PedTimer *timer);
+extern int fat_resize (PedFileSystem *fs, PedGeometry *geom,
+ PedTimer *timer);
+
+typedef PedConstraint * (*resize_constraint_fn_t) (PedFileSystem const *fs);
+extern PedConstraint *hfsplus_get_resize_constraint (PedFileSystem const *fs);
+extern PedConstraint *hfs_get_resize_constraint (PedFileSystem const *fs);
+extern PedConstraint *fat_get_resize_constraint (PedFileSystem const *fs);
+
+static bool
+is_hfs_plus (char const *fs_type_name)
+{
+ return STREQ (fs_type_name, "hfsx") || STREQ (fs_type_name, "hfs+");
+}
+
+static open_fn_t
+open_fn (char const *fs_type_name)
+{
+ if (is_hfs_plus (fs_type_name))
+ return hfsplus_open;
+ if (STREQ (fs_type_name, "hfs"))
+ return hfs_open;
+ if (strncmp (fs_type_name, "fat", 3) == 0)
+ return fat_open;
+ return NULL;
+}
+
+static close_fn_t
+close_fn (char const *fs_type_name)
+{
+ if (is_hfs_plus (fs_type_name))
+ return hfsplus_close;
+ if (STREQ (fs_type_name, "hfs"))
+ return hfs_close;
+ if (strncmp (fs_type_name, "fat", 3) == 0)
+ return fat_close;
+ return NULL;
+}
+
+static resize_fn_t
+resize_fn (char const *fs_type_name)
+{
+ if (is_hfs_plus (fs_type_name))
+ return hfsplus_resize;
+ if (STREQ (fs_type_name, "hfs"))
+ return hfs_resize;
+ if (strncmp (fs_type_name, "fat", 3) == 0)
+ return fat_resize;
+ return NULL;
+}
+
+static resize_constraint_fn_t
+resize_constraint_fn (char const *fs_type_name)
+{
+ if (is_hfs_plus (fs_type_name))
+ return hfsplus_get_resize_constraint;
+ if (STREQ (fs_type_name, "hfs"))
+ return hfs_get_resize_constraint;
+ if (strncmp (fs_type_name, "fat", 3) == 0)
+ return fat_get_resize_constraint;
+ return NULL;
+}
+
+/**
+ * This function opens the file system stored on \p geom, if it
+ * can find one.
+ * It is often called in the following manner:
+ * \code
+ * fs = ped_file_system_open (&part.geom)
+ * \endcode
+ *
+ * \throws PED_EXCEPTION_ERROR if file system could not be detected
+ * \throws PED_EXCEPTION_ERROR if the file system is bigger than its volume
+ * \throws PED_EXCEPTION_NO_FEATURE if opening of a file system stored on
+ * \p geom is not implemented
+ *
+ * \return a PedFileSystem on success, \c NULL on failure.
+ */
+PedFileSystem *
+ped_file_system_open (PedGeometry* geom)
+{
+ PED_ASSERT (geom != NULL);
+
+ if (!ped_device_open (geom->dev))
+ goto error;
+
+ PedFileSystemType *type = ped_file_system_probe (geom);
+ if (!type) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("Could not detect file system."));
+ goto error_close_dev;
+ }
+
+ open_fn_t open_f = open_fn (type->name);
+ if (open_f == NULL) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("resizing %s file systems is not supported"),
+ type->name);
+ goto error_close_dev;
+ }
+
+ PedGeometry *probed_geom = ped_file_system_probe_specific (type, geom);
+ if (!probed_geom)
+ goto error_close_dev;
+ if (!ped_geometry_test_inside (geom, probed_geom)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The file system is bigger than its volume!"))
+ != PED_EXCEPTION_IGNORE)
+ goto error_destroy_probed_geom;
+ }
+
+ PedFileSystem *fs = (*open_f) (probed_geom);
+ if (!fs)
+ goto error_destroy_probed_geom;
+ ped_geometry_destroy (probed_geom);
+ fs->type = type;
+ return fs;
+
+error_destroy_probed_geom:
+ ped_geometry_destroy (probed_geom);
+error_close_dev:
+ ped_device_close (geom->dev);
+error:
+ return NULL;
+}
+
+/**
+ * Close file system \p fs.
+ *
+ * \return \c 1 on success, \c 0 on failure
+ */
+int
+ped_file_system_close (PedFileSystem* fs)
+{
+ PED_ASSERT (fs != NULL);
+ PedDevice *dev = fs->geom->dev;
+ close_fn_t fn = close_fn (fs->type->name);
+
+ if (!fn || !(fn (fs)))
+ goto error_close_dev;
+ ped_device_close (dev);
+ return 1;
+
+error_close_dev:
+ ped_device_close (dev);
+ return 0;
+}
+
+/**
+ * This function erases all file system signatures that indicate that a
+ * file system occupies a given region described by \p geom.
+ * After this operation ped_file_system_probe() won't detect any file system.
+ *
+ * \return \c 1 on success, \c 0 on failure
+ */
+static int
+ped_file_system_clobber (PedGeometry* geom)
+{
+ PED_ASSERT (geom != NULL);
+
+ if (!ped_device_open (geom->dev))
+ return 0;
+
+ /* Clear the first three and the last two sectors, albeit fewer
+ when GEOM is too small. */
+ PedSector len = MIN (geom->length, geom->dev->length);
+
+ int ok = (len <= 5
+ ? ptt_geom_clear_sectors (geom, 0, len)
+ : (ptt_geom_clear_sectors (geom, 0, 3)
+ && ptt_geom_clear_sectors (geom, geom->dev->length - 2, 2)));
+
+ ped_device_close (geom->dev);
+ return !!ok;
+}
+
+/* This function erases all signatures that indicate the presence of
+ * a file system in a particular region, without erasing any data
+ * contained inside the "exclude" region.
+ */
+static int
+ped_file_system_clobber_exclude (PedGeometry* geom,
+ const PedGeometry* exclude)
+{
+ PedGeometry* clobber_geom;
+ int status;
+
+ if (ped_geometry_test_sector_inside (exclude, geom->start))
+ return 1;
+
+ clobber_geom = ped_geometry_duplicate (geom);
+ if (ped_geometry_test_overlap (clobber_geom, exclude))
+ ped_geometry_set_end (clobber_geom, exclude->start - 1);
+
+ status = ped_file_system_clobber (clobber_geom);
+ ped_geometry_destroy (clobber_geom);
+ return status;
+}
+
+/**
+ * Resize \p fs to new geometry \p geom.
+ *
+ * \p geom should satisfy the ped_file_system_get_resize_constraint().
+ * (This isn't asserted, so it's not a bug not to... just it's likely
+ * to fail ;) If \p timer is non-NULL, it is used as the progress meter.
+ *
+ * \throws PED_EXCEPTION_NO_FEATURE if resizing of file system \p fs
+ * is not implemented yet
+ *
+ * \return \c 0 on failure
+ */
+int
+ped_file_system_resize (PedFileSystem *fs, PedGeometry *geom, PedTimer *timer)
+{
+ PED_ASSERT (fs != NULL);
+ PED_ASSERT (geom != NULL);
+
+ resize_fn_t resize_f = resize_fn (fs->type->name);
+ if (resize_f == NULL) {
+ ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+ _("resizing %s file systems is not supported"),
+ fs->type->name);
+ return 0;
+ }
+
+ if (!ped_file_system_clobber_exclude (geom, fs->geom))
+ return 0;
+
+ return resize_f (fs, geom, timer);
+}
+
+/**
+ * Return a constraint that represents all of the possible ways the
+ * file system \p fs can be resized with ped_file_system_resize().
+ * This takes into account the amount of used space on
+ * the filesystem \p fs and the capabilities of the resize algorithm.
+ * Hints:
+ * -# if constraint->start_align->grain_size == 0, or
+ * constraint->start_geom->length == 1, then the start cannot be moved
+ * -# constraint->min_size is the minimum size you can resize the partition
+ * to. You might want to tell the user this ;-).
+ *
+ * \return a PedConstraint on success, \c NULL on failure
+ */
+PedConstraint *
+ped_file_system_get_resize_constraint (const PedFileSystem *fs)
+{
+ PED_ASSERT (fs != NULL);
+
+ resize_constraint_fn_t resize_constraint_f =
+ resize_constraint_fn (fs->type->name);
+ if (resize_constraint_f == NULL)
+ return NULL;
+
+ return resize_constraint_f (fs);
+}
diff --git a/libparted/fs/r/hfs/advfs.c b/libparted/fs/r/hfs/advfs.c
new file mode 100644
index 0000000..cb66e9e
--- /dev/null
+++ b/libparted/fs/r/hfs/advfs.c
@@ -0,0 +1,332 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "file.h"
+
+#include "advfs.h"
+
+/* - if a < b, 0 if a == b, + if a > b */
+/* Comparaison is done in the following order : */
+/* CNID, then fork type, then start block */
+/* Note that HFS implementation in linux has a bug */
+/* in this function */
+static int
+hfs_extent_key_cmp(HfsPrivateGenericKey* a, HfsPrivateGenericKey* b)
+{
+ HfsExtentKey* key1 = (HfsExtentKey*) a;
+ HfsExtentKey* key2 = (HfsExtentKey*) b;
+
+ /* do NOT use a substraction, because */
+ /* 0xFFFFFFFF - 1 = 0xFFFFFFFE so this */
+ /* would return -2, despite the fact */
+ /* 0xFFFFFFFF > 1 !!! (this is the 2.4 bug) */
+ if (key1->file_ID != key2->file_ID)
+ return PED_BE32_TO_CPU(key1->file_ID) <
+ PED_BE32_TO_CPU(key2->file_ID) ?
+ -1 : +1;
+
+ if (key1->type != key2->type)
+ return (int)(key1->type - key2->type);
+
+ if (key1->start == key2->start)
+ return 0;
+ /* the whole thing wont work with 16 bits ints */
+ /* anyway */
+ return (int)( PED_BE16_TO_CPU(key1->start) -
+ PED_BE16_TO_CPU(key2->start) );
+}
+
+/* do a B-Tree lookup */
+/* read the first record immediatly inferior or egal to the given key */
+/* return 0 on error */
+/* record_out _must_ be large enough to receive record_size bytes */
+/* WARNING : the compare function called only handle Extents BTree */
+/* so modify this function if you want to do lookup in */
+/* other BTrees has well */
+int
+hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
+ void *record_out, unsigned int record_size,
+ HfsCPrivateLeafRec* record_ref)
+{
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+ HfsHeaderRecord* header;
+ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
+ HfsPrivateGenericKey* record_key = NULL;
+ unsigned int node_number, record_number;
+ int i;
+ uint16_t record_pos;
+
+ /* Read the header node */
+ if (!hfs_file_read_sector(b_tree_file, node, 0))
+ return 0;
+ uint16_t offset;
+ memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
+ header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
+
+ /* Get the node number of the root */
+ node_number = PED_BE32_TO_CPU(header->root_node);
+ if (!node_number)
+ return 0;
+
+ /* Read the root node */
+ if (!hfs_file_read_sector(b_tree_file, node, node_number))
+ return 0;
+
+ /* Follow the white rabbit */
+ while (1) {
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = record_number; i; i--) {
+ uint16_t value;
+ memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
+ record_pos = PED_BE16_TO_CPU(value);
+ record_key = (HfsPrivateGenericKey*) (node + record_pos);
+ /* check for obvious error in FS */
+ if ((record_pos< HFS_FIRST_REC)
+ || (record_pos>= PED_SECTOR_SIZE_DEFAULT
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ return 0;
+ }
+ if (hfs_extent_key_cmp(record_key, key) <= 0)
+ break;
+ }
+ if (!i) return 0;
+ if (desc->type == HFS_IDX_NODE) {
+ unsigned int skip;
+
+ skip = (1 + record_key->key_length + 1) & ~1;
+ uint32_t value;
+ memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
+ node_number = PED_BE32_TO_CPU(value);
+ if (!hfs_file_read_sector(b_tree_file, node,
+ node_number))
+ return 0;
+ } else
+ break;
+ }
+
+ /* copy the result if needed */
+ if (record_size)
+ memcpy (record_out, record_key, record_size);
+
+ /* send record reference if needed */
+ if (record_ref) {
+ record_ref->node_size = 1; /* in sectors */
+ record_ref->node_number = node_number;
+ record_ref->record_pos = record_pos;
+ record_ref->record_number = i;
+ }
+
+ /* success */
+ return 1;
+}
+
+/* free the bad blocks linked list */
+void
+hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first)
+{
+ HfsPrivateLinkExtent* next;
+
+ while (first) {
+ next = first->next;
+ free (first);
+ first = next;
+ }
+}
+
+/* This function reads bad blocks extents in the extents file
+ and store it in f.s. specific data of fs */
+int
+hfs_read_bad_blocks (const PedFileSystem *fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+
+ if (priv_data->bad_blocks_loaded)
+ return 1;
+
+ {
+ uint8_t record[sizeof (HfsExtentKey)
+ + sizeof (HfsExtDataRec)];
+ HfsExtentKey search;
+ HfsExtentKey* ret_key = (HfsExtentKey*) record;
+ HfsExtDescriptor* ret_cache = (HfsExtDescriptor*)
+ (record + sizeof (HfsExtentKey));
+ unsigned int block, last_start, first_pass = 1;
+
+ search.key_length = sizeof (HfsExtentKey) - 1;
+ search.type = HFS_DATA_FORK;
+ search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
+
+ last_start = -1; block = 0;
+ while (1) {
+ int i;
+
+ search.start = PED_CPU_TO_BE16 (block);
+ if (!hfs_btree_search (priv_data->extent_file,
+ (HfsPrivateGenericKey*) &search,
+ record, sizeof (record), NULL)
+ || ret_key->file_ID != search.file_ID
+ || ret_key->type != search.type) {
+ if (first_pass)
+ break;
+ else
+ goto errbb;
+ }
+ if (PED_BE16_TO_CPU (ret_key->start) == last_start)
+ break;
+
+ last_start = PED_BE16_TO_CPU (ret_key->start);
+ for (i = 0; i < HFS_EXT_NB; i++) {
+ if (ret_cache[i].block_count) {
+ HfsPrivateLinkExtent* new_xt =
+ (HfsPrivateLinkExtent*) ped_malloc (
+ sizeof (HfsPrivateLinkExtent));
+ if (!new_xt)
+ goto errbb;
+ new_xt->next = priv_data->bad_blocks_xtent_list;
+ memcpy(&(new_xt->extent), ret_cache+i,
+ sizeof (HfsExtDescriptor));
+ priv_data->bad_blocks_xtent_list = new_xt;
+ priv_data->bad_blocks_xtent_nb++;
+ block += PED_BE16_TO_CPU (
+ ret_cache[i].block_count);
+ }
+ }
+ first_pass = 0;
+ }
+
+ priv_data->bad_blocks_loaded = 1;
+ return 1;}
+
+errbb: hfs_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
+ priv_data->bad_blocks_xtent_list=NULL;
+ priv_data->bad_blocks_xtent_nb=0;
+ return 0;
+}
+
+/* This function check if fblock is a bad block */
+int _GL_ATTRIBUTE_PURE
+hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsPrivateLinkExtent* walk;
+
+ for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) {
+ /* Won't compile without the strange cast ! gcc bug ? */
+ /* or maybe C subtilties... */
+ if ((fblock >= PED_BE16_TO_CPU (walk->extent.start_block)) &&
+ (fblock < (unsigned int) (PED_BE16_TO_CPU (
+ walk->extent.start_block)
+ + PED_BE16_TO_CPU (
+ walk->extent.block_count))))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This function returns the first sector of the last free block of an
+ HFS volume we can get after a hfs_pack_free_space_from_block call */
+/* On error this function returns 0 */
+PedSector
+hfs_get_empty_end (const PedFileSystem *fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
+ unsigned int block, last_bad, end_free_blocks;
+
+ /* find the next block to the last bad block of the volume */
+ if (!hfs_read_bad_blocks (fs))
+ return 0;
+
+ HfsPrivateLinkExtent* l;
+ last_bad = 0;
+ for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
+ if ((unsigned int) PED_BE16_TO_CPU (l->extent.start_block)
+ + PED_BE16_TO_CPU (l->extent.block_count) > last_bad)
+ last_bad = PED_BE16_TO_CPU (l->extent.start_block)
+ + PED_BE16_TO_CPU (l->extent.block_count);
+ }
+
+ /* Count the free blocks from last_bad to the end of the volume */
+ end_free_blocks = 0;
+ for (block = last_bad;
+ block < PED_BE16_TO_CPU (mdb->total_blocks);
+ block++) {
+ if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ end_free_blocks++;
+ }
+
+ /* Calculate the block that will by the first free at the
+ end of the volume */
+ block = PED_BE16_TO_CPU (mdb->total_blocks) - end_free_blocks;
+
+ return (PedSector) PED_BE16_TO_CPU (mdb->start_block)
+ + (PedSector) block * (PED_BE32_TO_CPU (mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+}
+
+/* return the block which should be used to pack data to have at
+ least free fblock blocks at the end of the volume */
+unsigned int _GL_ATTRIBUTE_PURE
+hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ unsigned int block;
+
+ for (block = PED_BE16_TO_CPU (priv_data->mdb->total_blocks) - 1;
+ block && fblock;
+ block--) {
+ if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ fblock--;
+ }
+
+ while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ block--;
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ block++;
+
+ return block;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/advfs.h b/libparted/fs/r/hfs/advfs.h
new file mode 100644
index 0000000..094298e
--- /dev/null
+++ b/libparted/fs/r/hfs/advfs.h
@@ -0,0 +1,49 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _ADVFS_H
+#define _ADVFS_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfs_btree_search (HfsPrivateFile* b_tree_file, HfsPrivateGenericKey* key,
+ void *record_out, unsigned int record_size,
+ HfsCPrivateLeafRec* record_ref);
+
+void
+hfs_free_bad_blocks_list(HfsPrivateLinkExtent* first);
+
+int
+hfs_read_bad_blocks (const PedFileSystem *fs);
+
+int
+hfs_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
+
+PedSector
+hfs_get_empty_end (const PedFileSystem *fs);
+
+unsigned int
+hfs_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
+
+#endif /* _ADVFS_H */
diff --git a/libparted/fs/r/hfs/advfs_plus.c b/libparted/fs/r/hfs/advfs_plus.c
new file mode 100644
index 0000000..6104460
--- /dev/null
+++ b/libparted/fs/r/hfs/advfs_plus.c
@@ -0,0 +1,385 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "advfs.h"
+#include "file_plus.h"
+
+#include "advfs_plus.h"
+
+/* - if a < b, 0 if a == b, + if a > b */
+/* Comparaison is done in the following order : */
+/* CNID, then fork type, then start block */
+static int
+hfsplus_extent_key_cmp(HfsPPrivateGenericKey* a, HfsPPrivateGenericKey* b)
+{
+ HfsPExtentKey* key1 = (HfsPExtentKey*) a;
+ HfsPExtentKey* key2 = (HfsPExtentKey*) b;
+
+ if (key1->file_ID != key2->file_ID)
+ return PED_BE32_TO_CPU(key1->file_ID) <
+ PED_BE32_TO_CPU(key2->file_ID) ?
+ -1 : +1;
+
+ if (key1->type != key2->type)
+ return (int)(key1->type - key2->type);
+
+ if (key1->start == key2->start)
+ return 0;
+ return PED_BE32_TO_CPU(key1->start) <
+ PED_BE32_TO_CPU(key2->start) ?
+ -1 : +1;
+}
+
+/* do a B-Tree lookup */
+/* read the first record immediatly inferior or egal to the given key */
+/* return 0 on error */
+/* record_out _must_ be large enough to receive the whole record (key + data) */
+/* WARNING : the search function called only handle Extents BTree */
+/* so modify this function if you want to do lookup in */
+/* other BTrees has well */
+int
+hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
+ void *record_out, unsigned int record_size,
+ HfsCPrivateLeafRec* record_ref)
+{
+ uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
+ uint8_t* node;
+ HfsPHeaderRecord* header;
+ HfsPPrivateGenericKey* record_key = NULL;
+ unsigned int node_number, record_number, size, bsize;
+ int i;
+ uint16_t record_pos;
+
+ /* Read the header node */
+ if (!hfsplus_file_read_sector(b_tree_file, node_1, 0))
+ return 0;
+ header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC);
+
+ /* Get the node number of the root */
+ node_number = PED_BE32_TO_CPU (header->root_node);
+ if (!node_number)
+ return 0;
+
+ /* Get the size of a node in sectors and allocate buffer */
+ size = (bsize = PED_BE16_TO_CPU (header->node_size)) / PED_SECTOR_SIZE_DEFAULT;
+ node = ped_malloc (bsize);
+ if (!node)
+ return 0;
+ HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
+
+ /* Read the root node */
+ if (!hfsplus_file_read (b_tree_file, node,
+ (PedSector) node_number * size, size))
+ return 0;
+
+ /* Follow the white rabbit */
+ while (1) {
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = record_number; i; i--) {
+ uint16_t value;
+ memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
+ record_pos = PED_BE16_TO_CPU(value);
+ record_key = (HfsPPrivateGenericKey*) (node + record_pos);
+ /* check for obvious error in FS */
+ if ((record_pos < HFS_FIRST_REC)
+ || (record_pos >= (signed)bsize
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ free (node);
+ return 0;
+ }
+ if (hfsplus_extent_key_cmp(record_key, key) <= 0)
+ break;
+ }
+ if (!i) { free (node); return 0; }
+ if (desc->type == HFS_IDX_NODE) {
+ unsigned int skip;
+
+ skip = ( 2 + PED_BE16_TO_CPU (record_key->key_length)
+ + 1 ) & ~1;
+ uint32_t value;
+ memcpy(&value, node+record_pos+skip, sizeof(uint32_t));
+ node_number = PED_BE32_TO_CPU(value);
+ if (!hfsplus_file_read(b_tree_file, node,
+ (PedSector) node_number * size,
+ size)) {
+ free (node);
+ return 0;
+ }
+ } else
+ break;
+ }
+
+ /* copy the result if needed */
+ if (record_size)
+ memcpy (record_out, record_key, record_size);
+
+ /* send record reference if needed */
+ if (record_ref) {
+ record_ref->node_size = size; /* in sectors */
+ record_ref->node_number = node_number;
+ record_ref->record_pos = record_pos;
+ record_ref->record_number = i;
+ }
+
+ /* success */
+ free (node);
+ return 1;
+}
+
+/* free the bad blocks linked list */
+void
+hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first)
+{
+ HfsPPrivateLinkExtent* next;
+
+ while (first) {
+ next = first->next;
+ free (first);
+ first = next;
+ }
+}
+
+/* This function reads bad blocks extents in the extents file
+ and store it in f.s. specific data of fs */
+int
+hfsplus_read_bad_blocks (const PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+
+ if (priv_data->bad_blocks_loaded)
+ return 1;
+
+ {
+ uint8_t record[sizeof (HfsPExtentKey)
+ + sizeof (HfsPExtDataRec)];
+ HfsPExtentKey search;
+ HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
+ HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
+ (record + sizeof (HfsPExtentKey));
+ int block, first_pass = 1;
+ unsigned int last_start;
+
+ search.key_length = sizeof (HfsExtentKey) - 2;
+ search.type = HFS_DATA_FORK;
+ search.pad = 0;
+ search.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
+
+ last_start = -1; block = 0;
+ while (1) {
+ int i;
+
+ search.start = PED_CPU_TO_BE32 (block);
+ if (!hfsplus_btree_search (priv_data->extents_file,
+ (HfsPPrivateGenericKey*) &search,
+ record, sizeof (record), NULL)
+ || ret_key->file_ID != search.file_ID
+ || ret_key->type != search.type) {
+ if (first_pass)
+ break;
+ else
+ goto errbbp;
+ }
+ if (PED_BE32_TO_CPU (ret_key->start) == last_start)
+ break;
+
+ last_start = PED_BE32_TO_CPU (ret_key->start);
+ for (i = 0; i < HFSP_EXT_NB; i++) {
+ if (ret_cache[i].block_count) {
+ HfsPPrivateLinkExtent* new_xt =
+ (HfsPPrivateLinkExtent*) ped_malloc (
+ sizeof (HfsPPrivateLinkExtent));
+ if (!new_xt)
+ goto errbbp;
+ new_xt->next = priv_data->bad_blocks_xtent_list;
+ memcpy (&(new_xt->extent), ret_cache+i,
+ sizeof (HfsPExtDescriptor));
+ priv_data->bad_blocks_xtent_list = new_xt;
+ priv_data->bad_blocks_xtent_nb++;
+ block += PED_BE32_TO_CPU (
+ ret_cache[i].block_count);
+ }
+ }
+ first_pass = 0;
+ }
+
+ priv_data->bad_blocks_loaded = 1;
+ return 1;}
+
+errbbp: hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
+ priv_data->bad_blocks_xtent_list=NULL;
+ priv_data->bad_blocks_xtent_nb=0;
+ return 0;
+}
+
+/* This function check if fblock is a bad block */
+int _GL_ATTRIBUTE_PURE
+hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPPrivateLinkExtent* walk;
+
+ for (walk = priv_data->bad_blocks_xtent_list; walk; walk = walk->next) {
+ /* Won't compile without the strange cast ! gcc bug ? */
+ /* or maybe C subtilties... */
+ if ((fblock >= PED_BE32_TO_CPU (walk->extent.start_block)) &&
+ (fblock < (unsigned int)(PED_BE32_TO_CPU (
+ walk->extent.start_block)
+ + PED_BE32_TO_CPU (walk->extent.block_count))))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This function returns the first sector of the last free block of
+ an HFS+ volume we can get after a hfsplus_pack_free_space_from_block call */
+PedSector
+hfsplus_get_empty_end (const PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPVolumeHeader* vh = priv_data->vh;
+ unsigned int block, last_bad, end_free_blocks;
+
+ /* find the next block to the last bad block of the volume */
+ if (!hfsplus_read_bad_blocks (fs)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Bad blocks could not be read."));
+ return 0;
+ }
+
+ HfsPPrivateLinkExtent* l;
+ last_bad = 0;
+ for (l = priv_data->bad_blocks_xtent_list; l; l = l->next) {
+ if ((unsigned int) PED_BE32_TO_CPU (l->extent.start_block)
+ + PED_BE32_TO_CPU (l->extent.block_count) > last_bad)
+ last_bad = PED_BE32_TO_CPU (l->extent.start_block)
+ + PED_BE32_TO_CPU (l->extent.block_count);
+ }
+
+ /* Count the free blocks from last_bad to the end of the volume */
+ end_free_blocks = 0;
+ for (block = last_bad;
+ block < PED_BE32_TO_CPU (vh->total_blocks);
+ block++) {
+ if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ end_free_blocks++;
+ }
+
+ /* Calculate the block that will by the first free at
+ the end of the volume */
+ block = PED_BE32_TO_CPU (vh->total_blocks) - end_free_blocks;
+
+ return (PedSector) block * ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT );
+}
+
+/* On error, returns 0 */
+PedSector
+hfsplus_get_min_size (const PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ PedSector min_size;
+
+ /* don't need to add anything because every sector
+ can be part of allocation blocks in HFS+, and
+ the last block _must_ be reserved */
+ min_size = hfsplus_get_empty_end(fs);
+ if (!min_size) return 0;
+
+ if (priv_data->wrapper) {
+ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
+ priv_data->wrapper->type_specific;
+ unsigned int hfs_sect_block;
+ PedSector hgee;
+ hfs_sect_block =
+ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+ /*
+ * if hfs+ is embedded in an hfs wrapper then the new size is :
+ * the new size of the hfs+ volume rounded up to the size
+ * of hfs blocks
+ * + the minimum size of the hfs wrapper without any hfs+
+ * modification
+ * - the current size of the hfs+ volume in the hfs wrapper
+ */
+ hgee = hfs_get_empty_end(priv_data->wrapper);
+ if (!hgee) return 0;
+ min_size = ((min_size + hfs_sect_block - 1) / hfs_sect_block)
+ * hfs_sect_block
+ + hgee + 2
+ - (PedSector) PED_BE16_TO_CPU ( hfs_priv_data->mdb
+ ->old_new.embedded
+ .location.block_count )
+ * hfs_sect_block;
+ }
+
+ return min_size;
+}
+
+/* return the block which should be used to pack data to have
+ at least free fblock blocks at the end of the volume */
+unsigned int _GL_ATTRIBUTE_PURE
+hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ unsigned int block;
+
+ for (block = PED_BE32_TO_CPU (priv_data->vh->total_blocks) - 1;
+ block && fblock;
+ block--) {
+ if (!TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ fblock--;
+ }
+
+ while (block && !TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ block--;
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block))
+ block++;
+
+ return block;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/advfs_plus.h b/libparted/fs/r/hfs/advfs_plus.h
new file mode 100644
index 0000000..61972c2
--- /dev/null
+++ b/libparted/fs/r/hfs/advfs_plus.h
@@ -0,0 +1,52 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _ADVFS_PLUS_H
+#define _ADVFS_PLUS_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsplus_btree_search (HfsPPrivateFile* b_tree_file, HfsPPrivateGenericKey* key,
+ void *record_out, unsigned int record_size,
+ HfsCPrivateLeafRec* record_ref);
+
+void
+hfsplus_free_bad_blocks_list(HfsPPrivateLinkExtent* first);
+
+int
+hfsplus_read_bad_blocks (const PedFileSystem *fs);
+
+int
+hfsplus_is_bad_block (const PedFileSystem *fs, unsigned int fblock);
+
+PedSector
+hfsplus_get_empty_end (const PedFileSystem *fs);
+
+PedSector
+hfsplus_get_min_size (const PedFileSystem *fs);
+
+unsigned int
+hfsplus_find_start_pack (const PedFileSystem *fs, unsigned int fblock);
+
+#endif /* _ADVFS_PLUS_H */
diff --git a/libparted/fs/r/hfs/cache.c b/libparted/fs/r/hfs/cache.c
new file mode 100644
index 0000000..255f1fd
--- /dev/null
+++ b/libparted/fs/r/hfs/cache.c
@@ -0,0 +1,239 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+
+#include "cache.h"
+
+static HfsCPrivateCacheTable*
+hfsc_new_cachetable(unsigned int size)
+{
+ HfsCPrivateCacheTable* ret;
+
+ ret = (HfsCPrivateCacheTable*) ped_malloc(sizeof(*ret));
+ if (!ret) return NULL;
+
+ ret->next_cache = NULL;
+ ret->table_size = size;
+ ret->table_first_free = 0;
+
+ ret->table = ped_malloc(sizeof(*ret->table)*size);
+ if (!ret->table) { free(ret); return NULL; }
+ memset(ret->table, 0, sizeof(*ret->table)*size);
+
+ return ret;
+}
+
+HfsCPrivateCache*
+hfsc_new_cache(unsigned int block_number, unsigned int file_number)
+{
+ unsigned int cachetable_size, i;
+ HfsCPrivateCache* ret;
+
+ ret = (HfsCPrivateCache*) ped_malloc(sizeof(*ret));
+ if (!ret) return NULL;
+ ret->block_number = block_number;
+ /* following code avoid integer overflow */
+ ret->linked_ref_size = block_number > block_number + ((1<<CR_SHIFT)-1) ?
+ ( block_number >> CR_SHIFT ) + 1 :
+ ( block_number + ((1<<CR_SHIFT)-1) ) >> CR_SHIFT
+ ;
+
+ ret->linked_ref = (HfsCPrivateExtent**)
+ ped_malloc( sizeof(*ret->linked_ref)
+ * ret->linked_ref_size );
+ if (!ret->linked_ref) { free(ret); return NULL; }
+
+ cachetable_size = file_number + file_number / CR_OVER_DIV + CR_ADD_CST;
+ if (cachetable_size < file_number) cachetable_size = (unsigned) -1;
+ ret->first_cachetable_size = cachetable_size;
+ ret->table_list = hfsc_new_cachetable(cachetable_size);
+ if (!ret->table_list) {
+ free(ret->linked_ref);
+ free(ret);
+ return NULL;
+ }
+ ret->last_table = ret->table_list;
+
+ for (i = 0; i < ret->linked_ref_size; ++i)
+ ret->linked_ref[i] = NULL;
+
+ ret->needed_alloc_size = 0;
+
+ return ret;
+}
+
+static void
+hfsc_delete_cachetable(HfsCPrivateCacheTable* list)
+{
+ HfsCPrivateCacheTable* next;
+
+ while (list) {
+ free (list->table);
+ next = list->next_cache;
+ free (list);
+ list = next;
+ }
+}
+
+void
+hfsc_delete_cache(HfsCPrivateCache* cache)
+{
+ hfsc_delete_cachetable(cache->table_list);
+ free(cache->linked_ref);
+ free(cache);
+}
+
+HfsCPrivateExtent*
+hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
+ uint32_t block, uint16_t offset, uint8_t sbb,
+ uint8_t where, uint8_t ref_index)
+{
+ HfsCPrivateExtent* ext;
+ unsigned int idx = start >> CR_SHIFT;
+
+ PED_ASSERT(idx < cache->linked_ref_size);
+
+ for (ext = cache->linked_ref[idx];
+ ext && start != ext->ext_start;
+ ext = ext->next);
+
+ if (ext) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to register an extent starting at block "
+ "0x%X, but another one already exists at this "
+ "position. You should check the file system!"),
+ start);
+ return NULL;
+ }
+
+ if ( cache->last_table->table_first_free
+ == cache->last_table->table_size ) {
+ cache->last_table->next_cache =
+ hfsc_new_cachetable( ( cache->first_cachetable_size
+ / CR_NEW_ALLOC_DIV )
+ + CR_ADD_CST );
+ if (!cache->last_table->next_cache)
+ return NULL;
+ cache->last_table = cache->last_table->next_cache;
+ }
+
+ ext = cache->last_table->table+(cache->last_table->table_first_free++);
+
+ ext->ext_start = start;
+ ext->ext_length = length;
+ ext->ref_block = block;
+ ext->ref_offset = offset;
+ ext->sect_by_block = sbb;
+ ext->where = where;
+ ext->ref_index = ref_index;
+
+ ext->next = cache->linked_ref[idx];
+ cache->linked_ref[idx] = ext;
+
+ cache->needed_alloc_size = cache->needed_alloc_size >
+ (unsigned) PED_SECTOR_SIZE_DEFAULT * sbb ?
+ cache->needed_alloc_size :
+ (unsigned) PED_SECTOR_SIZE_DEFAULT * sbb;
+
+ return ext;
+}
+
+HfsCPrivateExtent* _GL_ATTRIBUTE_PURE
+hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start)
+{
+ HfsCPrivateExtent* ret;
+ unsigned int idx = start >> CR_SHIFT;
+
+ PED_ASSERT(idx < cache->linked_ref_size);
+
+ for (ret = cache->linked_ref[idx];
+ ret && start != ret->ext_start;
+ ret = ret->next);
+
+ return ret;
+}
+
+/* Can't fail if extent begining at old_start exists */
+/* Returns 0 if no such extent, or on error */
+HfsCPrivateExtent*
+hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
+ uint32_t new_start)
+{
+ HfsCPrivateExtent** ppext;
+ HfsCPrivateExtent* pext;
+
+ unsigned int idx1 = old_start >> CR_SHIFT;
+ unsigned int idx2 = new_start >> CR_SHIFT;
+
+ PED_ASSERT(idx1 < cache->linked_ref_size);
+ PED_ASSERT(idx2 < cache->linked_ref_size);
+
+ for (pext = cache->linked_ref[idx2];
+ pext && new_start != pext->ext_start;
+ pext = pext->next);
+
+ if (pext) {
+ ped_exception_throw (
+ PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to move an extent from block 0x%X to block "
+ "0x%X, but another one already exists at this "
+ "position. This should not happen!"),
+ old_start, new_start);
+ return NULL;
+ }
+
+ for (ppext = &(cache->linked_ref[idx1]);
+ (*ppext) && old_start != (*ppext)->ext_start;
+ ppext = &((*ppext)->next));
+
+ if (!(*ppext)) return NULL;
+
+ /* removing the extent from the cache */
+ pext = *ppext;
+ (*ppext) = pext->next;
+
+ /* change ext_start and insert the extent again */
+ pext->ext_start = new_start;
+ pext->next = cache->linked_ref[idx2];
+ cache->linked_ref[idx2] = pext;
+
+ return pext;
+}
+
+#endif /* DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/cache.h b/libparted/fs/r/hfs/cache.h
new file mode 100644
index 0000000..d009fd9
--- /dev/null
+++ b/libparted/fs/r/hfs/cache.h
@@ -0,0 +1,118 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef _CACHE_H
+#define _CACHE_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+/* CR => CACHE REF */
+#define CR_NULL 0 /* reserved */
+#define CR_PRIM_CAT 1
+#define CR_PRIM_EXT 2
+#define CR_PRIM_ATTR 3
+#define CR_PRIM_ALLOC 4
+#define CR_PRIM_START 5
+#define CR_BTREE_CAT 6
+#define CR_BTREE_ATTR 7
+#define CR_BTREE_EXT_0 8
+#define CR_BTREE_EXT_CAT 9
+#define CR_BTREE_EXT_EXT 10 /* should not happen ! */
+#define CR_BTREE_EXT_ATTR 11
+#define CR_BTREE_EXT_ALLOC 12
+#define CR_BTREE_EXT_START 13 /* unneeded in current code */
+#define CR_BTREE_CAT_JIB 14 /* journal info block */
+#define CR_BTREE_CAT_JL 15 /* journal */
+/* 16 -> 31 || high order bit */ /* reserved */
+
+/* tuning */
+#define CR_SHIFT 8 /* number of bits to shift start_block by */
+ /* to get the index of the linked list */
+#define CR_OVER_DIV 16 /* alloc a table for (1+1/CR_OVER_DIV) *
+ file_number + CR_ADD_CST */
+#define CR_ADD_CST 16
+#define CR_NEW_ALLOC_DIV 4 /* divide the size of the first alloc table
+ by this value to allocate next tables */
+
+/* See DOC for an explaination of this structure */
+/* Access read only from outside cache.c */
+struct _HfsCPrivateExtent {
+ struct _HfsCPrivateExtent* next;
+ uint32_t ext_start;
+ uint32_t ext_length;
+ uint32_t ref_block;
+ uint16_t ref_offset;
+ uint8_t sect_by_block;
+ unsigned where : 5;
+ unsigned ref_index : 3; /* 0 -> 7 */
+};
+typedef struct _HfsCPrivateExtent HfsCPrivateExtent;
+
+/* Internaly used by cache.c for custom memory managment only */
+struct _HfsCPrivateCacheTable {
+ struct _HfsCPrivateCacheTable* next_cache;
+ HfsCPrivateExtent* table;
+ unsigned int table_size;
+ unsigned int table_first_free;
+ /* first_elemt ? */
+};
+typedef struct _HfsCPrivateCacheTable HfsCPrivateCacheTable;
+
+/* Internaly used by cache.c for custom memory managment
+ and cache handling only */
+struct _HfsCPrivateCache {
+ HfsCPrivateCacheTable* table_list;
+ HfsCPrivateCacheTable* last_table;
+ HfsCPrivateExtent** linked_ref;
+ unsigned int linked_ref_size;
+ unsigned int block_number;
+ unsigned int first_cachetable_size;
+ unsigned int needed_alloc_size;
+};
+typedef struct _HfsCPrivateCache HfsCPrivateCache;
+
+HfsCPrivateCache*
+hfsc_new_cache(unsigned int block_number, unsigned int file_number);
+
+void
+hfsc_delete_cache(HfsCPrivateCache* cache);
+
+HfsCPrivateExtent*
+hfsc_cache_add_extent(HfsCPrivateCache* cache, uint32_t start, uint32_t length,
+ uint32_t block, uint16_t offset, uint8_t sbb,
+ uint8_t where, uint8_t index);
+
+HfsCPrivateExtent*
+hfsc_cache_search_extent(HfsCPrivateCache* cache, uint32_t start);
+
+HfsCPrivateExtent*
+hfsc_cache_move_extent(HfsCPrivateCache* cache, uint32_t old_start,
+ uint32_t new_start);
+
+static __inline__ unsigned int
+hfsc_cache_needed_buffer(HfsCPrivateCache* cache)
+{
+ return cache->needed_alloc_size;
+}
+
+#endif /* _CACHE_H */
diff --git a/libparted/fs/r/hfs/file.c b/libparted/fs/r/hfs/file.c
new file mode 100644
index 0000000..6024d84
--- /dev/null
+++ b/libparted/fs/r/hfs/file.c
@@ -0,0 +1,229 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "advfs.h"
+
+#include "file.h"
+
+/* Open the data fork of a file with its first three extents and its CNID */
+HfsPrivateFile*
+hfs_file_open (PedFileSystem *fs, uint32_t CNID,
+ HfsExtDataRec ext_desc, PedSector sect_nb)
+{
+ HfsPrivateFile* file;
+
+ file = (HfsPrivateFile*) ped_malloc (sizeof (HfsPrivateFile));
+ if (!file) return NULL;
+
+ file->fs = fs;
+ file->sect_nb = sect_nb;
+ file->CNID = CNID;
+ memcpy(file->first, ext_desc, sizeof (HfsExtDataRec));
+ file->start_cache = 0;
+
+ return file;
+}
+
+/* Close an HFS file */
+void
+hfs_file_close (HfsPrivateFile* file)
+{
+ free (file);
+}
+
+/* warning : only works on data forks */
+static int
+hfs_get_extent_containing (HfsPrivateFile* file, unsigned int block,
+ HfsExtDataRec cache, uint16_t* ptr_start_cache)
+{
+ uint8_t record[sizeof (HfsExtentKey)
+ + sizeof (HfsExtDataRec)];
+ HfsExtentKey search;
+ HfsExtentKey* ret_key = (HfsExtentKey*) record;
+ HfsExtDescriptor* ret_cache = (HfsExtDescriptor*)
+ (record + sizeof (HfsExtentKey));
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ file->fs->type_specific;
+
+ search.key_length = sizeof (HfsExtentKey) - 1;
+ search.type = HFS_DATA_FORK;
+ search.file_ID = file->CNID;
+ search.start = PED_CPU_TO_BE16 (block);
+
+ if (!hfs_btree_search (priv_data->extent_file,
+ (HfsPrivateGenericKey*) &search,
+ record, sizeof (record), NULL))
+ return 0;
+
+ if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
+ return 0;
+
+ memcpy (cache, ret_cache, sizeof(HfsExtDataRec));
+ *ptr_start_cache = PED_BE16_TO_CPU (ret_key->start);
+
+ return 1;
+}
+
+/* find and return the nth sector of a file */
+/* return 0 on error */
+static PedSector
+hfs_file_find_sector (HfsPrivateFile* file, PedSector sector)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ file->fs->type_specific;
+ unsigned int sect_by_block = PED_BE32_TO_CPU (
+ priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+ unsigned int i, s, vol_block;
+ unsigned int block = sector / sect_by_block;
+ unsigned int offset = sector % sect_by_block;
+
+ /* in the three first extent */
+ for (s = 0, i = 0; i < HFS_EXT_NB; i++) {
+ if ((block >= s) && ( block < s + PED_BE16_TO_CPU (
+ file->first[i].block_count))) {
+ vol_block = (block - s) + PED_BE16_TO_CPU (
+ file->first[i].start_block);
+ goto sector_found;
+ }
+ s += PED_BE16_TO_CPU (file->first[i].block_count);
+ }
+
+ /* in the three cached extent */
+ if (file->start_cache && block >= file->start_cache)
+ for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
+ if ((block >= s) && (block < s + PED_BE16_TO_CPU (
+ file->cache[i].block_count))) {
+ vol_block = (block - s) + PED_BE16_TO_CPU (
+ file->cache[i].start_block);
+ goto sector_found;
+ }
+ s += PED_BE16_TO_CPU (file->cache[i].block_count);
+ }
+
+ /* update cache */
+ if (!hfs_get_extent_containing (file, block, file->cache,
+ &(file->start_cache))) {
+ ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_CANCEL,
+ _("Could not update the extent cache for HFS file with "
+ "CNID %X."),
+ PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ /* in the three cached extent */
+ PED_ASSERT(file->start_cache && block >= file->start_cache);
+ for (s = file->start_cache, i = 0; i < HFS_EXT_NB; i++) {
+ if ((block >= s) && (block < s + PED_BE16_TO_CPU (
+ file->cache[i].block_count))) {
+ vol_block = (block - s) + PED_BE16_TO_CPU (
+ file->cache[i].start_block);
+ goto sector_found;
+ }
+ s += PED_BE16_TO_CPU (file->cache[i].block_count);
+ }
+
+ return 0;
+
+ sector_found:
+ return (PedSector) PED_BE16_TO_CPU (priv_data->mdb->start_block)
+ + (PedSector) vol_block * sect_by_block
+ + offset;
+}
+
+/* Read the nth sector of a file */
+/* return 0 on error */
+int
+hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector)
+{
+ PedSector abs_sector;
+
+ if (sector >= file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to read HFS file with CNID %X behind EOF."),
+ PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ abs_sector = hfs_file_find_sector (file, sector);
+ if (!abs_sector) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not find sector %lli of HFS file with "
+ "CNID %X."),
+ sector, PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ return ped_geometry_read (file->fs->geom, buf, abs_sector, 1);
+}
+
+/* Write the nth sector of a file */
+/* return 0 on error */
+int
+hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector)
+{
+ PedSector abs_sector;
+
+ if (sector >= file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to write HFS file with CNID %X behind EOF."),
+ PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ abs_sector = hfs_file_find_sector (file, sector);
+ if (!abs_sector) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not find sector %lli of HFS file with "
+ "CNID %X."),
+ sector, PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ return ped_geometry_write (file->fs->geom, buf, abs_sector, 1);
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/file.h b/libparted/fs/r/hfs/file.h
new file mode 100644
index 0000000..f8cb485
--- /dev/null
+++ b/libparted/fs/r/hfs/file.h
@@ -0,0 +1,42 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _FILE_H
+#define _FILE_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+HfsPrivateFile*
+hfs_file_open (PedFileSystem *fs, uint32_t CNID,
+ HfsExtDataRec ext_desc, PedSector sect_nb);
+
+void
+hfs_file_close (HfsPrivateFile* file);
+
+int
+hfs_file_read_sector (HfsPrivateFile* file, void *buf, PedSector sector);
+
+int
+hfs_file_write_sector (HfsPrivateFile* file, void *buf, PedSector sector);
+
+#endif /* _FILE_H */
diff --git a/libparted/fs/r/hfs/file_plus.c b/libparted/fs/r/hfs/file_plus.c
new file mode 100644
index 0000000..aeff5ee
--- /dev/null
+++ b/libparted/fs/r/hfs/file_plus.c
@@ -0,0 +1,274 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "advfs_plus.h"
+
+#include "file_plus.h"
+
+/* Open the data fork of a file with its first eight extents and its CNID */
+/* CNID and ext_desc must be in disc order, sect_nb in CPU order */
+/* return null on failure */
+HfsPPrivateFile*
+hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
+ HfsPExtDataRec ext_desc, PedSector sect_nb)
+{
+ HfsPPrivateFile* file;
+
+ file = (HfsPPrivateFile*) ped_malloc (sizeof (HfsPPrivateFile));
+ if (!file) return NULL;
+
+ file->fs = fs;
+ file->sect_nb = sect_nb;
+ file->CNID = CNID;
+ memcpy(file->first, ext_desc, sizeof (HfsPExtDataRec));
+ file->start_cache = 0;
+
+ return file;
+}
+
+/* Close an HFS+ file */
+void
+hfsplus_file_close (HfsPPrivateFile* file)
+{
+ free (file);
+}
+
+/* warning : only works on data forks */
+static int
+hfsplus_get_extent_containing (HfsPPrivateFile* file, unsigned int block,
+ HfsPExtDataRec cache, uint32_t* ptr_start_cache)
+{
+ uint8_t record[sizeof (HfsPExtentKey)
+ + sizeof (HfsPExtDataRec)];
+ HfsPExtentKey search;
+ HfsPExtentKey* ret_key = (HfsPExtentKey*) record;
+ HfsPExtDescriptor* ret_cache = (HfsPExtDescriptor*)
+ (record + sizeof (HfsPExtentKey));
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ file->fs->type_specific;
+
+ search.key_length = PED_CPU_TO_BE16 (sizeof (HfsPExtentKey) - 2);
+ search.type = HFS_DATA_FORK;
+ search.pad = 0;
+ search.file_ID = file->CNID;
+ search.start = PED_CPU_TO_BE32 (block);
+
+ if (!hfsplus_btree_search (priv_data->extents_file,
+ (HfsPPrivateGenericKey*) &search,
+ record, sizeof (record), NULL))
+ return 0;
+
+ if (ret_key->file_ID != search.file_ID || ret_key->type != search.type)
+ return 0;
+
+ memcpy (cache, ret_cache, sizeof(HfsPExtDataRec));
+ *ptr_start_cache = PED_BE32_TO_CPU (ret_key->start);
+
+ return 1;
+}
+
+/* find a sub extent contained in the desired area */
+/* and with the same starting point */
+/* return 0 in sector_count on error, or the physical area */
+/* on the volume corresponding to the logical area in the file */
+static HfsPPrivateExtent
+hfsplus_file_find_extent (HfsPPrivateFile* file, PedSector sector,
+ unsigned int nb)
+{
+ HfsPPrivateExtent ret = {0,0};
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ file->fs->type_specific;
+ unsigned int sect_by_block = PED_BE32_TO_CPU (
+ priv_data->vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+ unsigned int i, s, vol_block, size;
+ PedSector sect_size;
+ unsigned int block = sector / sect_by_block;
+ unsigned int offset = sector % sect_by_block;
+
+ /* in the 8 first extent */
+ for (s = 0, i = 0; i < HFSP_EXT_NB; i++) {
+ if ((block >= s) && (block < s + PED_BE32_TO_CPU (
+ file->first[i].block_count))) {
+ vol_block = (block - s)
+ + PED_BE32_TO_CPU (file->first[i]
+ .start_block);
+ size = PED_BE32_TO_CPU (file->first[i].block_count)
+ + s - block;
+ goto plus_sector_found;
+ }
+ s += PED_BE32_TO_CPU (file->first[i].block_count);
+ }
+
+ /* in the 8 cached extent */
+ if (file->start_cache && block >= file->start_cache)
+ for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
+ if ((block >= s) && (block < s + PED_BE32_TO_CPU (
+ file->cache[i].block_count))) {
+ vol_block = (block - s)
+ + PED_BE32_TO_CPU (file->cache[i]
+ .start_block);
+ size = PED_BE32_TO_CPU (file->cache[i].block_count)
+ + s - block;
+ goto plus_sector_found;
+ }
+ s += PED_BE32_TO_CPU (file->cache[i].block_count);
+ }
+
+ /* update cache */
+ if (!hfsplus_get_extent_containing (file, block, file->cache,
+ &(file->start_cache))) {
+ ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_CANCEL,
+ _("Could not update the extent cache for HFS+ file "
+ "with CNID %X."),
+ PED_BE32_TO_CPU(file->CNID));
+ return ret; /* ret == {0,0} */
+ }
+
+ /* ret == {0,0} */
+ PED_ASSERT(file->start_cache && block >= file->start_cache);
+
+ for (s = file->start_cache, i = 0; i < HFSP_EXT_NB; i++) {
+ if ((block >= s) && (block < s + PED_BE32_TO_CPU (
+ file->cache[i].block_count))) {
+ vol_block = (block - s)
+ + PED_BE32_TO_CPU (file->cache[i]
+ .start_block);
+ size = PED_BE32_TO_CPU (file->cache[i].block_count)
+ + s - block;
+ goto plus_sector_found;
+ }
+ s += PED_BE32_TO_CPU (file->cache[i].block_count);
+ }
+
+ return ret;
+
+plus_sector_found:
+ sect_size = (PedSector) size * sect_by_block - offset;
+ ret.start_sector = vol_block * sect_by_block + offset;
+ ret.sector_count = (sect_size < nb) ? sect_size : nb;
+ return ret;
+}
+
+int
+hfsplus_file_read(HfsPPrivateFile* file, void *buf, PedSector sector,
+ unsigned int nb)
+{
+ HfsPPrivateExtent phy_area;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ file->fs->type_specific;
+ char *b = buf;
+
+ if (sector+nb < sector /* detect overflow */
+ || sector+nb > file->sect_nb) /* out of file */ {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to read HFS+ file with CNID %X behind EOF."),
+ PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ while (nb) {
+ phy_area = hfsplus_file_find_extent(file, sector, nb);
+ if (phy_area.sector_count == 0) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not find sector %lli of HFS+ file "
+ "with CNID %X."),
+ sector, PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+ if (!ped_geometry_read(priv_data->plus_geom, b,
+ phy_area.start_sector,
+ phy_area.sector_count))
+ return 0;
+
+ nb -= phy_area.sector_count; /* < nb anyway ... */
+ sector += phy_area.sector_count;
+ b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
+ }
+
+ return 1;
+}
+
+int
+hfsplus_file_write(HfsPPrivateFile* file, void *buf, PedSector sector,
+ unsigned int nb)
+{
+ HfsPPrivateExtent phy_area;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ file->fs->type_specific;
+ char *b = buf;
+
+ if (sector+nb < sector /* detect overflow */
+ || sector+nb > file->sect_nb) /* out of file */ {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Trying to write HFS+ file with CNID %X behind EOF."),
+ PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+
+ while (nb) {
+ phy_area = hfsplus_file_find_extent(file, sector, nb);
+ if (phy_area.sector_count == 0) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not find sector %lli of HFS+ file "
+ "with CNID %X."),
+ sector, PED_BE32_TO_CPU(file->CNID));
+ return 0;
+ }
+ if (!ped_geometry_write(priv_data->plus_geom, b,
+ phy_area.start_sector,
+ phy_area.sector_count))
+ return 0;
+
+ nb -= phy_area.sector_count; /* < nb anyway ... */
+ sector += phy_area.sector_count;
+ b += phy_area.sector_count * PED_SECTOR_SIZE_DEFAULT;
+ }
+
+ return 1;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/file_plus.h b/libparted/fs/r/hfs/file_plus.h
new file mode 100644
index 0000000..cd54f3f
--- /dev/null
+++ b/libparted/fs/r/hfs/file_plus.h
@@ -0,0 +1,61 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _FILE_PLUS_H
+#define _FILE_PLUS_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+HfsPPrivateFile*
+hfsplus_file_open (PedFileSystem *fs, HfsPNodeID CNID,
+ HfsPExtDataRec ext_desc, PedSector sect_nb);
+
+void
+hfsplus_file_close (HfsPPrivateFile* file);
+
+int
+hfsplus_file_read(HfsPPrivateFile* file, void *buf,
+ PedSector sector, unsigned int nb);
+
+int
+hfsplus_file_write(HfsPPrivateFile* file, void *buf,
+ PedSector sector, unsigned int nb);
+
+/* Read the nth sector of a file */
+/* return 0 on error */
+static __inline__ int
+hfsplus_file_read_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
+{
+ return hfsplus_file_read(file, buf, sector, 1);
+}
+
+/* Write the nth sector of a file */
+/* return 0 on error */
+static __inline__ int
+hfsplus_file_write_sector (HfsPPrivateFile* file, void *buf, PedSector sector)
+{
+ return hfsplus_file_write(file, buf, sector, 1);
+}
+
+
+#endif /* _FILE_PLUS_H */
diff --git a/libparted/fs/r/hfs/hfs.c b/libparted/fs/r/hfs/hfs.c
new file mode 100644
index 0000000..8959b47
--- /dev/null
+++ b/libparted/fs/r/hfs/hfs.c
@@ -0,0 +1,1166 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 2003-2005, 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/>.
+*/
+
+/*
+ Author : Guillaume Knispel <k_guillaume@libertysurf.fr>
+ Report bug to <bug-parted@gnu.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "probe.h"
+
+uint8_t* hfs_block = NULL;
+uint8_t* hfsp_block = NULL;
+unsigned hfs_block_count;
+unsigned hfsp_block_count;
+
+#define HFS_BLOCK_SIZES ((int[2]){512, 0})
+#define HFSP_BLOCK_SIZES ((int[2]){512, 0})
+#define HFSX_BLOCK_SIZES ((int[2]){512, 0})
+
+#ifndef DISCOVER_ONLY
+#include "file.h"
+#include "reloc.h"
+#include "advfs.h"
+
+static PedFileSystemType hfs_type;
+static PedFileSystemType hfsplus_type;
+
+
+/* ----- HFS ----- */
+
+PedFileSystem *
+hfs_open (PedGeometry* geom)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedFileSystem* fs;
+ HfsMasterDirectoryBlock* mdb;
+ HfsPrivateFSData* priv_data;
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ /* Read MDB */
+ if (!ped_geometry_read (geom, buf, 2, 1))
+ return NULL;
+
+ /* Allocate memory */
+ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
+ if (!fs) goto ho;
+ mdb = (HfsMasterDirectoryBlock*)
+ ped_malloc (sizeof (HfsMasterDirectoryBlock));
+ if (!mdb) goto ho_fs;
+ priv_data = (HfsPrivateFSData*)
+ ped_malloc (sizeof (HfsPrivateFSData));
+ if (!priv_data) goto ho_mdb;
+
+ memcpy (mdb, buf, sizeof (HfsMasterDirectoryBlock));
+
+ /* init structures */
+ priv_data->mdb = mdb;
+ priv_data->bad_blocks_loaded = 0;
+ priv_data->bad_blocks_xtent_nb = 0;
+ priv_data->bad_blocks_xtent_list = NULL;
+ priv_data->extent_file =
+ hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
+ mdb->extents_file_rec,
+ PED_CPU_TO_BE32 (mdb->extents_file_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->extent_file) goto ho_pd;
+ priv_data->catalog_file =
+ hfs_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
+ mdb->catalog_file_rec,
+ PED_CPU_TO_BE32 (mdb->catalog_file_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->catalog_file) goto ho_ce;
+ /* Read allocation blocks */
+ if (!ped_geometry_read(geom, priv_data->alloc_map,
+ PED_BE16_TO_CPU (mdb->volume_bitmap_block),
+ ( PED_BE16_TO_CPU (mdb->total_blocks)
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8) ) )
+ goto ho_cf;
+
+ fs->type = &hfs_type;
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom) goto ho_cf;
+ fs->type_specific = (void*) priv_data;
+ fs->checked = ( PED_BE16_TO_CPU (mdb->volume_attributes)
+ >> HFS_UNMOUNTED ) & 1;
+
+ return fs;
+
+/*--- clean error handling ---*/
+ho_cf: hfs_file_close(priv_data->catalog_file);
+ho_ce: hfs_file_close(priv_data->extent_file);
+ho_pd: free(priv_data);
+ho_mdb: free(mdb);
+ho_fs: free(fs);
+ho: return NULL;
+}
+
+int
+hfs_close (PedFileSystem *fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*) fs->type_specific;
+
+ hfs_file_close (priv_data->extent_file);
+ hfs_file_close (priv_data->catalog_file);
+ if (priv_data->bad_blocks_loaded)
+ hfs_free_bad_blocks_list (priv_data->bad_blocks_xtent_list);
+ free (priv_data->mdb);
+ free (priv_data);
+ ped_geometry_destroy (fs->geom);
+ free (fs);
+
+ return 1;
+}
+
+PedConstraint *
+hfs_get_resize_constraint (const PedFileSystem *fs)
+{
+ PedDevice* dev = fs->geom->dev;
+ PedAlignment start_align;
+ PedGeometry start_sector;
+ PedGeometry full_dev;
+ PedSector min_size;
+
+ if (!ped_alignment_init (&start_align, fs->geom->start, 0))
+ return NULL;
+ if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
+ return NULL;
+ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
+ return NULL;
+ /* 2 = last two sectors (alternate MDB and unused sector) */
+ min_size = hfs_get_empty_end(fs) + 2;
+ if (min_size == 2) return NULL;
+
+ return ped_constraint_new (&start_align, ped_alignment_any,
+ &start_sector, &full_dev, min_size,
+ fs->geom->length);
+}
+
+int
+hfs_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ unsigned int nblock, nfree;
+ unsigned int block, to_free;
+ HfsPrivateFSData* priv_data;
+ HfsMasterDirectoryBlock* mdb;
+ int resize = 1;
+ unsigned int hfs_sect_block;
+ PedSector hgee;
+
+ /* check preconditions */
+ PED_ASSERT (fs != NULL);
+ PED_ASSERT (fs->geom != NULL);
+ PED_ASSERT (geom != NULL);
+#ifdef DEBUG
+ PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
+#else
+ if ((hgee = hfs_get_empty_end(fs)) == 0)
+ return 0;
+#endif
+
+ PED_ASSERT ((hgee = hfs_get_empty_end(fs)) != 0);
+
+ if (ped_geometry_test_equal(fs->geom, geom))
+ return 1;
+
+ priv_data = (HfsPrivateFSData*) fs->type_specific;
+ mdb = priv_data->mdb;
+ hfs_sect_block = PED_BE32_TO_CPU (mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+
+ if (fs->geom->start != geom->start
+ || geom->length > fs->geom->length
+ || geom->length < hgee + 2) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Sorry, HFS cannot be resized that way yet."));
+ return 0;
+ }
+
+ /* Flush caches */
+ if (!ped_geometry_sync(fs->geom))
+ return 0;
+
+ /* Clear the unmounted bit */
+ mdb->volume_attributes &= PED_CPU_TO_BE16 (~( 1 << HFS_UNMOUNTED ));
+ if (!ped_geometry_read (fs->geom, buf, 2, 1))
+ return 0;
+ memcpy (buf, mdb, sizeof (HfsMasterDirectoryBlock));
+ if ( !ped_geometry_write (fs->geom, buf, 2, 1)
+ || !ped_geometry_sync (fs->geom))
+ return 0;
+
+ ped_timer_reset (timer);
+ ped_timer_set_state_name(timer, _("shrinking"));
+ ped_timer_update(timer, 0.0);
+ /* relocate data */
+ to_free = ( fs->geom->length - geom->length
+ + hfs_sect_block - 1 )
+ / hfs_sect_block ;
+ block = hfs_find_start_pack (fs, to_free);
+ if (!hfs_pack_free_space_from_block (fs, block, timer, to_free)) {
+ resize = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Data relocation has failed."));
+ goto write_MDB;
+ }
+
+ /* Calculate new block number and other MDB field */
+ nblock = ( geom->length - (PED_BE16_TO_CPU (mdb->start_block) + 2) )
+ / hfs_sect_block;
+ nfree = PED_BE16_TO_CPU (mdb->free_blocks)
+ - ( PED_BE16_TO_CPU (mdb->total_blocks) - nblock );
+
+ /* Check that all block after future end are really free */
+ for (block = nblock;
+ block < PED_BE16_TO_CPU (mdb->total_blocks);
+ block++) {
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
+ resize = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Data relocation left some data in the end "
+ "of the volume."));
+ goto write_MDB;
+ }
+ }
+
+ /* Mark out of volume blocks as used
+ (broken implementations compatibility) */
+ for ( block = nblock; block < (1 << 16); ++block)
+ SET_BLOC_OCCUPATION(priv_data->alloc_map,block);
+
+ /* save the allocation map
+ I do not write until start of allocation blocks
+ but only until pre-resize end of bitmap blocks
+ because the specifications do _not_ assert that everything
+ until allocation blocks is boot, mdb and alloc */
+ ped_geometry_write(fs->geom, priv_data->alloc_map,
+ PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
+ ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1)
+ / (PED_SECTOR_SIZE_DEFAULT * 8));
+
+ /* Update geometry */
+ if (resize) {
+ /* update in fs structure */
+ if (PED_BE16_TO_CPU (mdb->next_allocation) >= nblock)
+ mdb->next_allocation = PED_CPU_TO_BE16 (0);
+ mdb->total_blocks = PED_CPU_TO_BE16 (nblock);
+ mdb->free_blocks = PED_CPU_TO_BE16 (nfree);
+ /* update parted structure */
+ fs->geom->length = geom->length;
+ fs->geom->end = fs->geom->start + geom->length - 1;
+ }
+
+ /* Set the unmounted bit */
+ mdb->volume_attributes |= PED_CPU_TO_BE16 ( 1 << HFS_UNMOUNTED );
+
+ /* Effective write */
+ write_MDB:
+ ped_timer_set_state_name(timer,_("writing HFS Master Directory Block"));
+
+ if (!hfs_update_mdb(fs)) {
+ ped_geometry_sync(geom);
+ return 0;
+ }
+
+ if (!ped_geometry_sync(geom))
+ return 0;
+
+ ped_timer_update(timer, 1.0);
+
+ return (resize);
+}
+
+/* ----- HFS+ ----- */
+
+#include "file_plus.h"
+#include "advfs_plus.h"
+#include "reloc_plus.h"
+#include "journal.h"
+
+int
+hfsplus_close (PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+
+ if (priv_data->bad_blocks_loaded)
+ hfsplus_free_bad_blocks_list(priv_data->bad_blocks_xtent_list);
+ free(priv_data->alloc_map);
+ free(priv_data->dirty_alloc_map);
+ hfsplus_file_close (priv_data->allocation_file);
+ hfsplus_file_close (priv_data->attributes_file);
+ hfsplus_file_close (priv_data->catalog_file);
+ hfsplus_file_close (priv_data->extents_file);
+ if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom);
+ if (priv_data->wrapper) hfs_close(priv_data->wrapper);
+ ped_geometry_destroy (fs->geom);
+ free(priv_data->vh);
+ free(priv_data);
+ free(fs);
+
+ return 1;
+}
+
+PedFileSystem*
+hfsplus_open (PedGeometry* geom)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedFileSystem* fs;
+ HfsPVolumeHeader* vh;
+ HfsPPrivateFSData* priv_data;
+ PedGeometry* wrapper_geom;
+ unsigned int map_sectors;
+
+ if (!hfsc_can_use_geom (geom))
+ return NULL;
+
+ fs = (PedFileSystem*) ped_malloc (sizeof (PedFileSystem));
+ if (!fs) goto hpo;
+ vh = (HfsPVolumeHeader*) ped_malloc (sizeof (HfsPVolumeHeader));
+ if (!vh) goto hpo_fs;
+ priv_data = (HfsPPrivateFSData*)ped_malloc (sizeof (HfsPPrivateFSData));
+ if (!priv_data) goto hpo_vh;
+
+ fs->geom = ped_geometry_duplicate (geom);
+ if (!fs->geom) goto hpo_pd;
+ fs->type_specific = (void*) priv_data;
+
+ if ((wrapper_geom = hfs_and_wrapper_probe (geom))) {
+ HfsPrivateFSData* hfs_priv_data;
+ PedSector abs_sect, length;
+ unsigned int bs;
+
+ ped_geometry_destroy (wrapper_geom);
+ priv_data->wrapper = hfs_open(geom);
+ if (!priv_data->wrapper) goto hpo_gm;
+ hfs_priv_data = (HfsPrivateFSData*)
+ priv_data->wrapper->type_specific;
+ bs = PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+ abs_sect = (PedSector) geom->start
+ + (PedSector) PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->start_block)
+ + (PedSector) PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->old_new
+ .embedded.location.start_block )
+ * bs;
+ length = (PedSector) PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->old_new
+ .embedded.location.block_count)
+ * bs;
+ priv_data->plus_geom = ped_geometry_new (geom->dev, abs_sect,
+ length);
+ if (!priv_data->plus_geom) goto hpo_wr;
+ priv_data->free_geom = 1;
+ } else {
+ priv_data->wrapper = NULL;
+ priv_data->plus_geom = fs->geom;
+ priv_data->free_geom = 0;
+ }
+
+ if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1)) goto hpo_pg;
+ memcpy (vh, buf, sizeof (HfsPVolumeHeader));
+ priv_data->vh = vh;
+
+ if (vh->signature != PED_CPU_TO_BE16(HFSP_SIGNATURE)
+ && vh->signature != PED_CPU_TO_BE16(HFSX_SIGNATURE)) {
+ ped_exception_throw (
+ PED_EXCEPTION_BUG,
+ PED_EXCEPTION_CANCEL,
+ _("No valid HFS[+X] signature has been found while "
+ "opening."));
+ goto hpo_pg;
+ }
+
+ if (vh->signature == PED_CPU_TO_BE16(HFSP_SIGNATURE)
+ && vh->version != PED_CPU_TO_BE16(HFSP_VERSION)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Version %d of HFS+ isn't supported."),
+ PED_BE16_TO_CPU(vh->version))
+ != PED_EXCEPTION_IGNORE)
+ goto hpo_pg;
+ }
+
+ if (vh->signature == PED_CPU_TO_BE16(HFSX_SIGNATURE)
+ && vh->version != PED_CPU_TO_BE16(HFSX_VERSION)) {
+ if (ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("Version %d of HFSX isn't supported."),
+ PED_BE16_TO_CPU(vh->version))
+ != PED_EXCEPTION_IGNORE)
+ goto hpo_pg;
+ }
+
+ priv_data->jib_start_block = 0;
+ priv_data->jl_start_block = 0;
+ if (vh->attributes & PED_CPU_TO_BE32(1<<HFSP_JOURNALED)) {
+ if (!hfsj_replay_journal(fs))
+ goto hpo_pg;
+ }
+
+ priv_data->bad_blocks_loaded = 0;
+ priv_data->bad_blocks_xtent_nb = 0;
+ priv_data->bad_blocks_xtent_list = NULL;
+ priv_data->extents_file =
+ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_XTENT_ID),
+ vh->extents_file.extents,
+ PED_BE64_TO_CPU (
+ vh->extents_file.logical_size )
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->extents_file) goto hpo_pg;
+ priv_data->catalog_file =
+ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFS_CATALOG_ID),
+ vh->catalog_file.extents,
+ PED_BE64_TO_CPU (
+ vh->catalog_file.logical_size )
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->catalog_file) goto hpo_ce;
+ priv_data->attributes_file =
+ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ATTRIB_ID),
+ vh->attributes_file.extents,
+ PED_BE64_TO_CPU (
+ vh->attributes_file.logical_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->attributes_file) goto hpo_cc;
+
+ map_sectors = ( PED_BE32_TO_CPU (vh->total_blocks)
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8);
+ priv_data->dirty_alloc_map = (uint8_t*)
+ ped_malloc ((map_sectors + 7) / 8);
+ if (!priv_data->dirty_alloc_map) goto hpo_cl;
+ memset(priv_data->dirty_alloc_map, 0, (map_sectors + 7) / 8);
+ priv_data->alloc_map = (uint8_t*)
+ ped_malloc (map_sectors * PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->alloc_map) goto hpo_dm;
+
+ priv_data->allocation_file =
+ hfsplus_file_open (fs, PED_CPU_TO_BE32 (HFSP_ALLOC_ID),
+ vh->allocation_file.extents,
+ PED_BE64_TO_CPU (
+ vh->allocation_file.logical_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (!priv_data->allocation_file) goto hpo_am;
+ if (!hfsplus_file_read (priv_data->allocation_file,
+ priv_data->alloc_map, 0, map_sectors)) {
+ hfsplus_close(fs);
+ return NULL;
+ }
+
+ fs->type = &hfsplus_type;
+ fs->checked = ((PED_BE32_TO_CPU (vh->attributes) >> HFS_UNMOUNTED) & 1)
+ && !((PED_BE32_TO_CPU (vh->attributes) >> HFSP_INCONSISTENT) & 1);
+
+ return fs;
+
+/*--- clean error handling ---*/
+hpo_am: free(priv_data->alloc_map);
+hpo_dm: free(priv_data->dirty_alloc_map);
+hpo_cl: hfsplus_file_close (priv_data->attributes_file);
+hpo_cc: hfsplus_file_close (priv_data->catalog_file);
+hpo_ce: hfsplus_file_close (priv_data->extents_file);
+hpo_pg: if (priv_data->free_geom) ped_geometry_destroy (priv_data->plus_geom);
+hpo_wr: if (priv_data->wrapper) hfs_close(priv_data->wrapper);
+hpo_gm: ped_geometry_destroy (fs->geom);
+hpo_pd: free(priv_data);
+hpo_vh: free(vh);
+hpo_fs: free(fs);
+hpo: return NULL;
+}
+
+PedConstraint *
+hfsplus_get_resize_constraint (const PedFileSystem *fs)
+{
+ PedDevice* dev = fs->geom->dev;
+ PedAlignment start_align;
+ PedGeometry start_sector;
+ PedGeometry full_dev;
+ PedSector min_size;
+
+ if (!ped_alignment_init (&start_align, fs->geom->start, 0))
+ return NULL;
+ if (!ped_geometry_init (&start_sector, dev, fs->geom->start, 1))
+ return NULL;
+ if (!ped_geometry_init (&full_dev, dev, 0, dev->length - 1))
+ return NULL;
+
+ min_size = hfsplus_get_min_size (fs);
+ if (!min_size) return NULL;
+
+ return ped_constraint_new (&start_align, ped_alignment_any,
+ &start_sector, &full_dev, min_size,
+ fs->geom->length);
+}
+
+static int
+hfsplus_volume_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ unsigned int nblock, nfree, mblock;
+ unsigned int block, to_free, old_blocks;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPVolumeHeader* vh = priv_data->vh;
+ int resize = 1;
+ unsigned int hfsp_sect_block =
+ ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT );
+ unsigned int map_sectors;
+
+ old_blocks = PED_BE32_TO_CPU (vh->total_blocks);
+
+ /* Flush caches */
+ if (!ped_geometry_sync(priv_data->plus_geom))
+ return 0;
+
+ /* Clear the unmounted bit */
+ /* and set the implementation code (Apple Creator Code) */
+ vh->attributes &= PED_CPU_TO_BE32 (~( 1 << HFS_UNMOUNTED ));
+ vh->last_mounted_version = PED_CPU_TO_BE32(HFSP_IMPL_Shnk);
+ if (!ped_geometry_read (priv_data->plus_geom, buf, 2, 1))
+ return 0;
+ memcpy (buf, vh, sizeof (HfsPVolumeHeader));
+ if ( !ped_geometry_write (priv_data->plus_geom, buf, 2, 1)
+ || !ped_geometry_sync (priv_data->plus_geom))
+ return 0;
+
+ ped_timer_reset (timer);
+ ped_timer_set_state_name(timer, _("shrinking"));
+ ped_timer_update(timer, 0.0);
+ /* relocate data */
+ to_free = ( priv_data->plus_geom->length
+ - geom->length + hfsp_sect_block
+ - 1 ) / hfsp_sect_block;
+ block = hfsplus_find_start_pack (fs, to_free);
+ if (!hfsplus_pack_free_space_from_block (fs, block, timer, to_free)) {
+ resize = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Data relocation has failed."));
+ goto write_VH;
+ }
+
+ /* Calculate new block number and other VH field */
+ /* nblock must be rounded _down_ */
+ nblock = geom->length / hfsp_sect_block;
+ nfree = PED_BE32_TO_CPU (vh->free_blocks)
+ - (old_blocks - nblock);
+ /* free block readjustement is only needed when incorrect nblock
+ was used by my previous implementation, so detect the case */
+ if (priv_data->plus_geom->length < old_blocks
+ * ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT) ) {
+ if (priv_data->plus_geom->length % hfsp_sect_block == 1)
+ nfree++;
+ }
+
+ /* Check that all block after future end are really free */
+ mblock = ( priv_data->plus_geom->length - 2 )
+ / hfsp_sect_block;
+ if (mblock > old_blocks - 1)
+ mblock = old_blocks - 1;
+ for ( block = nblock;
+ block < mblock;
+ block++ ) {
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,block)) {
+ resize = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Data relocation left some data at the end "
+ "of the volume."));
+ goto write_VH;
+ }
+ }
+
+ /* Mark out of volume blocks as used */
+ map_sectors = ( ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8) )
+ * (PED_SECTOR_SIZE_DEFAULT * 8);
+ for ( block = nblock; block < map_sectors; ++block)
+ SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
+
+ /* Update geometry */
+ if (resize) {
+ /* update in fs structure */
+ if (PED_BE32_TO_CPU (vh->next_allocation) >= nblock)
+ vh->next_allocation = PED_CPU_TO_BE32 (0);
+ vh->total_blocks = PED_CPU_TO_BE32 (nblock);
+ vh->free_blocks = PED_CPU_TO_BE32 (nfree);
+ /* update parted structure */
+ priv_data->plus_geom->length = geom->length;
+ priv_data->plus_geom->end = priv_data->plus_geom->start
+ + geom->length - 1;
+ }
+
+ /* Effective write */
+ write_VH:
+ /* lasts two sectors are allocated by the alternate VH
+ and a reserved sector, and last block is always reserved */
+ block = (priv_data->plus_geom->length - 1) / hfsp_sect_block;
+ if (block < PED_BE32_TO_CPU (vh->total_blocks))
+ SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
+ block = (priv_data->plus_geom->length - 2) / hfsp_sect_block;
+ if (block < PED_BE32_TO_CPU (vh->total_blocks))
+ SET_BLOC_OCCUPATION(priv_data->alloc_map, block);
+ SET_BLOC_OCCUPATION(priv_data->alloc_map,
+ PED_BE32_TO_CPU (vh->total_blocks) - 1);
+
+ /* Write the _old_ area to set out of volume blocks as used */
+ map_sectors = ( old_blocks + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8);
+ if (!hfsplus_file_write (priv_data->allocation_file,
+ priv_data->alloc_map, 0, map_sectors)) {
+ resize = 0;
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Error while writing the allocation file."));
+ } else {
+ /* Write remaining part of allocation bitmap */
+ /* This is necessary to handle pre patch-11 and third party */
+ /* implementations */
+ memset(buf, 0xFF, PED_SECTOR_SIZE_DEFAULT);
+ for (block = map_sectors;
+ block < priv_data->allocation_file->sect_nb;
+ ++block) {
+ if (!hfsplus_file_write_sector (
+ priv_data->allocation_file,
+ buf, block)) {
+ ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("Error while writing the "
+ "compatibility part of the "
+ "allocation file."));
+ break;
+ }
+ }
+ }
+ ped_geometry_sync (priv_data->plus_geom);
+
+ if (resize) {
+ /* Set the unmounted bit and clear the inconsistent bit */
+ vh->attributes |= PED_CPU_TO_BE32 ( 1 << HFS_UNMOUNTED );
+ vh->attributes &= ~ PED_CPU_TO_BE32 ( 1 << HFSP_INCONSISTENT );
+ }
+
+ ped_timer_set_state_name(timer, _("writing HFS+ Volume Header"));
+ if (!hfsplus_update_vh(fs)) {
+ ped_geometry_sync(priv_data->plus_geom);
+ return 0;
+ }
+
+ if (!ped_geometry_sync(priv_data->plus_geom))
+ return 0;
+
+ ped_timer_update(timer, 1.0);
+
+ return (resize);
+}
+
+/* Update the HFS wrapper mdb and bad blocks file to reflect
+ the new geometry of the embedded HFS+ volume */
+static int
+hfsplus_wrapper_update (PedFileSystem* fs)
+{
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+ HfsCPrivateLeafRec ref;
+ HfsExtentKey key;
+ HfsNodeDescriptor* node_desc = (HfsNodeDescriptor*) node;
+ HfsExtentKey* ret_key;
+ HfsExtDescriptor* ret_data;
+ unsigned int i;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
+ priv_data->wrapper->type_specific;
+ unsigned int hfs_sect_block =
+ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT ;
+ PedSector hfsplus_sect = (PedSector)
+ PED_BE32_TO_CPU (priv_data->vh->total_blocks)
+ * ( PED_BE32_TO_CPU (priv_data->vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT );
+ unsigned int hfs_blocks_embedded =
+ (hfsplus_sect + hfs_sect_block - 1)
+ / hfs_sect_block;
+ unsigned int hfs_blocks_embedded_old;
+
+ /* update HFS wrapper MDB */
+ hfs_blocks_embedded_old = PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->old_new
+ .embedded.location.block_count );
+ hfs_priv_data->mdb->old_new.embedded.location.block_count =
+ PED_CPU_TO_BE16 (hfs_blocks_embedded);
+ /* maybe macOS will boot with this */
+ /* update : yes it does \o/ :) */
+ hfs_priv_data->mdb->free_blocks =
+ PED_CPU_TO_BE16 ( PED_BE16_TO_CPU (hfs_priv_data->mdb->free_blocks)
+ + hfs_blocks_embedded_old
+ - hfs_blocks_embedded );
+
+ if (!hfs_update_mdb(priv_data->wrapper))
+ return 0;
+
+ /* force reload bad block list */
+ if (hfs_priv_data->bad_blocks_loaded) {
+ hfs_free_bad_blocks_list (hfs_priv_data->bad_blocks_xtent_list);
+ hfs_priv_data->bad_blocks_xtent_list = NULL;
+ hfs_priv_data->bad_blocks_xtent_nb = 0;
+ hfs_priv_data->bad_blocks_loaded = 0;
+ }
+
+ /* clean HFS wrapper allocation map */
+ for (i = PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->old_new.embedded
+ .location.start_block )
+ + hfs_blocks_embedded;
+ i < PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->old_new.embedded
+ .location.start_block )
+ + hfs_blocks_embedded_old;
+ i++ ) {
+ CLR_BLOC_OCCUPATION(hfs_priv_data->alloc_map, i);
+ }
+ /* and save it */
+ if (!ped_geometry_write (fs->geom, hfs_priv_data->alloc_map,
+ PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->volume_bitmap_block ),
+ ( PED_BE16_TO_CPU (
+ hfs_priv_data->mdb->total_blocks )
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8)))
+ return 0;
+ if (!ped_geometry_sync (fs->geom))
+ return 0;
+
+ /* search and update the bad blocks file */
+ key.key_length = sizeof(key) - 1;
+ key.type = HFS_DATA_FORK;
+ key.file_ID = PED_CPU_TO_BE32 (HFS_BAD_BLOCK_ID);
+ key.start = 0;
+ if (!hfs_btree_search (hfs_priv_data->extent_file,
+ (HfsPrivateGenericKey*) &key, NULL, 0, &ref)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("An error occurred while looking for the mandatory "
+ "bad blocks file."));
+ return 0;
+ }
+ if (!hfs_file_read_sector (hfs_priv_data->extent_file, node,
+ ref.node_number))
+ return 0;
+ ret_key = (HfsExtentKey*) (node + ref.record_pos);
+ ret_data = (HfsExtDescriptor*) ( node + ref.record_pos
+ + sizeof (HfsExtentKey) );
+
+ while (ret_key->type == key.type && ret_key->file_ID == key.file_ID) {
+ for (i = 0; i < HFS_EXT_NB; i++) {
+ if ( ret_data[i].start_block
+ == hfs_priv_data->mdb->old_new
+ .embedded.location.start_block) {
+ ret_data[i].block_count =
+ hfs_priv_data->mdb->old_new
+ .embedded.location.block_count;
+ /* found ! : update */
+ if (!hfs_file_write_sector (
+ hfs_priv_data->extent_file,
+ node, ref.node_number)
+ || !ped_geometry_sync(fs->geom))
+ return 0;
+ return 1;
+ }
+ }
+
+ if (ref.record_number < PED_BE16_TO_CPU (node_desc->rec_nb)) {
+ ref.record_number++;
+ } else {
+ ref.node_number = PED_BE32_TO_CPU (node_desc->next);
+ if (!ref.node_number
+ || !hfs_file_read_sector(hfs_priv_data->extent_file,
+ node, ref.node_number))
+ goto bb_not_found;
+ ref.record_number = 1;
+ }
+
+ uint16_t value;
+ memcpy(&value, node+PED_SECTOR_SIZE_DEFAULT - (2*ref.record_number), sizeof(uint16_t));
+ ref.record_pos = PED_BE16_TO_CPU(value);
+ ret_key = (HfsExtentKey*) (node + ref.record_pos);
+ ret_data = (HfsExtDescriptor*) (node + ref.record_pos
+ + sizeof (HfsExtentKey) );
+ }
+
+bb_not_found:
+ /* not found : not a valid hfs+ wrapper : failure */
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("It seems there is an error in the HFS wrapper: the bad "
+ "blocks file doesn't contain the embedded HFS+ volume."));
+ return 0;
+}
+
+int
+hfsplus_resize (PedFileSystem* fs, PedGeometry* geom, PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data;
+ PedTimer* timer_plus;
+ PedGeometry* embedded_geom;
+ PedSector hgms;
+
+ /* check preconditions */
+ PED_ASSERT (fs != NULL);
+ PED_ASSERT (fs->geom != NULL);
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (fs->geom->dev == geom->dev);
+#ifdef DEBUG
+ PED_ASSERT ((hgms = hfsplus_get_min_size (fs)) != 0);
+#else
+ if ((hgms = hfsplus_get_min_size (fs)) == 0)
+ return 0;
+#endif
+
+ if (ped_geometry_test_equal(fs->geom, geom))
+ return 1;
+
+ priv_data = (HfsPPrivateFSData*) fs->type_specific;
+
+ if (fs->geom->start != geom->start
+ || geom->length > fs->geom->length
+ || geom->length < hgms) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Sorry, HFS+ cannot be resized that way yet."));
+ return 0;
+ }
+
+ if (priv_data->wrapper) {
+ PedSector red, hgee;
+ HfsPrivateFSData* hfs_priv_data = (HfsPrivateFSData*)
+ priv_data->wrapper->type_specific;
+ unsigned int hfs_sect_block =
+ PED_BE32_TO_CPU (hfs_priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT;
+
+ /* There is a wrapper so we must calculate the new geometry
+ of the embedded HFS+ volume */
+ red = ( (fs->geom->length - geom->length + hfs_sect_block - 1)
+ / hfs_sect_block ) * hfs_sect_block;
+ /* Can't we shrink the hfs+ volume by the desired size ? */
+ hgee = hfsplus_get_empty_end (fs);
+ if (!hgee) return 0;
+ if (red > priv_data->plus_geom->length - hgee) {
+ /* No, shrink hfs+ by the greatest possible value */
+ hgee = ((hgee + hfs_sect_block - 1) / hfs_sect_block)
+ * hfs_sect_block;
+ red = priv_data->plus_geom->length - hgee;
+ }
+ embedded_geom = ped_geometry_new (geom->dev,
+ priv_data->plus_geom->start,
+ priv_data->plus_geom->length
+ - red);
+
+ /* There is a wrapper so the resize process is a two stages
+ process (embedded resizing then wrapper resizing) :
+ we create a sub timer */
+ ped_timer_reset (timer);
+ ped_timer_set_state_name (timer,
+ _("shrinking embedded HFS+ volume"));
+ ped_timer_update(timer, 0.0);
+ timer_plus = ped_timer_new_nested (timer, 0.98);
+ } else {
+ /* No wrapper : the desired geometry is the desired
+ HFS+ volume geometry */
+ embedded_geom = geom;
+ timer_plus = timer;
+ }
+
+ /* Resize the HFS+ volume */
+ if (!hfsplus_volume_resize (fs, embedded_geom, timer_plus)) {
+ if (timer_plus != timer) ped_timer_destroy_nested (timer_plus);
+ if (priv_data->wrapper) ped_geometry_destroy (embedded_geom);
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Resizing the HFS+ volume has failed."));
+ return 0;
+ }
+
+ if (priv_data->wrapper) {
+ ped_geometry_destroy (embedded_geom);
+ ped_timer_destroy_nested (timer_plus);
+ ped_timer_set_state_name(timer, _("shrinking HFS wrapper"));
+ timer_plus = ped_timer_new_nested (timer, 0.02);
+ /* There's a wrapper : second stage = resizing it */
+ if (!hfsplus_wrapper_update (fs)
+ || !hfs_resize (priv_data->wrapper, geom, timer_plus)) {
+ ped_timer_destroy_nested (timer_plus);
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Updating the HFS wrapper has failed."));
+ return 0;
+ }
+ ped_timer_destroy_nested (timer_plus);
+ }
+ ped_timer_update(timer, 1.0);
+
+ return 1;
+}
+
+#ifdef HFS_EXTRACT_FS
+/* The following is for debugging purpose only, NOT for packaging */
+
+#include <stdio.h>
+
+uint8_t* extract_buffer = NULL;
+
+static int
+hfs_extract_file(const char* filename, HfsPrivateFile* hfs_file)
+{
+ FILE* fout;
+ PedSector sect;
+
+ fout = fopen(filename, "w");
+ if (!fout) return 0;
+
+ for (sect = 0; sect < hfs_file->sect_nb; ++sect) {
+ if (!hfs_file_read_sector(hfs_file, extract_buffer, sect))
+ goto err_close;
+ if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
+ goto err_close;
+ }
+
+ return (fclose(fout) == 0 ? 1 : 0);
+
+err_close:
+ fclose(fout);
+ return 0;
+}
+
+static int
+hfs_extract_bitmap(const char* filename, PedFileSystem* fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
+ unsigned int count;
+ FILE* fout;
+ PedSector sect;
+
+ fout = fopen(filename, "w");
+ if (!fout) return 0;
+
+ for (sect = PED_BE16_TO_CPU(mdb->volume_bitmap_block);
+ sect < PED_BE16_TO_CPU(mdb->start_block);
+ sect += count) {
+ uint16_t st_block = PED_BE16_TO_CPU(mdb->start_block);
+ count = (st_block-sect) < BLOCK_MAX_BUFF ?
+ (st_block-sect) : BLOCK_MAX_BUFF;
+ if (!ped_geometry_read(fs->geom, extract_buffer, sect, count))
+ goto err_close;
+ if (!fwrite (extract_buffer, count * PED_SECTOR_SIZE_DEFAULT,
+ 1, fout))
+ goto err_close;
+ }
+
+ return (fclose(fout) == 0 ? 1 : 0);
+
+err_close:
+ fclose(fout);
+ return 0;
+}
+
+static int
+hfs_extract_mdb (const char* filename, PedFileSystem* fs)
+{
+ FILE* fout;
+
+ fout = fopen(filename, "w");
+ if (!fout) return 0;
+
+ if (!ped_geometry_read(fs->geom, extract_buffer, 2, 1))
+ goto err_close;
+ if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
+ goto err_close;
+
+ return (fclose(fout) == 0 ? 1 : 0);
+
+err_close:
+ fclose(fout);
+ return 0;
+}
+
+static int
+hfs_extract (PedFileSystem* fs, PedTimer* timer)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This is not a real %s check. This is going to extract "
+ "special low level files for debugging purposes."),
+ "HFS");
+
+ extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
+ if (!extract_buffer) return 0;
+
+ hfs_extract_mdb(HFS_MDB_FILENAME, fs);
+ hfs_extract_file(HFS_CATALOG_FILENAME, priv_data->catalog_file);
+ hfs_extract_file(HFS_EXTENTS_FILENAME, priv_data->extent_file);
+ hfs_extract_bitmap(HFS_BITMAP_FILENAME, fs);
+
+ free(extract_buffer); extract_buffer = NULL;
+ return 0; /* nothing has been fixed by us ! */
+}
+
+static int
+hfsplus_extract_file(const char* filename, HfsPPrivateFile* hfsp_file)
+{
+ FILE* fout;
+ unsigned int cp_sect;
+ PedSector rem_sect;
+
+ fout = fopen(filename, "w");
+ if (!fout) return 0;
+
+ for (rem_sect = hfsp_file->sect_nb; rem_sect; rem_sect -= cp_sect) {
+ cp_sect = rem_sect < BLOCK_MAX_BUFF ? rem_sect : BLOCK_MAX_BUFF;
+ if (!hfsplus_file_read(hfsp_file, extract_buffer,
+ hfsp_file->sect_nb - rem_sect, cp_sect))
+ goto err_close;
+ if (!fwrite (extract_buffer, cp_sect * PED_SECTOR_SIZE_DEFAULT,
+ 1, fout))
+ goto err_close;
+ }
+
+ return (fclose(fout) == 0 ? 1 : 0);
+
+err_close:
+ fclose(fout);
+ return 0;
+}
+
+static int
+hfsplus_extract_vh (const char* filename, PedFileSystem* fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ FILE* fout;
+ PedGeometry* geom = priv_data->plus_geom;
+
+
+ fout = fopen(filename, "w");
+ if (!fout) return 0;
+
+ if (!ped_geometry_read(geom, extract_buffer, 2, 1))
+ goto err_close;
+ if (!fwrite(extract_buffer, PED_SECTOR_SIZE_DEFAULT, 1, fout))
+ goto err_close;
+
+ return (fclose(fout) == 0 ? 1 : 0);
+
+err_close:
+ fclose(fout);
+ return 0;
+}
+
+/* TODO : use the timer to report what is happening */
+/* TODO : use exceptions to report errors */
+static int
+hfsplus_extract (PedFileSystem* fs, PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPVolumeHeader* vh = priv_data->vh;
+ HfsPPrivateFile* startup_file;
+
+ if (priv_data->wrapper) {
+ /* TODO : create nested timer */
+ hfs_extract (priv_data->wrapper, timer);
+ }
+
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This is not a real %s check. This is going to extract "
+ "special low level files for debugging purposes."),
+ "HFS+");
+
+ extract_buffer = ped_malloc(BLOCK_MAX_BUFF * PED_SECTOR_SIZE_DEFAULT);
+ if (!extract_buffer) return 0;
+
+ hfsplus_extract_vh(HFSP_VH_FILENAME, fs);
+ hfsplus_extract_file(HFSP_CATALOG_FILENAME, priv_data->catalog_file);
+ hfsplus_extract_file(HFSP_EXTENTS_FILENAME, priv_data->extents_file);
+ hfsplus_extract_file(HFSP_ATTRIB_FILENAME, priv_data->attributes_file);
+ hfsplus_extract_file(HFSP_BITMAP_FILENAME, priv_data->allocation_file);
+
+ startup_file = hfsplus_file_open(fs, PED_CPU_TO_BE32(HFSP_STARTUP_ID),
+ vh->startup_file.extents,
+ PED_BE64_TO_CPU (
+ vh->startup_file.logical_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+ if (startup_file) {
+ hfsplus_extract_file(HFSP_STARTUP_FILENAME, startup_file);
+ hfsplus_file_close(startup_file); startup_file = NULL;
+ }
+
+ free(extract_buffer); extract_buffer = NULL;
+ return 0; /* nothing has been fixed by us ! */
+}
+#endif /* HFS_EXTRACT_FS */
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/hfs.h b/libparted/fs/r/hfs/hfs.h
new file mode 100644
index 0000000..5b9138c
--- /dev/null
+++ b/libparted/fs/r/hfs/hfs.h
@@ -0,0 +1,648 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2003-2005, 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/>.
+*/
+
+#ifndef _HFS_H
+#define _HFS_H
+
+/* WARNING : bn is used 2 times in theses macro */
+/* so _never_ use side effect operators when using them */
+#define TST_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) & (1<<(7-((bn)&7))))
+#define SET_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) |= (1<<(7-((bn)&7))))
+#define CLR_BLOC_OCCUPATION(tab,bn) \
+ (((tab)[(bn)/8]) &= ~(1<<(7-((bn)&7))))
+
+/* Maximum number of blocks for the copy buffers */
+#define BLOCK_MAX_BUFF 256
+/* Maximum size of the copy buffers, in bytes */
+#define BYTES_MAX_BUFF 8388608
+
+/* Apple Creator Codes follow */
+#define HFSP_IMPL_Shnk 0x53686e6b /* in use */
+#define HFSP_IMPL_Xpnd 0x58706e64 /* reserved */
+#define HFSP_IMPL_Resz 0x5265737a /* reserved */
+#define HFSP_IMPL_PHpx 0x50482b78 /* reserved */
+#define HFSP_IMPL_traP 0x74726150 /* reserved */
+#define HFSP_IMPL_GnuP 0x476e7550 /* reserved */
+
+#define HFS_SIGNATURE 0x4244 /* 'BD' */
+#define HFSP_SIGNATURE 0x482B /* 'H+' */
+#define HFSX_SIGNATURE 0x4858 /* 'HX' */
+
+#define HFSP_VERSION 4
+#define HFSX_VERSION 5
+
+#define HFS_HARD_LOCK 7
+#define HFS_UNMOUNTED 8
+#define HFS_BAD_SPARED 9
+#define HFS_SOFT_LOCK 15
+#define HFSP_NO_CACHE 10
+#define HFSP_INCONSISTENT 11
+#define HFSP_REUSE_CNID 12
+#define HFSP_JOURNALED 13
+
+#define HFS_IDX_NODE 0x00
+#define HFS_HDR_NODE 0x01
+#define HFS_MAP_NODE 0x02
+#define HFS_LEAF_NODE 0xFF
+
+#define HFS_FIRST_REC 0x0E
+#define HFS_NSD_HD_REC 0x78
+#define HFS_MAP_REC 0xF8
+
+#define HFS_DATA_FORK 0x00
+#define HFS_RES_FORK 0xFF
+
+#define HFS_CAT_DIR 0x01
+#define HFS_CAT_FILE 0x02
+#define HFS_CAT_DIR_TH 0x03
+#define HFS_CAT_FILE_TH 0x04
+
+#define HFSP_ATTR_INLINE 0x10
+#define HFSP_ATTR_FORK 0x20
+#define HFSP_ATTR_EXTENTS 0x30
+
+#define HFS_ROOT_PAR_ID 0x01
+#define HFS_ROOT_DIR_ID 0x02
+#define HFS_XTENT_ID 0x03
+#define HFS_CATALOG_ID 0x04
+#define HFS_BAD_BLOCK_ID 0x05
+#define HFSP_ALLOC_ID 0x06
+#define HFSP_STARTUP_ID 0x07
+#define HFSP_ATTRIB_ID 0x08
+#define HFSP_BOGUS_ID 0x0F
+#define HFSP_FIRST_AV_ID 0x10
+
+#define HFSJ_JOURN_IN_FS 0x00
+#define HFSJ_JOURN_OTHER_DEV 0x01
+#define HFSJ_JOURN_NEED_INIT 0x02
+
+#define HFSJ_HEADER_MAGIC 0x4a4e4c78
+#define HFSJ_ENDIAN_MAGIC 0x12345678
+
+#define HFSX_CASE_FOLDING 0xCF /* case insensitive HFSX */
+#define HFSX_BINARY_COMPARE 0xBC /* case sensitive HFSX */
+
+#define HFS_EXT_NB 3
+#define HFSP_EXT_NB 8
+
+/* Define the filenames used by the FS extractor */
+#ifdef HFS_EXTRACT_FS
+
+#define HFS_MDB_FILENAME "mdb.hfs"
+#define HFS_CATALOG_FILENAME "catalog.hfs"
+#define HFS_EXTENTS_FILENAME "extents.hfs"
+#define HFS_BITMAP_FILENAME "bitmap.hfs"
+
+#define HFSP_VH_FILENAME "vh.hfsplus"
+#define HFSP_CATALOG_FILENAME "catalog.hfsplus"
+#define HFSP_EXTENTS_FILENAME "extents.hfsplus"
+#define HFSP_BITMAP_FILENAME "bitmap.hfsplus"
+#define HFSP_ATTRIB_FILENAME "attributes.hfsplus"
+#define HFSP_STARTUP_FILENAME "startup.hfsplus"
+
+#endif /* HFS_EXTRACT_FS */
+
+
+
+/* ----------------------------------- */
+/* -- HFS DATA STRUCTURES -- */
+/* ----------------------------------- */
+
+/* Extent descriptor */
+struct __attribute__ ((packed)) _HfsExtDescriptor {
+ uint16_t start_block;
+ uint16_t block_count;
+};
+typedef struct _HfsExtDescriptor HfsExtDescriptor;
+typedef HfsExtDescriptor HfsExtDataRec[HFS_EXT_NB];
+
+/* Volume header */
+struct __attribute__ ((packed)) _HfsMasterDirectoryBlock {
+ uint16_t signature;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint16_t volume_attributes;
+ uint16_t files_in_root;
+ uint16_t volume_bitmap_block; /* in sectors */
+ uint16_t next_allocation;
+ uint16_t total_blocks;
+ uint32_t block_size; /* in bytes */
+ uint32_t def_clump_size; /* in bytes */
+ uint16_t start_block; /* in sectors */
+ uint32_t next_free_node;
+ uint16_t free_blocks;
+ uint8_t name_length;
+ char name[27];
+ uint32_t backup_date;
+ uint16_t backup_number;
+ uint32_t write_count;
+ uint32_t extents_clump;
+ uint32_t catalog_clump;
+ uint16_t dirs_in_root;
+ uint32_t file_count;
+ uint32_t dir_count;
+ uint32_t finder_info[8];
+ union __attribute__ ((packed)) {
+ struct __attribute__ ((packed)) {
+ uint16_t volume_cache_size; /* in blocks */
+ uint16_t bitmap_cache_size; /* in blocks */
+ uint16_t common_cache_size; /* in blocks */
+ } legacy;
+ struct __attribute__ ((packed)) {
+ uint16_t signature;
+ HfsExtDescriptor location;
+ } embedded;
+ } old_new;
+ uint32_t extents_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec extents_file_rec;
+ uint32_t catalog_file_size; /* in bytes, block size multiple */
+ HfsExtDataRec catalog_file_rec;
+};
+typedef struct _HfsMasterDirectoryBlock HfsMasterDirectoryBlock;
+
+/* B*-Tree Node Descriptor */
+struct __attribute__ ((packed)) _HfsNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsNodeDescriptor HfsNodeDescriptor;
+
+/* Header record of a whole B*-Tree */
+struct __attribute__ ((packed)) _HfsHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes;
+ int8_t reserved[76];
+};
+typedef struct _HfsHeaderRecord HfsHeaderRecord;
+
+/* Catalog key for B*-Tree lookup in the catalog file */
+struct __attribute__ ((packed)) _HfsCatalogKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t reserved;
+ uint32_t parent_ID;
+ uint8_t name_length;
+ char name[31]; /* in fact physicaly 1 upto 31 */
+};
+typedef struct _HfsCatalogKey HfsCatalogKey;
+
+/* Extents overflow key for B*-Tree lookup */
+struct __attribute__ ((packed)) _HfsExtentKey {
+ uint8_t key_length; /* length of the key without key_length */
+ uint8_t type; /* data or ressource fork */
+ uint32_t file_ID;
+ uint16_t start;
+};
+typedef struct _HfsExtentKey HfsExtentKey;
+
+/* Catalog subdata case directory */
+struct __attribute__ ((packed)) _HfsDir {
+ uint16_t flags;
+ uint16_t valence; /* number of files in this directory */
+ uint32_t dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t reserved[4];
+};
+typedef struct _HfsDir HfsDir;
+
+/* Catalog subdata case file */
+struct __attribute__ ((packed)) _HfsFile {
+ int8_t flags;
+ int8_t type; /* should be 0 */
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t file_ID;
+ uint16_t data_start_block;
+ uint32_t data_sz_byte;
+ uint32_t data_sz_block;
+ uint16_t res_start_block;
+ uint32_t res_sz_byte;
+ uint32_t res_sz_block;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint16_t clump_size;
+ HfsExtDataRec extents_data;
+ HfsExtDataRec extents_res;
+ uint32_t reserved;
+};
+typedef struct _HfsFile HfsFile;
+
+/* Catalog subdata case directory thread */
+struct __attribute__ ((packed)) _HfsDirTh {
+ uint32_t reserved[2];
+ uint32_t parent_ID;
+ int8_t name_length;
+ char name[31];
+};
+typedef struct _HfsDirTh HfsDirTh;
+
+/* Catalog subdata case file thread */
+typedef struct _HfsDirTh HfsFileTh; /* same as directory thread */
+
+/* Catalog data */
+struct __attribute__ ((packed)) _HfsCatalog {
+ int8_t type;
+ int8_t reserved;
+ union {
+ HfsDir dir;
+ HfsFile file;
+ HfsDirTh dir_th;
+ HfsFileTh file_th;
+ } sel;
+};
+typedef struct _HfsCatalog HfsCatalog;
+
+
+
+/* ------------------------------------ */
+/* -- HFS+ DATA STRUCTURES -- */
+/* ------------------------------------ */
+
+/* documented since 2004 in tn1150 */
+struct __attribute__ ((packed)) _HfsPPerms {
+ uint32_t owner_ID;
+ uint32_t group_ID;
+ uint32_t permissions;
+ uint32_t special_devices;
+};
+typedef struct _HfsPPerms HfsPPerms;
+
+/* HFS+ extent descriptor*/
+struct __attribute__ ((packed)) _HfsPExtDescriptor {
+ uint32_t start_block;
+ uint32_t block_count;
+};
+typedef struct _HfsPExtDescriptor HfsPExtDescriptor;
+typedef HfsPExtDescriptor HfsPExtDataRec[HFSP_EXT_NB];
+
+/* HFS+ fork data structure */
+struct __attribute__ ((packed)) _HfsPForkData {
+ uint64_t logical_size;
+ uint32_t clump_size;
+ uint32_t total_blocks;
+ HfsPExtDataRec extents;
+};
+typedef struct _HfsPForkData HfsPForkData;
+
+/* HFS+ catalog node ID */
+typedef uint32_t HfsPNodeID;
+
+/* HFS+ file names */
+typedef uint16_t unichar;
+struct __attribute__ ((packed)) _HfsPUniStr255 {
+ uint16_t length;
+ unichar unicode[255]; /* 1 upto 255 */
+};
+typedef struct _HfsPUniStr255 HfsPUniStr255;
+
+/* HFS+ volume header */
+struct __attribute__ ((packed)) _HfsPVolumeHeader {
+ uint16_t signature;
+ uint16_t version;
+ uint32_t attributes;
+ uint32_t last_mounted_version;
+ uint32_t journal_info_block;
+
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t backup_date;
+ uint32_t checked_date;
+
+ uint32_t file_count;
+ uint32_t dir_count;
+
+ uint32_t block_size;
+ uint32_t total_blocks;
+ uint32_t free_blocks;
+
+ uint32_t next_allocation;
+ uint32_t res_clump_size;
+ uint32_t data_clump_size;
+ HfsPNodeID next_catalog_ID;
+
+ uint32_t write_count;
+ uint64_t encodings_bitmap;
+
+ uint8_t finder_info[32];
+
+ HfsPForkData allocation_file;
+ HfsPForkData extents_file;
+ HfsPForkData catalog_file;
+ HfsPForkData attributes_file;
+ HfsPForkData startup_file;
+};
+typedef struct _HfsPVolumeHeader HfsPVolumeHeader;
+
+/* HFS+ B-Tree Node Descriptor. Same as HFS btree. */
+struct __attribute__ ((packed)) _HfsPNodeDescriptor {
+ uint32_t next;
+ uint32_t previous;
+ int8_t type;
+ uint8_t height;
+ uint16_t rec_nb;
+ uint16_t reserved;
+};
+typedef struct _HfsPNodeDescriptor HfsPNodeDescriptor;
+
+/* Header record of a whole HFS+ B-Tree. */
+struct __attribute__ ((packed)) _HfsPHeaderRecord {
+ uint16_t depth;
+ uint32_t root_node;
+ uint32_t leaf_records;
+ uint32_t first_leaf_node;
+ uint32_t last_leaf_node;
+ uint16_t node_size;
+ uint16_t max_key_len;
+ uint32_t total_nodes;
+ uint32_t free_nodes; /* same as hfs btree until here */
+ uint16_t reserved1;
+
+ uint32_t clump_size;
+ uint8_t btree_type; /* must be 0 for HFS+ B-Tree */
+ uint8_t key_compare_type; /* hfsx => 0xCF = case folding */
+ /* 0xBC = binary compare */
+ /* otherwise, reserved */
+ uint32_t attributes;
+ uint32_t reserved3[16];
+};
+typedef struct _HfsPHeaderRecord HfsPHeaderRecord;
+
+/* Catalog key for B-Tree lookup in the HFS+ catalog file */
+struct __attribute__ ((packed)) _HfsPCatalogKey {
+ uint16_t key_length;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPCatalogKey HfsPCatalogKey;
+
+/* HFS+ catalog subdata case dir */
+struct __attribute__ ((packed)) _HfsPDir {
+ uint16_t flags;
+ uint32_t valence;
+ HfsPNodeID dir_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t DInfo[16]; /* used by Finder, handle as reserved */
+ int8_t DXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved;
+};
+typedef struct _HfsPDir HfsPDir;
+
+/* HFS+ catalog subdata case file */
+struct __attribute__ ((packed)) _HfsPFile {
+ uint16_t flags;
+ uint32_t reserved1;
+ HfsPNodeID file_ID;
+ uint32_t create_date;
+ uint32_t modify_date;
+ uint32_t attrib_mod_date;
+ uint32_t access_date;
+ uint32_t backup_date;
+ HfsPPerms permissions;
+ int8_t FInfo[16]; /* used by Finder, handle as reserved */
+ int8_t FXInfo[16]; /* used by Finder, handle as reserved */
+ uint32_t text_encoding;
+ uint32_t reserved2;
+
+ HfsPForkData data_fork;
+ HfsPForkData res_fork;
+};
+typedef struct _HfsPFile HfsPFile;
+
+/* HFS+ catalog subdata case thread */
+struct __attribute__ ((packed)) _HfsPThread {
+ int16_t reserved;
+ HfsPNodeID parent_ID;
+ HfsPUniStr255 node_name;
+};
+typedef struct _HfsPThread HfsPDirTh;
+typedef struct _HfsPThread HfsPFileTh;
+
+/* HFS+ Catalog leaf data */
+struct __attribute__ ((packed)) _HfsPCatalog {
+ int16_t type;
+ union {
+ HfsPDir dir;
+ HfsPFile file;
+ HfsPDirTh dir_th;
+ HfsPFileTh file_th;
+ } sel;
+};
+typedef struct _HfsPCatalog HfsPCatalog;
+
+/* HFS+ extents file key */
+struct __attribute__ ((packed)) _HfsPExtentKey {
+ uint16_t key_length;
+ uint8_t type;
+ uint8_t pad;
+ HfsPNodeID file_ID;
+ uint32_t start;
+};
+typedef struct _HfsPExtentKey HfsPExtentKey;
+
+/* extent file data is HfsPExtDataRec */
+
+/* Fork data attribute file */
+struct __attribute__ ((packed)) _HfsPForkDataAttr {
+ uint32_t record_type;
+ uint32_t reserved;
+ union __attribute__ ((packed)) {
+ HfsPForkData fork;
+ HfsPExtDataRec extents;
+ } fork_res;
+};
+typedef struct _HfsPForkDataAttr HfsPForkDataAttr;
+
+
+/* ----------- Journal data structures ----------- */
+
+/* Info block : stored in a block # defined in the VH */
+struct __attribute__ ((packed)) _HfsJJournalInfoBlock {
+ uint32_t flags;
+ uint32_t device_signature[8];
+ uint64_t offset;
+ uint64_t size;
+ uint32_t reserved[32];
+};
+typedef struct _HfsJJournalInfoBlock HfsJJournalInfoBlock;
+
+struct __attribute__ ((packed)) _HfsJJournalHeader {
+ uint32_t magic;
+ uint32_t endian;
+ uint64_t start;
+ uint64_t end;
+ uint64_t size;
+ uint32_t blhdr_size;
+ uint32_t checksum;
+ uint32_t jhdr_size;
+};
+typedef struct _HfsJJournalHeader HfsJJournalHeader;
+
+struct __attribute__ ((packed)) _HfsJBlockInfo {
+ uint64_t bnum; /* sector number */
+ uint32_t bsize; /* size in bytes */
+ uint32_t next;
+};
+typedef struct _HfsJBlockInfo HfsJBlockInfo;
+
+struct __attribute__ ((packed)) _HfsJBlockListHeader {
+ uint16_t max_blocks; /* reserved */
+ uint16_t num_blocks;
+ uint32_t bytes_used;
+ uint32_t checksum;
+ uint32_t pad;
+ HfsJBlockInfo binfo[];
+};
+typedef struct _HfsJBlockListHeader HfsJBlockListHeader;
+
+
+
+/* ---------------------------------------- */
+/* -- INTERNAL DATA STRUCTURES -- */
+/* ---------------------------------------- */
+
+/* Data of an opened HFS file */
+struct _HfsPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ uint32_t CNID; /* disk order (BE) */
+ HfsExtDataRec first; /* disk order (BE) */
+ HfsExtDataRec cache; /* disk order (BE) */
+ uint16_t start_cache; /* CPU order */
+};
+typedef struct _HfsPrivateFile HfsPrivateFile;
+
+/* To store bad block list */
+struct _HfsPrivateLinkExtent {
+ HfsExtDescriptor extent;
+ struct _HfsPrivateLinkExtent* next;
+};
+typedef struct _HfsPrivateLinkExtent HfsPrivateLinkExtent;
+
+/* HFS Filesystem specific data */
+struct _HfsPrivateFSData {
+ uint8_t alloc_map[(1<<16) / 8];
+ HfsMasterDirectoryBlock* mdb;
+ HfsPrivateFile* extent_file;
+ HfsPrivateFile* catalog_file;
+ HfsPrivateLinkExtent* bad_blocks_xtent_list;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+};
+typedef struct _HfsPrivateFSData HfsPrivateFSData;
+
+/* Generic btree key */
+struct __attribute__ ((packed)) _HfsPrivateGenericKey {
+ uint8_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPrivateGenericKey HfsPrivateGenericKey;
+
+/* ----- HFS+ ----- */
+
+/* Data of an opened HFS file */
+struct _HfsPPrivateFile {
+ PedSector sect_nb;
+ PedFileSystem* fs;
+ HfsPNodeID CNID; /* disk order (BE) */
+ HfsPExtDataRec first; /* disk order (BE) */
+ HfsPExtDataRec cache; /* disk order (BE) */
+ uint32_t start_cache; /* CPU order */
+};
+typedef struct _HfsPPrivateFile HfsPPrivateFile;
+
+struct _HfsPPrivateExtent {
+ PedSector start_sector;
+ PedSector sector_count;
+};
+typedef struct _HfsPPrivateExtent HfsPPrivateExtent;
+
+/* To store bad block list */
+struct _HfsPPrivateLinkExtent {
+ HfsPExtDescriptor extent;
+ struct _HfsPPrivateLinkExtent* next;
+};
+typedef struct _HfsPPrivateLinkExtent HfsPPrivateLinkExtent;
+
+/* HFS+ file system specific data */
+struct _HfsPPrivateFSData {
+ PedFileSystem* wrapper; /* NULL if hfs+ is not embedded */
+ PedGeometry* plus_geom; /* Geometry of HFS+ _volume_ */
+ uint8_t* alloc_map;
+ uint8_t* dirty_alloc_map;
+ HfsPVolumeHeader* vh;
+ HfsPPrivateFile* extents_file;
+ HfsPPrivateFile* catalog_file;
+ HfsPPrivateFile* attributes_file;
+ HfsPPrivateFile* allocation_file;
+ HfsPPrivateLinkExtent* bad_blocks_xtent_list;
+ uint32_t jib_start_block;
+ uint32_t jl_start_block;
+ unsigned int bad_blocks_xtent_nb;
+ char bad_blocks_loaded;
+ char free_geom; /* 1 = plus_geom must be freed */
+};
+typedef struct _HfsPPrivateFSData HfsPPrivateFSData;
+
+/* Generic + btree key */
+struct __attribute__ ((packed)) _HfsPPrivateGenericKey {
+ uint16_t key_length;
+ uint8_t key_content[1]; /* we use 1 as a minimum size */
+};
+typedef struct _HfsPPrivateGenericKey HfsPPrivateGenericKey;
+
+/* ---- common ---- */
+
+/* node and lead record reference for a BTree search */
+struct _HfsCPrivateLeafRec {
+ unsigned int node_size; /* in sectors */
+ unsigned int node_number;
+ unsigned int record_pos;
+ unsigned int record_number;
+};
+typedef struct _HfsCPrivateLeafRec HfsCPrivateLeafRec;
+
+extern uint8_t* hfs_block;
+extern uint8_t* hfsp_block;
+extern unsigned hfs_block_count;
+extern unsigned hfsp_block_count;
+
+#endif /* _HFS_H */
diff --git a/libparted/fs/r/hfs/journal.c b/libparted/fs/r/hfs/journal.c
new file mode 100644
index 0000000..7a2a8dc
--- /dev/null
+++ b/libparted/fs/r/hfs/journal.c
@@ -0,0 +1,392 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "reloc_plus.h"
+
+#include "journal.h"
+
+static int hfsj_vh_replayed = 0;
+static int is_le = 0;
+
+static uint32_t
+hfsj_calc_checksum(uint8_t *ptr, int len)
+{
+ int i;
+ uint32_t cksum=0;
+
+ for (i=0; i < len; i++, ptr++) {
+ cksum = (cksum << 8) ^ (cksum + *ptr);
+ }
+
+ return (~cksum);
+}
+
+int
+hfsj_update_jib(PedFileSystem* fs, uint32_t block)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+
+ priv_data->vh->journal_info_block = PED_CPU_TO_BE32(block);
+
+ if (!hfsplus_update_vh (fs))
+ return 0;
+
+ priv_data->jib_start_block = block;
+ return 1;
+}
+
+int
+hfsj_update_jl(PedFileSystem* fs, uint32_t block)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedSector sector;
+ uint64_t offset;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsJJournalInfoBlock* jib;
+ int binsect;
+
+ binsect = HFS_32_TO_CPU(priv_data->vh->block_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
+ sector = (PedSector) priv_data->jib_start_block * binsect;
+ if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
+ return 0;
+ jib = (HfsJJournalInfoBlock*) buf;
+
+ offset = (uint64_t)block * PED_SECTOR_SIZE_DEFAULT * binsect;
+ jib->offset = HFS_CPU_TO_64(offset, is_le);
+
+ if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
+ || !ped_geometry_sync(priv_data->plus_geom))
+ return 0;
+
+ priv_data->jl_start_block = block;
+ return 1;
+}
+
+/* Return the sector in the journal that is after the area read */
+/* or 0 on error */
+static PedSector
+hfsj_journal_read(PedGeometry* geom, HfsJJournalHeader* jh,
+ PedSector journ_sect, PedSector journ_length,
+ PedSector read_sect, unsigned int nb_sect,
+ void* buf)
+{
+ int r;
+
+ while (nb_sect--) {
+ r = ped_geometry_read(geom, buf, journ_sect + read_sect, 1);
+ if (!r) return 0;
+
+ buf = ((uint8_t*)buf) + PED_SECTOR_SIZE_DEFAULT;
+ read_sect++;
+ if (read_sect == journ_length)
+ read_sect = 1; /* skip journal header
+ which is asserted to be
+ 1 sector long */
+ }
+
+ return read_sect;
+}
+
+static int
+hfsj_replay_transaction(PedFileSystem* fs, HfsJJournalHeader* jh,
+ PedSector jsector, PedSector jlength)
+{
+ PedSector start, sector;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsJBlockListHeader* blhdr;
+ uint8_t* block;
+ unsigned int blhdr_nbsect;
+ int i, r;
+ uint32_t cksum, size;
+
+ blhdr_nbsect = HFS_32_TO_CPU(jh->blhdr_size, is_le) / PED_SECTOR_SIZE_DEFAULT;
+ blhdr = (HfsJBlockListHeader*)
+ ped_malloc (blhdr_nbsect * PED_SECTOR_SIZE_DEFAULT);
+ if (!blhdr) return 0;
+
+ start = HFS_64_TO_CPU(jh->start, is_le) / PED_SECTOR_SIZE_DEFAULT;
+ do {
+ start = hfsj_journal_read(priv_data->plus_geom, jh, jsector,
+ jlength, start, blhdr_nbsect, blhdr);
+ if (!start) goto err_replay;
+
+ cksum = HFS_32_TO_CPU(blhdr->checksum, is_le);
+ blhdr->checksum = 0;
+ if (cksum!=hfsj_calc_checksum((uint8_t*)blhdr, sizeof(*blhdr))){
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Bad block list header checksum."));
+ goto err_replay;
+ }
+ blhdr->checksum = HFS_CPU_TO_32(cksum, is_le);
+
+ for (i=1; i < HFS_16_TO_CPU(blhdr->num_blocks, is_le); ++i) {
+ size = HFS_32_TO_CPU(blhdr->binfo[i].bsize, is_le);
+ sector = HFS_64_TO_CPU(blhdr->binfo[i].bnum, is_le);
+ if (!size) continue;
+ if (size % PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw(
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Invalid size of a transaction "
+ "block while replaying the journal "
+ "(%i bytes)."),
+ size);
+ goto err_replay;
+ }
+ block = (uint8_t*) ped_malloc(size);
+ if (!block) goto err_replay;
+ start = hfsj_journal_read(priv_data->plus_geom, jh,
+ jsector, jlength, start,
+ size / PED_SECTOR_SIZE_DEFAULT,
+ block);
+ if (!start) {
+ free (block);
+ goto err_replay;
+ }
+ /* the sector stored in the journal seems to be
+ relative to the begin of the block device which
+ contains the hfs+ journaled volume */
+ if (sector != ~0LL)
+ r = ped_geometry_write (fs->geom, block, sector,
+ size / PED_SECTOR_SIZE_DEFAULT);
+ else
+ r = 1;
+ free (block);
+ /* check if wrapper mdb or vh with no wrapper has
+ changed */
+ if ( (sector != ~0LL)
+ && (2 >= sector)
+ && (2 < sector + size / PED_SECTOR_SIZE_DEFAULT) )
+ hfsj_vh_replayed = 1;
+ /* check if vh of embedded hfs+ has changed */
+ if ( (sector != ~0LL)
+ && (priv_data->plus_geom != fs->geom)
+ && (sector
+ + fs->geom->start
+ - priv_data->plus_geom->start <= 2)
+ && (sector
+ + size / PED_SECTOR_SIZE_DEFAULT
+ + fs->geom->start
+ - priv_data->plus_geom->start > 2) )
+ hfsj_vh_replayed = 1;
+ if (!r) goto err_replay;
+ }
+ } while (blhdr->binfo[0].next);
+
+ jh->start = HFS_CPU_TO_64(start * PED_SECTOR_SIZE_DEFAULT, is_le);
+
+ free (blhdr);
+ return (ped_geometry_sync (fs->geom));
+
+err_replay:
+ free (blhdr);
+ return 0;
+}
+
+/* 0 => Failure, don't continue to open ! */
+/* 1 => Success, the journal has been completly replayed, or don't need to */
+int
+hfsj_replay_journal(PedFileSystem* fs)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ PedSector sector, length;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsJJournalInfoBlock* jib;
+ HfsJJournalHeader* jh;
+ int binsect;
+ uint32_t cksum;
+
+ binsect = PED_BE32_TO_CPU(priv_data->vh->block_size) / PED_SECTOR_SIZE_DEFAULT;
+ priv_data->jib_start_block =
+ PED_BE32_TO_CPU(priv_data->vh->journal_info_block);
+ sector = (PedSector) priv_data->jib_start_block * binsect;
+ if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
+ return 0;
+ jib = (HfsJJournalInfoBlock*) buf;
+
+ if ( (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
+ && !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
+ priv_data->jl_start_block = HFS_64_TO_CPU(jib->offset, is_le)
+ / ( PED_SECTOR_SIZE_DEFAULT * binsect );
+ }
+
+ if (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_NEED_INIT))
+ return 1;
+
+ if ( !(jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_IN_FS))
+ || (jib->flags & PED_CPU_TO_BE32(1 << HFSJ_JOURN_OTHER_DEV)) ) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Journal stored outside of the volume are "
+ "not supported. Try to deactivate the "
+ "journal and run Parted again."));
+ return 0;
+ }
+
+ if ( (PED_BE64_TO_CPU(jib->offset) % PED_SECTOR_SIZE_DEFAULT)
+ || (PED_BE64_TO_CPU(jib->size) % PED_SECTOR_SIZE_DEFAULT) ) {
+ ped_exception_throw (
+ PED_EXCEPTION_NO_FEATURE,
+ PED_EXCEPTION_CANCEL,
+ _("Journal offset or size is not multiple of "
+ "the sector size."));
+ return 0;
+ }
+
+ sector = PED_BE64_TO_CPU(jib->offset) / PED_SECTOR_SIZE_DEFAULT;
+ length = PED_BE64_TO_CPU(jib->size) / PED_SECTOR_SIZE_DEFAULT;
+
+ jib = NULL;
+ if (!ped_geometry_read(priv_data->plus_geom, buf, sector, 1))
+ return 0;
+ jh = (HfsJJournalHeader*) buf;
+
+ if (jh->endian == PED_LE32_TO_CPU(HFSJ_ENDIAN_MAGIC))
+ is_le = 1;
+
+ if ( (jh->magic != HFS_32_TO_CPU(HFSJ_HEADER_MAGIC, is_le))
+ || (jh->endian != HFS_32_TO_CPU(HFSJ_ENDIAN_MAGIC, is_le)) ) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Incorrect magic values in the journal header."));
+ return 0;
+ }
+
+ if ( (HFS_64_TO_CPU(jh->size, is_le)%PED_SECTOR_SIZE_DEFAULT)
+ || (HFS_64_TO_CPU(jh->size, is_le)/PED_SECTOR_SIZE_DEFAULT
+ != (uint64_t)length) ) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Journal size mismatch between journal info block "
+ "and journal header."));
+ return 0;
+ }
+
+ if ( (HFS_64_TO_CPU(jh->start, is_le) % PED_SECTOR_SIZE_DEFAULT)
+ || (HFS_64_TO_CPU(jh->end, is_le) % PED_SECTOR_SIZE_DEFAULT)
+ || (HFS_32_TO_CPU(jh->blhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT)
+ || (HFS_32_TO_CPU(jh->jhdr_size, is_le) % PED_SECTOR_SIZE_DEFAULT) ) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Some header fields are not multiple of the sector "
+ "size."));
+ return 0;
+ }
+
+ if (HFS_32_TO_CPU(jh->jhdr_size, is_le) != PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The sector size stored in the journal is not 512 "
+ "bytes. Parted only supports 512 bytes length "
+ "sectors."));
+ return 0;
+ }
+
+ cksum = HFS_32_TO_CPU(jh->checksum, is_le);
+ jh->checksum = 0;
+ if (cksum != hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Bad journal checksum."));
+ return 0;
+ }
+ jh->checksum = HFS_CPU_TO_32(cksum, is_le);
+
+ /* https://github.com/apple-opensource/hfs/blob/master/core/hfs_journal.c#L1167
+ * indicates that this is:
+ * wrap the start ptr if it points to the very end of the journal
+ */
+ if (jh->start == jh->size)
+ jh->start = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
+ if (jh->end == jh->size)
+ jh->end = HFS_CPU_TO_64(PED_SECTOR_SIZE_DEFAULT, is_le);
+
+ if (jh->start == jh->end)
+ return 1;
+
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_FIX | PED_EXCEPTION_CANCEL,
+ _("The journal is not empty. Parted must replay the "
+ "transactions before opening the file system. This will "
+ "modify the file system."))
+ != PED_EXCEPTION_FIX)
+ return 0;
+
+ while (jh->start != jh->end) {
+ /* Replay one complete transaction */
+ if (!hfsj_replay_transaction(fs, jh, sector, length))
+ return 0;
+
+ /* Recalculate cksum of the journal header */
+ jh->checksum = 0; /* need to be 0 while calculating the cksum */
+ cksum = hfsj_calc_checksum((uint8_t*)jh, sizeof(*jh));
+ jh->checksum = HFS_CPU_TO_32(cksum, is_le);
+
+ /* Update the Journal Header */
+ if (!ped_geometry_write(priv_data->plus_geom, buf, sector, 1)
+ || !ped_geometry_sync(priv_data->plus_geom))
+ return 0;
+ }
+
+ if (hfsj_vh_replayed) {
+ /* probe could have reported incorrect info ! */
+ /* is there a way to ask parted to quit ? */
+ ped_exception_throw(
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_OK,
+ _("The volume header or the master directory block has "
+ "changed while replaying the journal. You should "
+ "restart Parted."));
+ return 0;
+ }
+
+ return 1;
+}
+
+#endif /* DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/journal.h b/libparted/fs/r/hfs/journal.h
new file mode 100644
index 0000000..66eb2b1
--- /dev/null
+++ b/libparted/fs/r/hfs/journal.h
@@ -0,0 +1,45 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _JOURNAL_H
+#define _JOURNAL_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsj_replay_journal(PedFileSystem* fs);
+
+int
+hfsj_update_jib(PedFileSystem* fs, uint32_t block);
+
+int
+hfsj_update_jl(PedFileSystem* fs, uint32_t block);
+
+#define HFS_16_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_LE16_TO_CPU(x) : (uint16_t)PED_BE16_TO_CPU(x))
+#define HFS_32_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_LE32_TO_CPU(x) : (uint32_t)PED_BE32_TO_CPU(x))
+#define HFS_64_TO_CPU(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_LE64_TO_CPU(x) : (uint64_t)PED_BE64_TO_CPU(x))
+#define HFS_CPU_TO_16(x, is_little_endian) ((is_little_endian) ? (uint16_t)PED_CPU_TO_LE16(x) : (uint16_t)PED_CPU_TO_BE16(x))
+#define HFS_CPU_TO_32(x, is_little_endian) ((is_little_endian) ? (uint32_t)PED_CPU_TO_LE32(x) : (uint32_t)PED_CPU_TO_BE32(x))
+#define HFS_CPU_TO_64(x, is_little_endian) ((is_little_endian) ? (uint64_t)PED_CPU_TO_LE64(x) : (uint64_t)PED_CPU_TO_BE64(x))
+
+#endif /* _JOURNAL_H */
diff --git a/libparted/fs/r/hfs/probe.c b/libparted/fs/r/hfs/probe.c
new file mode 100644
index 0000000..ee4ae31
--- /dev/null
+++ b/libparted/fs/r/hfs/probe.c
@@ -0,0 +1,99 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+
+#include "probe.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom)
+{
+ PedDevice* dev;
+
+ dev = geom->dev;
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (dev != NULL);
+
+ if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Parted can't use HFS file systems on disks "
+ "with a sector size not equal to %d bytes."),
+ (int)PED_SECTOR_SIZE_DEFAULT );
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Probe an HFS volume, detecting it even if
+it is in fact a wrapper to an HFS+ volume */
+/* Used by hfsplus_probe and hfs_probe */
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom)
+{
+ uint8_t buf[PED_SECTOR_SIZE_DEFAULT];
+ HfsMasterDirectoryBlock *mdb;
+ PedGeometry* geom_ret;
+ PedSector search, max;
+
+ PED_ASSERT (geom != NULL);
+ PED_ASSERT (hfsc_can_use_geom (geom));
+
+ mdb = (HfsMasterDirectoryBlock *) buf;
+
+ /* is 5 an intelligent value ? */
+ if ((geom->length < 5)
+ || (!ped_geometry_read (geom, buf, 2, 1))
+ || (mdb->signature != PED_CPU_TO_BE16 (HFS_SIGNATURE)) )
+ return NULL;
+
+ search = ((PedSector) PED_BE16_TO_CPU (mdb->start_block)
+ + ((PedSector) PED_BE16_TO_CPU (mdb->total_blocks)
+ * (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT )));
+ max = search + (PED_BE32_TO_CPU (mdb->block_size) / PED_SECTOR_SIZE_DEFAULT);
+ if (!(geom_ret = ped_geometry_new (geom->dev, geom->start, search + 2)))
+ return NULL;
+
+ for (; search < max; search++) {
+ if (!ped_geometry_set (geom_ret, geom_ret->start, search + 2)
+ || !ped_geometry_read (geom_ret, buf, search, 1))
+ break;
+ if (mdb->signature == PED_CPU_TO_BE16 (HFS_SIGNATURE))
+ return geom_ret;
+ }
+
+ ped_geometry_destroy (geom_ret);
+ return NULL;
+}
diff --git a/libparted/fs/r/hfs/probe.h b/libparted/fs/r/hfs/probe.h
new file mode 100644
index 0000000..21be916
--- /dev/null
+++ b/libparted/fs/r/hfs/probe.h
@@ -0,0 +1,35 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef _PROBE_H
+#define _PROBE_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsc_can_use_geom (PedGeometry* geom);
+
+PedGeometry*
+hfs_and_wrapper_probe (PedGeometry* geom);
+
+#endif /* _PROBE_H */
diff --git a/libparted/fs/r/hfs/reloc.c b/libparted/fs/r/hfs/reloc.c
new file mode 100644
index 0000000..05ec76a
--- /dev/null
+++ b/libparted/fs/r/hfs/reloc.c
@@ -0,0 +1,676 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "file.h"
+#include "advfs.h"
+#include "cache.h"
+
+#include "reloc.h"
+
+/* This function moves data of size blocks starting
+ at block *ptr_fblock to block *ptr_to_fblock */
+/* return new start or -1 on failure */
+static int
+hfs_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
+ unsigned int *ptr_to_fblock, unsigned int size)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ unsigned int i, ok = 0;
+ unsigned int next_to_fblock;
+ unsigned int start, stop;
+
+ PED_ASSERT (hfs_block != NULL);
+ PED_ASSERT (*ptr_to_fblock <= *ptr_fblock);
+ /* quiet gcc */
+ start = stop = 0;
+
+/*
+ Try to fit the extent AT or _BEFORE_ the wanted place,
+ or then in the gap between dest and source.
+ If failed try to fit the extent after source, for 2 pass relocation
+ The extent is always copied in a non overlapping way
+*/
+
+ /* Backward search */
+ /* 1 pass relocation AT or BEFORE *ptr_to_fblock */
+ if (*ptr_to_fblock != *ptr_fblock) {
+ start = stop = *ptr_fblock < *ptr_to_fblock+size ?
+ *ptr_fblock : *ptr_to_fblock+size;
+ while (start && stop-start != size) {
+ --start;
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
+ stop = start;
+ }
+ ok = (stop-start == size);
+ }
+
+ /* Forward search */
+ /* 1 pass relocation in the gap merged with 2 pass reloc after source */
+ if (!ok && *ptr_to_fblock != *ptr_fblock) {
+ start = stop = *ptr_to_fblock+1;
+ while (stop < PED_BE16_TO_CPU(priv_data->mdb->total_blocks)
+ && stop-start != size) {
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
+ start = stop + 1;
+ ++stop;
+ }
+ ok = (stop-start == size);
+ }
+
+ /* new non overlapping room has been found ? */
+ if (ok) {
+ /* enough room */
+ unsigned int j;
+ unsigned int start_block =
+ PED_BE16_TO_CPU (priv_data->mdb->start_block );
+ unsigned int block_sz =
+ (PED_BE32_TO_CPU (priv_data->mdb->block_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+
+ if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
+ /* Fit in the gap */
+ next_to_fblock = stop;
+ else
+ /* Before or after the gap */
+ next_to_fblock = *ptr_to_fblock;
+
+ /* move blocks */
+ for (i = 0; i < size; /*i+=j*/) {
+ PedSector abs_sector;
+ unsigned int ai;
+
+ j = size - i; j = (j < hfs_block_count) ?
+ j : hfs_block_count ;
+
+ abs_sector = start_block
+ + (PedSector) (*ptr_fblock + i) * block_sz;
+ if (!ped_geometry_read (fs->geom, hfs_block, abs_sector,
+ block_sz * j))
+ return -1;
+
+ abs_sector = start_block
+ + (PedSector) (start + i) * block_sz;
+ if (!ped_geometry_write (fs->geom,hfs_block,abs_sector,
+ block_sz * j))
+ return -1;
+
+ for (ai = i+j; i < ai; i++) {
+ /* free source block */
+ CLR_BLOC_OCCUPATION(priv_data->alloc_map,
+ *ptr_fblock + i);
+
+ /* set dest block */
+ SET_BLOC_OCCUPATION(priv_data->alloc_map,
+ start + i);
+ }
+ }
+ if (!ped_geometry_sync_fast (fs->geom))
+ return -1;
+
+ *ptr_fblock += size;
+ *ptr_to_fblock = next_to_fblock;
+ } else {
+ if (*ptr_fblock != *ptr_to_fblock)
+ /* not enough room, but try to continue */
+ ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("An extent has not been relocated."));
+ start = *ptr_fblock;
+ *ptr_fblock = *ptr_to_fblock = start + size;
+ }
+
+ return start;
+}
+
+/* Update MDB */
+/* Return 0 if an error occurred */
+/* Return 1 if everything ok */
+int
+hfs_update_mdb (PedFileSystem *fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+
+ if (!ped_geometry_read (fs->geom, node, 2, 1))
+ return 0;
+ memcpy (node, priv_data->mdb, sizeof (HfsMasterDirectoryBlock));
+ if ( !ped_geometry_write (fs->geom, node, 2, 1)
+ || !ped_geometry_write (fs->geom, node, fs->geom->length - 2, 1)
+ || !ped_geometry_sync_fast (fs->geom))
+ return 0;
+ return 1;
+}
+
+/* Generic relocator */
+/* replace previous hfs_do_move_* */
+static int
+hfs_do_move (PedFileSystem* fs, unsigned int *ptr_src,
+ unsigned int *ptr_dest, HfsCPrivateCache* cache,
+ HfsCPrivateExtent* ref)
+{
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsPrivateFile* file;
+ HfsExtDescriptor* extent;
+ HfsCPrivateExtent* move;
+ int new_start;
+
+ new_start = hfs_effect_move_extent (fs, ptr_src, ptr_dest,
+ ref->ext_length);
+ if (new_start == -1) return -1;
+
+ if (ref->ext_start != (unsigned) new_start) {
+ /* Load, modify & save */
+ switch (ref->where) {
+ /******** MDB *********/
+ case CR_PRIM_CAT :
+ priv_data->catalog_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE16(new_start);
+ goto CR_PRIM;
+ case CR_PRIM_EXT :
+ priv_data->extent_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE16(new_start);
+ CR_PRIM :
+ extent = ( HfsExtDescriptor* )
+ ( (uint8_t*)priv_data->mdb + ref->ref_offset );
+ extent[ref->ref_index].start_block =
+ PED_CPU_TO_BE16(new_start);
+ if (!hfs_update_mdb(fs)) return -1;
+ break;
+
+ /********* BTREE *******/
+ case CR_BTREE_EXT_CAT :
+ if (priv_data->catalog_file
+ ->cache[ref->ref_index].start_block
+ == PED_CPU_TO_BE16(ref->ext_start))
+ priv_data->catalog_file
+ ->cache[ref->ref_index].start_block =
+ PED_CPU_TO_BE16(new_start);
+ /* FALLTHROUGH */
+ case CR_BTREE_EXT_0 :
+ file = priv_data->extent_file;
+ goto CR_BTREE;
+ case CR_BTREE_CAT :
+ file = priv_data->catalog_file;
+ CR_BTREE:
+ PED_ASSERT(ref->sect_by_block == 1
+ && ref->ref_offset < PED_SECTOR_SIZE_DEFAULT);
+ if (!hfs_file_read_sector(file, node, ref->ref_block))
+ return -1;
+ extent = ( HfsExtDescriptor* ) (node + ref->ref_offset);
+ extent[ref->ref_index].start_block =
+ PED_CPU_TO_BE16(new_start);
+ if (!hfs_file_write_sector(file, node, ref->ref_block)
+ || !ped_geometry_sync_fast (fs->geom))
+ return -1;
+ break;
+
+ /********** BUG ********/
+ default :
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("A reference to an extent comes from a place "
+ "it should not. You should check the file "
+ "system!"));
+ return -1;
+ break;
+ }
+
+ /* Update the cache */
+ move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
+ if (!move) return -1; /* "cleanly" fail */
+ PED_ASSERT(move == ref); /* generate a bug */
+ }
+
+ return new_start;
+}
+
+/* 0 error, 1 ok */
+static int
+hfs_save_allocation(PedFileSystem* fs)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ unsigned int map_sectors;
+
+ map_sectors = ( PED_BE16_TO_CPU (priv_data->mdb->total_blocks)
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1 )
+ / (PED_SECTOR_SIZE_DEFAULT * 8);
+ return ( ped_geometry_write (fs->geom, priv_data->alloc_map,
+ PED_BE16_TO_CPU (priv_data->mdb->volume_bitmap_block),
+ map_sectors) );
+}
+
+/* This function moves an extent starting at block fblock to block to_fblock
+ if there's enough room */
+/* Return 1 if everything was fine */
+/* Return -1 if an error occurred */
+/* Return 0 if no extent was found */
+/* Generic search thanks to the file system cache */
+static int
+hfs_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
+ unsigned int *ptr_to_fblock,
+ HfsCPrivateCache* cache)
+{
+ HfsCPrivateExtent* ref;
+ unsigned int old_start, new_start;
+
+ /* Reference search powered by the cache... */
+ /* This is the optimisation secret :) */
+ ref = hfsc_cache_search_extent(cache, *ptr_fblock);
+ if (!ref) return 0; /* not found */
+
+ old_start = *ptr_fblock;
+ new_start = hfs_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
+ if (new_start == (unsigned int) -1) return -1;
+ if (new_start > old_start) { /* detect 2 pass reloc */
+ new_start = hfs_do_move(fs,&new_start,ptr_to_fblock,cache,ref);
+ if (new_start == (unsigned int) -1 || new_start > old_start)
+ return -1;
+ }
+
+ /* allocation bitmap save is not atomic with data relocation */
+ /* so we only do it a few times, and without syncing */
+ /* The unmounted bit protect us anyway */
+ hfs_save_allocation(fs);
+ return 1;
+}
+
+static int
+hfs_cache_from_mdb(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsExtDescriptor* extent;
+ unsigned int j;
+
+ extent = priv_data->mdb->extents_file_rec;
+ for (j = 0; j < HFS_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE16_TO_CPU(extent[j].start_block),
+ PED_BE16_TO_CPU(extent[j].block_count),
+ 0, /* unused for mdb */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
+ 1, /* load/save only 1 sector */
+ CR_PRIM_EXT,
+ j )
+ )
+ return 0;
+ }
+
+ extent = priv_data->mdb->catalog_file_rec;
+ for (j = 0; j < HFS_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE16_TO_CPU(extent[j].start_block),
+ PED_BE16_TO_CPU(extent[j].block_count),
+ 0,
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->mdb),
+ 1,
+ CR_PRIM_CAT,
+ j )
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+hfs_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+ HfsHeaderRecord* header;
+ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
+ HfsCatalogKey* catalog_key;
+ HfsCatalog* catalog_data;
+ HfsExtDescriptor* extent;
+ unsigned int leaf_node, record_number;
+ unsigned int i, j;
+ uint16_t catalog_pos;
+
+ if (!priv_data->catalog_file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This HFS volume has no catalog file. "
+ "This is very unusual!"));
+ return 1;
+ }
+
+ if (!hfs_file_read_sector (priv_data->catalog_file, node, 0))
+ return 0;
+ uint16_t offset;
+ memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
+ header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
+
+ for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
+ leaf_node;
+ leaf_node = PED_BE32_TO_CPU (desc->next)) {
+ if (!hfs_file_read_sector (priv_data->catalog_file,
+ node, leaf_node))
+ return 0;
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = 1; i <= record_number; ++i) {
+ /* undocumented alignement */
+ uint16_t value;
+ memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
+ catalog_pos = PED_BE16_TO_CPU(value);
+ catalog_key = (HfsCatalogKey*) (node + catalog_pos);
+ unsigned int skip;
+ skip = (1 + catalog_key->key_length + 1) & ~1;
+ catalog_data = (HfsCatalog*)(node+catalog_pos+skip);
+ /* check for obvious error in FS */
+ if ((catalog_pos < HFS_FIRST_REC)
+ || ((uint8_t*)catalog_data - node
+ >= PED_SECTOR_SIZE_DEFAULT
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ return 0;
+ }
+
+ if (catalog_data->type != HFS_CAT_FILE) continue;
+
+ extent = catalog_data->sel.file.extents_data;
+ for (j = 0; j < HFS_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE16_TO_CPU(extent[j].start_block),
+ PED_BE16_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ 1, /* hfs => btree block = 512 b */
+ CR_BTREE_CAT,
+ j )
+ )
+ return 0;
+ }
+
+ extent = catalog_data->sel.file.extents_res;
+ for (j = 0; j < HFS_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE16_TO_CPU(extent[j].start_block),
+ PED_BE16_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ 1, /* hfs => btree block = 512 b */
+ CR_BTREE_CAT,
+ j )
+ )
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int
+hfs_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+ HfsHeaderRecord* header;
+ HfsNodeDescriptor* desc = (HfsNodeDescriptor*) node;
+ HfsExtentKey* extent_key;
+ HfsExtDescriptor* extent;
+ unsigned int leaf_node, record_number;
+ unsigned int i, j;
+ uint16_t extent_pos;
+
+ if (!priv_data->extent_file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This HFS volume has no extents overflow "
+ "file. This is quite unusual!"));
+ return 1;
+ }
+
+ if (!hfs_file_read_sector (priv_data->extent_file, node, 0))
+ return 0;
+ uint16_t offset;
+ memcpy(&offset, node+(PED_SECTOR_SIZE_DEFAULT-2), sizeof(uint16_t));
+ header = (HfsHeaderRecord*) (node + PED_BE16_TO_CPU(offset));
+
+ for (leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
+ leaf_node;
+ leaf_node = PED_BE32_TO_CPU (desc->next)) {
+ if (!hfs_file_read_sector (priv_data->extent_file, node,
+ leaf_node))
+ return 0;
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = 1; i <= record_number; i++) {
+ uint8_t where;
+ uint16_t value;
+ memcpy(&value, node+(PED_SECTOR_SIZE_DEFAULT - (2*i)), sizeof(uint16_t));
+ extent_pos = PED_BE16_TO_CPU(value);
+ extent_key = (HfsExtentKey*)(node + extent_pos);
+ /* size is cst */
+ extent = (HfsExtDescriptor*)(node+extent_pos+sizeof(HfsExtentKey));
+ /* check for obvious error in FS */
+ if ((extent_pos < HFS_FIRST_REC)
+ || ((uint8_t*)extent - node
+ >= PED_SECTOR_SIZE_DEFAULT
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ return 0;
+ }
+
+ switch (extent_key->file_ID) {
+ case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The extents overflow file should not"
+ " contain its own extents! You "
+ "should check the file system."))
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ where = CR_BTREE_EXT_EXT;
+ break;
+ case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
+ where = CR_BTREE_EXT_CAT;
+ break;
+ default :
+ where = CR_BTREE_EXT_0;
+ break;
+ }
+
+ for (j = 0; j < HFS_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE16_TO_CPU(extent[j].start_block),
+ PED_BE16_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ 1, /* hfs => btree block = 512 b */
+ where,
+ j )
+ )
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/* This function cache every extents start and length stored in any
+ fs structure into the adt defined in cache.[ch]
+ Returns NULL on failure */
+static HfsCPrivateCache*
+hfs_cache_extents(PedFileSystem *fs, PedTimer* timer)
+{
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsCPrivateCache* ret;
+ unsigned int file_number, block_number;
+
+ file_number = PED_BE32_TO_CPU(priv_data->mdb->file_count);
+ block_number = PED_BE16_TO_CPU(priv_data->mdb->total_blocks);
+ ret = hfsc_new_cache(block_number, file_number);
+ if (!ret) return NULL;
+
+ if (!hfs_cache_from_mdb(ret, fs, timer) ||
+ !hfs_cache_from_catalog(ret, fs, timer) ||
+ !hfs_cache_from_extent(ret, fs, timer)) {
+ ped_exception_throw(
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not cache the file system in memory."));
+ hfsc_delete_cache(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* This function moves file's data to compact used and free space,
+ starting at fblock block */
+/* return 0 on error */
+int
+hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
+ PedTimer* timer, unsigned int to_free)
+{
+ PedSector bytes_buff;
+ HfsPrivateFSData* priv_data = (HfsPrivateFSData*)
+ fs->type_specific;
+ HfsMasterDirectoryBlock* mdb = priv_data->mdb;
+ HfsCPrivateCache* cache;
+ unsigned int to_fblock = fblock;
+ unsigned int start = fblock;
+ unsigned int divisor = PED_BE16_TO_CPU (mdb->total_blocks)
+ + 1 - start - to_free;
+ int ret;
+
+ PED_ASSERT (!hfs_block);
+
+ cache = hfs_cache_extents (fs, timer);
+ if (!cache)
+ return 0;
+
+ /* Calculate the size of the copy buffer :
+ * Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
+ * takes the maximum number of HFS blocks so that the buffer
+ * will remain smaller than or equal to BYTES_MAX_BUFF, with
+ * a minimum of 1 HFS block */
+ bytes_buff = PED_BE32_TO_CPU (priv_data->mdb->block_size)
+ * (PedSector) BLOCK_MAX_BUFF;
+ if (bytes_buff > BYTES_MAX_BUFF) {
+ hfs_block_count = BYTES_MAX_BUFF
+ / PED_BE32_TO_CPU (priv_data->mdb->block_size);
+ if (!hfs_block_count)
+ hfs_block_count = 1;
+ bytes_buff = (PedSector) hfs_block_count
+ * PED_BE32_TO_CPU (priv_data->mdb->block_size);
+ } else
+ hfs_block_count = BLOCK_MAX_BUFF;
+
+ /* If the cache code requests more space, give it to him */
+ if (bytes_buff < hfsc_cache_needed_buffer (cache))
+ bytes_buff = hfsc_cache_needed_buffer (cache);
+
+ hfs_block = (uint8_t*) ped_malloc (bytes_buff);
+ if (!hfs_block)
+ goto error_cache;
+
+ if (!hfs_read_bad_blocks (fs)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Bad blocks list could not be loaded."));
+ goto error_alloc;
+ }
+
+ while (fblock < PED_BE16_TO_CPU (mdb->total_blocks)) {
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,fblock)
+ && (!hfs_is_bad_block (fs, fblock))) {
+ if (!(ret = hfs_move_extent_starting_at (fs, &fblock,
+ &to_fblock, cache)))
+ to_fblock = ++fblock;
+ else if (ret == -1) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("An error occurred during extent "
+ "relocation."));
+ goto error_alloc;
+ }
+ } else {
+ fblock++;
+ }
+
+ ped_timer_update(timer, (float)(to_fblock - start)/divisor);
+ }
+
+ free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
+ hfsc_delete_cache (cache);
+ return 1;
+
+error_alloc:
+ free (hfs_block); hfs_block = NULL; hfs_block_count = 0;
+error_cache:
+ hfsc_delete_cache (cache);
+ return 0;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/reloc.h b/libparted/fs/r/hfs/reloc.h
new file mode 100644
index 0000000..d8b1e6d
--- /dev/null
+++ b/libparted/fs/r/hfs/reloc.h
@@ -0,0 +1,36 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _RELOC_H
+#define _RELOC_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfs_update_mdb (PedFileSystem *fs);
+
+int
+hfs_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
+ PedTimer* timer, unsigned int to_free);
+
+#endif /* _RELOC_H */
diff --git a/libparted/fs/r/hfs/reloc_plus.c b/libparted/fs/r/hfs/reloc_plus.c
new file mode 100644
index 0000000..904929c
--- /dev/null
+++ b/libparted/fs/r/hfs/reloc_plus.c
@@ -0,0 +1,948 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004-2005, 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/>.
+*/
+
+#ifndef DISCOVER_ONLY
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+#include <stdint.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include "hfs.h"
+#include "file_plus.h"
+#include "advfs_plus.h"
+#include "cache.h"
+#include "journal.h"
+
+#include "reloc_plus.h"
+
+/* This function moves data of size blocks starting at block *ptr_fblock
+ to block *ptr_to_fblock */
+/* return new start or -1 on failure */
+/* -1 is ok because there can only be 2^32-1 blocks, so the max possible
+ last one is 2^32-2 (and anyway it contains Alternate VH), so
+ -1 (== 2^32-1[2^32]) never represent a valid block */
+static int
+hfsplus_effect_move_extent (PedFileSystem *fs, unsigned int *ptr_fblock,
+ unsigned int *ptr_to_fblock, unsigned int size)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ unsigned int i, ok = 0;
+ unsigned int next_to_fblock;
+ unsigned int start, stop;
+
+ PED_ASSERT (hfsp_block != NULL);
+ PED_ASSERT (*ptr_to_fblock <= *ptr_fblock);
+ /* quiet GCC */
+ start = stop = 0;
+
+/*
+ Try to fit the extent AT or _BEFORE_ the wanted place,
+ or then in the gap between dest and source.
+ If failed try to fit the extent after source, for 2 pass relocation
+ The extent is always copied in a non overlapping way
+*/
+
+ /* Backward search */
+ /* 1 pass relocation AT or BEFORE *ptr_to_fblock */
+ if (*ptr_to_fblock != *ptr_fblock) {
+ start = stop = *ptr_fblock < *ptr_to_fblock+size ?
+ *ptr_fblock : *ptr_to_fblock+size;
+ while (start && stop-start != size) {
+ --start;
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,start))
+ stop = start;
+ }
+ ok = (stop-start == size);
+ }
+
+ /* Forward search */
+ /* 1 pass relocation in the gap merged with 2 pass reloc after source */
+ if (!ok && *ptr_to_fblock != *ptr_fblock) {
+ start = stop = *ptr_to_fblock+1;
+ while (stop < PED_BE32_TO_CPU(priv_data->vh->total_blocks)
+ && stop-start != size) {
+ if (TST_BLOC_OCCUPATION(priv_data->alloc_map,stop))
+ start = stop + 1;
+ ++stop;
+ }
+ ok = (stop-start == size);
+ }
+
+ /* new non overlapping room has been found ? */
+ if (ok) {
+ /* enough room */
+ PedSector abs_sector;
+ unsigned int ai, j, block;
+ unsigned int block_sz = (PED_BE32_TO_CPU (
+ priv_data->vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT);
+
+ if (stop > *ptr_to_fblock && stop <= *ptr_fblock)
+ /* Fit in the gap */
+ next_to_fblock = stop;
+ else
+ /* Before or after the gap */
+ next_to_fblock = *ptr_to_fblock;
+
+ /* move blocks */
+ for (i = 0; i < size; /*i++*/) {
+ j = size - i; j = (j < hfsp_block_count) ?
+ j : hfsp_block_count ;
+
+ abs_sector = (PedSector) (*ptr_fblock + i) * block_sz;
+ if (!ped_geometry_read (priv_data->plus_geom,
+ hfsp_block, abs_sector,
+ block_sz * j))
+ return -1;
+
+ abs_sector = (PedSector) (start + i) * block_sz;
+ if (!ped_geometry_write (priv_data->plus_geom,
+ hfsp_block, abs_sector,
+ block_sz * j))
+ return -1;
+
+ for (ai = i+j; i < ai; i++) {
+ /* free source block */
+ block = *ptr_fblock + i;
+ CLR_BLOC_OCCUPATION(priv_data->alloc_map,block);
+ SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
+ block/(PED_SECTOR_SIZE_DEFAULT*8));
+
+ /* set dest block */
+ block = start + i;
+ SET_BLOC_OCCUPATION(priv_data->alloc_map,block);
+ SET_BLOC_OCCUPATION(priv_data->dirty_alloc_map,
+ block/(PED_SECTOR_SIZE_DEFAULT*8));
+ }
+ }
+ if (!ped_geometry_sync_fast (priv_data->plus_geom))
+ return -1;
+
+ *ptr_fblock += size;
+ *ptr_to_fblock = next_to_fblock;
+ } else {
+ if (*ptr_fblock != *ptr_to_fblock)
+ /* not enough room */
+ ped_exception_throw (PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE,
+ _("An extent has not been relocated."));
+ start = *ptr_fblock;
+ *ptr_fblock = *ptr_to_fblock = start + size;
+ }
+
+ return start;
+}
+
+/* Returns 0 on error */
+/* 1 on succes */
+int
+hfsplus_update_vh (PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ uint8_t node[PED_SECTOR_SIZE_DEFAULT];
+
+ if (!ped_geometry_read (priv_data->plus_geom, node, 2, 1))
+ return 0;
+ memcpy (node, priv_data->vh, sizeof (HfsPVolumeHeader));
+ if (!ped_geometry_write (priv_data->plus_geom, node, 2, 1)
+ || !ped_geometry_write (priv_data->plus_geom, node,
+ priv_data->plus_geom->length - 2, 1)
+ || !ped_geometry_sync_fast (priv_data->plus_geom))
+ return 0;
+ return 1;
+}
+
+static int
+hfsplus_do_move (PedFileSystem* fs, unsigned int *ptr_src,
+ unsigned int *ptr_dest, HfsCPrivateCache* cache,
+ HfsCPrivateExtent* ref)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPPrivateFile* file;
+ HfsPExtDescriptor* extent;
+ HfsCPrivateExtent* move;
+ int new_start;
+
+ new_start = hfsplus_effect_move_extent (fs, ptr_src, ptr_dest,
+ ref->ext_length);
+
+ if (new_start == -1) return -1;
+
+ if (ref->ext_start != (unsigned) new_start) {
+ switch (ref->where) {
+ /************ VH ************/
+ case CR_PRIM_CAT :
+ priv_data->catalog_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_PRIM;
+ case CR_PRIM_EXT :
+ priv_data->extents_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_PRIM;
+ case CR_PRIM_ATTR :
+ priv_data->attributes_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_PRIM;
+ case CR_PRIM_ALLOC :
+ priv_data->allocation_file
+ ->first[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_PRIM;
+ case CR_PRIM_START :
+ /* No startup file opened */
+ CR_PRIM :
+ extent = ( HfsPExtDescriptor* )
+ ( (uint8_t*)priv_data->vh + ref->ref_offset );
+ extent[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ if (!hfsplus_update_vh(fs))
+ return -1;
+ break;
+
+ /************** BTREE *************/
+ case CR_BTREE_CAT_JIB :
+ if (!hfsj_update_jib(fs, new_start))
+ return -1;
+ goto BTREE_CAT;
+
+ case CR_BTREE_CAT_JL :
+ if (!hfsj_update_jl(fs, new_start))
+ return -1;
+ goto BTREE_CAT;
+
+ BTREE_CAT:
+ case CR_BTREE_CAT :
+ file = priv_data->catalog_file;
+ goto CR_BTREE;
+
+ case CR_BTREE_ATTR :
+ file = priv_data->attributes_file;
+ goto CR_BTREE;
+
+ case CR_BTREE_EXT_ATTR :
+ if (priv_data->attributes_file
+ ->cache[ref->ref_index].start_block
+ == PED_CPU_TO_BE32(ref->ext_start))
+ priv_data->attributes_file
+ ->cache[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_BTREE_EXT;
+ case CR_BTREE_EXT_CAT :
+ if (priv_data->catalog_file
+ ->cache[ref->ref_index].start_block
+ == PED_CPU_TO_BE32(ref->ext_start))
+ priv_data->catalog_file
+ ->cache[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_BTREE_EXT;
+ case CR_BTREE_EXT_ALLOC :
+ if (priv_data->allocation_file
+ ->cache[ref->ref_index].start_block
+ == PED_CPU_TO_BE32(ref->ext_start))
+ priv_data->allocation_file
+ ->cache[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ goto CR_BTREE_EXT;
+ case CR_BTREE_EXT_START :
+ /* No startup file opened */
+ CR_BTREE_EXT :
+ case CR_BTREE_EXT_0 :
+ file = priv_data->extents_file;
+
+ CR_BTREE :
+ PED_ASSERT(PED_SECTOR_SIZE_DEFAULT * ref->sect_by_block
+ > ref->ref_offset);
+ if (!hfsplus_file_read(file, hfsp_block,
+ (PedSector)ref->ref_block * ref->sect_by_block,
+ ref->sect_by_block))
+ return -1;
+ extent = ( HfsPExtDescriptor* )
+ ( hfsp_block + ref->ref_offset );
+ extent[ref->ref_index].start_block =
+ PED_CPU_TO_BE32(new_start);
+ if (!hfsplus_file_write(file, hfsp_block,
+ (PedSector)ref->ref_block * ref->sect_by_block,
+ ref->sect_by_block)
+ || !ped_geometry_sync_fast (priv_data->plus_geom))
+ return -1;
+ break;
+
+ /********** BUG *********/
+ default :
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("A reference to an extent comes from a place "
+ "it should not. You should check the file "
+ "system!"));
+ return -1;
+ break;
+ }
+
+ move = hfsc_cache_move_extent(cache, ref->ext_start, new_start);
+ if (!move) return -1;
+ PED_ASSERT(move == ref);
+ }
+
+ return new_start;
+}
+
+/* save any dirty sector of the allocation bitmap file */
+static int
+hfsplus_save_allocation(PedFileSystem *fs)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ unsigned int map_sectors, i, j;
+ int ret = 1;
+
+ map_sectors = ( PED_BE32_TO_CPU (priv_data->vh->total_blocks)
+ + PED_SECTOR_SIZE_DEFAULT * 8 - 1 ) / (PED_SECTOR_SIZE_DEFAULT * 8);
+
+ for (i = 0; i < map_sectors;) {
+ for (j = i;
+ (TST_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j));
+ ++j)
+ CLR_BLOC_OCCUPATION(priv_data->dirty_alloc_map,j);
+ if (j-i) {
+ ret = hfsplus_file_write(priv_data->allocation_file,
+ priv_data->alloc_map + i * PED_SECTOR_SIZE_DEFAULT,
+ i, j-i) && ret;
+ i = j;
+ } else
+ ++i;
+ }
+
+ return ret;
+}
+
+/* This function moves an extent starting at block fblock
+ to block to_fblock if there's enough room */
+/* Return 1 if everything was fine */
+/* Return -1 if an error occurred */
+/* Return 0 if no extent was found */
+static int
+hfsplus_move_extent_starting_at (PedFileSystem *fs, unsigned int *ptr_fblock,
+ unsigned int *ptr_to_fblock,
+ HfsCPrivateCache* cache)
+{
+ HfsCPrivateExtent* ref;
+ unsigned int old_start, new_start;
+
+ ref = hfsc_cache_search_extent(cache, *ptr_fblock);
+ if (!ref) return 0;
+
+ old_start = *ptr_fblock;
+ new_start = hfsplus_do_move(fs, ptr_fblock, ptr_to_fblock, cache, ref);
+ if (new_start == (unsigned)-1) return -1;
+ if (new_start > old_start) {
+ new_start = hfsplus_do_move(fs, &new_start, ptr_to_fblock,
+ cache, ref);
+ if (new_start == (unsigned)-1 || new_start > old_start)
+ return -1;
+ }
+
+ hfsplus_save_allocation(fs);
+ return 1;
+}
+
+static int
+hfsplus_cache_from_vh(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPExtDescriptor* extent;
+ unsigned int j;
+
+ extent = priv_data->vh->allocation_file.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ 0, /* unused for vh */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
+ 1, /* load / save 1 sector */
+ CR_PRIM_ALLOC,
+ j )
+ )
+ return 0;
+ }
+
+ extent = priv_data->vh->extents_file.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ 0, /* unused for vh */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
+ 1, /* load / save 1 sector */
+ CR_PRIM_EXT,
+ j )
+ )
+ return 0;
+ }
+
+ extent = priv_data->vh->catalog_file.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ 0, /* unused for vh */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
+ 1, /* load / save 1 sector */
+ CR_PRIM_CAT,
+ j )
+ )
+ return 0;
+ }
+
+ extent = priv_data->vh->attributes_file.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ 0, /* unused for vh */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
+ 1, /* load / save 1 sector */
+ CR_PRIM_ATTR,
+ j )
+ )
+ return 0;
+ }
+
+ extent = priv_data->vh->startup_file.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ 0, /* unused for vh */
+ ((uint8_t*)extent) - ((uint8_t*)priv_data->vh),
+ 1, /* load / save 1 sector */
+ CR_PRIM_START,
+ j )
+ )
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+hfsplus_cache_from_catalog(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
+ uint8_t* node;
+ HfsPHeaderRecord* header;
+ HfsPCatalogKey* catalog_key;
+ HfsPCatalog* catalog_data;
+ HfsPExtDescriptor* extent;
+ unsigned int leaf_node, record_number;
+ unsigned int i, j, size, bsize;
+ uint32_t jib = priv_data->jib_start_block,
+ jl = priv_data->jl_start_block;
+ uint16_t catalog_pos;
+
+ if (!priv_data->catalog_file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This HFS+ volume has no catalog file. "
+ "This is very unusual!"));
+ return 1;
+ }
+
+ /* Search the extent starting at *ptr_block in the catalog file */
+ if (!hfsplus_file_read_sector (priv_data->catalog_file, node_1, 0))
+ return 0;
+ header = (HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC);
+ leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
+ bsize = PED_BE16_TO_CPU (header->node_size);
+ size = bsize / PED_SECTOR_SIZE_DEFAULT;
+ PED_ASSERT(size < 256);
+
+ node = (uint8_t*) ped_malloc(bsize);
+ if (!node) return 0;
+ HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
+
+ for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
+ if (!hfsplus_file_read (priv_data->catalog_file, node,
+ (PedSector) leaf_node * size, size)) {
+ free (node);
+ return 0;
+ }
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = 1; i <= record_number; i++) {
+ unsigned int skip;
+ uint8_t where;
+
+ uint16_t value;
+ memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
+ catalog_pos = PED_BE16_TO_CPU(value);
+ catalog_key = (HfsPCatalogKey*)(node + catalog_pos);
+ skip = ( 2 + PED_BE16_TO_CPU (catalog_key->key_length)
+ + 1) & ~1;
+ catalog_data = (HfsPCatalog*)
+ (((uint8_t*)catalog_key) + skip);
+ /* check for obvious error in FS */
+ if ((catalog_pos < HFS_FIRST_REC)
+ || ((uint8_t*)catalog_data - node
+ >= (signed) bsize
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ free (node);
+ return 0;
+ }
+
+ if (PED_BE16_TO_CPU(catalog_data->type)!=HFS_CAT_FILE)
+ continue;
+
+ extent = catalog_data->sel.file.data_fork.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ where = CR_BTREE_CAT;
+ if ( PED_BE32_TO_CPU(extent[j].start_block)
+ == jib ) {
+ jib = 0;
+ where = CR_BTREE_CAT_JIB;
+ } else
+ if ( PED_BE32_TO_CPU(extent[j].start_block)
+ == jl ) {
+ jl = 0;
+ where = CR_BTREE_CAT_JL;
+ }
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ size,
+ where,
+ j )
+ ) {
+ free (node);
+ return 0;
+ }
+ }
+
+ extent = catalog_data->sel.file.res_fork.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ size,
+ CR_BTREE_CAT,
+ j )
+ ) {
+ free (node);
+ return 0;
+ }
+ }
+ }
+ }
+
+ free (node);
+ return 1;
+}
+
+static int
+hfsplus_cache_from_extent(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
+ uint8_t* node;
+ HfsPHeaderRecord* header;
+ HfsPExtentKey* extent_key;
+ HfsPExtDescriptor* extent;
+ unsigned int leaf_node, record_number;
+ unsigned int i, j, size, bsize;
+ uint16_t extent_pos;
+
+ if (!priv_data->extents_file->sect_nb) {
+ ped_exception_throw (
+ PED_EXCEPTION_INFORMATION,
+ PED_EXCEPTION_OK,
+ _("This HFS+ volume has no extents overflow "
+ "file. This is quite unusual!"));
+ return 1;
+ }
+
+ if (!hfsplus_file_read_sector (priv_data->extents_file, node_1, 0))
+ return 0;
+ header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC));
+ leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
+ bsize = PED_BE16_TO_CPU (header->node_size);
+ size = bsize / PED_SECTOR_SIZE_DEFAULT;
+ PED_ASSERT(size < 256);
+
+ node = (uint8_t*) ped_malloc (bsize);
+ if (!node) return -1;
+ HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
+
+ for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
+ if (!hfsplus_file_read (priv_data->extents_file, node,
+ (PedSector) leaf_node * size, size)) {
+ free (node);
+ return 0;
+ }
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = 1; i <= record_number; i++) {
+ uint8_t where;
+ uint16_t value;
+ memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
+ extent_pos = PED_BE16_TO_CPU(value);
+ extent_key = (HfsPExtentKey*)(node + extent_pos);
+ extent = (HfsPExtDescriptor*)
+ (((uint8_t*)extent_key) + sizeof (HfsPExtentKey));
+ /* check for obvious error in FS */
+ if ((extent_pos < HFS_FIRST_REC)
+ || ((uint8_t*)extent - node
+ >= (signed)bsize
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ free (node);
+ return -1;
+ }
+
+ switch (extent_key->file_ID) {
+ case PED_CPU_TO_BE32 (HFS_XTENT_ID) :
+ if (ped_exception_throw (
+ PED_EXCEPTION_WARNING,
+ PED_EXCEPTION_IGNORE_CANCEL,
+ _("The extents overflow file should not"
+ " contain its own extents! You should "
+ "check the file system."))
+ != PED_EXCEPTION_IGNORE)
+ return 0;
+ where = CR_BTREE_EXT_EXT;
+ break;
+ case PED_CPU_TO_BE32 (HFS_CATALOG_ID) :
+ where = CR_BTREE_EXT_CAT;
+ break;
+ case PED_CPU_TO_BE32 (HFSP_ALLOC_ID) :
+ where = CR_BTREE_EXT_ALLOC;
+ break;
+ case PED_CPU_TO_BE32 (HFSP_STARTUP_ID) :
+ where = CR_BTREE_EXT_START;
+ break;
+ case PED_CPU_TO_BE32 (HFSP_ATTRIB_ID) :
+ where = CR_BTREE_EXT_ATTR;
+ break;
+ default :
+ where = CR_BTREE_EXT_0;
+ break;
+ }
+
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU(extent[j].start_block),
+ PED_BE32_TO_CPU(extent[j].block_count),
+ leaf_node,
+ (uint8_t*)extent - node,
+ size,
+ where,
+ j )
+ ) {
+ free (node);
+ return 0;
+ }
+ }
+ }
+ }
+
+ free (node);
+ return 1;
+}
+
+static int
+hfsplus_cache_from_attributes(HfsCPrivateCache* cache, PedFileSystem* fs,
+ PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ uint8_t node_1[PED_SECTOR_SIZE_DEFAULT];
+ uint8_t* node;
+ HfsPHeaderRecord* header;
+ HfsPPrivateGenericKey* generic_key;
+ HfsPForkDataAttr* fork_ext_data;
+ HfsPExtDescriptor* extent;
+ unsigned int leaf_node, record_number;
+ unsigned int i, j, size, bsize;
+ uint16_t generic_pos;
+
+ /* attributes file is facultative */
+ if (!priv_data->attributes_file->sect_nb)
+ return 1;
+
+ /* Search the extent starting at *ptr_block in the catalog file */
+ if (!hfsplus_file_read_sector (priv_data->attributes_file, node_1, 0))
+ return 0;
+ header = ((HfsPHeaderRecord*) (node_1 + HFS_FIRST_REC));
+ leaf_node = PED_BE32_TO_CPU (header->first_leaf_node);
+ bsize = PED_BE16_TO_CPU (header->node_size);
+ size = bsize / PED_SECTOR_SIZE_DEFAULT;
+ PED_ASSERT(size < 256);
+
+ node = (uint8_t*) ped_malloc(bsize);
+ if (!node) return 0;
+ HfsPNodeDescriptor *desc = (HfsPNodeDescriptor*) node;
+
+ for (; leaf_node; leaf_node = PED_BE32_TO_CPU (desc->next)) {
+ if (!hfsplus_file_read (priv_data->attributes_file, node,
+ (PedSector) leaf_node * size, size)) {
+ free (node);
+ return 0;
+ }
+ record_number = PED_BE16_TO_CPU (desc->rec_nb);
+ for (i = 1; i <= record_number; i++) {
+ unsigned int skip;
+ uint16_t value;
+ memcpy(&value, node+(bsize - (2*i)), sizeof(uint16_t));
+ generic_pos = PED_BE16_TO_CPU(value);
+ generic_key = (HfsPPrivateGenericKey*)(node + generic_pos);
+ skip = ( 2 + PED_BE16_TO_CPU (generic_key->key_length)
+ + 1 ) & ~1;
+ fork_ext_data = (HfsPForkDataAttr*)(node+generic_pos+skip);
+ /* check for obvious error in FS */
+ if ((generic_pos < HFS_FIRST_REC)
+ || ((uint8_t*)fork_ext_data - node
+ >= (signed) bsize
+ - 2 * (signed)(record_number+1))) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("The file system contains errors."));
+ free (node);
+ return 0;
+ }
+
+ if (fork_ext_data->record_type
+ == PED_CPU_TO_BE32 ( HFSP_ATTR_FORK ) ) {
+ extent = fork_ext_data->fork_res.fork.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU (
+ extent[j].start_block ),
+ PED_BE32_TO_CPU (
+ extent[j].block_count ),
+ leaf_node,
+ (uint8_t*)extent-node,
+ size,
+ CR_BTREE_ATTR,
+ j )
+ ) {
+ free(node);
+ return 0;
+ }
+ }
+ } else if (fork_ext_data->record_type
+ == PED_CPU_TO_BE32 ( HFSP_ATTR_EXTENTS ) ) {
+ extent = fork_ext_data->fork_res.extents;
+ for (j = 0; j < HFSP_EXT_NB; ++j) {
+ if (!extent[j].block_count) break;
+ if (!hfsc_cache_add_extent(
+ cache,
+ PED_BE32_TO_CPU (
+ extent[j].start_block ),
+ PED_BE32_TO_CPU (
+ extent[j].block_count ),
+ leaf_node,
+ (uint8_t*)extent-node,
+ size,
+ CR_BTREE_ATTR,
+ j )
+ ) {
+ free(node);
+ return 0;
+ }
+ }
+ } else continue;
+ }
+ }
+
+ free (node);
+ return 1;
+}
+
+static HfsCPrivateCache*
+hfsplus_cache_extents(PedFileSystem* fs, PedTimer* timer)
+{
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsCPrivateCache* ret;
+ unsigned int file_number, block_number;
+
+ file_number = PED_BE32_TO_CPU(priv_data->vh->file_count);
+ block_number = PED_BE32_TO_CPU(priv_data->vh->total_blocks);
+ ret = hfsc_new_cache(block_number, file_number);
+ if (!ret) return NULL;
+
+ if (!hfsplus_cache_from_vh(ret, fs, timer) ||
+ !hfsplus_cache_from_catalog(ret, fs, timer) ||
+ !hfsplus_cache_from_extent(ret, fs, timer) ||
+ !hfsplus_cache_from_attributes(ret, fs, timer)) {
+ ped_exception_throw(
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Could not cache the file system in memory."));
+ hfsc_delete_cache(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+/* This function moves file's data to compact used and free space,
+ starting at fblock block */
+/* return 0 on error */
+int
+hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
+ PedTimer* timer, unsigned int to_free)
+{
+ PedSector bytes_buff;
+ HfsPPrivateFSData* priv_data = (HfsPPrivateFSData*)
+ fs->type_specific;
+ HfsPVolumeHeader* vh = priv_data->vh;
+ HfsCPrivateCache* cache;
+ unsigned int to_fblock = fblock;
+ unsigned int start = fblock;
+ unsigned int divisor = PED_BE32_TO_CPU (vh->total_blocks)
+ + 1 - start - to_free;
+ int ret;
+
+ PED_ASSERT (!hfsp_block);
+
+ cache = hfsplus_cache_extents (fs, timer);
+ if (!cache)
+ return 0;
+
+ /* Calculate the size of the copy buffer :
+ * Takes BLOCK_MAX_BUFF HFS blocks, but if > BYTES_MAX_BUFF
+ * takes the maximum number of HFS blocks so that the buffer
+ * will remain smaller than or equal to BYTES_MAX_BUFF, with
+ * a minimum of 1 HFS block */
+ bytes_buff = PED_BE32_TO_CPU (priv_data->vh->block_size)
+ * (PedSector) BLOCK_MAX_BUFF;
+ if (bytes_buff > BYTES_MAX_BUFF) {
+ hfsp_block_count = BYTES_MAX_BUFF
+ / PED_BE32_TO_CPU (priv_data->vh->block_size);
+ if (!hfsp_block_count)
+ hfsp_block_count = 1;
+ bytes_buff = (PedSector) hfsp_block_count
+ * PED_BE32_TO_CPU (priv_data->vh->block_size);
+ } else
+ hfsp_block_count = BLOCK_MAX_BUFF;
+
+ /* If the cache code requests more space, give it to him */
+ if (bytes_buff < hfsc_cache_needed_buffer (cache))
+ bytes_buff = hfsc_cache_needed_buffer (cache);
+
+ hfsp_block = (uint8_t*) ped_malloc (bytes_buff);
+ if (!hfsp_block)
+ goto error_cache;
+
+ if (!hfsplus_read_bad_blocks (fs)) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("Bad blocks list could not be loaded."));
+ goto error_alloc;
+ }
+
+ while ( fblock < ( priv_data->plus_geom->length - 2 )
+ / ( PED_BE32_TO_CPU (vh->block_size)
+ / PED_SECTOR_SIZE_DEFAULT ) ) {
+ if (TST_BLOC_OCCUPATION (priv_data->alloc_map, fblock)
+ && (!hfsplus_is_bad_block (fs, fblock))) {
+ if (!(ret = hfsplus_move_extent_starting_at (fs,
+ &fblock, &to_fblock, cache)))
+ to_fblock = ++fblock;
+ else if (ret == -1) {
+ ped_exception_throw (
+ PED_EXCEPTION_ERROR,
+ PED_EXCEPTION_CANCEL,
+ _("An error occurred during extent "
+ "relocation."));
+ goto error_alloc;
+ }
+ } else {
+ fblock++;
+ }
+
+ ped_timer_update(timer, (float)(to_fblock - start) / divisor);
+ }
+
+ free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
+ hfsc_delete_cache (cache);
+ return 1;
+
+error_alloc:
+ free (hfsp_block); hfsp_block = NULL; hfsp_block_count = 0;
+error_cache:
+ hfsc_delete_cache (cache);
+ return 0;
+}
+
+#endif /* !DISCOVER_ONLY */
diff --git a/libparted/fs/r/hfs/reloc_plus.h b/libparted/fs/r/hfs/reloc_plus.h
new file mode 100644
index 0000000..8c5998a
--- /dev/null
+++ b/libparted/fs/r/hfs/reloc_plus.h
@@ -0,0 +1,37 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2004, 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/>.
+*/
+
+#ifndef _RELOC_PLUS_H
+#define _RELOC_PLUS_H
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#include "hfs.h"
+
+int
+hfsplus_update_vh (PedFileSystem *fs);
+
+int
+hfsplus_pack_free_space_from_block (PedFileSystem *fs, unsigned int fblock,
+ PedTimer* timer, unsigned int to_free);
+
+
+#endif /* _RELOC_PLUS_H */
diff --git a/libparted/fs/reiserfs/reiserfs.c b/libparted/fs/reiserfs/reiserfs.c
new file mode 100644
index 0000000..0638f3e
--- /dev/null
+++ b/libparted/fs/reiserfs/reiserfs.c
@@ -0,0 +1,94 @@
+/*
+ reiserfs.c -- ReiserFS detection
+ Copyright (C) 2001-2002, 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 <config.h>
+
+#include <uuid/uuid.h>
+#include <fcntl.h>
+#include <errno.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
+
+#include "reiserfs.h"
+
+static PedSector reiserfs_super_offset[] = { 128, 16, -1 };
+static PedFileSystemType* reiserfs_type;
+
+static PedGeometry *reiserfs_probe(PedGeometry *geom)
+{
+ int i;
+
+ PED_ASSERT(geom != NULL);
+ reiserfs_super_block_t *sb = alloca (geom->dev->sector_size);
+
+ for (i = 0; reiserfs_super_offset[i] != -1; i++) {
+ if (reiserfs_super_offset[i] >= geom->length)
+ continue;
+ if (!ped_geometry_read (geom, sb, reiserfs_super_offset[i], 1))
+ continue;
+
+ if (strncmp(REISERFS_SIGNATURE, sb->s_magic,
+ strlen(REISERFS_SIGNATURE)) == 0
+ || strncmp(REISER2FS_SIGNATURE, sb->s_magic,
+ strlen(REISER2FS_SIGNATURE)) == 0
+ || strncmp(REISER3FS_SIGNATURE, sb->s_magic,
+ strlen(REISER3FS_SIGNATURE)) == 0) {
+ PedSector block_size;
+ PedSector block_count;
+
+ block_size = PED_LE16_TO_CPU(sb->s_blocksize)
+ / geom->dev->sector_size;
+ block_count = PED_LE32_TO_CPU(sb->s_block_count);
+ return ped_geometry_new(geom->dev, geom->start,
+ block_size * block_count);
+ }
+ }
+ return NULL;
+}
+
+
+static PedFileSystemOps reiserfs_simple_ops = {
+ probe: reiserfs_probe,
+};
+
+static PedFileSystemType reiserfs_simple_type = {
+ next: NULL,
+ ops: &reiserfs_simple_ops,
+ name: "reiserfs",
+};
+
+void ped_file_system_reiserfs_init()
+{
+ reiserfs_type = &reiserfs_simple_type;
+ ped_file_system_type_register(reiserfs_type);
+}
+
+void ped_file_system_reiserfs_done()
+{
+ ped_file_system_type_unregister(reiserfs_type);
+}
diff --git a/libparted/fs/reiserfs/reiserfs.h b/libparted/fs/reiserfs/reiserfs.h
new file mode 100644
index 0000000..ee92b62
--- /dev/null
+++ b/libparted/fs/reiserfs/reiserfs.h
@@ -0,0 +1,109 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2000, 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/>.
+*/
+
+#ifndef REISERFS_H
+#define REISERFS_H
+
+#define REISERFS_API_VERSION 0
+
+#define REISERFS_SIGNATURE "ReIsErFs"
+#define REISER2FS_SIGNATURE "ReIsEr2Fs"
+#define REISER3FS_SIGNATURE "ReIsEr3Fs"
+
+#define DEFAULT_BLOCK_SIZE 4096
+
+struct reiserfs_super_block {
+ uint32_t s_block_count;
+ uint32_t s_free_blocks;
+ uint32_t s_root_block;
+ uint32_t s_journal_block;
+ uint32_t s_journal_dev;
+ uint32_t s_orig_journal_size;
+ uint32_t s_journal_trans_max;
+ uint32_t s_journal_block_count;
+ uint32_t s_journal_max_batch;
+ uint32_t s_journal_max_commit_age;
+ uint32_t s_journal_max_trans_age;
+ uint16_t s_blocksize;
+ uint16_t s_oid_maxsize;
+ uint16_t s_oid_cursize;
+ uint16_t s_state;
+ char s_magic[10];
+ uint16_t s_fsck_state;
+ uint32_t s_hash_function_code;
+ uint16_t s_tree_height;
+ uint16_t s_bmap_nr;
+ uint16_t s_version;
+ char padding[438];
+};
+
+typedef struct reiserfs_super_block reiserfs_super_block_t;
+
+enum reiserfs_exception_type {
+ EXCEPTION_INFORMATION = 1,
+ EXCEPTION_WARNING = 2,
+ EXCEPTION_ERROR = 3,
+ EXCEPTION_FATAL = 4,
+ EXCEPTION_BUG = 5,
+ EXCEPTION_NO_FEATURE = 6
+};
+
+typedef enum reiserfs_exception_type reiserfs_exception_type_t;
+
+enum reiserfs_exception_option {
+ EXCEPTION_UNHANDLED = 1 << 0,
+ EXCEPTION_FIX = 1 << 1,
+ EXCEPTION_YES = 1 << 2,
+ EXCEPTION_NO = 1 << 3,
+ EXCEPTION_OK = 1 << 4,
+ EXCEPTION_RETRY = 1 << 5,
+ EXCEPTION_IGNORE = 1 << 6,
+ EXCEPTION_CANCEL = 1 << 7
+};
+
+typedef enum reiserfs_exception_option reiserfs_exception_option_t;
+
+typedef void (reiserfs_gauge_handler_t)(const char *, unsigned int, void *, int, int, int);
+
+typedef void * reiserfs_exception_t;
+typedef void * reiserfs_gauge_t;
+typedef void * reiserfs_fs_t;
+
+#define FS_FORMAT_3_5 0
+#define FS_FORMAT_3_6 2
+
+#define SUPER_OFFSET_IN_BYTES 64*1024
+
+#define DEFAULT_JOURNAL_SIZE 8192
+
+#define JOURNAL_MIN_SIZE 512
+#define JOURNAL_MIN_TRANS 256
+#define JOURNAL_MAX_TRANS 1024
+
+#define JOURNAL_DEF_RATIO 8
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_BATCH 900
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+
+#define TEA_HASH 1
+#define YURA_HASH 2
+#define R5_HASH 3
+
+#endif
diff --git a/libparted/fs/udf/udf.c b/libparted/fs/udf/udf.c
new file mode 100644
index 0000000..a48a42e
--- /dev/null
+++ b/libparted/fs/udf/udf.c
@@ -0,0 +1,175 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2018-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>
+
+/* Read bytes using ped_geometry_read() function */
+static int read_bytes (const PedGeometry* geom, void* buffer, PedSector offset, PedSector count)
+{
+ char* sector_buffer;
+ PedSector sector_offset, sector_count, buffer_offset;
+
+ sector_offset = offset / geom->dev->sector_size;
+ sector_count = (offset + count + geom->dev->sector_size - 1) / geom->dev->sector_size - sector_offset;
+ buffer_offset = offset - sector_offset * geom->dev->sector_size;
+
+ sector_buffer = alloca (sector_count * geom->dev->sector_size);
+
+ if (!ped_geometry_read (geom, sector_buffer, sector_offset, sector_count))
+ return 0;
+
+ memcpy (buffer, sector_buffer + buffer_offset, count);
+ return 1;
+}
+
+/* Scan VSR and check for UDF VSD */
+static int check_vrs (const PedGeometry* geom, unsigned int vsdsize)
+{
+ PedSector block;
+ PedSector offset;
+ unsigned char ident[5];
+
+ /* Check only first 64 blocks, but theoretically standard does not define upper limit */
+ for (block = 0; block < 64; block++) {
+ /* VRS starts at fixed offset 32kB, it is independent of block size or vsd size */
+ offset = 32768 + block * vsdsize;
+
+ /* Read VSD identifier, it is at offset 1 */
+ if (!read_bytes (geom, ident, offset + 1, 5))
+ return 0;
+
+ /* Check for UDF identifier */
+ if (memcmp (ident, "NSR02", 5) == 0 ||
+ memcmp (ident, "NSR03", 5) == 0)
+ return 1;
+
+ /* Unknown VSD identifier means end of VRS */
+ if (memcmp (ident, "BEA01", 5) != 0 &&
+ memcmp (ident, "TEA01", 5) != 0 &&
+ memcmp (ident, "BOOT2", 5) != 0 &&
+ memcmp (ident, "CD001", 5) != 0 &&
+ memcmp (ident, "CDW02", 5) != 0)
+ break;
+ }
+
+ return 0;
+}
+
+/* Check for UDF AVDP */
+static int check_anchor (const PedGeometry* geom, unsigned int blocksize, int rel_block)
+{
+ PedSector block;
+ unsigned char tag[16];
+
+ /* Negative block means relative to the end of device */
+ if (rel_block < 0) {
+ block = geom->length * geom->dev->sector_size / blocksize;
+ if (block <= (PedSector)(-rel_block))
+ return 0;
+ block -= (PedSector)(-rel_block);
+ if (block < 257)
+ return 0;
+ } else {
+ block = rel_block;
+ }
+
+ if (!read_bytes (geom, tag, block * blocksize, 16))
+ return 0;
+
+ /* Check for AVDP type (0x0002) */
+ if (((unsigned short)tag[0] | ((unsigned short)tag[1] << 8)) != 0x0002)
+ return 0;
+
+ /* Check that location stored in AVDP matches */
+ if (((unsigned long)tag[12] | ((unsigned long)tag[13] << 8) | ((unsigned long)tag[14] << 16) | ((unsigned long)tag[15] << 24)) != block)
+ return 0;
+
+ return 1;
+}
+
+/* Detect presence of UDF AVDP */
+static int detect_anchor(const PedGeometry* geom, unsigned int blocksize)
+{
+ /* All possible AVDP locations in preferred order */
+ static int anchors[] = { 256, -257, -1, 512 };
+ size_t i;
+
+ for (i = 0; i < sizeof (anchors)/sizeof (*anchors); i++) {
+ if (check_anchor (geom, blocksize, anchors[i]))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Detect UDF filesystem, it must have VRS and AVDP */
+static int detect_udf (const PedGeometry* geom)
+{
+ unsigned int blocksize;
+
+ /* VSD size is min(2048, UDF block size), check for block sizes <= 2048 */
+ if (check_vrs (geom, 2048)) {
+ for (blocksize = 512; blocksize <= 2048; blocksize *= 2) {
+ if (detect_anchor (geom, blocksize))
+ return 1;
+ }
+ }
+
+ /* Check for block sizes larger then 2048, maximal theoretical block size is 32kB */
+ for (blocksize = 4096; blocksize <= 32768; blocksize *= 2) {
+ if (!check_vrs (geom, blocksize))
+ continue;
+ if (detect_anchor (geom, blocksize))
+ return 1;
+ }
+
+ return 0;
+}
+
+PedGeometry*
+udf_probe (PedGeometry* geom)
+{
+ if (!detect_udf (geom))
+ return NULL;
+
+ return ped_geometry_duplicate (geom);
+}
+
+static PedFileSystemOps udf_ops = {
+ probe: udf_probe,
+};
+
+static PedFileSystemType udf_type = {
+ next: NULL,
+ ops: &udf_ops,
+ name: "udf",
+};
+
+void
+ped_file_system_udf_init ()
+{
+ ped_file_system_type_register (&udf_type);
+}
+
+void
+ped_file_system_udf_done ()
+{
+ ped_file_system_type_unregister (&udf_type);
+}
diff --git a/libparted/fs/ufs/ufs.c b/libparted/fs/ufs/ufs.c
new file mode 100644
index 0000000..d2bf421
--- /dev/null
+++ b/libparted/fs/ufs/ufs.c
@@ -0,0 +1,281 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2001, 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/>.
+
+ Contributor: Ben Collins <bcollins@debian.org>
+*/
+
+#include <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+#include <parted/debug.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <unistd.h>
+#include <string.h>
+
+/* taken from ufs_fs.h in Linux */
+#define UFS_MAXNAMLEN 255
+#define UFS_MAXMNTLEN 512
+#define UFS_MAXCSBUFS 31
+#define UFS_LINK_MAX 32000
+
+#define UFS_MAGIC 0x00011954
+#define UFS_MAGIC_LFN 0x00095014
+#define UFS_MAGIC_FEA 0x00195612
+#define UFS_MAGIC_4GB 0x05231994
+
+struct __attribute__ ((packed)) ufs_csum {
+ uint32_t cs_ndir; /* number of directories */
+ uint32_t cs_nbfree; /* number of free blocks */
+ uint32_t cs_nifree; /* number of free inodes */
+ uint32_t cs_nffree; /* number of free frags */
+};
+
+struct __attribute__ ((packed)) ufs_super_block {
+ uint32_t fs_link; /* UNUSED */
+ uint32_t fs_rlink; /* UNUSED */
+ uint32_t fs_sblkno; /* addr of super-block in filesys */
+ uint32_t fs_cblkno; /* offset of cyl-block in filesys */
+ uint32_t fs_iblkno; /* offset of inode-blocks in filesys */
+ uint32_t fs_dblkno; /* offset of first data after cg */
+ uint32_t fs_cgoffset; /* cylinder group offset in cylinder */
+ uint32_t fs_cgmask; /* used to calc mod fs_ntrak */
+ uint32_t fs_time; /* last time written -- time_t */
+ uint32_t fs_size; /* number of blocks in fs */
+ uint32_t fs_dsize; /* number of data blocks in fs */
+ uint32_t fs_ncg; /* number of cylinder groups */
+ uint32_t fs_bsize; /* size of basic blocks in fs */
+ uint32_t fs_fsize; /* size of frag blocks in fs */
+ uint32_t fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ uint32_t fs_minfree; /* minimum percentage of free blocks */
+ uint32_t fs_rotdelay; /* num of ms for optimal next block */
+ uint32_t fs_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ uint32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
+ uint32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
+ uint32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
+ uint32_t fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ uint32_t fs_maxcontig; /* max number of contiguous blks */
+ uint32_t fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ uint32_t fs_fragshift; /* block to frag shift */
+ uint32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ uint32_t fs_sbsize; /* actual size of super block */
+ uint32_t fs_csmask; /* csum block offset */
+ uint32_t fs_csshift; /* csum block number */
+ uint32_t fs_nindir; /* value of NINDIR */
+ uint32_t fs_inopb; /* value of INOPB */
+ uint32_t fs_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ uint32_t fs_optim; /* optimization preference, see below */
+/* these fields are derived from the hardware */
+ union {
+ struct {
+ uint32_t fs_npsect; /* # sectors/track including spares */
+ } fs_sun;
+ struct {
+ int32_t fs_state; /* file system state timestamp */
+ } fs_sunx86;
+ } fs_u1;
+ uint32_t fs_interleave; /* hardware sector interleave */
+ uint32_t fs_trackskew; /* sector 0 skew, per track */
+/* a unique id for this file system (currently unused and unmaintained) */
+/* In 4.3 Tahoe this space is used by fs_headswitch and fs_trkseek */
+/* Neither of those fields is used in the Tahoe code right now but */
+/* there could be problems if they are. */
+ uint32_t fs_id[2]; /* file system id */
+/* sizes determined by number of cylinder groups and their sizes */
+ uint32_t fs_csaddr; /* blk addr of cyl grp summary area */
+ uint32_t fs_cssize; /* size of cyl grp summary area */
+ uint32_t fs_cgsize; /* cylinder group size */
+/* these fields are derived from the hardware */
+ uint32_t fs_ntrak; /* tracks per cylinder */
+ uint32_t fs_nsect; /* sectors per track */
+ uint32_t fs_spc; /* sectors per cylinder */
+/* this comes from the disk driver partitioning */
+ uint32_t fs_ncyl; /* cylinders in file system */
+/* these fields can be computed from the others */
+ uint32_t fs_cpg; /* cylinders per group */
+ uint32_t fs_ipg; /* inodes per group */
+ uint32_t fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct ufs_csum fs_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ int8_t fs_fmod; /* super block modified flag */
+ int8_t fs_clean; /* file system is clean flag */
+ int8_t fs_ronly; /* mounted read-only flag */
+ int8_t fs_flags; /* currently unused flag */
+ int8_t fs_fsmnt[UFS_MAXMNTLEN]; /* name mounted on */
+/* these fields retain the current block allocation info */
+ uint32_t fs_cgrotor; /* last cg searched */
+ uint32_t fs_csp[UFS_MAXCSBUFS]; /* list of fs_cs info buffers */
+ uint32_t fs_maxcluster;
+ uint32_t fs_cpc; /* cyl per cycle in postbl */
+ uint16_t fs_opostbl[16][8]; /* old rotation block list head */
+ union {
+ struct {
+ int32_t fs_sparecon[53];/* reserved for future constants */
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ int32_t fs_state; /* file system state timestamp */
+ uint32_t fs_qbmask[2]; /* ~usb_bmask */
+ uint32_t fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sun;
+ struct {
+ int32_t fs_sparecon[53];/* reserved for future constants */
+ int32_t fs_reclaim;
+ int32_t fs_sparecon2[1];
+ uint32_t fs_npsect; /* # sectors/track including spares */
+ uint32_t fs_qbmask[2]; /* ~usb_bmask */
+ uint32_t fs_qfmask[2]; /* ~usb_fmask */
+ } fs_sunx86;
+ struct {
+ int32_t fs_sparecon[50];/* reserved for future constants */
+ int32_t fs_contigsumsize;/* size of cluster summary array */
+ int32_t fs_maxsymlinklen;/* max length of an internal symlink */
+ int32_t fs_inodefmt; /* format of on-disk inodes */
+ uint32_t fs_maxfilesize[2]; /* max representable file size */
+ uint32_t fs_qbmask[2]; /* ~usb_bmask */
+ uint32_t fs_qfmask[2]; /* ~usb_fmask */
+ int32_t fs_state; /* file system state timestamp */
+ } fs_44;
+ } fs_u2;
+ int32_t fs_postblformat; /* format of positional layout tables */
+ int32_t fs_nrpos; /* number of rotational positions */
+ int32_t fs_postbloff; /* (__s16) rotation block list head */
+ int32_t fs_rotbloff; /* (uint8_t) blocks for each rotation */
+ int32_t fs_magic; /* magic number */
+ uint8_t fs_space[4]; /* list of blocks for each rotation */
+};
+
+static PedGeometry*
+ufs_probe_sun (PedGeometry* geom)
+{
+ const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ uint8_t* buf = alloca (sectors * geom->dev->sector_size);
+ struct ufs_super_block *sb;
+
+ if (geom->length < 5)
+ return 0;
+ if (!ped_geometry_read (geom, buf, 16 * 512 / geom->dev->sector_size, sectors))
+ return 0;
+
+ sb = (struct ufs_super_block *)buf;
+
+ if (PED_BE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
+ PedSector block_size = PED_BE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
+ PedSector block_count = PED_BE32_TO_CPU(sb->fs_size);
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ }
+ if (PED_LE32_TO_CPU(sb->fs_magic) == UFS_MAGIC) {
+ PedSector block_size = PED_LE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
+ PedSector block_count = PED_LE32_TO_CPU(sb->fs_size);
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ }
+ return NULL;
+}
+
+static PedGeometry*
+ufs_probe_hp (PedGeometry* geom)
+{
+ struct ufs_super_block *sb;
+ PedSector block_size;
+ PedSector block_count;
+
+ if (geom->length < 5)
+ return 0;
+ const int sectors = ((3 * 512) + geom->dev->sector_size - 1) /
+ geom->dev->sector_size;
+ uint8_t* buf = alloca (sectors * geom->dev->sector_size);
+
+ if (!ped_geometry_read (geom, buf, 16 * 512 / geom->dev->sector_size, sectors))
+ return 0;
+
+ sb = (struct ufs_super_block *)buf;
+
+ /* Try sane bytesex */
+ switch (PED_BE32_TO_CPU(sb->fs_magic)) {
+ case UFS_MAGIC_LFN:
+ case UFS_MAGIC_FEA:
+ case UFS_MAGIC_4GB:
+ block_size = PED_BE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
+ block_count = PED_BE32_TO_CPU(sb->fs_size);
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ }
+
+ /* Try perverted bytesex */
+ switch (PED_LE32_TO_CPU(sb->fs_magic)) {
+ case UFS_MAGIC_LFN:
+ case UFS_MAGIC_FEA:
+ case UFS_MAGIC_4GB:
+ block_size = PED_LE32_TO_CPU(sb->fs_bsize) / geom->dev->sector_size;
+ block_count = PED_LE32_TO_CPU(sb->fs_size);
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ }
+ return NULL;
+}
+
+static PedFileSystemOps ufs_ops_sun = {
+ probe: ufs_probe_sun,
+};
+
+static PedFileSystemOps ufs_ops_hp = {
+ probe: ufs_probe_hp,
+};
+
+static PedFileSystemType ufs_type_sun = {
+ next: NULL,
+ ops: &ufs_ops_sun,
+ name: "sun-ufs",
+};
+
+static PedFileSystemType ufs_type_hp = {
+ next: NULL,
+ ops: &ufs_ops_hp,
+ name: "hp-ufs",
+};
+
+void
+ped_file_system_ufs_init ()
+{
+ PED_ASSERT (sizeof (struct ufs_super_block) == 1380);
+
+ ped_file_system_type_register (&ufs_type_sun);
+ ped_file_system_type_register (&ufs_type_hp);
+}
+
+void
+ped_file_system_ufs_done ()
+{
+ ped_file_system_type_unregister (&ufs_type_hp);
+ ped_file_system_type_unregister (&ufs_type_sun);
+}
diff --git a/libparted/fs/xfs/platform_defs.h b/libparted/fs/xfs/platform_defs.h
new file mode 100644
index 0000000..a6ec8fb
--- /dev/null
+++ b/libparted/fs/xfs/platform_defs.h
@@ -0,0 +1,109 @@
+/* include/platform_defs.h. Generated automatically by configure. */
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ *
+ * @configure_input@
+ */
+#ifndef __XFS_PLATFORM_DEFS_H__
+#define __XFS_PLATFORM_DEFS_H__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <endian.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1)
+# define constpp const char * const *
+#else
+# define constpp char * const *
+#endif
+
+typedef loff_t xfs_off_t;
+typedef uint64_t xfs_ino_t;
+typedef uint32_t xfs_dev_t;
+typedef int64_t xfs_daddr_t;
+typedef char* xfs_caddr_t;
+
+/* long and pointer must be either 32 bit or 64 bit */
+/* #undef HAVE_64BIT_LONG */
+#define HAVE_32BIT_LONG 1
+#define HAVE_32BIT_PTR 1
+/* #undef HAVE_64BIT_PTR */
+
+/* Check if __psint_t is set to something meaningful */
+/* #undef HAVE___PSINT_T */
+#ifndef HAVE___PSINT_T
+# ifdef HAVE_32BIT_PTR
+typedef int __psint_t;
+# elif defined HAVE_64BIT_PTR
+# ifdef HAVE_64BIT_LONG
+typedef long __psint_t;
+# else
+/* This is a very strange architecture, which has 64 bit pointers but
+ * not 64 bit longs. So, I'd just punt here and assume long long is Ok */
+typedef long long __psint_t;
+# endif
+# else
+# error Unknown pointer size
+# endif
+#endif
+
+/* Check if __psunsigned_t is set to something meaningful */
+/* #undef HAVE___PSUNSIGNED_T */
+#ifndef HAVE___PSUNSIGNED_T
+# ifdef HAVE_32BIT_PTR
+typedef unsigned int __psunsigned_t;
+# elif defined HAVE_64BIT_PTR
+# ifdef HAVE_64BIT_LONG
+typedef long __psunsigned_t;
+# else
+/* This is a very strange architecture, which has 64 bit pointers but
+ * not 64 bit longs. So, I'd just punt here and assume long long is Ok */
+typedef unsigned long long __psunsigned_t;
+# endif
+# else
+# error Unknown pointer size
+# endif
+#endif
+
+#ifdef DEBUG
+# define ASSERT assert
+#else
+# define ASSERT(EX) ((void) 0)
+#endif
+
+#endif /* __XFS_PLATFORM_DEFS_H__ */
diff --git a/libparted/fs/xfs/xfs.c b/libparted/fs/xfs/xfs.c
new file mode 100644
index 0000000..f5cf96a
--- /dev/null
+++ b/libparted/fs/xfs/xfs.c
@@ -0,0 +1,87 @@
+/*
+ libparted - a library for manipulating disk partitions
+ Copyright (C) 2001, 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 <config.h>
+
+#include <parted/parted.h>
+#include <parted/endian.h>
+
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext (PACKAGE, String)
+#else
+# define _(String) (String)
+#endif /* ENABLE_NLS */
+
+#include <uuid/uuid.h>
+#include "platform_defs.h"
+#include "xfs_types.h"
+#include "xfs_sb.h"
+
+static PedGeometry*
+xfs_probe (PedGeometry* geom)
+{
+ PedSector block_size;
+ PedSector block_count;
+ struct xfs_sb *sb = alloca (geom->dev->sector_size);
+
+ if (geom->length < XFS_SB_DADDR + 1)
+ return NULL;
+ if (!ped_geometry_read (geom, sb, XFS_SB_DADDR, 1))
+ return NULL;
+
+ if (PED_LE32_TO_CPU (sb->sb_magicnum) == XFS_SB_MAGIC) {
+ block_size = PED_LE32_TO_CPU (sb->sb_blocksize) / geom->dev->sector_size;
+ block_count = PED_LE64_TO_CPU (sb->sb_dblocks);
+
+ return ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ }
+
+ if (PED_BE32_TO_CPU (sb->sb_magicnum) == XFS_SB_MAGIC) {
+ block_size = PED_BE32_TO_CPU (sb->sb_blocksize) / geom->dev->sector_size;
+ block_count = PED_BE64_TO_CPU (sb->sb_dblocks);
+
+ geom = ped_geometry_new (geom->dev, geom->start,
+ block_size * block_count);
+ return geom;
+ }
+ return NULL;
+}
+
+static PedFileSystemOps xfs_ops = {
+ probe: xfs_probe,
+};
+
+static PedFileSystemType xfs_type = {
+ next: NULL,
+ ops: &xfs_ops,
+ name: "xfs",
+};
+
+void
+ped_file_system_xfs_init ()
+{
+ ped_file_system_type_register (&xfs_type);
+}
+
+void
+ped_file_system_xfs_done ()
+{
+ ped_file_system_type_unregister (&xfs_type);
+}
diff --git a/libparted/fs/xfs/xfs_sb.h b/libparted/fs/xfs/xfs_sb.h
new file mode 100644
index 0000000..3484145
--- /dev/null
+++ b/libparted/fs/xfs/xfs_sb.h
@@ -0,0 +1,489 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_SB_H__
+#define __XFS_SB_H__
+
+/*
+ * Super block
+ * Fits into a 512-byte buffer at daddr_t 0 of each allocation group.
+ * Only the first of these is ever updated except during growfs.
+ */
+
+struct xfs_buf;
+struct xfs_mount;
+
+#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */
+#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */
+#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */
+#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */
+#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */
+#define XFS_SB_VERSION_NUMBITS 0x000f
+#define XFS_SB_VERSION_ALLFBITS 0xfff0
+#define XFS_SB_VERSION_SASHFBITS 0xf000
+#define XFS_SB_VERSION_REALFBITS 0x0ff0
+#define XFS_SB_VERSION_ATTRBIT 0x0010
+#define XFS_SB_VERSION_NLINKBIT 0x0020
+#define XFS_SB_VERSION_QUOTABIT 0x0040
+#define XFS_SB_VERSION_ALIGNBIT 0x0080
+#define XFS_SB_VERSION_DALIGNBIT 0x0100
+#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_EXTFLGBIT 0x1000
+#define XFS_SB_VERSION_DIRV2BIT 0x2000
+#define XFS_SB_VERSION_OKSASHFBITS \
+ (XFS_SB_VERSION_EXTFLGBIT | \
+ XFS_SB_VERSION_DIRV2BIT)
+#define XFS_SB_VERSION_OKREALFBITS \
+ (XFS_SB_VERSION_ATTRBIT | \
+ XFS_SB_VERSION_NLINKBIT | \
+ XFS_SB_VERSION_QUOTABIT | \
+ XFS_SB_VERSION_ALIGNBIT | \
+ XFS_SB_VERSION_DALIGNBIT | \
+ XFS_SB_VERSION_SHAREDBIT)
+#define XFS_SB_VERSION_OKSASHBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_REALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+#define XFS_SB_VERSION_OKREALBITS \
+ (XFS_SB_VERSION_NUMBITS | \
+ XFS_SB_VERSION_OKREALFBITS | \
+ XFS_SB_VERSION_OKSASHFBITS)
+#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2) \
+ (((ia) || (dia) || (extflag) || (dirv2)) ? \
+ (XFS_SB_VERSION_4 | \
+ ((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \
+ ((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \
+ ((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \
+ ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0)) : \
+ XFS_SB_VERSION_1)
+
+typedef struct xfs_sb
+{
+ uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */
+ uint32_t sb_blocksize; /* logical block size, bytes */
+ xfs_drfsbno_t sb_dblocks; /* number of data blocks */
+ xfs_drfsbno_t sb_rblocks; /* number of realtime blocks */
+ xfs_drtbno_t sb_rextents; /* number of realtime extents */
+ uuid_t sb_uuid; /* file system unique id */
+ xfs_dfsbno_t sb_logstart; /* starting block of log if internal */
+ xfs_ino_t sb_rootino; /* root inode number */
+ xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */
+ xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */
+ xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */
+ xfs_agblock_t sb_agblocks; /* size of an allocation group */
+ xfs_agnumber_t sb_agcount; /* number of allocation groups */
+ xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */
+ xfs_extlen_t sb_logblocks; /* number of log blocks */
+ uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */
+ uint16_t sb_sectsize; /* volume sector size, bytes */
+ uint16_t sb_inodesize; /* inode size, bytes */
+ uint16_t sb_inopblock; /* inodes per block */
+ char sb_fname[12]; /* file system name */
+ uint8_t sb_blocklog; /* log2 of sb_blocksize */
+ uint8_t sb_sectlog; /* log2 of sb_sectsize */
+ uint8_t sb_inodelog; /* log2 of sb_inodesize */
+ uint8_t sb_inopblog; /* log2 of sb_inopblock */
+ uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */
+ uint8_t sb_rextslog; /* log2 of sb_rextents */
+ uint8_t sb_inprogress; /* mkfs is in progress, don't mount */
+ uint8_t sb_imax_pct; /* max % of fs for inode space */
+ /* statistics */
+ /*
+ * These fields must remain contiguous. If you really
+ * want to change their layout, make sure you fix the
+ * code in xfs_trans_apply_sb_deltas().
+ */
+ uint64_t sb_icount; /* allocated inodes */
+ uint64_t sb_ifree; /* free inodes */
+ uint64_t sb_fdblocks; /* free data blocks */
+ uint64_t sb_frextents; /* free realtime extents */
+ /*
+ * End contiguous fields.
+ */
+ xfs_ino_t sb_uquotino; /* user quota inode */
+ xfs_ino_t sb_gquotino; /* group quota inode */
+ uint16_t sb_qflags; /* quota flags */
+ uint8_t sb_flags; /* misc. flags */
+ uint8_t sb_shared_vn; /* shared version number */
+ xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */
+ uint32_t sb_unit; /* stripe or raid unit */
+ uint32_t sb_width; /* stripe or raid width */
+ uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
+ uint8_t sb_dummy[7]; /* padding */
+} xfs_sb_t;
+
+/*
+ * Sequence number values for the fields.
+ */
+typedef enum {
+ XFS_SBS_MAGICNUM, XFS_SBS_BLOCKSIZE, XFS_SBS_DBLOCKS, XFS_SBS_RBLOCKS,
+ XFS_SBS_REXTENTS, XFS_SBS_UUID, XFS_SBS_LOGSTART, XFS_SBS_ROOTINO,
+ XFS_SBS_RBMINO, XFS_SBS_RSUMINO, XFS_SBS_REXTSIZE, XFS_SBS_AGBLOCKS,
+ XFS_SBS_AGCOUNT, XFS_SBS_RBMBLOCKS, XFS_SBS_LOGBLOCKS,
+ XFS_SBS_VERSIONNUM, XFS_SBS_SECTSIZE, XFS_SBS_INODESIZE,
+ XFS_SBS_INOPBLOCK, XFS_SBS_FNAME, XFS_SBS_BLOCKLOG,
+ XFS_SBS_SECTLOG, XFS_SBS_INODELOG, XFS_SBS_INOPBLOG, XFS_SBS_AGBLKLOG,
+ XFS_SBS_REXTSLOG, XFS_SBS_INPROGRESS, XFS_SBS_IMAX_PCT, XFS_SBS_ICOUNT,
+ XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
+ XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
+ XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
+ XFS_SBS_DUMMY,
+ XFS_SBS_FIELDCOUNT
+} xfs_sb_field_t;
+
+/*
+ * Mask values, defined based on the xfs_sb_field_t values.
+ * Only define the ones we're using.
+ */
+#define XFS_SB_MVAL(x) (1LL << XFS_SBS_ ## x)
+#define XFS_SB_UUID XFS_SB_MVAL(UUID)
+#define XFS_SB_FNAME XFS_SB_MVAL(FNAME)
+#define XFS_SB_ROOTINO XFS_SB_MVAL(ROOTINO)
+#define XFS_SB_RBMINO XFS_SB_MVAL(RBMINO)
+#define XFS_SB_RSUMINO XFS_SB_MVAL(RSUMINO)
+#define XFS_SB_VERSIONNUM XFS_SB_MVAL(VERSIONNUM)
+#define XFS_SB_UQUOTINO XFS_SB_MVAL(UQUOTINO)
+#define XFS_SB_GQUOTINO XFS_SB_MVAL(GQUOTINO)
+#define XFS_SB_QFLAGS XFS_SB_MVAL(QFLAGS)
+#define XFS_SB_SHARED_VN XFS_SB_MVAL(SHARED_VN)
+#define XFS_SB_UNIT XFS_SB_MVAL(UNIT)
+#define XFS_SB_WIDTH XFS_SB_MVAL(WIDTH)
+#define XFS_SB_NUM_BITS ((int)XFS_SBS_FIELDCOUNT)
+#define XFS_SB_ALL_BITS ((1LL << XFS_SB_NUM_BITS) - 1)
+#define XFS_SB_MOD_BITS \
+ (XFS_SB_UUID | XFS_SB_ROOTINO | XFS_SB_RBMINO | XFS_SB_RSUMINO | \
+ XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO | XFS_SB_GQUOTINO | \
+ XFS_SB_QFLAGS | XFS_SB_SHARED_VN | XFS_SB_UNIT | XFS_SB_WIDTH)
+
+/*
+ * Misc. Flags - warning - these will be cleared by xfs_repair unless
+ * a feature bit is set when the flag is used.
+ */
+#define XFS_SBF_NOFLAGS 0x00 /* no flags set */
+#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */
+
+/*
+ * define max. shared version we can interoperate with
+ */
+#define XFS_SB_MAX_SHARED_VN 0
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_NUM)
+int xfs_sb_version_num(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_NUM(sbp) xfs_sb_version_num(sbp)
+#else
+#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS)
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_GOOD_VERSION)
+int xfs_sb_good_version(xfs_sb_t *sbp);
+#define XFS_SB_GOOD_VERSION(sbp) xfs_sb_good_version(sbp)
+#else
+#define XFS_SB_GOOD_VERSION_INT(sbp) \
+ ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
+ ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKREALBITS)
+#ifdef __KERNEL__
+#define XFS_SB_GOOD_VERSION(sbp) \
+ (XFS_SB_GOOD_VERSION_INT(sbp) && \
+ (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN) ))
+#else
+/*
+ * extra 2 paren's here (( to unconfuse paren-matching editors
+ * like vi because XFS_SB_GOOD_VERSION_INT is a partial expression
+ * and the two XFS_SB_GOOD_VERSION's each 2 more close paren's to
+ * complete the expression.
+ */
+#define XFS_SB_GOOD_VERSION(sbp) \
+ (XFS_SB_GOOD_VERSION_INT(sbp) && \
+ (!((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) || \
+ (sbp)->sb_shared_vn <= XFS_SB_MAX_SHARED_VN)) ))
+#endif /* __KERNEL__ */
+#endif
+
+#define XFS_SB_GOOD_SASH_VERSION(sbp) \
+ ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
+ ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS)))
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TONEW)
+unsigned xfs_sb_version_tonew(unsigned v);
+#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v)
+#else
+#define XFS_SB_VERSION_TONEW(v) \
+ ((((v) == XFS_SB_VERSION_1) ? \
+ 0 : \
+ (((v) == XFS_SB_VERSION_2) ? \
+ XFS_SB_VERSION_ATTRBIT : \
+ (XFS_SB_VERSION_ATTRBIT | XFS_SB_VERSION_NLINKBIT))) | \
+ XFS_SB_VERSION_4)
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_TOOLD)
+unsigned xfs_sb_version_toold(unsigned v);
+#define XFS_SB_VERSION_TOOLD(v) xfs_sb_version_toold(v)
+#else
+#define XFS_SB_VERSION_TOOLD(v) \
+ (((v) & (XFS_SB_VERSION_QUOTABIT | XFS_SB_VERSION_ALIGNBIT)) ? \
+ 0 : \
+ (((v) & XFS_SB_VERSION_NLINKBIT) ? \
+ XFS_SB_VERSION_3 : \
+ (((v) & XFS_SB_VERSION_ATTRBIT) ? \
+ XFS_SB_VERSION_2 : \
+ XFS_SB_VERSION_1)))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASATTR)
+int xfs_sb_version_hasattr(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASATTR(sbp) xfs_sb_version_hasattr(sbp)
+#else
+#define XFS_SB_VERSION_HASATTR(sbp) \
+ (((sbp)->sb_versionnum == XFS_SB_VERSION_2) || \
+ ((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_ATTRBIT)))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDATTR)
+void xfs_sb_version_addattr(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDATTR(sbp) xfs_sb_version_addattr(sbp)
+#else
+#define XFS_SB_VERSION_ADDATTR(sbp) \
+ ((sbp)->sb_versionnum = \
+ (((sbp)->sb_versionnum == XFS_SB_VERSION_1) ? \
+ XFS_SB_VERSION_2 : \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) ? \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_ATTRBIT) : \
+ (XFS_SB_VERSION_4 | XFS_SB_VERSION_ATTRBIT))))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASNLINK)
+int xfs_sb_version_hasnlink(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASNLINK(sbp) xfs_sb_version_hasnlink(sbp)
+#else
+#define XFS_SB_VERSION_HASNLINK(sbp) \
+ (((sbp)->sb_versionnum == XFS_SB_VERSION_3) || \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_NLINKBIT)))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDNLINK)
+void xfs_sb_version_addnlink(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDNLINK(sbp) xfs_sb_version_addnlink(sbp)
+#else
+#define XFS_SB_VERSION_ADDNLINK(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum <= XFS_SB_VERSION_2 ? \
+ XFS_SB_VERSION_3 : \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_NLINKBIT)))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASQUOTA)
+int xfs_sb_version_hasquota(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASQUOTA(sbp) xfs_sb_version_hasquota(sbp)
+#else
+#define XFS_SB_VERSION_HASQUOTA(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_QUOTABIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDQUOTA)
+void xfs_sb_version_addquota(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDQUOTA(sbp) xfs_sb_version_addquota(sbp)
+#else
+#define XFS_SB_VERSION_ADDQUOTA(sbp) \
+ ((sbp)->sb_versionnum = \
+ (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4 ? \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_QUOTABIT) : \
+ (XFS_SB_VERSION_TONEW((sbp)->sb_versionnum) | \
+ XFS_SB_VERSION_QUOTABIT)))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASALIGN)
+int xfs_sb_version_hasalign(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASALIGN(sbp) xfs_sb_version_hasalign(sbp)
+#else
+#define XFS_SB_VERSION_HASALIGN(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_ALIGNBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBALIGN)
+void xfs_sb_version_subalign(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_SUBALIGN(sbp) xfs_sb_version_subalign(sbp)
+#else
+#define XFS_SB_VERSION_SUBALIGN(sbp) \
+ ((sbp)->sb_versionnum = \
+ XFS_SB_VERSION_TOOLD((sbp)->sb_versionnum & ~XFS_SB_VERSION_ALIGNBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDALIGN)
+int xfs_sb_version_hasdalign(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASDALIGN(sbp) xfs_sb_version_hasdalign(sbp)
+#else
+#define XFS_SB_VERSION_HASDALIGN(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_DALIGNBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDDALIGN)
+int xfs_sb_version_adddalign(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDDALIGN(sbp) xfs_sb_version_adddalign(sbp)
+#else
+#define XFS_SB_VERSION_ADDDALIGN(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_DALIGNBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASSHARED)
+int xfs_sb_version_hasshared(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASSHARED(sbp) xfs_sb_version_hasshared(sbp)
+#else
+#define XFS_SB_VERSION_HASSHARED(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_SHAREDBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDSHARED)
+int xfs_sb_version_addshared(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDSHARED(sbp) xfs_sb_version_addshared(sbp)
+#else
+#define XFS_SB_VERSION_ADDSHARED(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_SHAREDBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBSHARED)
+int xfs_sb_version_subshared(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_SUBSHARED(sbp) xfs_sb_version_subshared(sbp)
+#else
+#define XFS_SB_VERSION_SUBSHARED(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum & ~XFS_SB_VERSION_SHAREDBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASDIRV2)
+int xfs_sb_version_hasdirv2(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASDIRV2(sbp) xfs_sb_version_hasdirv2(sbp)
+#else
+#define XFS_SB_VERSION_HASDIRV2(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT)
+int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp)
+#else
+#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_ADDEXTFLGBIT)
+int xfs_sb_version_addextflgbit(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) xfs_sb_version_addextflgbit(sbp)
+#else
+#define XFS_SB_VERSION_ADDEXTFLGBIT(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum | XFS_SB_VERSION_EXTFLGBIT))
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_SUBEXTFLGBIT)
+int xfs_sb_version_subextflgbit(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) xfs_sb_version_subextflgbit(sbp)
+#else
+#define XFS_SB_VERSION_SUBEXTFLGBIT(sbp) \
+ ((sbp)->sb_versionnum = \
+ ((sbp)->sb_versionnum & ~XFS_SB_VERSION_EXTFLGBIT))
+#endif
+
+/*
+ * end of superblock version macros
+ */
+
+#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in file system/ag */
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_BLOCK)
+xfs_agblock_t xfs_sb_block(struct xfs_mount *mp);
+#define XFS_SB_BLOCK(mp) xfs_sb_block(mp)
+#else
+#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
+#endif
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_HDR_BLOCK)
+xfs_agblock_t xfs_hdr_block(struct xfs_mount *mp, xfs_daddr_t d);
+#define XFS_HDR_BLOCK(mp,d) xfs_hdr_block(mp,d)
+#else
+#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp,d)))
+#endif
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DADDR_TO_FSB)
+xfs_fsblock_t xfs_daddr_to_fsb(struct xfs_mount *mp, xfs_daddr_t d);
+#define XFS_DADDR_TO_FSB(mp,d) xfs_daddr_to_fsb(mp,d)
+#else
+#define XFS_DADDR_TO_FSB(mp,d) \
+ XFS_AGB_TO_FSB(mp, XFS_DADDR_TO_AGNO(mp,d), XFS_DADDR_TO_AGBNO(mp,d))
+#endif
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_FSB_TO_DADDR)
+xfs_daddr_t xfs_fsb_to_daddr(struct xfs_mount *mp, xfs_fsblock_t fsbno);
+#define XFS_FSB_TO_DADDR(mp,fsbno) xfs_fsb_to_daddr(mp,fsbno)
+#else
+#define XFS_FSB_TO_DADDR(mp,fsbno) \
+ XFS_AGB_TO_DADDR(mp, XFS_FSB_TO_AGNO(mp,fsbno), \
+ XFS_FSB_TO_AGBNO(mp,fsbno))
+#endif
+
+/*
+ * File system block to basic block conversions.
+ */
+#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSB(mp,bb) \
+ (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log)
+#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log)
+#define XFS_BB_FSB_OFFSET(mp,bb) ((bb) & ((mp)->m_bsize - 1))
+
+/*
+ * File system block to byte conversions.
+ */
+#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << \
+ (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSB(mp,b) \
+ ((((uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_TO_FSBT(mp,b) (((uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
+#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
+
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_BUF_TO_SBP)
+xfs_sb_t *xfs_buf_to_sbp(struct xfs_buf *bp);
+#define XFS_BUF_TO_SBP(bp) xfs_buf_to_sbp(bp)
+#else
+#define XFS_BUF_TO_SBP(bp) ((xfs_sb_t *)XFS_BUF_PTR(bp))
+#endif
+
+#endif /* __XFS_SB_H__ */
diff --git a/libparted/fs/xfs/xfs_types.h b/libparted/fs/xfs/xfs_types.h
new file mode 100644
index 0000000..89a0d61
--- /dev/null
+++ b/libparted/fs/xfs/xfs_types.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 3 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA 94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef __XFS_TYPES_H__
+#define __XFS_TYPES_H__
+
+/*
+ * Some types are conditional based on the selected configuration.
+ * Set XFS_BIG_FILES=1 or 0 and XFS_BIG_FILESYSTEMS=1 or 0 depending
+ * on the desired configuration.
+ * XFS_BIG_FILES needs pgno_t to be 64 bits (64-bit kernels).
+ * XFS_BIG_FILESYSTEMS needs daddr_t to be 64 bits (N32 and 64-bit kernels).
+ *
+ * Expect these to be set from klocaldefs, or from the machine-type
+ * defs files for the normal case.
+ */
+
+#define XFS_BIG_FILES 1
+#define XFS_BIG_FILESYSTEMS 1
+
+typedef uint32_t xfs_agblock_t; /* blockno in alloc. group */
+typedef uint32_t xfs_extlen_t; /* extent length in blocks */
+typedef uint32_t xfs_agnumber_t; /* allocation group number */
+typedef int32_t xfs_extnum_t; /* # of extents in a file */
+typedef int16_t xfs_aextnum_t; /* # extents in an attribute fork */
+typedef int64_t xfs_fsize_t; /* bytes in a file */
+typedef uint64_t xfs_ufsize_t; /* unsigned bytes in a file */
+
+typedef int32_t xfs_suminfo_t; /* type of bitmap summary info */
+typedef int32_t xfs_rtword_t; /* word type for bitmap manipulations */
+
+typedef int64_t xfs_lsn_t; /* log sequence number */
+typedef int32_t xfs_tid_t; /* transaction identifier */
+
+typedef uint32_t xfs_dablk_t; /* dir/attr block number (in file) */
+typedef uint32_t xfs_dahash_t; /* dir/attr hash value */
+
+typedef uint16_t xfs_prid_t; /* prid_t truncated to 16bits in XFS */
+
+/*
+ * These types are 64 bits on disk but are either 32 or 64 bits in memory.
+ * Disk based types:
+ */
+typedef uint64_t xfs_dfsbno_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_drfsbno_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_drtbno_t; /* extent (block) in realtime area */
+typedef uint64_t xfs_dfiloff_t; /* block number in a file */
+typedef uint64_t xfs_dfilblks_t; /* number of blocks in a file */
+
+/*
+ * Memory based types are conditional.
+ */
+#if XFS_BIG_FILESYSTEMS
+typedef uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint64_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+#else
+typedef uint32_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */
+typedef uint32_t xfs_rfsblock_t; /* blockno in filesystem (raw) */
+typedef uint32_t xfs_rtblock_t; /* extent (block) in realtime area */
+typedef int32_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */
+#endif
+#if XFS_BIG_FILES
+typedef uint64_t xfs_fileoff_t; /* block number in a file */
+typedef int64_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint64_t xfs_filblks_t; /* number of blocks in a file */
+#else
+typedef uint32_t xfs_fileoff_t; /* block number in a file */
+typedef int32_t xfs_sfiloff_t; /* signed block number in a file */
+typedef uint32_t xfs_filblks_t; /* number of blocks in a file */
+#endif
+
+typedef uint8_t xfs_arch_t; /* architecutre of an xfs fs */
+
+/*
+ * Null values for the types.
+ */
+#define NULLDFSBNO ((xfs_dfsbno_t)-1)
+#define NULLDRFSBNO ((xfs_drfsbno_t)-1)
+#define NULLDRTBNO ((xfs_drtbno_t)-1)
+#define NULLDFILOFF ((xfs_dfiloff_t)-1)
+
+#define NULLFSBLOCK ((xfs_fsblock_t)-1)
+#define NULLRFSBLOCK ((xfs_rfsblock_t)-1)
+#define NULLRTBLOCK ((xfs_rtblock_t)-1)
+#define NULLFILEOFF ((xfs_fileoff_t)-1)
+
+#define NULLAGBLOCK ((xfs_agblock_t)-1)
+#define NULLAGNUMBER ((xfs_agnumber_t)-1)
+#define NULLEXTNUM ((xfs_extnum_t)-1)
+
+#define NULLCOMMITLSN ((xfs_lsn_t)-1)
+
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */
+#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */
+#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */
+
+/*
+ * MAXNAMELEN is the length (including the terminating null) of
+ * the longest permissible file (component) name.
+ */
+#define MAXNAMELEN 256
+
+typedef enum {
+ XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi
+} xfs_lookup_t;
+
+typedef enum {
+ XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_BMAPi, XFS_BTNUM_INOi,
+ XFS_BTNUM_MAX
+} xfs_btnum_t;
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * XFS global statistics
+ */
+struct xfsstats {
+# define XFSSTAT_END_EXTENT_ALLOC 4
+ uint32_t xs_allocx;
+ uint32_t xs_allocb;
+ uint32_t xs_freex;
+ uint32_t xs_freeb;
+# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4)
+ uint32_t xs_abt_lookup;
+ uint32_t xs_abt_compare;
+ uint32_t xs_abt_insrec;
+ uint32_t xs_abt_delrec;
+# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7)
+ uint32_t xs_blk_mapr;
+ uint32_t xs_blk_mapw;
+ uint32_t xs_blk_unmap;
+ uint32_t xs_add_exlist;
+ uint32_t xs_del_exlist;
+ uint32_t xs_look_exlist;
+ uint32_t xs_cmp_exlist;
+# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4)
+ uint32_t xs_bmbt_lookup;
+ uint32_t xs_bmbt_compare;
+ uint32_t xs_bmbt_insrec;
+ uint32_t xs_bmbt_delrec;
+# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4)
+ uint32_t xs_dir_lookup;
+ uint32_t xs_dir_create;
+ uint32_t xs_dir_remove;
+ uint32_t xs_dir_getdents;
+# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3)
+ uint32_t xs_trans_sync;
+ uint32_t xs_trans_async;
+ uint32_t xs_trans_empty;
+# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7)
+ uint32_t xs_ig_attempts;
+ uint32_t xs_ig_found;
+ uint32_t xs_ig_frecycle;
+ uint32_t xs_ig_missed;
+ uint32_t xs_ig_dup;
+ uint32_t xs_ig_reclaims;
+ uint32_t xs_ig_attrchg;
+# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5)
+ uint32_t xs_log_writes;
+ uint32_t xs_log_blocks;
+ uint32_t xs_log_noiclogs;
+ uint32_t xs_log_force;
+ uint32_t xs_log_force_sleep;
+# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10)
+ uint32_t xs_try_logspace;
+ uint32_t xs_sleep_logspace;
+ uint32_t xs_push_ail;
+ uint32_t xs_push_ail_success;
+ uint32_t xs_push_ail_pushbuf;
+ uint32_t xs_push_ail_pinned;
+ uint32_t xs_push_ail_locked;
+ uint32_t xs_push_ail_flushing;
+ uint32_t xs_push_ail_restarts;
+ uint32_t xs_push_ail_flush;
+# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2)
+ uint32_t xs_xstrat_quick;
+ uint32_t xs_xstrat_split;
+# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2)
+ uint32_t xs_write_calls;
+ uint32_t xs_read_calls;
+# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4)
+ uint32_t xs_attr_get;
+ uint32_t xs_attr_set;
+ uint32_t xs_attr_remove;
+ uint32_t xs_attr_list;
+# define XFSSTAT_END_QUOTA_OPS (XFSSTAT_END_ATTRIBUTE_OPS+8)
+ uint32_t xs_qm_dqreclaims;
+ uint32_t xs_qm_dqreclaim_misses;
+ uint32_t xs_qm_dquot_dups;
+ uint32_t xs_qm_dqcachemisses;
+ uint32_t xs_qm_dqcachehits;
+ uint32_t xs_qm_dqwants;
+ uint32_t xs_qm_dqshake_reclaims;
+ uint32_t xs_qm_dqinact_reclaims;
+# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_QUOTA_OPS+3)
+ uint32_t xs_iflush_count;
+ uint32_t xs_icluster_flushcnt;
+ uint32_t xs_icluster_flushinode;
+# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8)
+ uint32_t vn_active; /* # vnodes not on free lists */
+ uint32_t vn_alloc; /* # times vn_alloc called */
+ uint32_t vn_get; /* # times vn_get called */
+ uint32_t vn_hold; /* # times vn_hold called */
+ uint32_t vn_rele; /* # times vn_rele called */
+ uint32_t vn_reclaim; /* # times vn_reclaim called */
+ uint32_t vn_remove; /* # times vn_remove called */
+ uint32_t vn_free; /* # times vn_free called */
+ struct xfsstats_xpc {
+ uint64_t xs_xstrat_bytes;
+ uint64_t xs_write_bytes;
+ uint64_t xs_read_bytes;
+ } xpc;
+} xfsstats;
+
+# define XFS_STATS_INC(count) ( xfsstats.##count ++ )
+# define XFS_STATS_DEC(count) ( xfsstats.##count -- )
+# define XFS_STATS_ADD(count, inc) ( xfsstats.##count += (inc) )
+# define XFS_STATS64_INC(count) ( xfsstats.xpc.##count ++ )
+# define XFS_STATS64_ADD(count, inc) ( xfsstats.xpc.##count += (inc) )
+#else /* !CONFIG_PROC_FS */
+# define XFS_STATS_INC(count)
+# define XFS_STATS_DEC(count)
+# define XFS_STATS_ADD(count, inc)
+# define XFS_STATS64_INC(count)
+# define XFS_STATS64_ADD(count, inc)
+#endif /* !CONFIG_PROC_FS */
+
+
+#ifdef __KERNEL__
+
+/* juggle IRIX device numbers - still used in ondisk structures */
+
+#define IRIX_DEV_BITSMAJOR 14
+#define IRIX_DEV_BITSMINOR 18
+#define IRIX_DEV_MAXMAJ 0x1ff
+#define IRIX_DEV_MAXMIN 0x3ffff
+#define IRIX_DEV_MAJOR(dev) ((int)(((unsigned)(dev)>>IRIX_DEV_BITSMINOR) \
+ & IRIX_DEV_MAXMAJ))
+#define IRIX_DEV_MINOR(dev) ((int)((dev)&IRIX_DEV_MAXMIN))
+#define IRIX_MKDEV(major,minor) ((xfs_dev_t)(((major)<<IRIX_DEV_BITSMINOR) \
+ | (minor&IRIX_DEV_MAXMIN)))
+
+#define IRIX_DEV_TO_KDEVT(dev) MKDEV(IRIX_DEV_MAJOR(dev),IRIX_DEV_MINOR(dev))
+#define IRIX_DEV_TO_DEVT(dev) ((IRIX_DEV_MAJOR(dev)<<8)|IRIX_DEV_MINOR(dev))
+
+/* __psint_t is the same size as a pointer */
+#if (BITS_PER_LONG == 32)
+typedef int32_t __psint_t;
+typedef uint32_t __psunsigned_t;
+#elif (BITS_PER_LONG == 64)
+typedef int64_t __psint_t;
+typedef uint64_t __psunsigned_t;
+#else
+#error BITS_PER_LONG must be 32 or 64
+#endif
+
+
+/*
+ * struct for passing owner/requestor id
+ */
+typedef struct flid {
+#ifdef CELL_CAPABLE
+ pid_t fl_pid;
+ sysid_t fl_sysid;
+#endif
+} flid_t;
+
+#endif /* __KERNEL__ */
+
+#endif /* !__XFS_TYPES_H */