diff options
Diffstat (limited to 'libparted/fs')
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 */ |