From f9cd53e85033abb1f3b7fa053f76faa61e89738b Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Tue, 23 Dec 2025 16:24:01 -0800 Subject: [PATCH] Use `bazel vendor` for f2fs-tools This sometimes fails to download. See https://bazel.build/external/vendor Only hand-written changes are in `base/cvd/vendor_src/.gitignore` and `base/cvd/.bazelrc`. The rest are from `bazel vendor --repo=@f2fs_tools` The buildozer build file validation is narrowed to `base/cvd/cuttlefish` to avoid detecting issues in vendored code we don't own. Bug: b/465511388 --- .github/workflows/presubmit.yaml | 8 +- base/cvd/.bazelrc | 2 + .../+_repo_rules3+f2fs_tools/.gitignore | 56 + .../+_repo_rules3+f2fs_tools/AUTHORS | 1 + .../+_repo_rules3+f2fs_tools/BUILD.bazel | 122 + .../+_repo_rules3+f2fs_tools/COPYING | 864 ++++ .../+_repo_rules3+f2fs_tools/ChangeLog | 4 + .../+_repo_rules3+f2fs_tools/Makefile.am | 5 + .../+_repo_rules3+f2fs_tools/README | 49 + .../+_repo_rules3+f2fs_tools/REPO.bazel | 0 .../+_repo_rules3+f2fs_tools/VERSION | 2 + .../+_repo_rules3+f2fs_tools/VERSIONING | 223 + .../+_repo_rules3+f2fs_tools/autogen.sh | 7 + .../+_repo_rules3+f2fs_tools/configure.ac | 315 ++ .../+_repo_rules3+f2fs_tools/fsck/Makefile.am | 23 + .../+_repo_rules3+f2fs_tools/fsck/common.h | 30 + .../+_repo_rules3+f2fs_tools/fsck/compress.c | 176 + .../+_repo_rules3+f2fs_tools/fsck/compress.h | 22 + .../+_repo_rules3+f2fs_tools/fsck/defrag.c | 103 + .../+_repo_rules3+f2fs_tools/fsck/dict.c | 1500 ++++++ .../+_repo_rules3+f2fs_tools/fsck/dict.h | 144 + .../+_repo_rules3+f2fs_tools/fsck/dir.c | 907 ++++ .../+_repo_rules3+f2fs_tools/fsck/dqblk_v2.h | 31 + .../+_repo_rules3+f2fs_tools/fsck/dump.c | 1110 +++++ .../+_repo_rules3+f2fs_tools/fsck/f2fs.h | 655 +++ .../+_repo_rules3+f2fs_tools/fsck/fsck.c | 3928 +++++++++++++++ .../+_repo_rules3+f2fs_tools/fsck/fsck.h | 364 ++ .../+_repo_rules3+f2fs_tools/fsck/inject.c | 1108 +++++ .../+_repo_rules3+f2fs_tools/fsck/inject.h | 41 + .../+_repo_rules3+f2fs_tools/fsck/main.c | 1412 ++++++ .../+_repo_rules3+f2fs_tools/fsck/mkquota.c | 415 ++ .../+_repo_rules3+f2fs_tools/fsck/mount.c | 4312 +++++++++++++++++ .../+_repo_rules3+f2fs_tools/fsck/node.c | 343 ++ .../+_repo_rules3+f2fs_tools/fsck/node.h | 179 + .../+_repo_rules3+f2fs_tools/fsck/quotaio.c | 232 + .../+_repo_rules3+f2fs_tools/fsck/quotaio.h | 264 + .../fsck/quotaio_tree.c | 687 +++ .../fsck/quotaio_tree.h | 72 + .../fsck/quotaio_v2.c | 328 ++ .../fsck/quotaio_v2.h | 60 + .../+_repo_rules3+f2fs_tools/fsck/resize.c | 778 +++ .../+_repo_rules3+f2fs_tools/fsck/segment.c | 826 ++++ .../+_repo_rules3+f2fs_tools/fsck/sload.c | 388 ++ .../+_repo_rules3+f2fs_tools/fsck/xattr.c | 272 ++ .../+_repo_rules3+f2fs_tools/fsck/xattr.h | 203 + .../include/android_config.h | 86 + .../include/f2fs_fs.h | 2205 +++++++++ .../+_repo_rules3+f2fs_tools/include/quota.h | 83 + .../+_repo_rules3+f2fs_tools/lib/Makefile.am | 25 + .../+_repo_rules3+f2fs_tools/lib/libf2fs.c | 1490 ++++++ .../+_repo_rules3+f2fs_tools/lib/libf2fs_io.c | 914 ++++ .../lib/libf2fs_zoned.c | 637 +++ .../+_repo_rules3+f2fs_tools/lib/nls_utf8.c | 935 ++++ .../+_repo_rules3+f2fs_tools/lib/utf8data.h | 4109 ++++++++++++++++ .../+_repo_rules3+f2fs_tools/m4/.gitignore | 2 + .../+_repo_rules3+f2fs_tools/man/Makefile.am | 3 + .../man/defrag.f2fs.8 | 82 + .../+_repo_rules3+f2fs_tools/man/dump.f2fs.8 | 109 + .../+_repo_rules3+f2fs_tools/man/f2fs_io.8 | 193 + .../+_repo_rules3+f2fs_tools/man/f2fslabel.8 | 33 + .../+_repo_rules3+f2fs_tools/man/fsck.f2fs.8 | 121 + .../man/inject.f2fs.8 | 225 + .../+_repo_rules3+f2fs_tools/man/mkfs.f2fs.8 | 306 ++ .../man/resize.f2fs.8 | 89 + .../+_repo_rules3+f2fs_tools/man/sload.f2fs.8 | 137 + .../+_repo_rules3+f2fs_tools/mkfs/Makefile.am | 30 + .../mkfs/f2fs_format.c | 1894 ++++++++ .../mkfs/f2fs_format_main.c | 562 +++ .../mkfs/f2fs_format_utils.c | 181 + .../mkfs/f2fs_format_utils.h | 15 + .../scripts/dumpf2fs.sh | 61 + .../scripts/spo_test.sh | 70 + .../scripts/tracepoint.sh | 71 + .../scripts/verify.sh | 137 + .../tools/Makefile.am | 19 + .../tools/f2fs_io/Android.bp | 15 + .../tools/f2fs_io/Makefile.am | 8 + .../tools/f2fs_io/f2fs_io.c | 2222 +++++++++ .../tools/f2fs_io/f2fs_io.h | 255 + .../tools/f2fs_io_parse.c | 323 ++ .../tools/f2fscrypt.8 | 102 + .../tools/f2fscrypt.c | 928 ++++ .../+_repo_rules3+f2fs_tools/tools/fibmap.c | 216 + .../+_repo_rules3+f2fs_tools/tools/sha512.c | 322 ++ base/cvd/vendor_src/.gitignore | 1 + .../@+_repo_rules3+f2fs_tools.marker | 2 + base/cvd/vendor_src/VENDOR.bazel | 12 + 87 files changed, 41797 insertions(+), 4 deletions(-) create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/.gitignore create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/AUTHORS create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/BUILD.bazel create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/COPYING create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/ChangeLog create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/README create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/REPO.bazel create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSION create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSIONING create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/autogen.sh create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/configure.ac create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/common.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/defrag.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dir.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dqblk_v2.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dump.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/f2fs.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/main.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mkquota.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mount.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/resize.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/segment.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/sload.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/android_config.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/f2fs_fs.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/quota.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_io.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_zoned.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/nls_utf8.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/utf8data.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/m4/.gitignore create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/defrag.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/dump.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fs_io.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fslabel.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/fsck.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/inject.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/mkfs.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/resize.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/sload.f2fs.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_main.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.h create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/dumpf2fs.sh create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/spo_test.sh create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/tracepoint.sh create mode 100755 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/verify.sh create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Android.bp create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Makefile.am create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.h create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io_parse.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.8 create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/fibmap.c create mode 100644 base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/sha512.c create mode 100644 base/cvd/vendor_src/.gitignore create mode 100644 base/cvd/vendor_src/@+_repo_rules3+f2fs_tools.marker create mode 100644 base/cvd/vendor_src/VENDOR.bazel diff --git a/.github/workflows/presubmit.yaml b/.github/workflows/presubmit.yaml index 7bb0b8773d8..25bfec490ca 100644 --- a/.github/workflows/presubmit.yaml +++ b/.github/workflows/presubmit.yaml @@ -29,8 +29,8 @@ jobs: working-directory: base/cvd if: '!cancelled()' run: | - if [[ $(buildozer '//...:__pkg__' format 2>&1) ]]; then - echo "Please format BUILD.bazel files with \"buildozer '//...:__pkg__' format\""; + if [[ $(buildozer '//cuttlefish/...:__pkg__' format 2>&1) ]]; then + echo "Please format BUILD.bazel files with \"buildozer '//cuttlefish/...:__pkg__' format\""; exit 1; fi - name: Validate no cc_binary targets under //cuttlefish @@ -64,9 +64,9 @@ jobs: if: '!cancelled()' working-directory: base/cvd run: | - if [[ $(buildozer -stdout=true '//...:__pkg__' 'fix unusedLoads') ]]; then + if [[ $(buildozer -stdout=true '//cuttlefish/...:__pkg__' 'fix unusedLoads') ]]; then buildozer '//...:__pkg__' 'fix unusedLoads' - echo "Please remove unused 'load' statements with \"buildozer '//...:__pkg__' 'fix unusedLoads'\""; + echo "Please remove unused 'load' statements with \"buildozer '//cuttlefish/...:__pkg__' 'fix unusedLoads'\""; exit 1; fi staticcheck: diff --git a/base/cvd/.bazelrc b/base/cvd/.bazelrc index 954a1390363..94daf974e80 100644 --- a/base/cvd/.bazelrc +++ b/base/cvd/.bazelrc @@ -1,3 +1,5 @@ +common --vendor_dir=vendor_src + build --build_tag_filters=-clang_tidy,-clang-tidy build --copt=-fdiagnostics-color=always build --output_filter='^//((?!(external/libarchive|external/libevent|external/rules_flex|external/rules_m4):).)*$' diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/.gitignore b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/.gitignore new file mode 100644 index 00000000000..49809446793 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/.gitignore @@ -0,0 +1,56 @@ +.* +*~ +*.[ao] +*.orig +*.tar.* +*.s +*.lo +*.la +*.so +*.so.dbg +*.mod.c +*.lst +*.orig +*.rej + +CVS +!.gitignore +tags +TAGS +GPATH +GRTAGS +GSYMS +GTAGS + +# +# Generated files +# +compile +install-sh +missing +depcomp +INSTALL +aclocal.m4 +autoconf-[0-9].* +autom4te.cache +build-aux +Makefile +Makefile.in +config.* +configure +configure.scan +ltmain.sh +libtool +stamp-h +stamp-h1 + +/mkfs/mkfs.f2fs +/fsck/fsck.f2fs +/tools/fibmap.f2fs +/tools/parse.f2fs +/tools/f2fscrypt +/tools/f2fs_io/f2fs_io + +# cscope files +cscope.* +ncscope.* diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/AUTHORS b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/AUTHORS new file mode 100644 index 00000000000..6ec186109b9 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/AUTHORS @@ -0,0 +1 @@ +This package has been developed by Praesto Team at Samsung Electronics Co., Ltd. diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/BUILD.bazel b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/BUILD.bazel new file mode 100755 index 00000000000..61182099924 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/BUILD.bazel @@ -0,0 +1,122 @@ +package( + default_visibility = ["@//:android_cuttlefish"], +) + +cc_binary( + name = "fsck.f2fs", + srcs = [ + "fsck/common.h", + "fsck/compress.h", + "fsck/defrag.c", + "fsck/dict.c", + "fsck/dict.h", + "fsck/dir.c", + "fsck/dqblk_v2.h", + "fsck/dump.c", + "fsck/f2fs.h", + "fsck/fsck.c", + "fsck/fsck.h", + "fsck/main.c", + "fsck/mkquota.c", + "fsck/mount.c", + "fsck/node.c", + "fsck/node.h", + "fsck/quotaio.c", + "fsck/quotaio.h", + "fsck/quotaio_tree.c", + "fsck/quotaio_tree.h", + "fsck/quotaio_v2.c", + "fsck/quotaio_v2.h", + "fsck/resize.c", + "fsck/segment.c", + "fsck/xattr.c", + "fsck/xattr.h", + ], + local_defines = [ + "WITH_RESIZE", + ], + deps = [ + ":libf2fs_format_utils", + ], +) + +cc_library( + name = "libf2fs", + srcs = [ + "lib/libf2fs.c", + "lib/libf2fs_io.c", + "lib/libf2fs_zoned.c", + "lib/nls_utf8.c", + "lib/utf8data.h", + "mkfs/f2fs_format.c", + "mkfs/f2fs_format_utils.h", + ], + includes = [ + "include", + "lib", + "mkfs", + ], + hdrs = glob([ + "include/*.h", + ]), + strip_include_prefix = "include", + defines = [ + "F2FS_MAJOR_VERSION=1", + "F2FS_MINOR_VERSION=16", + "F2FS_TOOLS_DATE=\\\"2023-04-11\\\"", + "F2FS_TOOLS_VERSION=\\\"1.16.0\\\"", + "WITH_ANDROID", + ], + deps = [ + "@//libbase", + "@//libsparse", + "@e2fsprogs//:libext2_uuid", + ], +) + +cc_library( + name = "libf2fs_format_utils", + srcs = [ + "mkfs/f2fs_format_utils.c", + ], + includes = [ + "mkfs", + ], + hdrs = [ + "mkfs/f2fs_format_utils.h", + ], + strip_include_prefix = "mkfs", + deps = [ + ":libf2fs", + ], +) + +cc_library( + name = "libf2fs_format_utils_blkdiscard", + srcs = [ + "mkfs/f2fs_format_utils.c", + ], + includes = [ + "mkfs", + ], + hdrs = [ + "mkfs/f2fs_format_utils.h", + ], + strip_include_prefix = "mkfs", + local_defines = [ + "WITH_BLKDISCARD", + ], + deps = [ + ":libf2fs", + ], +) + +cc_binary( + name = "make_f2fs", + srcs = [ + "mkfs/f2fs_format_main.c", + ], + deps = [ + ":libf2fs_format_utils_blkdiscard", + ], +) diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/COPYING b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/COPYING new file mode 100644 index 00000000000..52f956deb90 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/COPYING @@ -0,0 +1,864 @@ +The tools for F2FS are covered by GNU Public License version 2. +Exceptionally, the following files are also covered by the GNU Lesser General +Public License Version 2.1 as the dual licenses. +- include/f2fs_fs.h +- lib/libf2fs.c +- lib/libf2fs_io.c +- mkfs/f2fs_format.c +- mkfs/f2fs_format_main.c +- mkfs/f2fs_format_utils.c +- mkfs/f2fs_format_utils.h + +================================================================================ +Copyright (c) 2012 Samsung Electronics Co., Ltd. + http://www.samsung.com/ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +================================================================================ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 2 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +================================================================================ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/ChangeLog b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/ChangeLog new file mode 100644 index 00000000000..9739e99eed1 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/ChangeLog @@ -0,0 +1,4 @@ +f2fs-tools-1.0.0 Tue Aug 14, 2012 KST + * The first release of f2fs-tools. +f2fs-tools-1.0.1 Tue Jun 04, 2013 KST + * Added fsck and dump for f2fs-tools. diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/Makefile.am new file mode 100644 index 00000000000..d2921d626e4 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/Makefile.am @@ -0,0 +1,5 @@ +## Makefile.am + +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = man lib mkfs fsck tools diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/README b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/README new file mode 100644 index 00000000000..c9b0c1f6f72 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/README @@ -0,0 +1,49 @@ +F2FS format utility +--------------------- + +To use the f2fs filesystem, you should format the storage partition +with this utility. Otherwise, you cannot mount f2fs. + +Before compilation +------------------ + +You should install the following packages. + - libuuid-devel or uuid-dev + - autoconf + - libtool + - libselinux1-dev + +Initial compilation +------------------- + +Before initial compilation, autoconf/automake tools should be run. + + # ./autogen.sh + +How to compile +-------------- + + # ./configure + # make + # make install + +How to cross-compile (e.g., for ARM) +------------------------------------ + + 1. Add the below line into mkfs/Makefile.am: + mkfs_f2fs_LDFLAGS = -all-static + + 2. Add the below line into fsck/Makefile.am: + fsck_f2fs_LDFLAGS = -all-static + + 3. then, do: + # LDFLAGS=--static ./configure \ + --host=arm-none-linux-gnueabi --target=arm-none-linux-gnueabi + # make + +How to run by default +--------------------- + + $ mkfs.f2fs -l [LABEL] $DEV + +For more mkfs options, see the man page. diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/REPO.bazel b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/REPO.bazel new file mode 100644 index 00000000000..e69de29bb2d diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSION b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSION new file mode 100644 index 00000000000..bae2e2c9e20 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSION @@ -0,0 +1,2 @@ +1.16.0 +2023-04-11 diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSIONING b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSIONING new file mode 100644 index 00000000000..0b9c26bfcce --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/VERSIONING @@ -0,0 +1,223 @@ +------------------- +Written by Ted T'so +------------------- + +> https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html +> +> I understood that, if there is no interface change but some implementation +> changes, I need to bump revision. If new interface is added, for example, I +> need to bump current while revision=0 and age++. + +So part of the problem here is that libtool is doing something really +strange because they are trying to use some abstract concept that is +OS-independent. I don't use libtool because I find it horribly +complex and doesn't add enough value to be worth the complexity. + +So I'll tell you how things work with respect to Linux's ELF version +numbering system. Translating this to libtool's wierd "current, +revision, age" terminology is left as an exercise to the reader. I've +looked at the libtool documentation, and it confuses me horribly. +Reading it, I suspect it's wrong, but I don't have the time to +experiment to confirm that the documentation is wrong and how it +diverges from the libtool implementation. + +So let me explain things using the ELF shared library terminology, +which is "major version, minor version, patchlevel". This shows up in +the library name: + + libudev.so.1.6.11 + +So in this example, the major version number is 1, the minor version +is 6, and the patchlevel is 11. The patchlevel is entirely optional, +and many packages don't use it at all. The minor number is also +mostly useless on Linux, but it's still there for historical reasons. +The patchlevel and minor version numbers were useful back for SunOS +(and Linux a.out shared library), back when there weren't rpm and dpkg +as package managers. + +So many modern Linux shared libraries will only use the major and +minor version numbers, e.g: + + libext2fs.so.2.4 + +The only thing you really need to worry about is the major version +number, really. The minor version is *supposed* to change when new +interfaces has changed (but I and most other people don't do that any +more). But the big deal is that the major number *must* get bumped if +an existing interface has *changed*. + +So let's talk about the major version number, and then we'll talk +about why the minor version number isn't really a big deal for Linux. + +So if you change any of the library's function signatures --- and this +includes changing a type from a 32-bit integer to a 64-bit integer, +that's an ABI breakage, and so you must bump the major version number +so that a program that was linked against libfoo.so.4 doesn't try to +use libfoo.so.5. That's really the key --- will a program linked +against the previous version library break if it links against the +newer version. If it does, then you need to bump the version number. + +So for structures, if you change any of the existing fields, or if the +application program allocates the structure --- either by declaring it +on the stack, or via malloc() --- and you expand the structure, +obviously that will cause problem, and so that's an ABI break. + +If however, you arrange to have structures allocated by the library, +and struct members are always added at the end, then an older program +won't have any problems. You can guarantee this by simply only using +a pointer to the struct in your public header files, and defining the +struct in a private header file that is not available to userspace +programs. + +Similarly, adding new functions never breaks the ABI. That's because +older program won't try to use the newer interfaces. So if I need to +change an interface to a function, what I'll generally do is to define +a new function, and then implement the older function in terms of the +newer one. For example: + +extern errcode_t ext2fs_open(const char *name, int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *ret_fs); + +extern errcode_t ext2fs_open2(const char *name, const char *io_options, + int flags, int superblock, + unsigned int block_size, io_manager manager, + ext2_filsys *hret_fs); + +As far as the minor version numbers are concerned, the dynamic linker +doesn't use it. In SunOS 4, if you have a DT_NEEDED for libfoo.so.4, +and the dynamic linker finds in its search path: + + libfoo.so.4.8 + libfoo.so.4.9 + +It will preferentially use libfoo.so.4.9. + +That's not how it works in Linux, though. In Linux there will be a +symlink that points libfoo.so.4 to libfoo.so.4.9, and the linker just +looks for libfoo.so.4. One could imagine a package manager which +adjusts the symlink to point at the library with the highest version, +but given that libfoo.so.4.9 is supposed to contain a superset of +libfoo.so.4.8, there's no point. So we just in practice handle all of +this in the package manager, or via an ELF symbol map. Or, we just +assume that since vast majority of software comes from the +distribution, the distro package manager will just update libraries to +the newer version as a matter of course, and nothing special needs to +be done. + +So in practice I don't bump the minor version number for e2fsprogs +each time I add new interfaces, because in practice it really doesn't +matter for Linux. We have a much better system that gets used for +Debian. + +For example in Debian there is a file that contains when each symbol +was first introduced into a library, by its package version number. +See: + +https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/debian/libext2fs2.symbols + +This file contains a version number for each symbol in libext2fs2, and +it tells us what version of libext2fs you need to guarantee that a +particular symbol is present in the library. Then when *other* +packages are built that depend on libext2fs2, the minimum version of +libext2fs can be calculated based on which symbols they use. + +So for example the libf2fs-format4 package has a Debian dependency of: + +Depends: libblkid1 (>= 2.17.2), libc6 (>= 2.14), libf2fs5, libuuid1 (>= 2.16) + +The minimum version numbers needed for libblkid1 and libuuid1 are +determined by figuring out all of the symbols used by the +libf2fs-format4 package, and determining the minimum version number of +libblkid1 that supports all of those blkid functions. + +This gets done automatically, so I didn't have to figure this out. +All I have in the debian/control file is: + +Depends: ${misc:Depends}, ${shlibs:Depends} + +Sorry this got so long, but hopefully you'll find this useful. How +you bend libtool to your will is something you'll have to figure out, +because I don't use libtool in my packages.[1] + +Cheers, + + - Ted + + +[1] If you are interested in how I do things in e2fsprogs, take a look +at the Makefile.elf-lib, Makefile.solaris-lib, Makefile.darwin-lib, +etc. here: + +https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib + +This these Makefile fragments are then pulled into the generated +makefile using autoconf's substitution rules, here: + +https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git/tree/lib/ext2fs/Makefile.in + +(Search for "@MAKEFILE_ELF@" in the above Makefile.in). + +So when someone runs "configure --enable-elf-shlibs", they get the ELF +shared libraries built. On BSD and MacOS systems they just have to +run "configure --enable-bsd-shlibs", and so on. + +Personally, since most people don't bother to write truly portable +programs, as their C code is full of Linux'isms, using libtool is just +overkill, because they probably can't build on any other OS *anyway* +so libtool's slow and complex abstraction layer is totally wasted. +Might as well not use autoconf, automake, and libtool at all. + +On the other hand, if you really *do* worry about portability on other +OS's (e2fsprogs builds on MacOS, NetBSD, Hurd, Solaris, etc.) then +using autoconf makes sense --- but I *still* don't think the +complexity of libtool is worth it. + += Add-on = +If you are going to be making one less major update, this is the +perfect time to make sure that data structures are allocated by the +library, and are (ideally) opaque to the calling application (so they +only manipulate structure poitners). That is, the structure +definition is not exposed in the public header file, and you use +accessor functions to set and get fields in the structure. + +If you can't do that for all data structures, if you can do that with +your primary data structure that's going to make your life much easier +in the long term. For ext2fs, that's the file systme handle. It's +created by ext2fs_open(), and it's passed to all other library +functions as the first argument. + +The other thing you might want to consider doing is adding a magic +number to the beginning of each structure. That way you can tell if +the wrong structure gets passed to a library. It's also helpful for +doing the equivalent of subclassing in C. + +This is how we do it in libext2fs --- we use com_err to define the +magic numbers: + + error_table ext2 + +ec EXT2_ET_BASE, + "EXT2FS Library version @E2FSPROGS_VERSION@" + +ec EXT2_ET_MAGIC_EXT2FS_FILSYS, + "Wrong magic number for ext2_filsys structure" + +ec EXT2_ET_MAGIC_BADBLOCKS_LIST, + "Wrong magic number for badblocks_list structure" + ... + +And then every single structure starts like so: + +struct struct_ext2_filsys { + errcode_t magic; + ... + +struct ext2_struct_inode_scan { + errcode_t magic; + ... + +And then before we use any pointer we do this: + + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return EXT2_ET_MAGIC_EXT2_FILE; diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/autogen.sh b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/autogen.sh new file mode 100755 index 00000000000..2b0945d8f75 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/autogen.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +aclocal && \ +autoheader && \ +autoconf && \ +libtoolize && \ +automake -a -c diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/configure.ac b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/configure.ac new file mode 100644 index 00000000000..ddfc3b0f30e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/configure.ac @@ -0,0 +1,315 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.68]) + +# Get version from file VERSION +m4_define([f2fs_tools_version], m4_esyscmd([sed -n '1p' VERSION | tr -d '\n'])) +m4_define([f2fs_tools_date], m4_esyscmd([sed -n '2p' VERSION | tr -d '\n'])) +m4_define([f2fs_tools_gitdate], + m4_esyscmd([git log -1 --pretty=format:%ci 2> /dev/null])) + +AC_INIT([F2FS tools], [f2fs_tools_version], + [linux-f2fs-devel@lists.sourceforge.net]) + +AM_SILENT_RULES([yes]) + +AC_DEFINE([F2FS_TOOLS_VERSION], "f2fs_tools_version", [f2fs-tools version]) +AC_DEFINE([F2FS_MAJOR_VERSION], m4_bpatsubst(f2fs_tools_version, + [\([0-9]*\)\(\w\|\W\)*], [\1]), + [Major version for f2fs-tools]) +AC_DEFINE([F2FS_MINOR_VERSION], m4_bpatsubst(f2fs_tools_version, + [\([0-9]*\).\([0-9]*\)\(\w\|\W\)*], [\2]), + [Minor version for f2fs-tools]) + +AS_IF([test -d .git],[ + AC_DEFINE([F2FS_TOOLS_DATE], + "m4_bpatsubst(f2fs_tools_gitdate, + [\([0-9-]*\)\(\w\|\W\)*], [\1])", + [f2fs-tools date based on Git commits])],[ + AC_DEFINE([F2FS_TOOLS_DATE], + "f2fs_tools_date", + [f2fs-tools date based on Source releases])]) + +AC_CONFIG_SRCDIR([config.h.in]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([-Wall -Werror foreign tar-pax dist-xz]) + +# Test configure options. +AC_ARG_WITH([selinux], + [AS_HELP_STRING([--without-selinux], + [Ignore presence of libselinux and disable selinux support])], + [], + [with_selinux=check]) + +AC_ARG_WITH([blkid], + [AS_HELP_STRING([--without-blkid], + [Ignore presence of libblkid and disable blkid support])], + [], + [with_blkid=check]) + +AC_ARG_WITH([lzo2], + [AS_HELP_STRING([--without-lzo2], + [Ignore presence of liblzo2 and disable lzo2 support])], + [], + [with_lzo2=check]) + +AC_ARG_WITH([lz4], + [AS_HELP_STRING([--without-lz4], + [Ignore presence of liblz4 and disable lz4 support])], + [], + [with_lz4=check]) + +# Checks for programs. +AC_PROG_CC +AM_PROG_AR +LT_INIT +AC_PATH_PROG([LDCONFIG], [ldconfig], + [AC_MSG_ERROR([ldconfig not found])], + [$PATH:/sbin]) + +# Checks for libraries. +AS_IF([test "x$with_blkid" != xno], + [AC_CHECK_LIB([blkid], [blkid_probe_all], + [AC_SUBST([libblkid_LIBS], ["-lblkid"]) + AC_DEFINE([HAVE_LIBBLKID], [1], + [Define if you have libblkid]) + ], + [if test "x$with_blkid" != xcheck; then + AC_MSG_FAILURE( + [--with-blkid was given, but test for blkid failed]) + fi + ], -lblkid)]) + +AS_IF([test "x$with_lzo2" != xno], + [AC_CHECK_LIB([lzo2], [main], + [AC_SUBST([liblzo2_LIBS], ["-llzo2"]) + AC_DEFINE([HAVE_LIBLZO2], [1], + [Define if you have liblzo2]) + ], + [if test "x$with_lzo2" != xcheck; then + AC_MSG_FAILURE( + [--with-lzo2 was given, but test for lzo2 failed]) + fi + ], -llzo2)]) + +AS_IF([test "x$with_lz4" != xno], + [AC_CHECK_LIB([lz4], [main], + [AC_SUBST([liblz4_LIBS], ["-llz4"]) + AC_DEFINE([HAVE_LIBLZ4], [1], + [Define if you have liblz4]) + ], + [if test "x$with_lz4" != xcheck; then + AC_MSG_FAILURE( + [--with-lz4 was given, but test for lz4 failed]) + fi + ], -llz4)]) + +AS_IF([test "x$with_selinux" != xno], + [AC_CHECK_LIB([selinux], [getcon], + [AC_SUBST([libselinux_LIBS], ["-lselinux"]) + AC_DEFINE([HAVE_LIBSELINUX], [1], + [Define if you have libselinux]) + ], + [if test "x$with_selinux" != xcheck; then + AC_MSG_FAILURE( + [--with-selinux was given, but test for selinux failed]) + fi + ], -lselinux)]) + +AC_CHECK_LIB([uuid], [uuid_clear], + [AC_SUBST([libuuid_LIBS], ["-luuid"]) + AC_DEFINE([HAVE_LIBUUID], [1], + [Define if you have libuuid]) + ], [], []) + +AC_CHECK_LIB([winpthread], [clock_gettime], + [AC_SUBST([libwinpthread_LIBS], ["-lwinpthread"]) + AC_DEFINE([HAVE_LIBWINPTHREAD], [1], + [Define if you have libwinpthread]) + ], [], []) + +# Checks for header files. +AC_CHECK_HEADERS(m4_flatten([ + attr/xattr.h + blkid/blkid.h + byteswap.h + fcntl.h + kernel/uapi/linux/blkzoned.h + linux/blkzoned.h + linux/rw_hint.h + linux/fcntl.h + linux/falloc.h + linux/fiemap.h + linux/fs.h + linux/hdreg.h + linux/limits.h + linux/loop.h + linux/major.h + linux/posix_acl.h + linux/types.h + linux/xattr.h + mach/mach_time.h + mntent.h + pthread_time.h + scsi/sg.h + selinux/android.h + selinux/selinux.h + sparse/sparse.h + stdlib.h + string.h + sys/acl.h + sys/ioctl.h + sys/mount.h + sys/stat.h + sys/syscall.h + sys/sysmacros.h + sys/utsname.h + sys/xattr.h + unistd.h + uuid/uuid.h +])) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_INT32_T +AC_TYPE_INT8_T +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_GETMNTENT +AC_CHECK_FUNCS_ONCE([ + add_key + clock_gettime + fallocate + fsetxattr + fstat + fstat64 + fsync + getgid + getmntent + getuid + keyctl + memset + pread + pwrite + setmntent +]) + +AS_IF([test "$ac_cv_header_byteswap_h" = "yes"], + [AC_CHECK_DECLS([bswap_64],,,[#include ])]) + +AC_MSG_CHECKING([for CLOCK_BOOTIME]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ +#include +#ifdef HAVE_PTHREAD_TIME_H +#include +#endif +],[return CLOCK_BOOTTIME])], + [AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_CLOCK_BOOTTIME], [1], + [Define if CLOCK_BOOTTIME is available])], + [AC_MSG_RESULT([no])]) + +# AC_CANONICAL_HOST is needed to access the 'host_os' variable +AC_CANONICAL_HOST + +build_linux=no +build_windows=no +build_mac=no + +# Detect the target system +case "${host_os}" in +linux*|uclinux*) + build_linux=yes + ;; +cygwin*|mingw*) + build_windows=yes + ;; +darwin*) + build_mac=yes + ;; +*) + AC_MSG_ERROR(["OS $host_os is not supported"]) + ;; +esac + +# Pass the conditionals to automake +AM_CONDITIONAL([LINUX], [test "$build_linux" = "yes"]) +AM_CONDITIONAL([WINDOWS], [test "$build_windows" = "yes"]) +AM_CONDITIONAL([OSX], [test "$build_mac" = "yes"]) + +# Install directories +#AC_PREFIX_DEFAULT([/usr]) +#AC_SUBST([sbindir], [/sbin]) +#AC_SUBST([sysconfdir], [/etc]) +#AC_SUBST([localstatedir], [/var]) + +AC_ARG_WITH([root-libdir], +[ --with-root-libdir=DIR override location for /lib/libf2fs.so], +root_libdir=$withval, +root_libdir=NONE)dnl + +if test "$root_libdir" = NONE ; then + root_libdir="$libdir" +fi +AC_SUBST(root_libdir) + +AC_CONFIG_FILES([ + Makefile + man/Makefile + lib/Makefile + mkfs/Makefile + fsck/Makefile + tools/Makefile + tools/f2fs_io/Makefile +]) + +AC_CHECK_MEMBER([struct blk_zone.capacity], + [AC_DEFINE(HAVE_BLK_ZONE_REP_V2, [1], [report zones includes zone capacity])], + [], [[ +#ifdef HAVE_KERNEL_UAPI_LINUX_BLKZONED_H +#include +#elif defined(HAVE_LINUX_BLKZONED_H) +#include +#endif + ]]) + +# export library version info for mkfs/libf2fs_format_la +AC_SUBST(FMT_CURRENT, 9) +AC_SUBST(FMT_REVISION, 0) +AC_SUBST(FMT_AGE, 0) + +# export library version info for lib/libf2fs_la +AC_SUBST(LIBF2FS_CURRENT, 10) +AC_SUBST(LIBF2FS_REVISION, 0) +AC_SUBST(LIBF2FS_AGE, 0) + +AH_BOTTOM([ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifndef HAVE_GETUID +static inline unsigned int getuid(void) { return -1; } +#endif +#ifndef HAVE_GETGID +static inline unsigned int getgid(void) { return -1; } +#endif + +#ifndef S_ISLNK +#define S_ISLNK(mode) false +#endif +#ifndef S_ISSOCK +#define S_ISSOCK(mode) false +#endif + +#endif +]) + +AC_OUTPUT diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/Makefile.am new file mode 100644 index 00000000000..ea3b26a65aa --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/Makefile.am @@ -0,0 +1,23 @@ +## Makefile.am + +AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include +AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 +sbin_PROGRAMS = fsck.f2fs +noinst_HEADERS = common.h dict.h dqblk_v2.h f2fs.h fsck.h node.h quotaio.h \ + quotaio_tree.h quotaio_v2.h xattr.h compress.h inject.h +include_HEADERS = $(top_srcdir)/include/quota.h +fsck_f2fs_SOURCES = main.c fsck.c dump.c mount.c defrag.c resize.c \ + node.c segment.c dir.c sload.c xattr.c compress.c \ + dict.c mkquota.c quotaio.c quotaio_tree.c quotaio_v2.c \ + inject.c +fsck_f2fs_LDADD = ${libselinux_LIBS} ${libuuid_LIBS} \ + ${liblzo2_LIBS} ${liblz4_LIBS} ${libwinpthread_LIBS} \ + $(top_builddir)/lib/libf2fs.la + +install-data-hook: + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/dump.f2fs + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/defrag.f2fs + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/resize.f2fs + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/sload.f2fs + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/f2fslabel + ln -sf fsck.f2fs $(DESTDIR)/$(sbindir)/inject.f2fs diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/common.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/common.h new file mode 100644 index 00000000000..19a6ecc490e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/common.h @@ -0,0 +1,30 @@ +/** + * + * Various things common for all utilities + * + */ + +#ifndef __QUOTA_COMMON_H__ +#define __QUOTA_COMMON_H__ + +#undef DEBUG_QUOTA + +#ifndef __attribute__ +# if !defined __GNUC__ || __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__ +# define __attribute__(x) +# endif +#endif + +#define log_err(format, arg ...) \ + fprintf(stderr, "[ERROR] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) + +#ifdef DEBUG_QUOTA +# define log_debug(format, arg ...) \ + fprintf(stderr, "[DEBUG] %s:%d:%s:: " format "\n", \ + __FILE__, __LINE__, __func__, ## arg) +#else +# define log_debug(...) +#endif + +#endif /* __QUOTA_COMMON_H__ */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.c new file mode 100644 index 00000000000..b15f0a41c46 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.c @@ -0,0 +1,176 @@ +/** + * compress.c + * + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add sload compression support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* for config.h for general environment (non-Android) */ +#include "f2fs.h" + +#include "compress.h" +#ifdef HAVE_LIBLZO2 +#include /* for lzo1x_1_15_compress() */ +#endif +#ifdef HAVE_LIBLZ4 +#include /* for LZ4_compress_fast_extState() */ +#endif + +/* + * macro/constants borrowed from kernel header (GPL-2.0): + * include/linux/lzo.h, and include/linux/lz4.h + */ +#ifdef HAVE_LIBLZO2 +#define lzo1x_worst_compress(x) ((x) + (x) / 16 + 64 + 3 + 2) +#define LZO_WORK_SIZE ALIGN_UP(LZO1X_1_15_MEM_COMPRESS, 8) +#endif +#ifdef HAVE_LIBLZ4 +#define LZ4_MEMORY_USAGE 14 +#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ +#define LZ4_MEM_COMPRESS sizeof(LZ4_stream_t) +#define LZ4_ACCELERATION_DEFAULT 1 +#define LZ4_WORK_SIZE ALIGN_UP(LZ4_MEM_COMPRESS, 8) +#endif + +#if defined(HAVE_LIBLZO2) || defined(HAVE_LIBLZ4) +static void reset_cc(struct compress_ctx *cc) +{ + memset(cc->rbuf, 0, cc->cluster_size * F2FS_BLKSIZE); + memset(cc->cbuf->cdata, 0, cc->cluster_size * F2FS_BLKSIZE + - F2FS_BLKSIZE); +} +#endif + +#ifdef HAVE_LIBLZO2 +static void lzo_compress_init(struct compress_ctx *cc) +{ + size_t size = cc->cluster_size * F2FS_BLKSIZE; + size_t alloc = size + lzo1x_worst_compress(size) + + COMPRESS_HEADER_SIZE + LZO_WORK_SIZE; + cc->private = malloc(alloc); + ASSERT(cc->private); + cc->rbuf = (char *) cc->private + LZO_WORK_SIZE; + cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size); +} + +static int lzo_compress(struct compress_ctx *cc) +{ + int ret = lzo1x_1_15_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata, + (lzo_uintp)(&cc->clen), cc->private); + cc->cbuf->clen = cpu_to_le32(cc->clen); + return ret; +} +#endif + +#ifdef HAVE_LIBLZ4 +static void lz4_compress_init(struct compress_ctx *cc) +{ + size_t size = cc->cluster_size * F2FS_BLKSIZE; + size_t alloc = size + LZ4_COMPRESSBOUND(size) + + COMPRESS_HEADER_SIZE + LZ4_WORK_SIZE; + cc->private = malloc(alloc); + ASSERT(cc->private); + cc->rbuf = (char *) cc->private + LZ4_WORK_SIZE; + cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size); +} + +static int lz4_compress(struct compress_ctx *cc) +{ + cc->clen = LZ4_compress_fast_extState(cc->private, cc->rbuf, + (char *)cc->cbuf->cdata, cc->rlen, + cc->rlen - F2FS_BLKSIZE * c.compress.min_blocks - + COMPRESS_HEADER_SIZE, + LZ4_ACCELERATION_DEFAULT); + + if (!cc->clen) + return 1; + + cc->cbuf->clen = cpu_to_le32(cc->clen); + return 0; +} +#endif + +const char *supported_comp_names[] = { + "lzo", + "lz4", + "", +}; + +compress_ops supported_comp_ops[] = { +#ifdef HAVE_LIBLZO2 + {lzo_compress_init, lzo_compress, reset_cc}, +#else + {NULL, NULL, NULL}, +#endif +#ifdef HAVE_LIBLZ4 + {lz4_compress_init, lz4_compress, reset_cc}, +#else + {NULL, NULL, NULL}, +#endif +}; + +/* linked list */ +typedef struct _ext_t { + const char *ext; + struct _ext_t *next; +} ext_t; + +static ext_t *extension_list; + +static bool ext_found(const char *ext) +{ + ext_t *p = extension_list; + + while (p != NULL && strcmp(ext, p->ext)) + p = p->next; + return (p != NULL); +} + +static const char *get_ext(const char *path) +{ + char *p = strrchr(path, '.'); + + return p == NULL ? path + strlen(path) : p + 1; +} + +static bool ext_do_filter(const char *path) +{ + return (ext_found(get_ext(path)) == true) ^ + (c.compress.filter == COMPR_FILTER_ALLOW); +} + +static void ext_filter_add(const char *ext) +{ + ext_t *node; + + ASSERT(ext != NULL); + if (ext_found(ext)) + return; /* ext was already registered */ + node = malloc(sizeof(ext_t)); + ASSERT(node != NULL); + node->ext = ext; + node->next = extension_list; + extension_list = node; +} + +static void ext_filter_destroy(void) +{ + ext_t *p; + + while (extension_list != NULL) { + p = extension_list; + extension_list = p->next; + free(p); + } +} + +filter_ops ext_filter = { + .add = ext_filter_add, + .destroy = ext_filter_destroy, + .filter = ext_do_filter, +}; diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.h new file mode 100644 index 00000000000..917de2d6276 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/compress.h @@ -0,0 +1,22 @@ +/** + * compress.h + * + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add sload compression support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef COMPRESS_H +#define COMPRESS_H + +#include "f2fs_fs.h" + +extern const char *supported_comp_names[]; +extern compress_ops supported_comp_ops[]; +extern filter_ops ext_filter; + +#endif /* COMPRESS_H */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/defrag.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/defrag.c new file mode 100644 index 00000000000..9889b706e4d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/defrag.c @@ -0,0 +1,103 @@ +/** + * defrag.c + * + * Copyright (c) 2015 Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" + +static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to) +{ + void *raw = calloc(F2FS_BLKSIZE, 1); + struct seg_entry *se; + struct f2fs_summary sum; + u64 offset; + int ret, type; + + ASSERT(raw != NULL); + + /* read from */ + ret = dev_read_block(raw, from); + ASSERT(ret >= 0); + + /* get segment type */ + se = get_seg_entry(sbi, GET_SEGNO(sbi, from)); + /* write to */ + ret = dev_write_block(raw, to, f2fs_io_type_to_rw_hint(se->type)); + ASSERT(ret >= 0); + + /* update sit bitmap & valid_blocks && se->type */ + offset = OFFSET_IN_SEG(sbi, from); + type = se->type; + se->valid_blocks--; + f2fs_clear_bit(offset, (char *)se->cur_valid_map); + se->dirty = 1; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, to)); + offset = OFFSET_IN_SEG(sbi, to); + se->type = type; + se->valid_blocks++; + f2fs_set_bit(offset, (char *)se->cur_valid_map); + se->dirty = 1; + + /* read/write SSA */ + get_sum_entry(sbi, from, &sum); + update_sum_entry(sbi, to, &sum); + + /* if data block, read node and update node block */ + if (IS_DATASEG(type)) + update_data_blkaddr(sbi, le32_to_cpu(sum.nid), + le16_to_cpu(sum.ofs_in_node), to, NULL); + else + update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), to); + + DBG(1, "Migrate %s block %"PRIx64" -> %"PRIx64"\n", + IS_DATASEG(type) ? "data" : "node", + from, to); + free(raw); + return 0; +} + +int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left) +{ + struct seg_entry *se; + u64 idx, offset; + + /* flush NAT/SIT journal entries */ + flush_journal_entries(sbi); + + for (idx = from; idx < from + len; idx++) { + u64 target = to; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, idx)); + offset = OFFSET_IN_SEG(sbi, idx); + + if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map)) + continue; + + if (find_next_free_block(sbi, &target, left, se->type, false)) { + MSG(0, "Not enough space to migrate blocks"); + return -1; + } + + if (migrate_block(sbi, idx, target)) { + ASSERT_MSG("Found inconsistency: please run FSCK"); + return -1; + } + } + + /* update curseg info; can update sit->types */ + move_curseg_info(sbi, to, left); + zero_journal_entries(sbi); + write_curseg_info(sbi); + + /* flush dirty sit entries */ + flush_sit_entries(sbi); + + write_checkpoint(sbi); + + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.c new file mode 100644 index 00000000000..5b875bed81b --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.c @@ -0,0 +1,1500 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $ + * $Name: kazlib_1_20 $ + */ + +#define DICT_NODEBUG + +#include +#include +#ifdef DICT_NODEBUG +#define dict_assert(x) +#else +#include +#define dict_assert(x) assert(x) +#endif +#define DICT_IMPLEMENTATION +#include "dict.h" +#include + +#ifdef KAZLIB_RCSID +static const char rcsid[] = "$Id: dict.c,v 1.40.2.7 2000/11/13 01:36:44 kaz Exp $"; +#endif + +/* + * These macros provide short convenient names for structure members, + * which are embellished with dict_ prefixes so that they are + * properly confined to the documented namespace. It's legal for a + * program which uses dict to define, for instance, a macro called ``parent''. + * Such a macro would interfere with the dnode_t struct definition. + * In general, highly portable and reusable C modules which expose their + * structures need to confine structure member names to well-defined spaces. + * The resulting identifiers aren't necessarily convenient to use, nor + * readable, in the implementation, however! + */ + +#define left dict_left +#define right dict_right +#define parent dict_parent +#define color dict_color +#define key dict_key +#define data dict_data + +#define nilnode dict_nilnode +#define nodecount dict_nodecount +#define maxcount dict_maxcount +#define compare dict_compare +#define allocnode dict_allocnode +#define freenode dict_freenode +#define context dict_context +#define dupes dict_dupes + +#define dictptr dict_dictptr + +#define dict_root(D) ((D)->nilnode.left) +#define dict_nil(D) (&(D)->nilnode) +#define DICT_DEPTH_MAX 64 + +static dnode_t *dnode_alloc(void *context); +static void dnode_free(dnode_t *node, void *context); + +/* + * Perform a ``left rotation'' adjustment on the tree. The given node P and + * its right child C are rearranged so that the P instead becomes the left + * child of C. The left subtree of C is inherited as the new right subtree + * for P. The ordering of the keys within the tree is thus preserved. + */ +static void rotate_left(dnode_t *upper) +{ + dnode_t *lower, *lowleft, *upparent; + + lower = upper->right; + upper->right = lowleft = lower->left; + lowleft->parent = upper; + + lower->parent = upparent = upper->parent; + + /* don't need to check for root node here because root->parent is + the sentinel nil node, and root->parent->left points back to root */ + + if (upper == upparent->left) { + upparent->left = lower; + } else { + dict_assert(upper == upparent->right); + upparent->right = lower; + } + + lower->left = upper; + upper->parent = lower; +} + +/* + * This operation is the ``mirror'' image of rotate_left. It is + * the same procedure, but with left and right interchanged. + */ +static void rotate_right(dnode_t *upper) +{ + dnode_t *lower, *lowright, *upparent; + + lower = upper->left; + upper->left = lowright = lower->right; + lowright->parent = upper; + + lower->parent = upparent = upper->parent; + + if (upper == upparent->right) { + upparent->right = lower; + } else { + dict_assert(upper == upparent->left); + upparent->left = lower; + } + + lower->right = upper; + upper->parent = lower; +} + +/* + * Do a postorder traversal of the tree rooted at the specified + * node and free everything under it. Used by dict_free(). + */ +static void free_nodes(dict_t *dict, dnode_t *node, dnode_t *nil) +{ + if (node == nil) + return; + free_nodes(dict, node->left, nil); + free_nodes(dict, node->right, nil); + dict->freenode(node, dict->context); +} + +/* + * This procedure performs a verification that the given subtree is a binary + * search tree. It performs an inorder traversal of the tree using the + * dict_next() successor function, verifying that the key of each node is + * strictly lower than that of its successor, if duplicates are not allowed, + * or lower or equal if duplicates are allowed. This function is used for + * debugging purposes. + */ +#ifndef DICT_NODEBUG +static int verify_bintree(dict_t *dict) +{ + dnode_t *first, *next; + + first = dict_first(dict); + + if (dict->dupes) { + while (first && (next = dict_next(dict, first))) { + if (dict->compare(first->key, next->key) > 0) + return 0; + first = next; + } + } else { + while (first && (next = dict_next(dict, first))) { + if (dict->compare(first->key, next->key) >= 0) + return 0; + first = next; + } + } + return 1; +} + +/* + * This function recursively verifies that the given binary subtree satisfies + * three of the red black properties. It checks that every red node has only + * black children. It makes sure that each node is either red or black. And it + * checks that every path has the same count of black nodes from root to leaf. + * It returns the blackheight of the given subtree; this allows blackheights to + * be computed recursively and compared for left and right siblings for + * mismatches. It does not check for every nil node being black, because there + * is only one sentinel nil node. The return value of this function is the + * black height of the subtree rooted at the node ``root'', or zero if the + * subtree is not red-black. + */ +static unsigned int verify_redblack(dnode_t *nil, dnode_t *root) +{ + unsigned height_left, height_right; + + if (root != nil) { + height_left = verify_redblack(nil, root->left); + height_right = verify_redblack(nil, root->right); + if (height_left == 0 || height_right == 0) + return 0; + if (height_left != height_right) + return 0; + if (root->color == dnode_red) { + if (root->left->color != dnode_black) + return 0; + if (root->right->color != dnode_black) + return 0; + return height_left; + } + if (root->color != dnode_black) + return 0; + return height_left + 1; + } + return 1; +} + +/* + * Compute the actual count of nodes by traversing the tree and + * return it. This could be compared against the stored count to + * detect a mismatch. + */ +static dictcount_t verify_node_count(dnode_t *nil, dnode_t *root) +{ + if (root == nil) + return 0; + else + return 1 + verify_node_count(nil, root->left) + + verify_node_count(nil, root->right); +} +#endif + +/* + * Verify that the tree contains the given node. This is done by + * traversing all of the nodes and comparing their pointers to the + * given pointer. Returns 1 if the node is found, otherwise + * returns zero. It is intended for debugging purposes. + */ +static int verify_dict_has_node(dnode_t *nil, dnode_t *root, dnode_t *node) +{ + if (root != nil) { + return root == node + || verify_dict_has_node(nil, root->left, node) + || verify_dict_has_node(nil, root->right, node); + } + return 0; +} + +#ifdef FSCK_NOTUSED +/* + * Dynamically allocate and initialize a dictionary object. + */ +dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp) +{ + dict_t *new = malloc(sizeof *new); + + if (new) { + new->compare = comp; + new->allocnode = dnode_alloc; + new->freenode = dnode_free; + new->context = NULL; + new->nodecount = 0; + new->maxcount = maxcount; + new->nilnode.left = &new->nilnode; + new->nilnode.right = &new->nilnode; + new->nilnode.parent = &new->nilnode; + new->nilnode.color = dnode_black; + new->dupes = 0; + } + return new; +} +#endif /* FSCK_NOTUSED */ + +/* + * Select a different set of node allocator routines. + */ +void dict_set_allocator(dict_t *dict, dnode_alloc_t al, + dnode_free_t fr, void *context) +{ + dict_assert(dict_count(dict) == 0); + dict_assert((al == NULL && fr == NULL) || (al != NULL && fr != NULL)); + + dict->allocnode = al ? al : dnode_alloc; + dict->freenode = fr ? fr : dnode_free; + dict->context = context; +} + +#ifdef FSCK_NOTUSED +/* + * Free a dynamically allocated dictionary object. Removing the nodes + * from the tree before deleting it is required. + */ +void dict_destroy(dict_t *dict) +{ + dict_assert(dict_isempty(dict)); + free(dict); +} +#endif + +/* + * Free all the nodes in the dictionary by using the dictionary's + * installed free routine. The dictionary is emptied. + */ +void dict_free_nodes(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict); + free_nodes(dict, root, nil); + dict->nodecount = 0; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; +} + +#ifdef FSCK_NOTUSED +/* + * Obsolescent function, equivalent to dict_free_nodes + */ +void dict_free(dict_t *dict) +{ +#ifdef KAZLIB_OBSOLESCENT_DEBUG + dict_assert("call to obsolescent function dict_free()" && 0); +#endif + dict_free_nodes(dict); +} +#endif + +/* + * Initialize a user-supplied dictionary object. + */ +dict_t *dict_init(dict_t *dict, dictcount_t maxcount, dict_comp_t comp) +{ + dict->compare = comp; + dict->allocnode = dnode_alloc; + dict->freenode = dnode_free; + dict->context = NULL; + dict->nodecount = 0; + dict->maxcount = maxcount; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict->nilnode.color = dnode_black; + dict->dupes = 0; + return dict; +} + +#ifdef FSCK_NOTUSED +/* + * Initialize a dictionary in the likeness of another dictionary + */ +void dict_init_like(dict_t *dict, const dict_t *template) +{ + dict->compare = template->compare; + dict->allocnode = template->allocnode; + dict->freenode = template->freenode; + dict->context = template->context; + dict->nodecount = 0; + dict->maxcount = template->maxcount; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict->nilnode.color = dnode_black; + dict->dupes = template->dupes; + + dict_assert(dict_similar(dict, template)); +} + +/* + * Remove all nodes from the dictionary (without freeing them in any way). + */ +static void dict_clear(dict_t *dict) +{ + dict->nodecount = 0; + dict->nilnode.left = &dict->nilnode; + dict->nilnode.right = &dict->nilnode; + dict->nilnode.parent = &dict->nilnode; + dict_assert(dict->nilnode.color == dnode_black); +} +#endif /* FSCK_NOTUSED */ + +/* + * Verify the integrity of the dictionary structure. This is provided for + * debugging purposes, and should be placed in assert statements. Just because + * this function succeeds doesn't mean that the tree is not corrupt. Certain + * corruptions in the tree may simply cause undefined behavior. + */ +#ifndef DICT_NODEBUG +int dict_verify(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict); + + /* check that the sentinel node and root node are black */ + if (root->color != dnode_black) + return 0; + if (nil->color != dnode_black) + return 0; + if (nil->right != nil) + return 0; + /* nil->left is the root node; check that its parent pointer is nil */ + if (nil->left->parent != nil) + return 0; + /* perform a weak test that the tree is a binary search tree */ + if (!verify_bintree(dict)) + return 0; + /* verify that the tree is a red-black tree */ + if (!verify_redblack(nil, root)) + return 0; + if (verify_node_count(nil, root) != dict_count(dict)) + return 0; + return 1; +} +#endif /* DICT_NODEBUG */ + +#ifdef FSCK_NOTUSED +/* + * Determine whether two dictionaries are similar: have the same comparison and + * allocator functions, and same status as to whether duplicates are allowed. + */ +int dict_similar(const dict_t *left, const dict_t *right) +{ + if (left->compare != right->compare) + return 0; + + if (left->allocnode != right->allocnode) + return 0; + + if (left->freenode != right->freenode) + return 0; + + if (left->context != right->context) + return 0; + + if (left->dupes != right->dupes) + return 0; + + return 1; +} +#endif /* FSCK_NOTUSED */ + +/* + * Locate a node in the dictionary having the given key. + * If the node is not found, a null a pointer is returned (rather than + * a pointer that dictionary's nil sentinel node), otherwise a pointer to the + * located node is returned. + */ +dnode_t *dict_lookup(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *saved; + int result; + + /* simple binary search adapted for trees that contain duplicate keys */ + + while (root != nil) { + result = dict->compare(key, root->key); + if (result < 0) + root = root->left; + else if (result > 0) + root = root->right; + else { + if (!dict->dupes) { /* no duplicates, return match */ + return root; + } else { /* could be dupes, find leftmost one */ + do { + saved = root; + root = root->left; + while (root != nil && dict->compare(key, root->key)) + root = root->right; + } while (root != nil); + return saved; + } + } + } + + return NULL; +} + +#ifdef FSCK_NOTUSED +/* + * Look for the node corresponding to the lowest key that is equal to or + * greater than the given key. If there is no such node, return null. + */ +dnode_t *dict_lower_bound(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *tentative = 0; + + while (root != nil) { + int result = dict->compare(key, root->key); + + if (result > 0) { + root = root->right; + } else if (result < 0) { + tentative = root; + root = root->left; + } else { + if (!dict->dupes) { + return root; + } else { + tentative = root; + root = root->left; + } + } + } + + return tentative; +} + +/* + * Look for the node corresponding to the greatest key that is equal to or + * lower than the given key. If there is no such node, return null. + */ +dnode_t *dict_upper_bound(dict_t *dict, const void *key) +{ + dnode_t *root = dict_root(dict); + dnode_t *nil = dict_nil(dict); + dnode_t *tentative = 0; + + while (root != nil) { + int result = dict->compare(key, root->key); + + if (result < 0) { + root = root->left; + } else if (result > 0) { + tentative = root; + root = root->right; + } else { + if (!dict->dupes) { + return root; + } else { + tentative = root; + root = root->right; + } + } + } + + return tentative; +} +#endif + +/* + * Insert a node into the dictionary. The node should have been + * initialized with a data field. All other fields are ignored. + * The behavior is undefined if the user attempts to insert into + * a dictionary that is already full (for which the dict_isfull() + * function returns true). + */ +void dict_insert(dict_t *dict, dnode_t *node, const void *key) +{ + dnode_t *where = dict_root(dict), *nil = dict_nil(dict); + dnode_t *parent = nil, *uncle, *grandpa; + int result = -1; + + node->key = key; + + dict_assert(!dict_isfull(dict)); + dict_assert(!dict_contains(dict, node)); + dict_assert(!dnode_is_in_a_dict(node)); + + /* basic binary tree insert */ + + while (where != nil) { + parent = where; + result = dict->compare(key, where->key); + /* trap attempts at duplicate key insertion unless it's explicitly allowed */ + dict_assert(dict->dupes || result != 0); + if (result < 0) + where = where->left; + else + where = where->right; + } + + dict_assert(where == nil); + + if (result < 0) + parent->left = node; + else + parent->right = node; + + node->parent = parent; + node->left = nil; + node->right = nil; + + dict->nodecount++; + + /* red black adjustments */ + + node->color = dnode_red; + + while (parent->color == dnode_red) { + grandpa = parent->parent; + if (parent == grandpa->left) { + uncle = grandpa->right; + if (uncle->color == dnode_red) { /* red parent, red uncle */ + parent->color = dnode_black; + uncle->color = dnode_black; + grandpa->color = dnode_red; + node = grandpa; + parent = grandpa->parent; + } else { /* red parent, black uncle */ + if (node == parent->right) { + rotate_left(parent); + parent = node; + dict_assert(grandpa == parent->parent); + /* rotation between parent and child preserves grandpa */ + } + parent->color = dnode_black; + grandpa->color = dnode_red; + rotate_right(grandpa); + break; + } + } else { /* symmetric cases: parent == parent->parent->right */ + uncle = grandpa->left; + if (uncle->color == dnode_red) { + parent->color = dnode_black; + uncle->color = dnode_black; + grandpa->color = dnode_red; + node = grandpa; + parent = grandpa->parent; + } else { + if (node == parent->left) { + rotate_right(parent); + parent = node; + dict_assert(grandpa == parent->parent); + } + parent->color = dnode_black; + grandpa->color = dnode_red; + rotate_left(grandpa); + break; + } + } + } + + dict_root(dict)->color = dnode_black; + + dict_assert(dict_verify(dict)); +} + +#ifdef FSCK_NOTUSED +/* + * Delete the given node from the dictionary. If the given node does not belong + * to the given dictionary, undefined behavior results. A pointer to the + * deleted node is returned. + */ +dnode_t *dict_delete(dict_t *dict, dnode_t *delete) +{ + dnode_t *nil = dict_nil(dict), *child, *delparent = delete->parent; + + /* basic deletion */ + + dict_assert(!dict_isempty(dict)); + dict_assert(dict_contains(dict, delete)); + + /* + * If the node being deleted has two children, then we replace it with its + * successor (i.e. the leftmost node in the right subtree.) By doing this, + * we avoid the traditional algorithm under which the successor's key and + * value *only* move to the deleted node and the successor is spliced out + * from the tree. We cannot use this approach because the user may hold + * pointers to the successor, or nodes may be inextricably tied to some + * other structures by way of embedding, etc. So we must splice out the + * node we are given, not some other node, and must not move contents from + * one node to another behind the user's back. + */ + + if (delete->left != nil && delete->right != nil) { + dnode_t *next = dict_next(dict, delete); + dnode_t *nextparent = next->parent; + dnode_color_t nextcolor = next->color; + + dict_assert(next != nil); + dict_assert(next->parent != nil); + dict_assert(next->left == nil); + + /* + * First, splice out the successor from the tree completely, by + * moving up its right child into its place. + */ + + child = next->right; + child->parent = nextparent; + + if (nextparent->left == next) { + nextparent->left = child; + } else { + dict_assert(nextparent->right == next); + nextparent->right = child; + } + + /* + * Now that the successor has been extricated from the tree, install it + * in place of the node that we want deleted. + */ + + next->parent = delparent; + next->left = delete->left; + next->right = delete->right; + next->left->parent = next; + next->right->parent = next; + next->color = delete->color; + delete->color = nextcolor; + + if (delparent->left == delete) { + delparent->left = next; + } else { + dict_assert(delparent->right == delete); + delparent->right = next; + } + + } else { + dict_assert(delete != nil); + dict_assert(delete->left == nil || delete->right == nil); + + child = (delete->left != nil) ? delete->left : delete->right; + + child->parent = delparent = delete->parent; + + if (delete == delparent->left) { + delparent->left = child; + } else { + dict_assert(delete == delparent->right); + delparent->right = child; + } + } + + delete->parent = NULL; + delete->right = NULL; + delete->left = NULL; + + dict->nodecount--; + + dict_assert(verify_bintree(dict)); + + /* red-black adjustments */ + + if (delete->color == dnode_black) { + dnode_t *parent, *sister; + + dict_root(dict)->color = dnode_red; + + while (child->color == dnode_black) { + parent = child->parent; + if (child == parent->left) { + sister = parent->right; + dict_assert(sister != nil); + if (sister->color == dnode_red) { + sister->color = dnode_black; + parent->color = dnode_red; + rotate_left(parent); + sister = parent->right; + dict_assert(sister != nil); + } + if (sister->left->color == dnode_black + && sister->right->color == dnode_black) { + sister->color = dnode_red; + child = parent; + } else { + if (sister->right->color == dnode_black) { + dict_assert(sister->left->color == dnode_red); + sister->left->color = dnode_black; + sister->color = dnode_red; + rotate_right(sister); + sister = parent->right; + dict_assert(sister != nil); + } + sister->color = parent->color; + sister->right->color = dnode_black; + parent->color = dnode_black; + rotate_left(parent); + break; + } + } else { /* symmetric case: child == child->parent->right */ + dict_assert(child == parent->right); + sister = parent->left; + dict_assert(sister != nil); + if (sister->color == dnode_red) { + sister->color = dnode_black; + parent->color = dnode_red; + rotate_right(parent); + sister = parent->left; + dict_assert(sister != nil); + } + if (sister->right->color == dnode_black + && sister->left->color == dnode_black) { + sister->color = dnode_red; + child = parent; + } else { + if (sister->left->color == dnode_black) { + dict_assert(sister->right->color == dnode_red); + sister->right->color = dnode_black; + sister->color = dnode_red; + rotate_left(sister); + sister = parent->left; + dict_assert(sister != nil); + } + sister->color = parent->color; + sister->left->color = dnode_black; + parent->color = dnode_black; + rotate_right(parent); + break; + } + } + } + + child->color = dnode_black; + dict_root(dict)->color = dnode_black; + } + + dict_assert(dict_verify(dict)); + + return delete; +} +#endif /* FSCK_NOTUSED */ + +/* + * Allocate a node using the dictionary's allocator routine, give it + * the data item. + */ +int dict_alloc_insert(dict_t *dict, const void *key, void *data) +{ + dnode_t *node = dict->allocnode(dict->context); + + if (node) { + dnode_init(node, data); + dict_insert(dict, node, key); + return 1; + } + return 0; +} + +#ifdef FSCK_NOTUSED +void dict_delete_free(dict_t *dict, dnode_t *node) +{ + dict_delete(dict, node); + dict->freenode(node, dict->context); +} +#endif + +/* + * Return the node with the lowest (leftmost) key. If the dictionary is empty + * (that is, dict_isempty(dict) returns 1) a null pointer is returned. + */ +dnode_t *dict_first(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *left; + + if (root != nil) + while ((left = root->left) != nil) + root = left; + + return (root == nil) ? NULL : root; +} + +/* + * Return the node with the highest (rightmost) key. If the dictionary is empty + * (that is, dict_isempty(dict) returns 1) a null pointer is returned. + */ +dnode_t *dict_last(dict_t *dict) +{ + dnode_t *nil = dict_nil(dict), *root = dict_root(dict), *right; + + if (root != nil) + while ((right = root->right) != nil) + root = right; + + return (root == nil) ? NULL : root; +} + +/* + * Return the given node's successor node---the node which has the + * next key in the the left to right ordering. If the node has + * no successor, a null pointer is returned rather than a pointer to + * the nil node. + */ +dnode_t *dict_next(dict_t *dict, dnode_t *curr) +{ + dnode_t *nil = dict_nil(dict), *parent, *left; + + if (curr->right != nil) { + curr = curr->right; + while ((left = curr->left) != nil) + curr = left; + return curr; + } + + parent = curr->parent; + + while (parent != nil && curr == parent->right) { + curr = parent; + parent = curr->parent; + } + + return (parent == nil) ? NULL : parent; +} + +/* + * Return the given node's predecessor, in the key order. + * The nil sentinel node is returned if there is no predecessor. + */ +dnode_t *dict_prev(dict_t *dict, dnode_t *curr) +{ + dnode_t *nil = dict_nil(dict), *parent, *right; + + if (curr->left != nil) { + curr = curr->left; + while ((right = curr->right) != nil) + curr = right; + return curr; + } + + parent = curr->parent; + + while (parent != nil && curr == parent->left) { + curr = parent; + parent = curr->parent; + } + + return (parent == nil) ? NULL : parent; +} + +void dict_allow_dupes(dict_t *dict) +{ + dict->dupes = 1; +} + +#undef dict_count +#undef dict_isempty +#undef dict_isfull +#undef dnode_get +#undef dnode_put +#undef dnode_getkey + +dictcount_t dict_count(dict_t *dict) +{ + return dict->nodecount; +} + +int dict_isempty(dict_t *dict) +{ + return dict->nodecount == 0; +} + +int dict_isfull(dict_t *dict) +{ + return dict->nodecount == dict->maxcount; +} + +int dict_contains(dict_t *dict, dnode_t *node) +{ + return verify_dict_has_node(dict_nil(dict), dict_root(dict), node); +} + +static dnode_t *dnode_alloc(void *UNUSED(context)) +{ + return malloc(sizeof *dnode_alloc(NULL)); +} + +static void dnode_free(dnode_t *node, void *UNUSED(context)) +{ + free(node); +} + +dnode_t *dnode_create(void *data) +{ + dnode_t *new = malloc(sizeof *new); + if (new) { + new->data = data; + new->parent = NULL; + new->left = NULL; + new->right = NULL; + } + return new; +} + +dnode_t *dnode_init(dnode_t *dnode, void *data) +{ + dnode->data = data; + dnode->parent = NULL; + dnode->left = NULL; + dnode->right = NULL; + return dnode; +} + +void dnode_destroy(dnode_t *dnode) +{ + dict_assert(!dnode_is_in_a_dict(dnode)); + free(dnode); +} + +void *dnode_get(dnode_t *dnode) +{ + return dnode->data; +} + +const void *dnode_getkey(dnode_t *dnode) +{ + return dnode->key; +} + +#ifdef FSCK_NOTUSED +void dnode_put(dnode_t *dnode, void *data) +{ + dnode->data = data; +} +#endif + +#ifndef DICT_NODEBUG +int dnode_is_in_a_dict(dnode_t *dnode) +{ + return (dnode->parent && dnode->left && dnode->right); +} +#endif + +#ifdef FSCK_NOTUSED +void dict_process(dict_t *dict, void *context, dnode_process_t function) +{ + dnode_t *node = dict_first(dict), *next; + + while (node != NULL) { + /* check for callback function deleting */ + /* the next node from under us */ + dict_assert(dict_contains(dict, node)); + next = dict_next(dict, node); + function(dict, node, context); + node = next; + } +} + +static void load_begin_internal(dict_load_t *load, dict_t *dict) +{ + load->dictptr = dict; + load->nilnode.left = &load->nilnode; + load->nilnode.right = &load->nilnode; +} + +void dict_load_begin(dict_load_t *load, dict_t *dict) +{ + dict_assert(dict_isempty(dict)); + load_begin_internal(load, dict); +} + +void dict_load_next(dict_load_t *load, dnode_t *newnode, const void *key) +{ + dict_t *dict = load->dictptr; + dnode_t *nil = &load->nilnode; + + dict_assert(!dnode_is_in_a_dict(newnode)); + dict_assert(dict->nodecount < dict->maxcount); + +#ifndef DICT_NODEBUG + if (dict->nodecount > 0) { + if (dict->dupes) + dict_assert(dict->compare(nil->left->key, key) <= 0); + else + dict_assert(dict->compare(nil->left->key, key) < 0); + } +#endif + + newnode->key = key; + nil->right->left = newnode; + nil->right = newnode; + newnode->left = nil; + dict->nodecount++; +} + +void dict_load_end(dict_load_t *load) +{ + dict_t *dict = load->dictptr; + dnode_t *tree[DICT_DEPTH_MAX] = { 0 }; + dnode_t *curr, *dictnil = dict_nil(dict), *loadnil = &load->nilnode, *next; + dnode_t *complete = 0; + dictcount_t fullcount = DICTCOUNT_T_MAX, nodecount = dict->nodecount; + dictcount_t botrowcount; + unsigned baselevel = 0, level = 0, i; + + dict_assert(dnode_red == 0 && dnode_black == 1); + + while (fullcount >= nodecount && fullcount) + fullcount >>= 1; + + botrowcount = nodecount - fullcount; + + for (curr = loadnil->left; curr != loadnil; curr = next) { + next = curr->left; + + if (complete == NULL && botrowcount-- == 0) { + dict_assert(baselevel == 0); + dict_assert(level == 0); + baselevel = level = 1; + complete = tree[0]; + + if (complete != 0) { + tree[0] = 0; + complete->right = dictnil; + while (tree[level] != 0) { + tree[level]->right = complete; + complete->parent = tree[level]; + complete = tree[level]; + tree[level++] = 0; + } + } + } + + if (complete == NULL) { + curr->left = dictnil; + curr->right = dictnil; + curr->color = level % 2; + complete = curr; + + dict_assert(level == baselevel); + while (tree[level] != 0) { + tree[level]->right = complete; + complete->parent = tree[level]; + complete = tree[level]; + tree[level++] = 0; + } + } else { + curr->left = complete; + curr->color = (level + 1) % 2; + complete->parent = curr; + tree[level] = curr; + complete = 0; + level = baselevel; + } + } + + if (complete == NULL) + complete = dictnil; + + for (i = 0; i < DICT_DEPTH_MAX; i++) { + if (tree[i] != 0) { + tree[i]->right = complete; + complete->parent = tree[i]; + complete = tree[i]; + } + } + + dictnil->color = dnode_black; + dictnil->right = dictnil; + complete->parent = dictnil; + complete->color = dnode_black; + dict_root(dict) = complete; + + dict_assert(dict_verify(dict)); +} + +void dict_merge(dict_t *dest, dict_t *source) +{ + dict_load_t load; + dnode_t *leftnode = dict_first(dest), *rightnode = dict_first(source); + + dict_assert(dict_similar(dest, source)); + + if (source == dest) + return; + + dest->nodecount = 0; + load_begin_internal(&load, dest); + + for (;;) { + if (leftnode != NULL && rightnode != NULL) { + if (dest->compare(leftnode->key, rightnode->key) < 0) + goto copyleft; + else + goto copyright; + } else if (leftnode != NULL) { + goto copyleft; + } else if (rightnode != NULL) { + goto copyright; + } else { + dict_assert(leftnode == NULL && rightnode == NULL); + break; + } + +copyleft: + { + dnode_t *next = dict_next(dest, leftnode); +#ifndef DICT_NODEBUG + leftnode->left = NULL; /* suppress assertion in dict_load_next */ +#endif + dict_load_next(&load, leftnode, leftnode->key); + leftnode = next; + continue; + } + +copyright: + { + dnode_t *next = dict_next(source, rightnode); +#ifndef DICT_NODEBUG + rightnode->left = NULL; +#endif + dict_load_next(&load, rightnode, rightnode->key); + rightnode = next; + continue; + } + } + + dict_clear(source); + dict_load_end(&load); +} +#endif /* FSCK_NOTUSED */ + +#ifdef KAZLIB_TEST_MAIN + +#include +#include +#include +#include + +typedef char input_t[256]; + +static int tokenize(char *string, ...) +{ + char **tokptr; + va_list arglist; + int tokcount = 0; + + va_start(arglist, string); + tokptr = va_arg(arglist, char **); + while (tokptr) { + while (*string && isspace((unsigned char) *string)) + string++; + if (!*string) + break; + *tokptr = string; + while (*string && !isspace((unsigned char) *string)) + string++; + tokptr = va_arg(arglist, char **); + tokcount++; + if (!*string) + break; + *string++ = 0; + } + va_end(arglist); + + return tokcount; +} + +static int comparef(const void *key1, const void *key2) +{ + return strcmp(key1, key2); +} + +static char *dupstring(char *str) +{ + int sz = strlen(str) + 1; + char *new = malloc(sz); + if (new) + memcpy(new, str, sz); + return new; +} + +static dnode_t *new_node(void *c) +{ + static dnode_t few[5]; + static int count; + + if (count < 5) + return few + count++; + + return NULL; +} + +static void del_node(dnode_t *n, void *c) +{ +} + +static int prompt = 0; + +static void construct(dict_t *d) +{ + input_t in; + int done = 0; + dict_load_t dl; + dnode_t *dn; + char *tok1, *tok2, *val; + const char *key; + char *help = + "p turn prompt on\n" + "q finish construction\n" + "a add new entry\n"; + + if (!dict_isempty(d)) + puts("warning: dictionary not empty!"); + + dict_load_begin(&dl, d); + + while (!done) { + if (prompt) + putchar('>'); + fflush(stdout); + + if (!fgets(in, sizeof(input_t), stdin)) + break; + + switch (in[0]) { + case '?': + puts(help); + break; + case 'p': + prompt = 1; + break; + case 'q': + done = 1; + break; + case 'a': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } + key = dupstring(tok1); + val = dupstring(tok2); + dn = dnode_create(val); + + if (!key || !val || !dn) { + puts("out of memory"); + free((void *) key); + free(val); + if (dn) + dnode_destroy(dn); + } + + dict_load_next(&dl, dn, key); + break; + default: + putchar('?'); + putchar('\n'); + break; + } + } + + dict_load_end(&dl); +} + +int main(void) +{ + input_t in; + dict_t darray[10]; + dict_t *d = &darray[0]; + dnode_t *dn; + int i; + char *tok1, *tok2, *val; + const char *key; + + char *help = + "a add value to dictionary\n" + "d delete value from dictionary\n" + "l lookup value in dictionary\n" + "( lookup lower bound\n" + ") lookup upper bound\n" + "# switch to alternate dictionary (0-9)\n" + "j merge two dictionaries\n" + "f free the whole dictionary\n" + "k allow duplicate keys\n" + "c show number of entries\n" + "t dump whole dictionary in sort order\n" + "m make dictionary out of sorted items\n" + "p turn prompt on\n" + "s switch to non-functioning allocator\n" + "q quit"; + + for (i = 0; i < sizeof darray / sizeof *darray; i++) + dict_init(&darray[i], DICTCOUNT_T_MAX, comparef); + + for (;;) { + if (prompt) + putchar('>'); + fflush(stdout); + + if (!fgets(in, sizeof(input_t), stdin)) + break; + + switch(in[0]) { + case '?': + puts(help); + break; + case 'a': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } + key = dupstring(tok1); + val = dupstring(tok2); + + if (!key || !val) { + puts("out of memory"); + free((void *) key); + free(val); + } + + if (!dict_alloc_insert(d, key, val)) { + puts("dict_alloc_insert failed"); + free((void *) key); + free(val); + break; + } + break; + case 'd': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } + dn = dict_lookup(d, tok1); + if (!dn) { + puts("dict_lookup failed"); + break; + } + val = dnode_get(dn); + key = dnode_getkey(dn); + dict_delete_free(d, dn); + + free(val); + free((void *) key); + break; + case 'f': + dict_free(d); + break; + case 'l': + case '(': + case ')': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } + dn = 0; + switch (in[0]) { + case 'l': + dn = dict_lookup(d, tok1); + break; + case '(': + dn = dict_lower_bound(d, tok1); + break; + case ')': + dn = dict_upper_bound(d, tok1); + break; + } + if (!dn) { + puts("lookup failed"); + break; + } + val = dnode_get(dn); + puts(val); + break; + case 'm': + construct(d); + break; + case 'k': + dict_allow_dupes(d); + break; + case 'c': + printf("%lu\n", (unsigned long) dict_count(d)); + break; + case 't': + for (dn = dict_first(d); dn; dn = dict_next(d, dn)) { + printf("%s\t%s\n", (char *) dnode_getkey(dn), + (char *) dnode_get(dn)); + } + break; + case 'q': + exit(0); + break; + case '\0': + break; + case 'p': + prompt = 1; + break; + case 's': + dict_set_allocator(d, new_node, del_node, NULL); + break; + case '#': + if (tokenize(in+1, &tok1, (char **) 0) != 1) { + puts("what?"); + break; + } else { + int dictnum = atoi(tok1); + if (dictnum < 0 || dictnum > 9) { + puts("invalid number"); + break; + } + d = &darray[dictnum]; + } + break; + case 'j': + if (tokenize(in+1, &tok1, &tok2, (char **) 0) != 2) { + puts("what?"); + break; + } else { + int dict1 = atoi(tok1), dict2 = atoi(tok2); + if (dict1 < 0 || dict1 > 9 || dict2 < 0 || dict2 > 9) { + puts("invalid number"); + break; + } + dict_merge(&darray[dict1], &darray[dict2]); + } + break; + default: + putchar('?'); + putchar('\n'); + break; + } + } + + return 0; +} + +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.h new file mode 100644 index 00000000000..c59e1a29e1d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dict.h @@ -0,0 +1,144 @@ +/* + * Dictionary Abstract Data Type + * Copyright (C) 1997 Kaz Kylheku + * + * Free Software License: + * + * All rights are reserved by the author, with the following exceptions: + * Permission is granted to freely reproduce and distribute this software, + * possibly in exchange for a fee, provided that this copyright notice appears + * intact. Permission is also granted to adapt this software to produce + * derivative works, as long as the modified versions carry this copyright + * notice and additional notices stating that the work has been modified. + * This source code may be translated into executable form and incorporated + * into proprietary software; there is no requirement for such software to + * contain a copyright notice related to this source. + * + * $Id: dict.h,v 1.22.2.6 2000/11/13 01:36:44 kaz Exp $ + * $Name: kazlib_1_20 $ + */ + +#ifndef DICT_H +#define DICT_H + +#include +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#include "sfx.h" +#endif + +/* + * Blurb for inclusion into C++ translation units + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned long dictcount_t; +#define DICTCOUNT_T_MAX ULONG_MAX + +/* + * The dictionary is implemented as a red-black tree + */ + +typedef enum { dnode_red, dnode_black } dnode_color_t; + +typedef struct dnode_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + struct dnode_t *dict_left; + struct dnode_t *dict_right; + struct dnode_t *dict_parent; + dnode_color_t dict_color; + const void *dict_key; + void *dict_data; +#else + int dict_dummy; +#endif +} dnode_t; + +typedef int (*dict_comp_t)(const void *, const void *); +typedef dnode_t *(*dnode_alloc_t)(void *); +typedef void (*dnode_free_t)(dnode_t *, void *); + +typedef struct dict_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + dnode_t dict_nilnode; + dictcount_t dict_nodecount; + dictcount_t dict_maxcount; + dict_comp_t dict_compare; + dnode_alloc_t dict_allocnode; + dnode_free_t dict_freenode; + void *dict_context; + int dict_dupes; +#else + int dict_dummmy; +#endif +} dict_t; + +typedef void (*dnode_process_t)(dict_t *, dnode_t *, void *); + +typedef struct dict_load_t { +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) + dict_t *dict_dictptr; + dnode_t dict_nilnode; +#else + int dict_dummmy; +#endif +} dict_load_t; + +extern dict_t *dict_create(dictcount_t, dict_comp_t); +extern void dict_set_allocator(dict_t *, dnode_alloc_t, dnode_free_t, void *); +extern void dict_destroy(dict_t *); +extern void dict_free_nodes(dict_t *); +extern void dict_free(dict_t *); +extern dict_t *dict_init(dict_t *, dictcount_t, dict_comp_t); +extern void dict_init_like(dict_t *, const dict_t *); +extern int dict_verify(dict_t *); +extern int dict_similar(const dict_t *, const dict_t *); +extern dnode_t *dict_lookup(dict_t *, const void *); +extern dnode_t *dict_lower_bound(dict_t *, const void *); +extern dnode_t *dict_upper_bound(dict_t *, const void *); +extern void dict_insert(dict_t *, dnode_t *, const void *); +extern dnode_t *dict_delete(dict_t *, dnode_t *); +extern int dict_alloc_insert(dict_t *, const void *, void *); +extern void dict_delete_free(dict_t *, dnode_t *); +extern dnode_t *dict_first(dict_t *); +extern dnode_t *dict_last(dict_t *); +extern dnode_t *dict_next(dict_t *, dnode_t *); +extern dnode_t *dict_prev(dict_t *, dnode_t *); +extern dictcount_t dict_count(dict_t *); +extern int dict_isempty(dict_t *); +extern int dict_isfull(dict_t *); +extern int dict_contains(dict_t *, dnode_t *); +extern void dict_allow_dupes(dict_t *); +extern int dnode_is_in_a_dict(dnode_t *); +extern dnode_t *dnode_create(void *); +extern dnode_t *dnode_init(dnode_t *, void *); +extern void dnode_destroy(dnode_t *); +extern void *dnode_get(dnode_t *); +extern const void *dnode_getkey(dnode_t *); +extern void dnode_put(dnode_t *, void *); +extern void dict_process(dict_t *, void *, dnode_process_t); +extern void dict_load_begin(dict_load_t *, dict_t *); +extern void dict_load_next(dict_load_t *, dnode_t *, const void *); +extern void dict_load_end(dict_load_t *); +extern void dict_merge(dict_t *, dict_t *); + +#if defined(DICT_IMPLEMENTATION) || !defined(KAZLIB_OPAQUE_DEBUG) +#ifdef KAZLIB_SIDEEFFECT_DEBUG +#define dict_isfull(D) (SFX_CHECK(D)->dict_nodecount == (D)->dict_maxcount) +#else +#define dict_isfull(D) ((D)->dict_nodecount == (D)->dict_maxcount) +#endif +#define dict_count(D) ((D)->dict_nodecount) +#define dict_isempty(D) ((D)->dict_nodecount == 0) +#define dnode_get(N) ((N)->dict_data) +#define dnode_getkey(N) ((N)->dict_key) +#define dnode_put(N, X) ((N)->dict_data = (X)) +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dir.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dir.c new file mode 100644 index 00000000000..4debda81c92 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dir.c @@ -0,0 +1,907 @@ +/** + * dir.c + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "node.h" +#include + +static int room_for_filename(const u8 *bitmap, int slots, int max_slots) +{ + int bit_start = 0; + int zero_start, zero_end; +next: + zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start); + if (zero_start >= max_slots) + return max_slots; + + zero_end = find_next_bit_le(bitmap, max_slots, zero_start + 1); + + if (zero_end - zero_start >= slots) + return zero_start; + bit_start = zero_end; + goto next; + +} + +void make_dentry_ptr(struct f2fs_dentry_ptr *d, struct f2fs_node *node_blk, + void *src, int type) +{ + if (type == 1) { + struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src; + d->max = NR_DENTRY_IN_BLOCK; + d->nr_bitmap = SIZE_OF_DENTRY_BITMAP; + d->bitmap = t->dentry_bitmap; + d->dentry = F2FS_DENTRY_BLOCK_DENTRIES(t); + d->filename = F2FS_DENTRY_BLOCK_FILENAMES(t); + } else { + int entry_cnt = NR_INLINE_DENTRY(node_blk); + int bitmap_size = INLINE_DENTRY_BITMAP_SIZE(node_blk); + int reserved_size = INLINE_RESERVED_SIZE(node_blk); + + d->max = entry_cnt; + d->nr_bitmap = bitmap_size; + d->bitmap = (u8 *)src; + d->dentry = (struct f2fs_dir_entry *) + ((char *)src + bitmap_size + reserved_size); + d->filename = (__u8 (*)[F2FS_SLOT_LEN])((char *)src + + bitmap_size + reserved_size + + SIZE_OF_DIR_ENTRY * entry_cnt); + } +} + +static struct f2fs_dir_entry *find_target_dentry(const u8 *name, + unsigned int len, f2fs_hash_t namehash, int *max_slots, + struct f2fs_dentry_ptr *d) +{ + struct f2fs_dir_entry *de; + unsigned long bit_pos = 0; + int max_len = 0; + + if (max_slots) + *max_slots = 0; + while (bit_pos < (unsigned long)d->max) { + if (!test_bit_le(bit_pos, d->bitmap)) { + bit_pos++; + max_len++; + continue; + } + + de = &d->dentry[bit_pos]; + if (le16_to_cpu(de->name_len) == len && + de->hash_code == namehash && + !memcmp(d->filename[bit_pos], name, len)) { + goto found; + } + + if (max_slots && max_len > *max_slots) + *max_slots = max_len; + max_len = 0; + bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); + } + de = NULL; +found: + if (max_slots && max_len > *max_slots) + *max_slots = max_len; + return de; +} + +static struct f2fs_dir_entry *find_in_block(void *block, + const u8 *name, int len, f2fs_hash_t namehash, + int *max_slots) +{ + struct f2fs_dentry_ptr d; + + make_dentry_ptr(&d, NULL, block, 1); + return find_target_dentry(name, len, namehash, max_slots, &d); +} + +static int find_in_level(struct f2fs_sb_info *sbi, struct f2fs_node *dir, + unsigned int level, struct dentry *de) +{ + unsigned int nbucket, nblock; + unsigned int bidx, end_block; + struct f2fs_dir_entry *dentry = NULL; + struct dnode_of_data dn; + void *dentry_blk; + int max_slots = 214; + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(dir)->ino); + f2fs_hash_t namehash; + unsigned int dir_level = dir->i.i_dir_level; + int ret = 0; + + namehash = f2fs_dentry_hash(get_encoding(sbi), IS_CASEFOLDED(&dir->i), + de->name, de->len); + + nbucket = dir_buckets(level, dir_level); + nblock = bucket_blocks(level); + + bidx = dir_block_index(level, dir_level, le32_to_cpu(namehash) % nbucket); + end_block = bidx + nblock; + + dentry_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(dentry_blk); + + memset(&dn, 0, sizeof(dn)); + for (; bidx < end_block; bidx++) { + + /* Firstly, we should know direct node of target data blk */ + if (dn.node_blk && dn.node_blk != dn.inode_blk) + free(dn.node_blk); + + set_new_dnode(&dn, dir, NULL, ino); + get_dnode_of_data(sbi, &dn, bidx, LOOKUP_NODE); + if (dn.data_blkaddr == NULL_ADDR) + continue; + + ret = dev_read_block(dentry_blk, dn.data_blkaddr); + ASSERT(ret >= 0); + + dentry = find_in_block(dentry_blk, de->name, de->len, + namehash, &max_slots); + if (dentry) { + ret = 1; + de->ino = le32_to_cpu(dentry->ino); + break; + } + } + + if (dn.node_blk && dn.node_blk != dn.inode_blk) + free(dn.node_blk); + free(dentry_blk); + + return ret; +} + +static int f2fs_find_entry(struct f2fs_sb_info *sbi, + struct f2fs_node *dir, struct dentry *de) +{ + unsigned int max_depth; + unsigned int level; + + max_depth = le32_to_cpu(dir->i.i_current_depth); + for (level = 0; level < max_depth; level ++) { + if (find_in_level(sbi, dir, level, de)) + return 1; + } + return 0; +} + +/* return ino if file exists, otherwise return 0 */ +nid_t f2fs_lookup(struct f2fs_sb_info *sbi, struct f2fs_node *dir, + u8 *name, int len) +{ + int err; + struct dentry de = { + .name = name, + .len = len, + }; + + err = f2fs_find_entry(sbi, dir, &de); + if (err == 1) + return de.ino; + else + return 0; +} + +static void f2fs_update_dentry(nid_t ino, int file_type, + struct f2fs_dentry_ptr *d, + const unsigned char *name, int len, f2fs_hash_t name_hash, + unsigned int bit_pos) +{ + struct f2fs_dir_entry *de; + int slots = GET_DENTRY_SLOTS(len); + int i; + + de = &d->dentry[bit_pos]; + de->name_len = cpu_to_le16(len); + de->hash_code = name_hash; + memcpy(d->filename[bit_pos], name, len); + d->filename[bit_pos][len] = 0; + de->ino = cpu_to_le32(ino); + de->file_type = file_type; + for (i = 0; i < slots; i++) + test_and_set_bit_le(bit_pos + i, d->bitmap); +} + +/* + * f2fs_add_link - Add a new file(dir) to parent dir. + */ +int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent, + const unsigned char *name, int name_len, nid_t ino, + int file_type, block_t *p_blkaddr, int inc_link) +{ + int level = 0, current_depth, bit_pos; + int nbucket, nblock, bidx, block; + int slots = GET_DENTRY_SLOTS(name_len); + f2fs_hash_t dentry_hash; + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dentry_ptr d; + struct dnode_of_data dn; + nid_t pino; + unsigned int dir_level; + int ret; + bool datablk_alloced = false; + + if (parent == NULL) + return -EINVAL; + + dentry_hash = f2fs_dentry_hash(get_encoding(sbi), + IS_CASEFOLDED(&parent->i), + name, name_len); + pino = le32_to_cpu(F2FS_NODE_FOOTER(parent)->ino); + dir_level = parent->i.i_dir_level; + + if (!pino) { + ERR_MSG("Wrong parent ino:%d \n", pino); + return -EINVAL; + } + + dentry_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(dentry_blk); + + current_depth = le32_to_cpu(parent->i.i_current_depth); +start: + if (current_depth == MAX_DIR_HASH_DEPTH) { + free(dentry_blk); + ERR_MSG("\tError: MAX_DIR_HASH\n"); + return -ENOSPC; + } + + /* Need a new dentry block */ + if (level == current_depth) + ++current_depth; + + nbucket = dir_buckets(level, dir_level); + nblock = bucket_blocks(level); + bidx = dir_block_index(level, dir_level, le32_to_cpu(dentry_hash) % nbucket); + + memset(&dn, 0, sizeof(dn)); + for (block = bidx; block <= (bidx + nblock - 1); block++) { + + /* Firstly, we should know the direct node of target data blk */ + if (dn.node_blk && dn.node_blk != dn.inode_blk) + free(dn.node_blk); + + set_new_dnode(&dn, parent, NULL, pino); + get_dnode_of_data(sbi, &dn, block, ALLOC_NODE); + + if (dn.data_blkaddr == NULL_ADDR) { + new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA); + datablk_alloced = true; + } else { + ret = dev_read_block(dentry_blk, dn.data_blkaddr); + ASSERT(ret >= 0); + } + bit_pos = room_for_filename(dentry_blk->dentry_bitmap, + slots, NR_DENTRY_IN_BLOCK); + + if (bit_pos < NR_DENTRY_IN_BLOCK) + goto add_dentry; + } + level ++; + goto start; + +add_dentry: + make_dentry_ptr(&d, NULL, (void *)dentry_blk, 1); + f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos); + + if (c.zoned_model == F2FS_ZONED_HM) { + if (datablk_alloced) { + /* dentry uses hot data segment */ + ret = dev_write_block(dentry_blk, dn.data_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA)); + } else { + ret = update_block(sbi, dentry_blk, &dn.data_blkaddr, + dn.node_blk); + if (dn.inode_blk == dn.node_blk) + dn.idirty = 1; + else + dn.ndirty = 1; + } + } else { + /* dentry uses hot data segment */ + ret = dev_write_block(dentry_blk, dn.data_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA)); + } + ASSERT(ret >= 0); + + /* + * Parent inode needs updating, because its inode info may be changed. + * such as i_current_depth and i_blocks. + */ + if (parent->i.i_current_depth != cpu_to_le32(current_depth)) { + parent->i.i_current_depth = cpu_to_le32(current_depth); + dn.idirty = 1; + } + + /* Update parent's i_links info*/ + if (inc_link && (file_type == F2FS_FT_DIR)){ + u32 links = le32_to_cpu(parent->i.i_links); + parent->i.i_links = cpu_to_le32(links + 1); + dn.idirty = 1; + } + + if ((__u64)((block + 1) * F2FS_BLKSIZE) > + le64_to_cpu(parent->i.i_size)) { + parent->i.i_size = cpu_to_le64((block + 1) * F2FS_BLKSIZE); + dn.idirty = 1; + } + + if (dn.ndirty) { + struct seg_entry *se; + + /* get segment type for rw hint */ + se = get_seg_entry(sbi, GET_SEGNO(sbi, dn.node_blkaddr)); + ret = dn.alloced ? + dev_write_block(dn.node_blk, dn.node_blkaddr, + f2fs_io_type_to_rw_hint(se->type)) : + update_block(sbi, dn.node_blk, &dn.node_blkaddr, NULL); + ASSERT(ret >= 0); + } + + if (dn.idirty) { + ASSERT(parent == dn.inode_blk); + ret = update_inode(sbi, dn.inode_blk, p_blkaddr); + ASSERT(ret >= 0); + } + + if (dn.node_blk != dn.inode_blk) + free(dn.node_blk); + free(dentry_blk); + return 0; +} + +static void make_empty_dir(struct f2fs_sb_info *sbi, struct f2fs_node *inode) +{ + struct f2fs_dentry_block *dent_blk; + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(inode)->ino); + nid_t pino = le32_to_cpu(inode->i.i_pino); + struct f2fs_summary sum; + struct node_info ni; + block_t blkaddr = NULL_ADDR; + int ret; + + get_node_info(sbi, ino, &ni); + + dent_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(dent_blk); + + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 0).hash_code = 0; + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 0).ino = cpu_to_le32(ino); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 0).name_len = cpu_to_le16(1); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 0).file_type = F2FS_FT_DIR; + memcpy(F2FS_DENTRY_BLOCK_FILENAME(dent_blk, 0), ".", 1); + + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 1).hash_code = 0; + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 1).ino = cpu_to_le32(pino); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 1).name_len = cpu_to_le16(2); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, 1).file_type = F2FS_FT_DIR; + memcpy(F2FS_DENTRY_BLOCK_FILENAME(dent_blk, 1), "..", 2); + + test_and_set_bit_le(0, dent_blk->dentry_bitmap); + test_and_set_bit_le(1, dent_blk->dentry_bitmap); + + set_summary(&sum, ino, 0, ni.version); + ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_DATA, 0); + ASSERT(!ret); + + ret = dev_write_block(dent_blk, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA)); + ASSERT(ret >= 0); + + inode->i.i_addr[get_extra_isize(inode)] = cpu_to_le32(blkaddr); + free(dent_blk); +} + +static void page_symlink(struct f2fs_sb_info *sbi, struct f2fs_node *inode, + const char *symname, int symlen) +{ + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(inode)->ino); + struct f2fs_summary sum; + struct node_info ni; + char *data_blk; + block_t blkaddr = NULL_ADDR; + int ret; + + get_node_info(sbi, ino, &ni); + + /* store into inline_data */ + if ((unsigned long)(symlen + 1) <= MAX_INLINE_DATA(inode)) { + inode->i.i_inline |= F2FS_INLINE_DATA; + inode->i.i_inline |= F2FS_DATA_EXIST; + memcpy(inline_data_addr(inode), symname, symlen); + return; + } + + data_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(data_blk); + + memcpy(data_blk, symname, symlen); + + set_summary(&sum, ino, 0, ni.version); + ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_WARM_DATA, 0); + ASSERT(!ret); + + ret = dev_write_block(data_blk, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_WARM_DATA)); + ASSERT(ret >= 0); + + inode->i.i_addr[get_extra_isize(inode)] = cpu_to_le32(blkaddr); + free(data_blk); +} + +static inline int is_extension_exist(const char *s, + const char *sub) +{ + unsigned int slen = strlen(s); + unsigned int sublen = strlen(sub); + int i; + + /* + * filename format of multimedia file should be defined as: + * "filename + '.' + extension + (optional: '.' + temp extension)". + */ + if (slen < sublen + 2) + return 0; + + for (i = 1; i < slen - sublen; i++) { + if (s[i] != '.') + continue; + if (!strncasecmp(s + i + 1, sub, sublen)) + return 1; + } + + return 0; +} + +static void set_file_temperature(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk, + const unsigned char *name) +{ + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + int i, cold_count, hot_count; + + cold_count = le32_to_cpu(sbi->raw_super->extension_count); + hot_count = sbi->raw_super->hot_ext_count; + + for (i = 0; i < cold_count + hot_count; i++) { + if (is_extension_exist((const char *)name, + (const char *)extlist[i])) + break; + } + + if (i == cold_count + hot_count) + return; + + if (i < cold_count) + node_blk->i.i_advise |= FADVISE_COLD_BIT; + else + node_blk->i.i_advise |= FADVISE_HOT_BIT; +} + +static void init_inode_block(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk, struct dentry *de) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + mode_t mode = de->mode; + int links = 1; + unsigned int size; + int blocks = 1; + + if (de->file_type == F2FS_FT_DIR) { + mode |= S_IFDIR; + size = F2FS_BLKSIZE; + links++; + blocks++; + } else if (de->file_type == F2FS_FT_REG_FILE) { +#ifdef S_IFREG + mode |= S_IFREG; +#else + ASSERT(0); +#endif + size = 0; + } else if (de->file_type == F2FS_FT_SYMLINK) { + ASSERT(de->link); +#ifdef S_IFLNK + mode |= S_IFLNK; +#else + ASSERT(0); +#endif + size = strlen(de->link); + if (size + 1 > MAX_INLINE_DATA(node_blk)) + blocks++; + } else { + ASSERT(0); + } + + node_blk->i.i_mode = cpu_to_le16(mode); + node_blk->i.i_advise = 0; + node_blk->i.i_uid = cpu_to_le32(de->uid); + node_blk->i.i_gid = cpu_to_le32(de->gid); + node_blk->i.i_links = cpu_to_le32(links); + node_blk->i.i_size = cpu_to_le32(size); + node_blk->i.i_blocks = cpu_to_le32(blocks); + node_blk->i.i_atime = cpu_to_le64(de->mtime); + node_blk->i.i_ctime = cpu_to_le64(de->mtime); + node_blk->i.i_mtime = cpu_to_le64(de->mtime); + node_blk->i.i_atime_nsec = 0; + node_blk->i.i_ctime_nsec = 0; + node_blk->i.i_mtime_nsec = 0; + node_blk->i.i_generation = 0; + if (de->file_type == F2FS_FT_DIR) + node_blk->i.i_current_depth = cpu_to_le32(1); + else + node_blk->i.i_current_depth = cpu_to_le32(0); + node_blk->i.i_xattr_nid = 0; + node_blk->i.i_flags = 0; + node_blk->i.i_inline = F2FS_INLINE_XATTR; + node_blk->i.i_pino = cpu_to_le32(de->pino); + node_blk->i.i_namelen = cpu_to_le32(de->len); + memcpy(node_blk->i.i_name, de->name, de->len); + node_blk->i.i_name[de->len] = 0; + + if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { + node_blk->i.i_inline |= F2FS_EXTRA_ATTR; + node_blk->i.i_extra_isize = cpu_to_le16(calc_extra_isize()); + } + + set_file_temperature(sbi, node_blk, de->name); + + F2FS_NODE_FOOTER(node_blk)->ino = cpu_to_le32(de->ino); + F2FS_NODE_FOOTER(node_blk)->nid = cpu_to_le32(de->ino); + F2FS_NODE_FOOTER(node_blk)->flag = 0; + F2FS_NODE_FOOTER(node_blk)->cp_ver = ckpt->checkpoint_ver; + set_cold_node(node_blk, S_ISDIR(mode)); + + if (S_ISDIR(mode)) { + make_empty_dir(sbi, node_blk); + } else if (S_ISLNK(mode)) { + page_symlink(sbi, node_blk, de->link, size); + + free(de->link); + de->link = NULL; + } + + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + node_blk->i.i_inode_checksum = + cpu_to_le32(f2fs_inode_chksum(node_blk)); +} + +int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node, + block_t *p_blkaddr) +{ + struct f2fs_inode *inode = &(node->i); + unsigned int dir_level = node->i.i_dir_level; + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(node)->ino); + char inline_data[MAX_INLINE_DATA(node)]; + struct dnode_of_data dn; + struct f2fs_dentry_ptr d; + unsigned long bit_pos = 0; + int ret = 0; + bool datablk_alloced = false; + + if (!(inode->i_inline & F2FS_INLINE_DENTRY)) + return 0; + + memcpy(inline_data, inline_data_addr(node), MAX_INLINE_DATA(node)); + memset(inline_data_addr(node), 0, MAX_INLINE_DATA(node)); + inode->i_inline &= ~F2FS_INLINE_DENTRY; + + ret = update_block(sbi, node, p_blkaddr, NULL); + ASSERT(ret >= 0); + + memset(&dn, 0, sizeof(dn)); + if (!dir_level) { + struct f2fs_dentry_block *dentry_blk; + struct f2fs_dentry_ptr src, dst; + + dentry_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(dentry_blk); + + set_new_dnode(&dn, node, NULL, ino); + get_dnode_of_data(sbi, &dn, 0, ALLOC_NODE); + if (dn.data_blkaddr == NULL_ADDR) { + new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA); + datablk_alloced = true; + } + + make_dentry_ptr(&src, node, (void *)inline_data, 2); + make_dentry_ptr(&dst, NULL, (void *)dentry_blk, 1); + + /* copy data from inline dentry block to new dentry block */ + memcpy(dst.bitmap, src.bitmap, src.nr_bitmap); + memset(dst.bitmap + src.nr_bitmap, 0, + dst.nr_bitmap - src.nr_bitmap); + + memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max); + memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN); + + ret = datablk_alloced ? + dev_write_block(dentry_blk, dn.data_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA)) : + update_block(sbi, dentry_blk, &dn.data_blkaddr, NULL); + ASSERT(ret >= 0); + + MSG(1, "%s: copy inline entry to block\n", __func__); + + free(dentry_blk); + return ret; + } + + make_empty_dir(sbi, node); + make_dentry_ptr(&d, node, (void *)inline_data, 2); + + while (bit_pos < (unsigned long)d.max) { + struct f2fs_dir_entry *de; + const unsigned char *filename; + int namelen; + + if (!test_bit_le(bit_pos, d.bitmap)) { + bit_pos++; + continue; + } + + de = &d.dentry[bit_pos]; + if (!de->name_len) { + bit_pos++; + continue; + } + + filename = d.filename[bit_pos]; + namelen = le32_to_cpu(de->name_len); + + if (is_dot_dotdot(filename, namelen)) { + bit_pos += GET_DENTRY_SLOTS(namelen); + continue; + } + + ret = f2fs_add_link(sbi, node, filename, namelen, + le32_to_cpu(de->ino), + de->file_type, p_blkaddr, 0); + if (ret) + MSG(0, "Convert file \"%s\" ERR=%d\n", filename, ret); + else + MSG(1, "%s: add inline entry to block\n", __func__); + + bit_pos += GET_DENTRY_SLOTS(namelen); + } + + return 0; +} + +static int cmp_from_devino(const void *a, const void *b) { + u64 devino_a = ((struct hardlink_cache_entry*) a)->from_devino; + u64 devino_b = ((struct hardlink_cache_entry*) b)->from_devino; + + return (devino_a > devino_b) - (devino_a < devino_b); +} + +struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi, + struct dentry *de) +{ + struct hardlink_cache_entry *find_hardlink = NULL; + struct hardlink_cache_entry *found_hardlink = NULL; + void *search_result; + + /* This might be a hardlink, try to find it in the cache */ + find_hardlink = calloc(1, sizeof(struct hardlink_cache_entry)); + find_hardlink->from_devino = de->from_devino; + + search_result = tsearch(find_hardlink, &(sbi->hardlink_cache), + cmp_from_devino); + ASSERT(search_result != 0); + + found_hardlink = *(struct hardlink_cache_entry**) search_result; + ASSERT(find_hardlink->from_devino == found_hardlink->from_devino); + + /* If it was already in the cache, free the entry we just created */ + if (found_hardlink != find_hardlink) + free(find_hardlink); + + return found_hardlink; +} + +int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de) +{ + struct f2fs_node *parent, *child; + struct hardlink_cache_entry *found_hardlink = NULL; + struct node_info ni, hardlink_ni; + struct f2fs_summary sum; + block_t blkaddr = NULL_ADDR; + int ret; + bool nodeblk_alloced = false; + + /* Find if there is a */ + get_node_info(sbi, de->pino, &ni); + if (ni.blk_addr == NULL_ADDR) { + MSG(0, "No parent directory pino=%x\n", de->pino); + return -1; + } + + if (de->from_devino) + found_hardlink = f2fs_search_hardlink(sbi, de); + + parent = calloc(F2FS_BLKSIZE, 1); + ASSERT(parent); + + ret = dev_read_block(parent, ni.blk_addr); + ASSERT(ret >= 0); + + /* Must convert inline dentry before the following opertions */ + ret = convert_inline_dentry(sbi, parent, &ni.blk_addr); + if (ret) { + MSG(0, "Convert inline dentry for pino=%x failed.\n", de->pino); + ret = -1; + goto free_parent_dir; + } + + ret = f2fs_find_entry(sbi, parent, de); + if (ret) { + MSG(0, "Skip the existing \"%s\" pino=%x ERR=%d\n", + de->name, de->pino, ret); + if (de->file_type == F2FS_FT_REG_FILE) + de->ino = 0; + ret = 0; + goto free_parent_dir; + } + + child = calloc(F2FS_BLKSIZE, 1); + ASSERT(child); + + if (found_hardlink && found_hardlink->to_ino) { + /* + * If we found this devino in the cache, we're creating a + * hard link. + */ + get_node_info(sbi, found_hardlink->to_ino, &hardlink_ni); + if (hardlink_ni.blk_addr == NULL_ADDR) { + MSG(1, "No original inode for hard link to_ino=%x\n", + found_hardlink->to_ino); + ret = -1; + goto free_child_dir; + } + + /* Use previously-recorded inode */ + de->ino = found_hardlink->to_ino; + blkaddr = hardlink_ni.blk_addr; + MSG(1, "Info: Creating \"%s\" as hard link to inode %d\n", + de->path, de->ino); + } else { + f2fs_alloc_nid(sbi, &de->ino); + } + + init_inode_block(sbi, child, de); + + ret = f2fs_add_link(sbi, parent, child->i.i_name, + le32_to_cpu(child->i.i_namelen), + le32_to_cpu(F2FS_NODE_FOOTER(child)->ino), + map_de_type(le16_to_cpu(child->i.i_mode)), + &ni.blk_addr, 1); + if (ret) { + MSG(0, "Skip the existing \"%s\" pino=%x ERR=%d\n", + de->name, de->pino, ret); + ret = 0; + goto free_child_dir; + } + + if (found_hardlink) { + if (!found_hardlink->to_ino) { + MSG(2, "Adding inode %d from %s to hardlink cache\n", + de->ino, de->path); + found_hardlink->to_ino = de->ino; + } else { + /* Replace child with original block */ + free(child); + + child = calloc(F2FS_BLKSIZE, 1); + ASSERT(child); + + ret = dev_read_block(child, blkaddr); + ASSERT(ret >= 0); + + /* Increment links and skip to writing block */ + child->i.i_links = cpu_to_le32( + le32_to_cpu(child->i.i_links) + 1); + MSG(2, "Number of links on inode %d is now %d\n", + de->ino, le32_to_cpu(child->i.i_links)); + goto write_child_dir; + } + } + + /* write child */ + set_summary(&sum, de->ino, 0, ni.version); + ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE, 1); + nodeblk_alloced = true; + ASSERT(!ret); + + /* update nat info */ + update_nat_blkaddr(sbi, de->ino, de->ino, blkaddr); + +write_child_dir: + ret = nodeblk_alloced ? dev_write_block(child, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_NODE)) : + update_block(sbi, child, &blkaddr, NULL); + ASSERT(ret >= 0); + + update_free_segments(sbi); + MSG(1, "Info: Create %s -> %s\n" + " -- ino=%x, type=%x, mode=%x, uid=%x, " + "gid=%x, cap=%"PRIx64", size=%lu, link=%u " + "blocks=%"PRIx64" pino=%x\n", + de->full_path, de->path, + de->ino, de->file_type, de->mode, + de->uid, de->gid, de->capabilities, de->size, + le32_to_cpu(child->i.i_links), + le64_to_cpu(child->i.i_blocks), + de->pino); +free_child_dir: + free(child); +free_parent_dir: + free(parent); + return ret; +} + +int f2fs_mkdir(struct f2fs_sb_info *sbi, struct dentry *de) +{ + return f2fs_create(sbi, de); +} + +int f2fs_symlink(struct f2fs_sb_info *sbi, struct dentry *de) +{ + return f2fs_create(sbi, de); +} + +int f2fs_find_path(struct f2fs_sb_info *sbi, char *path, nid_t *ino) +{ + struct f2fs_node *parent; + struct node_info ni; + struct dentry de; + int err = 0; + int ret; + char *p; + + if (path[0] != '/') + return -ENOENT; + + *ino = F2FS_ROOT_INO(sbi); + parent = calloc(F2FS_BLKSIZE, 1); + ASSERT(parent); + + p = strtok(path, "/"); + while (p) { + de.name = (const u8 *)p; + de.len = strlen(p); + + get_node_info(sbi, *ino, &ni); + if (ni.blk_addr == NULL_ADDR) { + err = -ENOENT; + goto err; + } + ret = dev_read_block(parent, ni.blk_addr); + ASSERT(ret >= 0); + + ret = f2fs_find_entry(sbi, parent, &de); + if (!ret) { + err = -ENOENT; + goto err; + } + + *ino = de.ino; + p = strtok(NULL, "/"); + } +err: + free(parent); + return err; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dqblk_v2.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dqblk_v2.h new file mode 100644 index 00000000000..d12512a6a99 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dqblk_v2.h @@ -0,0 +1,31 @@ +/* + * Header file for disk format of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + */ + +#ifndef __QUOTA_DQBLK_V2_H__ +#define __QUOTA_DQBLK_V2_H__ + +#include "quotaio_tree.h" + +/* Structure for format specific information */ +struct v2_mem_dqinfo { + struct qtree_mem_dqinfo dqi_qtree; + unsigned int dqi_flags; /* Flags set in quotafile */ + unsigned int dqi_used_entries; /* Number of entries in file - + updated by scan_dquots */ + unsigned int dqi_data_blocks; /* Number of data blocks in file - + updated by scan_dquots */ +}; + +struct v2_mem_dqblk { + long long dqb_off; /* Offset of dquot in file */ +}; + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_2; + +#endif /* __QUOTA_DQBLK_V2_H__ */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dump.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dump.c new file mode 100644 index 00000000000..66d6c791ae0 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/dump.c @@ -0,0 +1,1110 @@ +/** + * dump.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include + +#include "node.h" +#include "fsck.h" +#include "xattr.h" +#ifdef HAVE_ATTR_XATTR_H +#include +#endif +#ifdef HAVE_LINUX_XATTR_H +#include +#endif +#include + +#define BUF_SZ 128 + +/* current extent info */ +struct extent_info dump_extent; + +const char *seg_type_name[SEG_TYPE_MAX + 1] = { + "SEG_TYPE_DATA", + "SEG_TYPE_CUR_DATA", + "SEG_TYPE_NODE", + "SEG_TYPE_CUR_NODE", + "SEG_TYPE_NONE", +}; + +void nat_dump(struct f2fs_sb_info *sbi, nid_t start_nat, nid_t end_nat) +{ + struct f2fs_nat_block *nat_block; + struct f2fs_node *node_block; + struct node_footer *footer; + nid_t nid; + pgoff_t block_addr; + char buf[BUF_SZ]; + int fd, ret, pack; + + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); + node_block = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_block); + footer = F2FS_NODE_FOOTER(node_block); + + fd = open("dump_nat", O_CREAT|O_WRONLY|O_TRUNC, 0666); + ASSERT(fd >= 0); + + for (nid = start_nat; nid < end_nat; nid++) { + struct f2fs_nat_entry raw_nat; + struct node_info ni; + int len; + if(nid == 0 || nid == F2FS_NODE_INO(sbi) || + nid == F2FS_META_INO(sbi)) + continue; + + ni.nid = nid; + block_addr = current_nat_addr(sbi, nid, &pack); + + if (lookup_nat_in_journal(sbi, nid, &raw_nat) >= 0) { + node_info_from_raw_nat(&ni, &raw_nat); + ret = dev_read_block(node_block, ni.blk_addr); + ASSERT(ret >= 0); + if (ni.blk_addr != 0x0) { + len = snprintf(buf, BUF_SZ, + "nid:%5u\tino:%5u\toffset:%5u" + "\tblkaddr:%10u\tpack:%d" + "\tcp_ver:0x%" PRIx64 "\n", + ni.nid, ni.ino, + le32_to_cpu(footer->flag) >> OFFSET_BIT_SHIFT, + ni.blk_addr, pack, + le64_to_cpu(footer->cp_ver)); + ret = write(fd, buf, len); + ASSERT(ret >= 0); + } + } else { + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + node_info_from_raw_nat(&ni, + &nat_block->entries[nid % NAT_ENTRY_PER_BLOCK]); + if (ni.blk_addr == 0) + continue; + + ret = dev_read_block(node_block, ni.blk_addr); + ASSERT(ret >= 0); + len = snprintf(buf, BUF_SZ, + "nid:%5u\tino:%5u\toffset:%5u" + "\tblkaddr:%10u\tpack:%d" + "\tcp_ver:0x%" PRIx64 "\n", + ni.nid, ni.ino, + le32_to_cpu(footer->flag) >> OFFSET_BIT_SHIFT, + ni.blk_addr, pack, + le64_to_cpu(footer->cp_ver)); + ret = write(fd, buf, len); + ASSERT(ret >= 0); + } + } + + free(nat_block); + free(node_block); + + close(fd); +} + +void sit_dump(struct f2fs_sb_info *sbi, unsigned int start_sit, + unsigned int end_sit) +{ + struct seg_entry *se; + struct sit_info *sit_i = SIT_I(sbi); + unsigned int segno; + char buf[BUF_SZ]; + u32 free_segs = 0;; + u64 valid_blocks = 0; + int ret; + int fd, i; + unsigned int offset; + + fd = open("dump_sit", O_CREAT|O_WRONLY|O_TRUNC, 0666); + ASSERT(fd >= 0); + + snprintf(buf, BUF_SZ, "segment_type(0:HD, 1:WD, 2:CD, " + "3:HN, 4:WN, 5:CN)\n"); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + for (segno = start_sit; segno < end_sit; segno++) { + se = get_seg_entry(sbi, segno); + offset = SIT_BLOCK_OFFSET(sit_i, segno); + memset(buf, 0, BUF_SZ); + snprintf(buf, BUF_SZ, + "\nsegno:%8u\tvblocks:%3u\tseg_type:%d\tsit_pack:%d\n\n", + segno, se->valid_blocks, se->type, + f2fs_test_bit(offset, sit_i->sit_bitmap) ? 2 : 1); + + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + if (se->valid_blocks == 0x0) { + free_segs++; + continue; + } + + ASSERT(se->valid_blocks <= 512); + valid_blocks += se->valid_blocks; + + for (i = 0; i < 64; i++) { + memset(buf, 0, BUF_SZ); + snprintf(buf, BUF_SZ, " %02x", + *(se->cur_valid_map + i)); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + if ((i + 1) % 16 == 0) { + snprintf(buf, BUF_SZ, "\n"); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + } + } + } + + memset(buf, 0, BUF_SZ); + snprintf(buf, BUF_SZ, + "valid_blocks:[0x%" PRIx64 "]\tvalid_segs:%d\t free_segs:%d\n", + valid_blocks, + SM_I(sbi)->main_segments - free_segs, + free_segs); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + close(fd); +} + +void ssa_dump(struct f2fs_sb_info *sbi, int start_ssa, int end_ssa) +{ + struct f2fs_summary_block *sum_blk; + char buf[BUF_SZ]; + int segno, type, i, ret; + int fd; + + fd = open("dump_ssa", O_CREAT|O_WRONLY|O_TRUNC, 0666); + ASSERT(fd >= 0); + + snprintf(buf, BUF_SZ, "Note: dump.f2fs -b blkaddr = 0x%x + segno * " + " 0x200 + offset\n", + sbi->sm_info->main_blkaddr); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + for (segno = start_ssa; segno < end_ssa; segno++) { + sum_blk = get_sum_block(sbi, segno, &type); + + memset(buf, 0, BUF_SZ); + switch (type) { + case SEG_TYPE_CUR_NODE: + snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Node\n", segno); + break; + case SEG_TYPE_CUR_DATA: + snprintf(buf, BUF_SZ, "\n\nsegno: %x, Current Data\n", segno); + break; + case SEG_TYPE_NODE: + snprintf(buf, BUF_SZ, "\n\nsegno: %x, Node\n", segno); + break; + case SEG_TYPE_DATA: + snprintf(buf, BUF_SZ, "\n\nsegno: %x, Data\n", segno); + break; + } + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + + for (i = 0; i < ENTRIES_IN_SUM; i++) { + memset(buf, 0, BUF_SZ); + if (i % 10 == 0) { + buf[0] = '\n'; + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + } + snprintf(buf, BUF_SZ, "[%3d: %6x]", i, + le32_to_cpu(sum_blk->entries[i].nid)); + ret = write(fd, buf, strlen(buf)); + ASSERT(ret >= 0); + } + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); + } + close(fd); +} + +static void print_extent(bool last) +{ + if (dump_extent.len == 0) + goto out; + + if (dump_extent.len == 1) + printf(" %d", dump_extent.blk); + else + printf(" %d-%d", + dump_extent.blk, + dump_extent.blk + dump_extent.len - 1); + dump_extent.len = 0; +out: + if (last) + printf("\n"); +} + +static void dump_folder_contents(struct f2fs_sb_info *sbi, u8 *bitmap, + struct f2fs_dir_entry *dentry, + __u8 (*filenames)[F2FS_SLOT_LEN], int max) +{ + int i; + int name_len; + char name[F2FS_NAME_LEN + 1] = {0}; + + for (i = 0; i < max; i++) { + if (test_bit_le(i, bitmap) == 0) + continue; + name_len = le16_to_cpu(dentry[i].name_len); + if (name_len == 0 || name_len > F2FS_NAME_LEN) { + MSG(c.force, "Wrong name info\n\n"); + ASSERT(name_len == 0 || name_len > F2FS_NAME_LEN); + } + if (name_len == 1 && filenames[i][0] == '.') + continue; + if (name_len == 2 && filenames[i][0] == '.' && filenames[i][1] == '.') + continue; + strncpy(name, (const char *)filenames[i], name_len); + name[name_len] = 0; + dump_node(sbi, le32_to_cpu(dentry[i].ino), 1, NULL, 0, 1, name); + } +} + +static void dump_data_blk(struct f2fs_sb_info *sbi, __u64 offset, u32 blkaddr, int type) +{ + char buf[F2FS_BLKSIZE]; + + if (c.show_file_map) { + if (c.show_file_map_max_offset < offset) { + ASSERT(blkaddr == NULL_ADDR); + return; + } + if (!is_valid_data_blkaddr(blkaddr)) { + print_extent(false); + dump_extent.blk = 0; + dump_extent.len = 1; + print_extent(false); + } else if (dump_extent.len == 0) { + dump_extent.blk = blkaddr; + dump_extent.len = 1; + } else if (dump_extent.blk + dump_extent.len == blkaddr) { + dump_extent.len++; + } else { + print_extent(false); + dump_extent.blk = blkaddr; + dump_extent.len = 1; + } + return; + } + + if (blkaddr == NULL_ADDR) + return; + + /* get data */ + if (blkaddr == NEW_ADDR || + !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) { + memset(buf, 0, F2FS_BLKSIZE); + } else { + int ret; + + ret = dev_read_block(buf, blkaddr); + ASSERT(ret >= 0); + } + + if (S_ISDIR(type)) { + struct f2fs_dentry_block *d = (struct f2fs_dentry_block *) buf; + + dump_folder_contents(sbi, d->dentry_bitmap, F2FS_DENTRY_BLOCK_DENTRIES(d), + F2FS_DENTRY_BLOCK_FILENAMES(d), NR_DENTRY_IN_BLOCK); +#if !defined(__MINGW32__) + } if (S_ISLNK(type)) { + dev_write_symlink(buf, c.dump_sym_target_len); +#endif + } else { + /* write blkaddr */ + dev_write_dump(buf, offset, F2FS_BLKSIZE); + } +} + +static void dump_node_blk(struct f2fs_sb_info *sbi, int ntype, + u32 nid, u32 addr_per_block, u64 *ofs, int type) +{ + struct node_info ni; + struct f2fs_node *node_blk; + u32 skip = 0; + u32 i, idx = 0; + + switch (ntype) { + case TYPE_DIRECT_NODE: + skip = idx = addr_per_block; + break; + case TYPE_INDIRECT_NODE: + idx = NIDS_PER_BLOCK; + skip = idx * addr_per_block; + break; + case TYPE_DOUBLE_INDIRECT_NODE: + skip = 0; + idx = NIDS_PER_BLOCK; + break; + } + + if (nid == 0) { + *ofs += skip; + return; + } + + get_node_info(sbi, nid, &ni); + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + dev_read_block(node_blk, ni.blk_addr); + + for (i = 0; i < idx; i++) { + switch (ntype) { + case TYPE_DIRECT_NODE: + dump_data_blk(sbi, *ofs * F2FS_BLKSIZE, + le32_to_cpu(node_blk->dn.addr[i]), type); + (*ofs)++; + break; + case TYPE_INDIRECT_NODE: + dump_node_blk(sbi, TYPE_DIRECT_NODE, + le32_to_cpu(node_blk->in.nid[i]), + addr_per_block, + ofs, type); + break; + case TYPE_DOUBLE_INDIRECT_NODE: + dump_node_blk(sbi, TYPE_INDIRECT_NODE, + le32_to_cpu(node_blk->in.nid[i]), + addr_per_block, + ofs, type); + break; + } + } + free(node_blk); +} + +#ifdef HAVE_FSETXATTR +static void dump_xattr(struct f2fs_sb_info *sbi, struct f2fs_node *node_blk, int type) +{ + void *xattr; + void *last_base_addr; + struct f2fs_xattr_entry *ent; + char xattr_name[F2FS_NAME_LEN] = {0}; + int ret; + + xattr = read_all_xattrs(sbi, node_blk, true); + if (!xattr) + return; + + last_base_addr = (void *)xattr + XATTR_SIZE(&node_blk->i); + + list_for_each_xattr(ent, xattr) { + char *name = strndup(ent->e_name, ent->e_name_len); + void *value = ent->e_name + ent->e_name_len; + + if ((void *)(ent) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + break; + } + + if (!name) + continue; + + switch (ent->e_name_index) { + case F2FS_XATTR_INDEX_USER: + ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", + XATTR_USER_PREFIX, name); + break; + + case F2FS_XATTR_INDEX_SECURITY: + ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", + XATTR_SECURITY_PREFIX, name); + break; + case F2FS_XATTR_INDEX_TRUSTED: + ret = snprintf(xattr_name, F2FS_NAME_LEN, "%s%s", + XATTR_TRUSTED_PREFIX, name); + break; + default: + MSG(0, "Unknown xattr index 0x%x\n", ent->e_name_index); + free(name); + continue; + } + if (ret >= F2FS_NAME_LEN) { + MSG(0, "XATTR index 0x%x name too long\n", ent->e_name_index); + free(name); + continue; + } + + DBG(1, "fd %d xattr_name %s\n", c.dump_fd, xattr_name); +#if defined(__linux__) + if (S_ISDIR(type)) { + ret = setxattr(".", xattr_name, value, + le16_to_cpu(ent->e_value_size), 0); + } if (S_ISLNK(type) && c.preserve_symlinks) { + ret = lsetxattr(c.dump_symlink, xattr_name, value, + le16_to_cpu(ent->e_value_size), 0); + } else { + ret = fsetxattr(c.dump_fd, xattr_name, value, + le16_to_cpu(ent->e_value_size), 0); + } + +#elif defined(__APPLE__) + if (S_ISDIR(type)) { + ret = setxattr(".", xattr_name, value, + le16_to_cpu(ent->e_value_size), 0, + XATTR_CREATE); + } if (S_ISLNK(type) && c.preserve_symlinks) { + ret = lsetxattr(c.dump_symlink, xattr_name, value, + le16_to_cpu(ent->e_value_size), 0, + XATTR_CREATE); + } else { + ret = fsetxattr(c.dump_fd, xattr_name, value, + le16_to_cpu(ent->e_value_size), 0, + XATTR_CREATE); + } +#endif + if (ret) + MSG(0, "XATTR index 0x%x set xattr failed error %d\n", + ent->e_name_index, errno); + + free(name); + } + + free(xattr); +} +#else +static void dump_xattr(struct f2fs_sb_info *UNUSED(sbi), + struct f2fs_node *UNUSED(node_blk), int UNUSED(is_dir)) +{ + MSG(0, "XATTR does not support\n"); +} +#endif + +static int dump_inode_blk(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_node *node_blk) +{ + u32 i = 0; + u64 ofs = 0; + u32 addr_per_block; + u16 type = le16_to_cpu(node_blk->i.i_mode); + int ret = 0; + + if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) { + DBG(3, "ino[0x%x] has inline data!\n", nid); + /* recover from inline data */ +#if !defined(__MINGW32__) + if (S_ISLNK(type) && c.preserve_symlinks) { + dev_write_symlink(inline_data_addr(node_blk), c.dump_sym_target_len); + } else +#endif + { + dev_write_dump(inline_data_addr(node_blk), + 0, MAX_INLINE_DATA(node_blk)); + } + ret = -1; + goto dump_xattr; + } + + if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) { + void *inline_dentry = inline_data_addr(node_blk); + struct f2fs_dentry_ptr d; + + make_dentry_ptr(&d, node_blk, inline_dentry, 2); + + DBG(3, "ino[0x%x] has inline dentries!\n", nid); + /* recover from inline dentry */ + dump_folder_contents(sbi, d.bitmap, d.dentry, d.filename, d.max); + ret = -1; + goto dump_xattr; + } + + c.show_file_map_max_offset = f2fs_max_file_offset(&node_blk->i); + + if (IS_DEVICE_ALIASING(&node_blk->i)) { + u32 blkaddr = le32_to_cpu(node_blk->i.i_ext.blk_addr); + u32 len = le32_to_cpu(node_blk->i.i_ext.len); + u32 idx; + + for (idx = 0; idx < len; idx++) + dump_data_blk(sbi, idx * F2FS_BLKSIZE, blkaddr++, type); + print_extent(true); + + goto dump_xattr; + } + + addr_per_block = ADDRS_PER_BLOCK(&node_blk->i); + + /* check data blocks in inode */ + for (i = 0; i < ADDRS_PER_INODE(&node_blk->i); i++, ofs++) + dump_data_blk(sbi, ofs * F2FS_BLKSIZE, le32_to_cpu( + node_blk->i.i_addr[get_extra_isize(node_blk) + i]), type); + + /* check node blocks in inode */ + for (i = 0; i < 5; i++) { + if (i == 0 || i == 1) + dump_node_blk(sbi, TYPE_DIRECT_NODE, + le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)), + addr_per_block, + &ofs, + type); + else if (i == 2 || i == 3) + dump_node_blk(sbi, TYPE_INDIRECT_NODE, + le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)), + addr_per_block, + &ofs, + type); + else if (i == 4) + dump_node_blk(sbi, TYPE_DOUBLE_INDIRECT_NODE, + le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, i)), + addr_per_block, + &ofs, + type); + else + ASSERT(0); + } + /* last block in extent cache */ + print_extent(true); +dump_xattr: + dump_xattr(sbi, node_blk, type); + return ret; +} + +static void dump_file(struct f2fs_sb_info *sbi, struct node_info *ni, + struct f2fs_node *node_blk, char *path) +{ + struct f2fs_inode *inode = &node_blk->i; + int ret; + + c.dump_fd = open(path, O_TRUNC|O_CREAT|O_RDWR, 0666); + ASSERT(c.dump_fd >= 0); + + /* dump file's data */ + dump_inode_blk(sbi, ni->ino, node_blk); + + /* adjust file size */ + ret = ftruncate(c.dump_fd, le32_to_cpu(inode->i_size)); + ASSERT(ret >= 0); + + close(c.dump_fd); +} + +static void dump_link(struct f2fs_sb_info *sbi, struct node_info *ni, + struct f2fs_node *node_blk, char *name) +{ +#if defined(__MINGW32__) + dump_file(sbi, ni, node_blk, name); +#else + struct f2fs_inode *inode = &node_blk->i; + int len = le64_to_cpu(inode->i_size); + + if (!c.preserve_symlinks) + return dump_file(sbi, ni, node_blk, name); + c.dump_symlink = name; + c.dump_sym_target_len = len + 1; + dump_inode_blk(sbi, ni->ino, node_blk); +#endif +} + +static void dump_folder(struct f2fs_sb_info *sbi, struct node_info *ni, + struct f2fs_node *node_blk, char *path, int is_root) +{ + if (!is_root) { +#if defined(__MINGW32__) + if (mkdir(path) < 0 && errno != EEXIST) { + MSG(0, "Failed to create directory %s\n", path); + return; + } +#else + if (mkdir(path, 0777) < 0 && errno != EEXIST) { + MSG(0, "Failed to create directory %s\n", path); + return; + } +#endif + ASSERT(chdir(path) == 0); + } + /* dump folder data */ + dump_inode_blk(sbi, ni->ino, node_blk); + if (!is_root) + ASSERT(chdir("..") == 0); +} + +static int dump_filesystem(struct f2fs_sb_info *sbi, struct node_info *ni, + struct f2fs_node *node_blk, int force, char *base_path, + bool is_base, bool allow_folder, char *dirent_name) +{ + struct f2fs_inode *inode = &node_blk->i; + u32 imode = le16_to_cpu(inode->i_mode); + u32 ilinks = le32_to_cpu(inode->i_links); + u32 i_namelen = le32_to_cpu(inode->i_namelen); + char i_name[F2FS_NAME_LEN + 1] = {0}; + char *name = NULL; + char path[1024] = {0}; + char ans[255] = {0}; + int is_encrypted = file_is_encrypt(inode); + int is_root = sbi->root_ino_num == ni->nid; + int ret; + + if (!S_ISDIR(imode) && ilinks != 1) { + MSG(force, "Warning: Hard link detected. Dumped files may be duplicated\n"); + } + + if (is_encrypted) { + MSG(force, "File is encrypted\n"); + return -1; + } + + if ((!S_ISREG(imode) && !S_ISLNK(imode) && !(S_ISDIR(imode) && allow_folder))) { + MSG(force, "Not a valid file type\n\n"); + return -1; + } + if (!is_root && !dirent_name && (i_namelen == 0 || i_namelen > F2FS_NAME_LEN)) { + MSG(force, "Wrong name info\n\n"); + return -1; + } + if (le32_to_cpu(inode->i_flags) & F2FS_NODUMP_FL) { + MSG(force, "File has nodump flag\n\n"); + return -1; + } + base_path = base_path ?: "./lost_found"; + if (force) + goto dump; + + /* dump file's data */ + if (c.show_file_map) + return dump_inode_blk(sbi, ni->ino, node_blk); + + printf("Do you want to dump this %s into %s/? [Y/N] ", + S_ISDIR(imode) ? "folder" : "file", + base_path); + ret = scanf("%s", ans); + ASSERT(ret >= 0); + + if (!strcasecmp(ans, "y")) { +dump: + if (is_base) { + ASSERT(getcwd(path, sizeof(path)) != NULL); +#if defined(__MINGW32__) + ret = mkdir(base_path); +#else + ret = mkdir(base_path, 0777); +#endif + + ASSERT(ret == 0 || errno == EEXIST); + ASSERT(chdir(base_path) == 0); + } + + /* make a file */ + if (!is_root) { + /* The i_name name may be out of date. Prefer dirent_name */ + if (dirent_name) { + name = dirent_name; + } else { + strncpy(i_name, (const char *)inode->i_name, i_namelen); + i_name[i_namelen] = 0; + name = i_name; + } + } + + if (S_ISREG(imode)) { + dump_file(sbi, ni, node_blk, name); + } else if (S_ISDIR(imode)) { + dump_folder(sbi, ni, node_blk, name, is_root); + } else { + dump_link(sbi, ni, node_blk, name); + } + +#if !defined(__MINGW32__) + /* fix up mode/owner */ + if (c.preserve_perms) { + if (is_root) { + name = i_name; + strncpy(name, ".", 2); + } + if (!S_ISLNK(imode)) + ASSERT(chmod(name, imode) == 0); + ASSERT(lchown(name, inode->i_uid, inode->i_gid) == 0); + } +#endif + if (is_base) + ASSERT(chdir(path) == 0); + } + return 0; +} + +bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr) +{ + struct seg_entry *se; + u32 offset; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, blk_addr)); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + return f2fs_test_bit(offset, + (const char *)se->cur_valid_map) != 0; +} + +void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct f2fs_node *node_blk; + pgoff_t blkaddr; + int ret; + pgoff_t start_blkaddr = SM_I(sbi)->main_blkaddr; + pgoff_t end_blkaddr = start_blkaddr + + (SM_I(sbi)->main_segments << sbi->log_blocks_per_seg); + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + MSG(0, "Info: scan all nid: %u from block_addr [%lu: %lu]\n", + nid, start_blkaddr, end_blkaddr); + + for (blkaddr = start_blkaddr; blkaddr < end_blkaddr; blkaddr++) { + struct seg_entry *se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr)); + if (se->type < CURSEG_HOT_NODE) + continue; + + ret = dev_read_block(node_blk, blkaddr); + ASSERT(ret >= 0); + if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) != nid || + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != nid) + continue; + MSG(0, "Info: nid: %u, blkaddr: %lu\n", nid, blkaddr); + MSG(0, "node_blk.footer.flag [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag)); + MSG(0, "node_blk.footer.cp_ver [%x]\n", (u32)(cpver_of_node(node_blk))); + print_inode_info(sbi, node_blk, 0); + } + + free(node_blk); +} + +int dump_node(struct f2fs_sb_info *sbi, nid_t nid, int force, char *base_path, int base, int allow_folder, char *dirent_name) +{ + struct node_info ni; + struct f2fs_node *node_blk; + int ret = 0; + + get_node_info(sbi, nid, &ni); + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + DBG(1, "Node ID [0x%x]\n", nid); + DBG(1, "nat_entry.block_addr [0x%x]\n", ni.blk_addr); + DBG(1, "nat_entry.version [0x%x]\n", ni.version); + DBG(1, "nat_entry.ino [0x%x]\n", ni.ino); + + if (!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) { + MSG(force, "Invalid node blkaddr: %u\n\n", ni.blk_addr); + goto out; + } + + dev_read_block(node_blk, ni.blk_addr); + + if (!is_sit_bitmap_set(sbi, ni.blk_addr)) + MSG(force, "Invalid sit bitmap, %u\n\n", ni.blk_addr); + + DBG(1, "node_blk.footer.ino [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino)); + DBG(1, "node_blk.footer.nid [0x%x]\n", le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid)); + + if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) == ni.ino && + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) == ni.nid) { + if (!c.show_file_map) + print_node_info(sbi, node_blk, force); + + if (ni.ino == ni.nid) + ret = dump_filesystem(sbi, &ni, node_blk, force, base_path, base, allow_folder, dirent_name); + } else { + print_node_info(sbi, node_blk, force); + MSG(force, "Invalid (i)node block\n\n"); + } +out: + free(node_blk); + return ret; +} + +static void dump_node_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) +{ + struct f2fs_node *node_blk; + int ret; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + ret = dev_read_block(node_blk, blk_addr); + ASSERT(ret >= 0); + + if (c.dbg_lv > 0) + print_node_info(sbi, node_blk, 0); + else + print_inode_info(sbi, node_blk, 1); + + free(node_blk); +} + +unsigned int start_bidx_of_node(unsigned int node_ofs, + struct f2fs_node *node_blk) +{ + unsigned int indirect_blks = 2 * NIDS_PER_BLOCK + 4; + unsigned int bidx; + + if (node_ofs == 0) + return 0; + + if (node_ofs <= 2) { + bidx = node_ofs - 1; + } else if (node_ofs <= indirect_blks) { + int dec = (node_ofs - 4) / (NIDS_PER_BLOCK + 1); + bidx = node_ofs - 2 - dec; + } else { + int dec = (node_ofs - indirect_blks - 3) / (NIDS_PER_BLOCK + 1); + bidx = node_ofs - 5 - dec; + } + return bidx * ADDRS_PER_BLOCK(&node_blk->i) + + ADDRS_PER_INODE(&node_blk->i); +} + +static void dump_data_offset(u32 blk_addr, int ofs_in_node) +{ + struct f2fs_node *node_blk; + unsigned int bidx; + unsigned int node_ofs; + int ret; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + ret = dev_read_block(node_blk, blk_addr); + ASSERT(ret >= 0); + + node_ofs = ofs_of_node(node_blk); + + bidx = start_bidx_of_node(node_ofs, node_blk); + bidx += ofs_in_node; + + setlocale(LC_ALL, ""); + MSG(0, " - Data offset : 0x%x (BLOCK), %'u (bytes)\n", + bidx, bidx * F2FS_BLKSIZE); + free(node_blk); +} + +static void dump_node_offset(u32 blk_addr) +{ + struct f2fs_node *node_blk; + int ret; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + ret = dev_read_block(node_blk, blk_addr); + ASSERT(ret >= 0); + + MSG(0, " - Node offset : 0x%x\n", ofs_of_node(node_blk)); + free(node_blk); +} + +static int has_dirent(u32 blk_addr, int is_inline, int *enc_name) +{ + struct f2fs_node *node_blk; + int ret, is_dentry = 0; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + ret = dev_read_block(node_blk, blk_addr); + ASSERT(ret >= 0); + + if (IS_INODE(node_blk) && S_ISDIR(le16_to_cpu(node_blk->i.i_mode))) + is_dentry = 1; + + if (is_inline && !(node_blk->i.i_inline & F2FS_INLINE_DENTRY)) + is_dentry = 0; + + *enc_name = file_is_encrypt(&node_blk->i); + + free(node_blk); + + return is_dentry; +} + +static void dump_dirent(u32 blk_addr, int is_inline, int enc_name) +{ + struct f2fs_dentry_ptr d; + void *inline_dentry, *blk; + int ret, i = 0, j; + + blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(blk); + + ret = dev_read_block(blk, blk_addr); + ASSERT(ret >= 0); + + if (is_inline) { + inline_dentry = inline_data_addr((struct f2fs_node *)blk); + make_dentry_ptr(&d, blk, inline_dentry, 2); + } else { + make_dentry_ptr(&d, NULL, blk, 1); + } + + DBG(1, "%sDentry block:\n", is_inline ? "Inline " : ""); + + while (i < d.max) { + struct f2fs_dir_entry *de; + char en[F2FS_PRINT_NAMELEN]; + u16 name_len; + int enc; + + if (!test_bit_le(i, d.bitmap)) { + i++; + continue; + } + + de = &d.dentry[i]; + + if (!de->name_len) { + i++; + continue; + } + + name_len = le16_to_cpu(de->name_len); + enc = enc_name; + + if (de->file_type == F2FS_FT_DIR) { + if ((d.filename[i][0] == '.' && name_len == 1) || + (d.filename[i][0] == '.' && + d.filename[i][1] == '.' && name_len == 2)) { + enc = 0; + } + } + + pretty_print_filename(d.filename[i], name_len, en, enc); + + DBG(1, "bitmap pos[0x%x] name[%s] len[0x%x] hash[0x%x] ino[0x%x] type[0x%x]\n", + i, en, + name_len, + le32_to_cpu(de->hash_code), + le32_to_cpu(de->ino), + de->file_type); + + DBG(1, "%s", "name(hex)["); + for (j = 0; j < F2FS_NAME_LEN && en[j]; j++) + MSG(1, "0x%x ", (unsigned char)en[j]); + MSG(1, "0x%x]\n", (unsigned char)en[j]); + + i += GET_DENTRY_SLOTS(name_len); + } + + free(blk); +} + +int dump_info_from_blkaddr(struct f2fs_sb_info *sbi, u32 blk_addr) +{ + nid_t nid; + int type; + struct f2fs_summary sum_entry; + struct node_info ni, ino_ni; + int enc_name; + int ret = 0; + + MSG(0, "\n== Dump data from block address ==\n\n"); + + if (blk_addr < SM_I(sbi)->seg0_blkaddr) { + MSG(0, "\nFS Reserved Area for SEG #0: "); + ret = -EINVAL; + } else if (blk_addr < SIT_I(sbi)->sit_base_addr) { + MSG(0, "\nFS Metadata Area: "); + ret = -EINVAL; + } else if (blk_addr < NM_I(sbi)->nat_blkaddr) { + MSG(0, "\nFS SIT Area: "); + ret = -EINVAL; + } else if (blk_addr < SM_I(sbi)->ssa_blkaddr) { + MSG(0, "\nFS NAT Area: "); + ret = -EINVAL; + } else if (blk_addr < SM_I(sbi)->main_blkaddr) { + MSG(0, "\nFS SSA Area: "); + ret = -EINVAL; + } else if (blk_addr > __end_block_addr(sbi)) { + MSG(0, "\nOut of address space: "); + ret = -EINVAL; + } + + if (ret) { + MSG(0, "User data is from 0x%x to 0x%x\n\n", + SM_I(sbi)->main_blkaddr, + __end_block_addr(sbi)); + return ret; + } + + if (!is_sit_bitmap_set(sbi, blk_addr)) + MSG(0, "\nblkaddr is not valid\n"); + + type = get_sum_entry(sbi, blk_addr, &sum_entry); + nid = le32_to_cpu(sum_entry.nid); + + get_node_info(sbi, nid, &ni); + + DBG(1, "Note: blkaddr = main_blkaddr + segno * 512 + offset\n"); + DBG(1, "Block_addr [0x%x]\n", blk_addr); + DBG(1, " - Segno [0x%x]\n", GET_SEGNO(sbi, blk_addr)); + DBG(1, " - Offset [0x%x]\n", OFFSET_IN_SEG(sbi, blk_addr)); + DBG(1, "SUM.nid [0x%x]\n", nid); + DBG(1, "SUM.type [%s]\n", type >= 0 ? + seg_type_name[type] : + "Broken"); + DBG(1, "SUM.version [%d]\n", sum_entry.version); + DBG(1, "SUM.ofs_in_node [0x%x]\n", sum_entry.ofs_in_node); + DBG(1, "NAT.blkaddr [0x%x]\n", ni.blk_addr); + DBG(1, "NAT.ino [0x%x]\n", ni.ino); + + get_node_info(sbi, ni.ino, &ino_ni); + + /* inode block address */ + if (ni.blk_addr == NULL_ADDR || ino_ni.blk_addr == NULL_ADDR) { + MSG(0, "FS Userdata Area: Obsolete block from 0x%x\n", + blk_addr); + return -EINVAL; + } + + /* print inode */ + if (c.dbg_lv > 0) + dump_node_from_blkaddr(sbi, ino_ni.blk_addr); + + if (type == SEG_TYPE_CUR_DATA || type == SEG_TYPE_DATA) { + MSG(0, "FS Userdata Area: Data block from 0x%x\n", blk_addr); + MSG(0, " - Direct node block : id = 0x%x from 0x%x\n", + nid, ni.blk_addr); + MSG(0, " - Inode block : id = 0x%x from 0x%x\n", + ni.ino, ino_ni.blk_addr); + dump_node_from_blkaddr(sbi, ino_ni.blk_addr); + dump_data_offset(ni.blk_addr, + le16_to_cpu(sum_entry.ofs_in_node)); + + if (has_dirent(ino_ni.blk_addr, 0, &enc_name)) + dump_dirent(blk_addr, 0, enc_name); + } else { + MSG(0, "FS Userdata Area: Node block from 0x%x\n", blk_addr); + if (ni.ino == ni.nid) { + MSG(0, " - Inode block : id = 0x%x from 0x%x\n", + ni.ino, ino_ni.blk_addr); + dump_node_from_blkaddr(sbi, ino_ni.blk_addr); + + if (has_dirent(ino_ni.blk_addr, 1, &enc_name)) + dump_dirent(blk_addr, 1, enc_name); + } else { + MSG(0, " - Node block : id = 0x%x from 0x%x\n", + nid, ni.blk_addr); + MSG(0, " - Inode block : id = 0x%x from 0x%x\n", + ni.ino, ino_ni.blk_addr); + dump_node_from_blkaddr(sbi, ino_ni.blk_addr); + dump_node_offset(ni.blk_addr); + } + } + + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/f2fs.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/f2fs.h new file mode 100644 index 00000000000..187e73cf9ae --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/f2fs.h @@ -0,0 +1,655 @@ +/** + * f2fs.h + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _F2FS_H_ +#define _F2FS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_MNTENT_H +#include +#endif +#ifdef HAVE_MACH_TIME_H +#include +#endif +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#include + +#define EXIT_ERR_CODE (-1) +#define ver_after(a, b) (typecheck(unsigned long long, a) && \ + typecheck(unsigned long long, b) && \ + ((long long)((a) - (b)) > 0)) + +#define container_of(ptr, type, member) ({ \ + const typeof(((type *)0)->member) * __mptr = (ptr); \ + (type *)((char *)__mptr - offsetof(type, member)); }) + +struct list_head { + struct list_head *next, *prev; +}; + +static inline void __list_add(struct list_head *new, + struct list_head *prev, + struct list_head *next) +{ + next->prev = new; + new->next = next; + new->prev = prev; + prev->next = new; +} + +static inline void __list_del(struct list_head * prev, struct list_head * next) +{ + next->prev = prev; + prev->next = next; +} + +static inline void list_del(struct list_head *entry) +{ + __list_del(entry->prev, entry->next); +} + +static inline void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + +#define LIST_HEAD_INIT(name) { &(name), &(name) } + +#define list_entry(ptr, type, member) \ + container_of(ptr, type, member) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_next_entry(pos, member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + n = list_next_entry(pos, member); \ + &pos->member != (head); \ + pos = n, n = list_next_entry(n, member)) + +/* + * indicate meta/data type + */ +enum { + META_CP, + META_NAT, + META_SIT, + META_SSA, + META_MAX, + META_POR, + DATA_GENERIC, +}; + +#define MAX_RA_BLOCKS 64 + +enum { + NAT_BITMAP, + SIT_BITMAP +}; + +struct node_info { + nid_t nid; + nid_t ino; + u32 blk_addr; + unsigned char version; +}; + +struct f2fs_nm_info { + block_t nat_blkaddr; + block_t nat_blocks; + nid_t max_nid; + nid_t init_scan_nid; + nid_t next_scan_nid; + + unsigned int nat_cnt; + unsigned int fcnt; + + char *nat_bitmap; + int bitmap_size; + char *nid_bitmap; +}; + +struct seg_entry { + unsigned short valid_blocks; /* # of valid blocks */ + unsigned short ckpt_valid_blocks; /* # of valid blocks last cp, for recovered data/node */ + unsigned char *cur_valid_map; /* validity bitmap of blocks */ + unsigned char *ckpt_valid_map; /* validity bitmap of blocks last cp, for recovered data/node */ + unsigned char type; /* segment type like CURSEG_XXX_TYPE */ + unsigned char orig_type; /* segment type like CURSEG_XXX_TYPE */ + unsigned char ckpt_type; /* segment type like CURSEG_XXX_TYPE , for recovered data/node */ + unsigned long long mtime; /* modification time of the segment */ + int dirty; +}; + +struct sec_entry { + unsigned int valid_blocks; /* # of valid blocks in a section */ +}; + +struct sit_info { + + block_t sit_base_addr; /* start block address of SIT area */ + block_t sit_blocks; /* # of blocks used by SIT area */ + block_t written_valid_blocks; /* # of valid blocks in main area */ + unsigned char *bitmap; /* all bitmaps pointer */ + char *sit_bitmap; /* SIT bitmap pointer */ + unsigned int bitmap_size; /* SIT bitmap size */ + + unsigned long *dirty_sentries_bitmap; /* bitmap for dirty sentries */ + unsigned int dirty_sentries; /* # of dirty sentries */ + unsigned int sents_per_block; /* # of SIT entries per block */ + struct seg_entry *sentries; /* SIT segment-level cache */ + struct sec_entry *sec_entries; /* SIT section-level cache */ + + unsigned long long elapsed_time; /* elapsed time after mount */ + unsigned long long mounted_time; /* mount time */ + unsigned long long min_mtime; /* min. modification time */ + unsigned long long max_mtime; /* max. modification time */ +}; + +struct curseg_info { + struct f2fs_summary_block *sum_blk; /* cached summary block */ + unsigned char alloc_type; /* current allocation type */ + unsigned int segno; /* current segment number */ + unsigned short next_blkoff; /* next block offset to write */ + unsigned int zone; /* current zone number */ + unsigned int next_segno; /* preallocated segment */ +}; + +struct f2fs_sm_info { + struct sit_info *sit_info; + struct curseg_info *curseg_array; + struct curseg_info saved_curseg_warm_node; + + block_t seg0_blkaddr; + block_t main_blkaddr; + block_t ssa_blkaddr; + + unsigned int segment_count; + unsigned int main_segments; + unsigned int reserved_segments; + unsigned int ovp_segments; + unsigned int free_segments; +}; + +struct f2fs_dentry_ptr { + struct inode *inode; + u8 *bitmap; + struct f2fs_dir_entry *dentry; + __u8 (*filename)[F2FS_SLOT_LEN]; + int max; + int nr_bitmap; +}; + +struct dentry { + char *path; + char *full_path; + const u8 *name; + int len; + char *link; + unsigned long size; + u8 file_type; + u16 mode; + u16 uid; + u16 gid; + u32 *inode; + u32 mtime; + char *secon; + uint64_t capabilities; + nid_t ino; + nid_t pino; + u64 from_devino; +}; + +/* different from dnode_of_data in kernel */ +struct dnode_of_data { + struct f2fs_node *inode_blk; /* inode page */ + struct f2fs_node *node_blk; /* cached direct node page */ + nid_t nid; + unsigned int ofs_in_node; + block_t data_blkaddr; + block_t node_blkaddr; + int idirty, ndirty, alloced; +}; + +struct hardlink_cache_entry { + u64 from_devino; + nid_t to_ino; + int nbuild; +}; + +struct f2fs_sb_info { + struct f2fs_fsck *fsck; + + struct f2fs_super_block *raw_super; + struct f2fs_nm_info *nm_info; + struct f2fs_sm_info *sm_info; + struct f2fs_checkpoint *ckpt; + int cur_cp; + + /* basic file system units */ + unsigned int log_sectors_per_block; /* log2 sectors per block */ + unsigned int log_blocksize; /* log2 block size */ + unsigned int blocksize; /* block size */ + unsigned int root_ino_num; /* root inode number*/ + unsigned int node_ino_num; /* node inode number*/ + unsigned int meta_ino_num; /* meta inode number*/ + unsigned int log_blocks_per_seg; /* log2 blocks per segment */ + unsigned int blocks_per_seg; /* blocks per segment */ + unsigned int segs_per_sec; /* segments per section */ + unsigned int secs_per_zone; /* sections per zone */ + unsigned int total_sections; /* total section count */ + unsigned int total_node_count; /* total node block count */ + unsigned int total_valid_node_count; /* valid node block count */ + unsigned int total_valid_inode_count; /* valid inode count */ + int active_logs; /* # of active logs */ + + block_t user_block_count; /* # of user blocks */ + block_t total_valid_block_count; /* # of valid blocks */ + block_t alloc_valid_block_count; /* # of allocated blocks */ + block_t last_valid_block_count; /* for recovery */ + u32 s_next_generation; /* for NFS support */ + + unsigned int cur_victim_sec; /* current victim section num */ + u32 free_segments; + + int cp_backuped; /* backup valid checkpoint */ + + /* true if late_build_segment_manger() is called */ + bool seg_manager_done; + + /* keep track of hardlinks so we can recreate them */ + void *hardlink_cache; +}; + +static inline struct f2fs_super_block *F2FS_RAW_SUPER(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_super_block *)(sbi->raw_super); +} + +static inline struct f2fs_checkpoint *F2FS_CKPT(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_checkpoint *)(sbi->ckpt); +} + +static inline struct f2fs_fsck *F2FS_FSCK(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_fsck *)(sbi->fsck); +} + +static inline struct f2fs_nm_info *NM_I(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_nm_info *)(sbi->nm_info); +} + +static inline struct f2fs_sm_info *SM_I(struct f2fs_sb_info *sbi) +{ + return (struct f2fs_sm_info *)(sbi->sm_info); +} + +static inline struct sit_info *SIT_I(struct f2fs_sb_info *sbi) +{ + return (struct sit_info *)(SM_I(sbi)->sit_info); +} + +static inline void *inline_data_addr(struct f2fs_node *node_blk) +{ + int ofs = get_extra_isize(node_blk) + DEF_INLINE_RESERVED_SIZE; + + return (void *)&(node_blk->i.i_addr[ofs]); +} + +static inline unsigned int ofs_of_node(struct f2fs_node *node_blk) +{ + unsigned flag = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag); + return flag >> OFFSET_BIT_SHIFT; +} + +static inline unsigned long long cur_cp_version(struct f2fs_checkpoint *cp) +{ + return le64_to_cpu(cp->checkpoint_ver); +} + +static inline __u64 cur_cp_crc(struct f2fs_checkpoint *cp) +{ + size_t crc_offset = le32_to_cpu(cp->checksum_offset); + return le32_to_cpu(*((__le32 *)((unsigned char *)cp + crc_offset))); +} + +static inline bool is_set_ckpt_flags(struct f2fs_checkpoint *cp, unsigned int f) +{ + unsigned int ckpt_flags = le32_to_cpu(cp->ckpt_flags); + return ckpt_flags & f ? 1 : 0; +} + +static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + + /* return NAT or SIT bitmap */ + if (flag == NAT_BITMAP) + return le32_to_cpu(ckpt->nat_ver_bitmap_bytesize); + else if (flag == SIT_BITMAP) + return le32_to_cpu(ckpt->sit_ver_bitmap_bytesize); + + return 0; +} + +static inline block_t __cp_payload(struct f2fs_sb_info *sbi) +{ + return le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload); +} + +static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + int offset; + + if (is_set_ckpt_flags(ckpt, CP_LARGE_NAT_BITMAP_FLAG)) { + unsigned int chksum_size = 0; + + offset = (flag == SIT_BITMAP) ? + le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0; + + if (le32_to_cpu(ckpt->checksum_offset) == + CP_MIN_CHKSUM_OFFSET) + chksum_size = sizeof(__le32); + + return &ckpt->sit_nat_version_bitmap[offset + chksum_size]; + } + + if (le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_payload) > 0) { + if (flag == NAT_BITMAP) + return &ckpt->sit_nat_version_bitmap; + else + return ((char *)ckpt + F2FS_BLKSIZE); + } else { + offset = (flag == NAT_BITMAP) ? + le32_to_cpu(ckpt->sit_ver_bitmap_bytesize) : 0; + return &ckpt->sit_nat_version_bitmap[offset]; + } +} + +static inline block_t __start_cp_addr(struct f2fs_sb_info *sbi) +{ + block_t start_addr = le32_to_cpu(F2FS_RAW_SUPER(sbi)->cp_blkaddr); + + if (sbi->cur_cp == 2) + start_addr += sbi->blocks_per_seg; + return start_addr; +} + +static inline block_t __start_sum_addr(struct f2fs_sb_info *sbi) +{ + return le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); +} + +static inline block_t __end_block_addr(struct f2fs_sb_info *sbi) +{ + return SM_I(sbi)->main_blkaddr + + (le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_main) << + sbi->log_blocks_per_seg); +} + +#define BLKS_PER_SEC(sbi) \ + ((sbi)->segs_per_sec * (sbi)->blocks_per_seg) +#define GET_ZONENO_FROM_SEGNO(sbi, segno) \ + ((segno / sbi->segs_per_sec) / sbi->secs_per_zone) + +#define IS_DATASEG(t) \ + ((t == CURSEG_HOT_DATA) || (t == CURSEG_COLD_DATA) || \ + (t == CURSEG_WARM_DATA)) + +#define IS_NODESEG(t) \ + ((t == CURSEG_HOT_NODE) || (t == CURSEG_COLD_NODE) || \ + (t == CURSEG_WARM_NODE)) + +#define MAIN_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) +#define SEG0_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr)) + +#define GET_SUM_BLKADDR(sbi, segno) \ + ((sbi->sm_info->ssa_blkaddr) + segno) + +#define GET_SEGOFF_FROM_SEG0(sbi, blk_addr) \ + ((blk_addr) - SM_I(sbi)->seg0_blkaddr) + +#define GET_SEGNO_FROM_SEG0(sbi, blk_addr) \ + (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg) + +#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr) \ + (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1)) + +#define GET_SEC_FROM_SEG(sbi, segno) \ + ((segno) / (sbi)->segs_per_sec) +#define GET_SEG_FROM_SEC(sbi, secno) \ + ((secno) * (sbi)->segs_per_sec) + +#define FREE_I_START_SEGNO(sbi) \ + GET_SEGNO_FROM_SEG0(sbi, SM_I(sbi)->main_blkaddr) +#define GET_R2L_SEGNO(sbi, segno) (segno + FREE_I_START_SEGNO(sbi)) + +#define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments) +#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count) +#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg) +#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi)) + +#define START_BLOCK(sbi, segno) (SM_I(sbi)->main_blkaddr + \ + ((segno) << sbi->log_blocks_per_seg)) + +#define NEXT_FREE_BLKADDR(sbi, curseg) \ + (START_BLOCK(sbi, (curseg)->segno) + (curseg)->next_blkoff) + +#define SIT_BLK_CNT(sbi) \ + ((MAIN_SEGS(sbi) + SIT_ENTRY_PER_BLOCK - 1) / SIT_ENTRY_PER_BLOCK) + +static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type) +{ + return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); +} + +static inline block_t start_sum_block(struct f2fs_sb_info *sbi) +{ + return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_start_sum); +} + +static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type) +{ + return __start_cp_addr(sbi) + le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count) + - (base + 1) + type; +} + +/* for the list of fsync inodes, used only during recovery */ +struct fsync_inode_entry { + struct list_head list; /* list head */ + nid_t ino; /* inode number */ + block_t blkaddr; /* block address locating the last fsync */ + block_t last_dentry; /* block address locating the last dentry */ +}; + +#define nats_in_cursum(jnl) (le16_to_cpu(jnl->n_nats)) +#define sits_in_cursum(jnl) (le16_to_cpu(jnl->n_sits)) + +#define nat_in_journal(jnl, i) (jnl->nat_j.entries[i].ne) +#define nid_in_journal(jnl, i) (jnl->nat_j.entries[i].nid) +#define sit_in_journal(jnl, i) (jnl->sit_j.entries[i].se) +#define segno_in_journal(jnl, i) (jnl->sit_j.entries[i].segno) + +#define SIT_ENTRY_OFFSET(sit_i, segno) \ + ((segno) % sit_i->sents_per_block) +#define SIT_BLOCK_OFFSET(sit_i, segno) \ + ((segno) / SIT_ENTRY_PER_BLOCK) + +static inline bool IS_VALID_NID(struct f2fs_sb_info *sbi, u32 nid) +{ + return (nid < (NAT_ENTRY_PER_BLOCK * + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count_nat) + << (sbi->log_blocks_per_seg - 1))); +} + +static inline bool is_valid_data_blkaddr(block_t blkaddr) +{ + if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR || + blkaddr == COMPRESS_ADDR) + return 0; + return 1; +} + +static inline int IS_CUR_SEGNO(struct f2fs_sb_info *sbi, u32 segno) +{ + int i; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + + if (segno == curseg->segno) + return 1; + } + return 0; +} + +static inline u64 BLKOFF_FROM_MAIN(struct f2fs_sb_info *sbi, u64 blk_addr) +{ + ASSERT(blk_addr >= SM_I(sbi)->main_blkaddr); + return blk_addr - SM_I(sbi)->main_blkaddr; +} + +static inline u32 GET_SEGNO(struct f2fs_sb_info *sbi, u64 blk_addr) +{ + return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr) + >> sbi->log_blocks_per_seg); +} + +static inline u32 OFFSET_IN_SEG(struct f2fs_sb_info *sbi, u64 blk_addr) +{ + return (u32)(BLKOFF_FROM_MAIN(sbi, blk_addr) + % (1 << sbi->log_blocks_per_seg)); +} + +static inline void node_info_from_raw_nat(struct node_info *ni, + struct f2fs_nat_entry *raw_nat) +{ + ni->ino = le32_to_cpu(raw_nat->ino); + ni->blk_addr = le32_to_cpu(raw_nat->block_addr); + ni->version = raw_nat->version; +} + +static inline void set_summary(struct f2fs_summary *sum, nid_t nid, + unsigned int ofs_in_node, unsigned char version) +{ + sum->nid = cpu_to_le32(nid); + sum->ofs_in_node = cpu_to_le16(ofs_in_node); + sum->version = version; +} + +#define S_SHIFT 12 +static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = { + [S_IFREG >> S_SHIFT] = F2FS_FT_REG_FILE, + [S_IFDIR >> S_SHIFT] = F2FS_FT_DIR, + [S_IFCHR >> S_SHIFT] = F2FS_FT_CHRDEV, + [S_IFBLK >> S_SHIFT] = F2FS_FT_BLKDEV, + [S_IFIFO >> S_SHIFT] = F2FS_FT_FIFO, +#ifdef S_IFSOCK + [S_IFSOCK >> S_SHIFT] = F2FS_FT_SOCK, +#endif +#ifdef S_IFLNK + [S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK, +#endif +}; + +static inline int map_de_type(umode_t mode) +{ + return f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT]; +} + +static inline void *inline_xattr_addr(struct f2fs_inode *inode) +{ + return (void *)&(inode->i_addr[DEF_ADDRS_PER_INODE - + get_inline_xattr_addrs(inode)]); +} + +static inline int inline_xattr_size(struct f2fs_inode *inode) +{ + return get_inline_xattr_addrs(inode) * sizeof(__le32); +} + +extern int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, struct f2fs_nat_entry *ne); +#define IS_SUM_NODE_SEG(sum) (F2FS_SUMMARY_BLOCK_FOOTER(sum)->entry_type == SUM_TYPE_NODE) +#define IS_SUM_DATA_SEG(sum) (F2FS_SUMMARY_BLOCK_FOOTER(sum)->entry_type == SUM_TYPE_DATA) + +static inline unsigned int dir_buckets(unsigned int level, int dir_level) +{ + if (level + dir_level < MAX_DIR_HASH_DEPTH / 2) + return 1 << (level + dir_level); + else + return MAX_DIR_BUCKETS; +} + +static inline unsigned int bucket_blocks(unsigned int level) +{ + if (level < MAX_DIR_HASH_DEPTH / 2) + return 2; + else + return 4; +} + +static inline unsigned long dir_block_index(unsigned int level, + int dir_level, unsigned int idx) +{ + unsigned long i; + unsigned long bidx = 0; + + for (i = 0; i < level; i++) + bidx += dir_buckets(i, dir_level) * bucket_blocks(i); + bidx += idx * bucket_blocks(level); + return bidx; +} + +static inline int is_dot_dotdot(const unsigned char *name, const int len) +{ + if (len == 1 && name[0] == '.') + return 1; + if (len == 2 && name[0] == '.' && name[1] == '.') + return 1; + return 0; +} + +static inline int get_encoding(struct f2fs_sb_info *sbi) +{ + return le16_to_cpu(F2FS_RAW_SUPER(sbi)->s_encoding); +} + +#endif /* _F2FS_H_ */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.c new file mode 100644 index 00000000000..893eea70863 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.c @@ -0,0 +1,3928 @@ +/** + * fsck.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "xattr.h" +#include "quotaio.h" +#include + +char *tree_mark; +uint32_t tree_mark_size = 256; + +const char *f2fs_fault_name[FAULT_MAX] = { + [FAULT_SEG_TYPE] = "FAULT_SEG_TYPE", + [FAULT_SUM_TYPE] = "FAULT_SUM_TYPE", + [FAULT_SUM_ENT] = "FAULT_SUM_ENTRY", + [FAULT_NAT] = "FAULT_NAT_ENTRY", + [FAULT_NODE] = "FAULT_NODE_BLOCK", + [FAULT_XATTR_ENT] = "FAULT_XATTR_ENTRY", + [FAULT_COMPR] = "FAULT_COMPR_TYPE", + [FAULT_INODE] = "FAULT_INODE_ENTRY", + [FAULT_DENTRY] = "FAULT_DENTRY_BLOCK", + [FAULT_DATA] = "FAULT_DATA_BLOCK", + [FAULT_QUOTA] = "FAULT_QUOTA", +}; + +int f2fs_set_main_bitmap(struct f2fs_sb_info *sbi, u32 blk, int type) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct seg_entry *se; + int fix = 0; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, blk)); + if (time_to_inject(FAULT_SEG_TYPE) || + (se->type >= NO_CHECK_TYPE) || + (IS_DATASEG(se->type) != IS_DATASEG(type))) + fix = 1; + + /* just check data and node types */ + if (fix) { + DBG(1, "Wrong segment type [0x%x] %x -> %x", + GET_SEGNO(sbi, blk), se->type, type); + se->type = type; + } + return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->main_area_bitmap); +} + +static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), + fsck->main_area_bitmap); +} + +int f2fs_clear_main_bitmap(struct f2fs_sb_info *sbi, u32 blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + return f2fs_clear_bit(BLKOFF_FROM_MAIN(sbi, blk), + fsck->main_area_bitmap); +} + +static inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + return f2fs_test_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap); +} + +int f2fs_set_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap); +} + +int f2fs_clear_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + return f2fs_clear_bit(BLKOFF_FROM_MAIN(sbi, blk), + fsck->sit_area_bitmap); +} + +static int add_into_hard_link_list(struct f2fs_sb_info *sbi, + u32 nid, u32 link_cnt) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct hard_link_node *node = NULL, *tmp = NULL, *prev = NULL; + + node = calloc(sizeof(struct hard_link_node), 1); + ASSERT(node != NULL); + + node->nid = nid; + node->links = link_cnt; + node->actual_links = 1; + node->next = NULL; + + if (fsck->hard_link_list_head == NULL) { + fsck->hard_link_list_head = node; + goto out; + } + + tmp = fsck->hard_link_list_head; + + /* Find insertion position */ + while (tmp && (nid < tmp->nid)) { + ASSERT(tmp->nid != nid); + prev = tmp; + tmp = tmp->next; + } + + if (tmp == fsck->hard_link_list_head) { + node->next = tmp; + fsck->hard_link_list_head = node; + } else { + prev->next = node; + node->next = tmp; + } + +out: + DBG(2, "ino[0x%x] has hard links [0x%x]\n", nid, link_cnt); + return 0; +} + +static int find_and_dec_hard_link_list(struct f2fs_sb_info *sbi, u32 nid) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct hard_link_node *node = NULL, *prev = NULL; + + if (fsck->hard_link_list_head == NULL) + return -EINVAL; + + node = fsck->hard_link_list_head; + + while (node && (nid < node->nid)) { + prev = node; + node = node->next; + } + + if (node == NULL || (nid != node->nid)) + return -EINVAL; + + /* Decrease link count */ + node->links = node->links - 1; + node->actual_links++; + + /* if link count becomes one, remove the node */ + if (node->links == 1) { + if (fsck->hard_link_list_head == node) + fsck->hard_link_list_head = node->next; + else + prev->next = node->next; + free(node); + } + return 0; +} + +static int is_valid_ssa_node_blk(struct f2fs_sb_info *sbi, u32 nid, + u32 blk_addr) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_summary_block *sum_blk; + struct f2fs_summary *sum_entry; + struct seg_entry * se; + u32 segno, offset; + int need_fix = 0, ret = 0; + int type; + + if (get_sb(feature) & F2FS_FEATURE_RO) + return 0; + + segno = GET_SEGNO(sbi, blk_addr); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + sum_blk = get_sum_block(sbi, segno, &type); + + if (time_to_inject(FAULT_SUM_TYPE) || + (type != SEG_TYPE_NODE && type != SEG_TYPE_CUR_NODE)) { + /* can't fix current summary, then drop the block */ + if (!c.fix_on || type < 0) { + ASSERT_MSG("Summary footer is not for node segment"); + ret = -EINVAL; + goto out; + } + + need_fix = 1; + se = get_seg_entry(sbi, segno); + if(IS_NODESEG(se->type)) { + ASSERT_MSG("Summary footer indicates a node segment: 0x%x", segno); + F2FS_SUMMARY_BLOCK_FOOTER(sum_blk)->entry_type = SUM_TYPE_NODE; + } else { + ret = -EINVAL; + goto out; + } + } + + sum_entry = &(sum_blk->entries[offset]); + + if (time_to_inject(FAULT_SUM_ENT) || + (le32_to_cpu(sum_entry->nid) != nid)) { + if (!c.fix_on || type < 0) { + DBG(0, "nid [0x%x]\n", nid); + DBG(0, "target blk_addr [0x%x]\n", blk_addr); + DBG(0, "summary blk_addr [0x%x]\n", + GET_SUM_BLKADDR(sbi, + GET_SEGNO(sbi, blk_addr))); + DBG(0, "seg no / offset [0x%x / 0x%x]\n", + GET_SEGNO(sbi, blk_addr), + OFFSET_IN_SEG(sbi, blk_addr)); + DBG(0, "summary_entry.nid [0x%x]\n", + le32_to_cpu(sum_entry->nid)); + DBG(0, "--> node block's nid [0x%x]\n", nid); + ASSERT_MSG("Invalid node seg summary\n"); + ret = -EINVAL; + } else { + ASSERT_MSG("Set node summary 0x%x -> [0x%x] [0x%x]", + segno, nid, blk_addr); + sum_entry->nid = cpu_to_le32(nid); + need_fix = 1; + } + } + if (need_fix && f2fs_dev_is_writable()) { + u64 ssa_blk; + int ret2; + + ssa_blk = GET_SUM_BLKADDR(sbi, segno); + ret2 = dev_write_block(sum_blk, ssa_blk, WRITE_LIFE_NONE); + ASSERT(ret2 >= 0); + } +out: + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); + return ret; +} + +static int is_valid_summary(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, + u32 blk_addr) +{ + u16 ofs_in_node = le16_to_cpu(sum->ofs_in_node); + u32 nid = le32_to_cpu(sum->nid); + struct f2fs_node *node_blk = NULL; + __le32 target_blk_addr; + struct node_info ni; + int ret = 0; + + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk != NULL); + + if (!IS_VALID_NID(sbi, nid)) + goto out; + + get_node_info(sbi, nid, &ni); + + if (!f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) + goto out; + + /* read node_block */ + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + + if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != nid) + goto out; + + /* check its block address */ + if (IS_INODE(node_blk)) { + int ofs = get_extra_isize(node_blk); + + if (ofs + ofs_in_node >= DEF_ADDRS_PER_INODE) + goto out; + target_blk_addr = node_blk->i.i_addr[ofs + ofs_in_node]; + } else { + if (ofs_in_node >= DEF_ADDRS_PER_BLOCK) + goto out; + target_blk_addr = node_blk->dn.addr[ofs_in_node]; + } + + if (blk_addr == le32_to_cpu(target_blk_addr)) + ret = 1; +out: + free(node_blk); + return ret; +} + +static int is_valid_ssa_data_blk(struct f2fs_sb_info *sbi, u32 blk_addr, + u32 parent_nid, u16 idx_in_node, u8 version) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_summary_block *sum_blk; + struct f2fs_summary *sum_entry; + struct seg_entry * se; + u32 segno, offset; + int need_fix = 0, ret = 0, fault_sum_ent = 0; + int type; + + if (get_sb(feature) & F2FS_FEATURE_RO) + return 0; + + segno = GET_SEGNO(sbi, blk_addr); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + sum_blk = get_sum_block(sbi, segno, &type); + + if (time_to_inject(FAULT_SUM_TYPE) || + (type != SEG_TYPE_DATA && type != SEG_TYPE_CUR_DATA)) { + /* can't fix current summary, then drop the block */ + if (!c.fix_on || type < 0) { + ASSERT_MSG("Summary footer is not for data segment"); + ret = -EINVAL; + goto out; + } + + need_fix = 1; + se = get_seg_entry(sbi, segno); + if (IS_DATASEG(se->type)) { + ASSERT_MSG("Summary footer indicates a data segment: 0x%x", segno); + F2FS_SUMMARY_BLOCK_FOOTER(sum_blk)->entry_type = SUM_TYPE_DATA; + } else { + ret = -EINVAL; + goto out; + } + } + + sum_entry = &(sum_blk->entries[offset]); + + if (time_to_inject(FAULT_SUM_ENT)) + fault_sum_ent = 1; + + if (fault_sum_ent || le32_to_cpu(sum_entry->nid) != parent_nid || + sum_entry->version != version || + le16_to_cpu(sum_entry->ofs_in_node) != idx_in_node) { + if (!c.fix_on || type < 0) { + DBG(0, "summary_entry.nid [0x%x]\n", + le32_to_cpu(sum_entry->nid)); + DBG(0, "summary_entry.version [0x%x]\n", + sum_entry->version); + DBG(0, "summary_entry.ofs_in_node [0x%x]\n", + le16_to_cpu(sum_entry->ofs_in_node)); + DBG(0, "parent nid [0x%x]\n", + parent_nid); + DBG(0, "version from nat [0x%x]\n", version); + DBG(0, "idx in parent node [0x%x]\n", + idx_in_node); + + DBG(0, "Target data block addr [0x%x]\n", blk_addr); + ASSERT_MSG("Invalid data seg summary\n"); + ret = -EINVAL; + } else if (!fault_sum_ent && + is_valid_summary(sbi, sum_entry, blk_addr)) { + /* delete wrong index */ + ret = -EINVAL; + } else { + ASSERT_MSG("Set data summary 0x%x -> [0x%x] [0x%x] [0x%x]", + segno, parent_nid, version, idx_in_node); + sum_entry->nid = cpu_to_le32(parent_nid); + sum_entry->version = version; + sum_entry->ofs_in_node = cpu_to_le16(idx_in_node); + need_fix = 1; + } + } + if (need_fix && f2fs_dev_is_writable()) { + u64 ssa_blk; + int ret2; + + ssa_blk = GET_SUM_BLKADDR(sbi, segno); + ret2 = dev_write_block(sum_blk, ssa_blk, WRITE_LIFE_NONE); + ASSERT(ret2 >= 0); + } +out: + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); + return ret; +} + +static int __check_inode_mode(u32 nid, enum FILE_TYPE ftype, u16 mode) +{ + if (ftype >= F2FS_FT_MAX) + return 0; + /* f2fs_iget will return -EIO if mode is not valid file type */ + if (!S_ISLNK(mode) && !S_ISREG(mode) && !S_ISDIR(mode) && + !S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode) && + !S_ISSOCK(mode)) { + ASSERT_MSG("inode [0x%x] unknown file type i_mode [0x%x]", + nid, mode); + return -1; + } + + if (S_ISLNK(mode) && ftype != F2FS_FT_SYMLINK) + goto err; + if (S_ISREG(mode) && ftype != F2FS_FT_REG_FILE) + goto err; + if (S_ISDIR(mode) && ftype != F2FS_FT_DIR) + goto err; + if (S_ISCHR(mode) && ftype != F2FS_FT_CHRDEV) + goto err; + if (S_ISBLK(mode) && ftype != F2FS_FT_BLKDEV) + goto err; + if (S_ISFIFO(mode) && ftype != F2FS_FT_FIFO) + goto err; + if (S_ISSOCK(mode) && ftype != F2FS_FT_SOCK) + goto err; + return 0; +err: + ASSERT_MSG("inode [0x%x] mismatch i_mode [0x%x vs. 0x%x]", + nid, ftype, mode); + return -1; +} + +static int sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid, + struct node_info *ni) +{ + if (time_to_inject(FAULT_NAT)) { + ASSERT_MSG("%s is injected.", f2fs_fault_name[FAULT_NAT]); + return -EINVAL; + } + + if (!IS_VALID_NID(sbi, nid)) { + ASSERT_MSG("nid is not valid. [0x%x]", nid); + return -EINVAL; + } + + get_node_info(sbi, nid, ni); + if (ni->ino == 0) { + ASSERT_MSG("nid[0x%x] ino is 0", nid); + return -EINVAL; + } + + if (!is_valid_data_blkaddr(ni->blk_addr)) { + ASSERT_MSG("nid->blk_addr is 0x%x. [0x%x]", ni->blk_addr, nid); + return -EINVAL; + } + + if (!f2fs_is_valid_blkaddr(sbi, ni->blk_addr, DATA_GENERIC)) { + ASSERT_MSG("blkaddress is not valid. [0x%x]", ni->blk_addr); + return -EINVAL; + } + + return 0; +} + +int fsck_sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid) +{ + struct node_info ni; + + return sanity_check_nat(sbi, nid, &ni); +} + +static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_node *node_blk, + enum FILE_TYPE ftype, enum NODE_TYPE ntype, + struct node_info *ni) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + int ret; + + if (time_to_inject(FAULT_NODE)) { + ASSERT_MSG("%s is injected.", f2fs_fault_name[FAULT_NODE]); + return -EINVAL; + } + + ret = sanity_check_nat(sbi, nid, ni); + if (ret) + return ret; + + ret = dev_read_block(node_blk, ni->blk_addr); + ASSERT(ret >= 0); + + if (ntype == TYPE_INODE && + F2FS_NODE_FOOTER(node_blk)->nid != F2FS_NODE_FOOTER(node_blk)->ino) { + ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]", + nid, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid), + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino)); + return -EINVAL; + } + if (ni->ino != le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino)) { + ASSERT_MSG("nid[0x%x] nat_entry->ino[0x%x] footer.ino[0x%x]", + nid, ni->ino, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino)); + return -EINVAL; + } + if (ntype != TYPE_INODE && IS_INODE(node_blk)) { + ASSERT_MSG("nid[0x%x] footer.nid[0x%x] footer.ino[0x%x]", + nid, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid), + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino)); + return -EINVAL; + } + + if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != nid) { + ASSERT_MSG("nid[0x%x] blk_addr[0x%x] footer.nid[0x%x]", + nid, ni->blk_addr, + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid)); + return -EINVAL; + } + + if (ntype == TYPE_XATTR) { + u32 flag = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag); + + if ((flag >> OFFSET_BIT_SHIFT) != XATTR_NODE_OFFSET) { + ASSERT_MSG("xnid[0x%x] has wrong ofs:[0x%x]", + nid, flag); + return -EINVAL; + } + } + + if ((ntype == TYPE_INODE && ftype == F2FS_FT_DIR) || + (ntype == TYPE_XATTR && ftype == F2FS_FT_XATTR)) { + /* not included '.' & '..' */ + if (f2fs_test_main_bitmap(sbi, ni->blk_addr) != 0) { + ASSERT_MSG("Duplicated node blk. nid[0x%x][0x%x]\n", + nid, ni->blk_addr); + return -EINVAL; + } + } + + /* this if only from fix_hard_links */ + if (ftype == F2FS_FT_MAX) + return 0; + + if (ntype == TYPE_INODE && + __check_inode_mode(nid, ftype, le16_to_cpu(node_blk->i.i_mode))) + return -EINVAL; + + /* workaround to fix later */ + if (ftype != F2FS_FT_ORPHAN || + f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0) { + f2fs_clear_bit(nid, fsck->nat_area_bitmap); + /* avoid reusing nid when reconnecting files */ + f2fs_set_bit(nid, NM_I(sbi)->nid_bitmap); + } else + ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n", + nid); + + if (is_valid_ssa_node_blk(sbi, nid, ni->blk_addr)) { + ASSERT_MSG("summary node block is not valid. [0x%x]", nid); + return -EINVAL; + } + + if (f2fs_test_sit_bitmap(sbi, ni->blk_addr) == 0) + ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", + ni->blk_addr); + + if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) { + + fsck->chk.valid_blk_cnt++; + fsck->chk.valid_node_cnt++; + + /* Progress report */ + if (!c.show_file_map && sbi->total_valid_node_count > 1000) { + unsigned int p10 = sbi->total_valid_node_count / 10; + + if (++sbi->fsck->chk.checked_node_cnt % p10) + return 0; + + printf("[FSCK] Check node %"PRIu64" / %u (%.2f%%)\n", + sbi->fsck->chk.checked_node_cnt, + sbi->total_valid_node_count, + 10 * (float)sbi->fsck->chk.checked_node_cnt / + p10); + } + } + return 0; +} + +int fsck_sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid, + enum FILE_TYPE ftype, enum NODE_TYPE ntype) +{ + struct f2fs_node *node_blk = NULL; + struct node_info ni; + int ret; + + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk != NULL); + + ret = sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni); + + free(node_blk); + return ret; +} + +static int fsck_chk_xattr_blk(struct f2fs_sb_info *sbi, u32 ino, + u32 x_nid, u32 *blk_cnt) +{ + struct f2fs_node *node_blk = NULL; + struct node_info ni; + int ret = 0; + + if (x_nid == 0x0) + return 0; + + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk != NULL); + + /* Sanity check */ + if (sanity_check_nid(sbi, x_nid, node_blk, + F2FS_FT_XATTR, TYPE_XATTR, &ni)) { + ret = -EINVAL; + goto out; + } + + *blk_cnt = *blk_cnt + 1; + f2fs_set_main_bitmap(sbi, ni.blk_addr, CURSEG_COLD_NODE); + DBG(2, "ino[0x%x] x_nid[0x%x]\n", ino, x_nid); +out: + free(node_blk); + return ret; +} + +int fsck_chk_node_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, + u32 nid, enum FILE_TYPE ftype, enum NODE_TYPE ntype, + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct child_info *child) +{ + struct node_info ni; + struct f2fs_node *node_blk = NULL; + + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk != NULL); + + if (sanity_check_nid(sbi, nid, node_blk, ftype, ntype, &ni)) + goto err; + + if (ntype == TYPE_INODE) { + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + fsck_chk_inode_blk(sbi, nid, ftype, node_blk, blk_cnt, cbc, + &ni, child); + quota_add_inode_usage(fsck->qctx, nid, &node_blk->i); + } else { + switch (ntype) { + case TYPE_DIRECT_NODE: + f2fs_set_main_bitmap(sbi, ni.blk_addr, + CURSEG_WARM_NODE); + fsck_chk_dnode_blk(sbi, inode, nid, ftype, node_blk, + blk_cnt, cbc, child, &ni); + break; + case TYPE_INDIRECT_NODE: + f2fs_set_main_bitmap(sbi, ni.blk_addr, + CURSEG_COLD_NODE); + fsck_chk_idnode_blk(sbi, inode, ftype, node_blk, + blk_cnt, cbc, child); + break; + case TYPE_DOUBLE_INDIRECT_NODE: + f2fs_set_main_bitmap(sbi, ni.blk_addr, + CURSEG_COLD_NODE); + fsck_chk_didnode_blk(sbi, inode, ftype, node_blk, + blk_cnt, cbc, child); + break; + default: + ASSERT(0); + } + } + free(node_blk); + return 0; +err: + free(node_blk); + return -EINVAL; +} + +int fsck_chk_root_inode(struct f2fs_sb_info *sbi) +{ + struct f2fs_node *node_blk; + int segment_count = SM_I(sbi)->main_segments; + int segno; + bool valid_bitmap = true; + block_t last_blkaddr = NULL_ADDR; + nid_t root_ino = sbi->root_ino_num; + u64 last_ctime = 0; + u32 last_ctime_nsec = 0; + int ret = -EINVAL; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + MSG(0, "Info: root inode is corrupted, search and relink it\n"); + +retry: + for (segno = 0; segno < segment_count; segno++) { + struct seg_entry *se = get_seg_entry(sbi, segno); + block_t blkaddr = START_BLOCK(sbi, segno); + int ret; + int i; + + if (IS_DATASEG(se->type)) + continue; + + dev_readahead(blkaddr << F2FS_BLKSIZE_BITS, + sbi->blocks_per_seg << F2FS_BLKSIZE_BITS); + + for (i = 0; i < sbi->blocks_per_seg; i++, blkaddr++) { + if (valid_bitmap ^ is_sit_bitmap_set(sbi, blkaddr)) + continue; + + ret = dev_read_block(node_blk, blkaddr); + ASSERT(ret >= 0); + + if (le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino) != + root_ino || + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid) != + root_ino) + continue; + + if (!IS_INODE(node_blk)) + continue; + + if (le32_to_cpu(node_blk->i.i_generation) || + le32_to_cpu(node_blk->i.i_namelen)) + continue; + break; + } + + if (i == sbi->blocks_per_seg) + continue; + + if (valid_bitmap) { + last_blkaddr = blkaddr; + MSG(0, "Info: possible root inode blkaddr: 0x%x\n", + last_blkaddr); + goto fix; + } + + if (last_blkaddr == NULL_ADDR) + goto init; + if (le64_to_cpu(node_blk->i.i_ctime) < last_ctime) + continue; + if (le64_to_cpu(node_blk->i.i_ctime) == last_ctime && + le32_to_cpu(node_blk->i.i_ctime_nsec) <= + last_ctime_nsec) + continue; +init: + last_blkaddr = blkaddr; + last_ctime = le64_to_cpu(node_blk->i.i_ctime); + last_ctime_nsec = le32_to_cpu(node_blk->i.i_ctime_nsec); + + MSG(0, "Info: possible root inode blkaddr: %u\n", + last_blkaddr); + } + + if (valid_bitmap) { + valid_bitmap = false; + goto retry; + } +fix: + if (!last_blkaddr) { + MSG(0, "Info: there is no valid root inode\n"); + } else if (c.fix_on) { + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + FIX_MSG("Relink root inode, blkaddr: 0x%x", last_blkaddr); + update_nat_blkaddr(sbi, root_ino, root_ino, last_blkaddr); + + if (f2fs_test_bit(root_ino, fsck->nat_area_bitmap)) + f2fs_clear_bit(root_ino, fsck->nat_area_bitmap); + fsck->chk.valid_nat_entry_cnt++; + + if (!f2fs_test_sit_bitmap(sbi, last_blkaddr)) + f2fs_set_sit_bitmap(sbi, last_blkaddr); + ret = 0; + } + free(node_blk); + return ret; +} + +static inline void get_extent_info(struct extent_info *ext, + struct f2fs_extent *i_ext) +{ + ext->fofs = le32_to_cpu(i_ext->fofs); + ext->blk = le32_to_cpu(i_ext->blk_addr); + ext->len = le32_to_cpu(i_ext->len); +} + +static void check_extent_info(struct child_info *child, + block_t blkaddr, int last) +{ + struct extent_info *ei = &child->ei; + u32 pgofs = child->pgofs; + int is_hole = 0; + + if (!ei->len) + return; + + if (child->state & FSCK_UNMATCHED_EXTENT) + return; + + if ((child->state & FSCK_INLINE_INODE) && ei->len) + goto unmatched; + + if (last) { + /* hole exist in the back of extent */ + if (child->last_blk != ei->blk + ei->len - 1) + child->state |= FSCK_UNMATCHED_EXTENT; + return; + } + + if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) + is_hole = 1; + + if (pgofs >= ei->fofs && pgofs < ei->fofs + ei->len) { + /* unmatched blkaddr */ + if (is_hole || (blkaddr != pgofs - ei->fofs + ei->blk)) + goto unmatched; + + if (!child->last_blk) { + /* hole exists in the front of extent */ + if (pgofs != ei->fofs) + goto unmatched; + } else if (child->last_blk + 1 != blkaddr) { + /* hole exists in the middle of extent */ + goto unmatched; + } + child->last_blk = blkaddr; + return; + } + + if (is_hole) + return; + + if (blkaddr < ei->blk || blkaddr >= ei->blk + ei->len) + return; + /* unmatched file offset */ +unmatched: + child->state |= FSCK_UNMATCHED_EXTENT; +} + +void fsck_reada_node_block(struct f2fs_sb_info *sbi, u32 nid) +{ + struct node_info ni; + + if (nid != 0 && IS_VALID_NID(sbi, nid)) { + get_node_info(sbi, nid, &ni); + if (f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) + dev_reada_block(ni.blk_addr); + } +} + +void fsck_reada_all_direct_node_blocks(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk) +{ + int i; + + for (i = 0; i < NIDS_PER_BLOCK; i++) { + u32 nid = le32_to_cpu(node_blk->in.nid[i]); + + fsck_reada_node_block(sbi, nid); + } +} + +static bool is_zeroed(const u8 *p, size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) { + if (p[i]) + return false; + } + return true; +} + +int chk_extended_attributes(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_node *inode) +{ + void *xattr; + void *last_base_addr; + struct f2fs_xattr_entry *ent; + __u32 xattr_size = XATTR_SIZE(&inode->i); + bool need_fix = false; + + if (xattr_size == 0) + return 0; + + xattr = read_all_xattrs(sbi, inode, false); + ASSERT(xattr); + + last_base_addr = (void *)xattr + xattr_size; + + list_for_each_xattr(ent, xattr) { + if ((void *)(ent) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) { + ASSERT_MSG("[0x%x] last xattr entry (offset: %lx) " + "crosses the boundary", + nid, (long int)((void *)ent - xattr)); + need_fix = true; + break; + } + } + if (!need_fix && + !is_zeroed((u8 *)ent, (u8 *)last_base_addr - (u8 *)ent)) { + ASSERT_MSG("[0x%x] nonzero bytes in xattr space after " + "end of list", nid); + need_fix = true; + } + if ((time_to_inject(FAULT_XATTR_ENT) || need_fix) && c.fix_on) { + memset(ent, 0, (u8 *)last_base_addr - (u8 *)ent); + write_all_xattrs(sbi, inode, xattr_size, xattr); + FIX_MSG("[0x%x] nullify wrong xattr entries", nid); + free(xattr); + return 1; + } + free(xattr); + return 0; +} + +/* start with valid nid and blkaddr */ +void fsck_chk_inode_blk(struct f2fs_sb_info *sbi, u32 nid, + enum FILE_TYPE ftype, struct f2fs_node *node_blk, + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct node_info *ni, struct child_info *child_d) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct child_info child; + enum NODE_TYPE ntype; + u32 i_links = le32_to_cpu(node_blk->i.i_links); + u64 i_size = le64_to_cpu(node_blk->i.i_size); + u64 i_blocks = le64_to_cpu(node_blk->i.i_blocks); + bool compr_supported = c.feature & F2FS_FEATURE_COMPRESSION; + u32 i_flags = le32_to_cpu(node_blk->i.i_flags); + bool compressed = i_flags & F2FS_COMPR_FL; + bool compr_rel = node_blk->i.i_inline & F2FS_COMPRESS_RELEASED; + u64 i_compr_blocks = le64_to_cpu(node_blk->i.i_compr_blocks); + nid_t i_xattr_nid = le32_to_cpu(node_blk->i.i_xattr_nid); + int ofs; + char *en; + u32 namelen; + unsigned int addrs, idx = 0; + unsigned short i_gc_failures; + int need_fix = 0; + int ret; + u32 cluster_size = 1 << node_blk->i.i_log_cluster_size; + bool is_aliasing = IS_DEVICE_ALIASING(&node_blk->i); + + if (!compressed) + goto check_next; + + if (time_to_inject(FAULT_COMPR) || !compr_supported || + (node_blk->i.i_inline & F2FS_INLINE_DATA)) { + /* + * The 'compression' flag in i_flags affects the traverse of + * the node tree. Thus, it must be fixed unconditionally + * in the memory (node_blk). + */ + i_flags &= ~F2FS_COMPR_FL; + compressed = false; + if (c.fix_on) { + need_fix = 1; + FIX_MSG("[0x%x] i_flags=0x%x -> 0x%x", + nid, node_blk->i.i_flags, i_flags); + } + node_blk->i.i_flags = cpu_to_le32(i_flags); + } +check_next: + memset(&child, 0, sizeof(child)); + child.links = 2; + child.p_ino = nid; + child.pp_ino = le32_to_cpu(node_blk->i.i_pino); + child.dir_level = node_blk->i.i_dir_level; + + if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) + fsck->chk.valid_inode_cnt++; + + if (ftype == F2FS_FT_DIR) { + f2fs_set_main_bitmap(sbi, ni->blk_addr, CURSEG_HOT_NODE); + namelen = le32_to_cpu(node_blk->i.i_namelen); + if (namelen > F2FS_NAME_LEN) + namelen = F2FS_NAME_LEN; + memcpy(child.p_name, node_blk->i.i_name, namelen); + } else { + if (f2fs_test_main_bitmap(sbi, ni->blk_addr) == 0) { + f2fs_set_main_bitmap(sbi, ni->blk_addr, + CURSEG_WARM_NODE); + + if (time_to_inject(FAULT_INODE) || + (i_links == 0 && (ftype == F2FS_FT_CHRDEV || + ftype == F2FS_FT_BLKDEV || + ftype == F2FS_FT_FIFO || + ftype == F2FS_FT_SOCK || + ftype == F2FS_FT_SYMLINK || + ftype == F2FS_FT_REG_FILE))) { + ASSERT_MSG("ino: 0x%x ftype: %d has i_links: %u", + nid, ftype, i_links); + if (c.fix_on) { + node_blk->i.i_links = cpu_to_le32(1); + need_fix = 1; + FIX_MSG("ino: 0x%x ftype: %d fix i_links: %u -> 1", + nid, ftype, i_links); + } + } + if (i_links > 1 && ftype != F2FS_FT_ORPHAN && + !is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) { + /* First time. Create new hard link node */ + add_into_hard_link_list(sbi, nid, i_links); + fsck->chk.multi_hard_link_files++; + } + } else { + DBG(3, "[0x%x] has hard links [0x%x]\n", nid, i_links); + if (find_and_dec_hard_link_list(sbi, nid)) { + ASSERT_MSG("[0x%x] needs more i_links=0x%x", + nid, i_links); + if (c.fix_on) { + node_blk->i.i_links = + cpu_to_le32(i_links + 1); + need_fix = 1; + FIX_MSG("File: 0x%x " + "i_links= 0x%x -> 0x%x", + nid, i_links, i_links + 1); + } + goto skip_blkcnt_fix; + } + /* No need to go deep into the node */ + return; + } + } + + /* readahead xattr node block */ + fsck_reada_node_block(sbi, i_xattr_nid); + + if (fsck_chk_xattr_blk(sbi, nid, i_xattr_nid, blk_cnt)) { + if (c.fix_on) { + node_blk->i.i_xattr_nid = 0; + need_fix = 1; + FIX_MSG("Remove xattr block: 0x%x, x_nid = 0x%x", + nid, i_xattr_nid); + } + } + + if (ftype == F2FS_FT_CHRDEV || ftype == F2FS_FT_BLKDEV || + ftype == F2FS_FT_FIFO || ftype == F2FS_FT_SOCK) + goto check; + + /* init extent info */ + get_extent_info(&child.ei, &node_blk->i.i_ext); + child.last_blk = 0; + + if (f2fs_has_extra_isize(&node_blk->i)) { + if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { + unsigned int isize = + le16_to_cpu(node_blk->i.i_extra_isize); + if (time_to_inject(FAULT_INODE) || + (isize > 4 * DEF_ADDRS_PER_INODE)) { + ASSERT_MSG("[0x%x] wrong i_extra_isize=0x%x", + nid, isize); + if (c.fix_on) { + FIX_MSG("ino[0x%x] recover i_extra_isize " + "from %u to %u", + nid, isize, + calc_extra_isize()); + node_blk->i.i_extra_isize = + cpu_to_le16(calc_extra_isize()); + need_fix = 1; + } + } + } else { + ASSERT_MSG("[0x%x] wrong extra_attr flag", nid); + if (c.fix_on) { + FIX_MSG("ino[0x%x] remove F2FS_EXTRA_ATTR " + "flag in i_inline:%u", + nid, node_blk->i.i_inline); + /* we don't support tuning F2FS_FEATURE_EXTRA_ATTR now */ + node_blk->i.i_inline &= ~F2FS_EXTRA_ATTR; + need_fix = 1; + } + } + + if ((c.feature & F2FS_FEATURE_FLEXIBLE_INLINE_XATTR) && + (node_blk->i.i_inline & F2FS_INLINE_XATTR)) { + unsigned int inline_size = + le16_to_cpu(node_blk->i.i_inline_xattr_size); + + if (time_to_inject(FAULT_INODE) || + (!inline_size || + inline_size > MAX_INLINE_XATTR_SIZE)) { + ASSERT_MSG("[0x%x] wrong inline_xattr_size:%u", + nid, inline_size); + if (c.fix_on) { + FIX_MSG("ino[0x%x] recover inline xattr size " + "from %u to %u", + nid, inline_size, + DEFAULT_INLINE_XATTR_ADDRS); + node_blk->i.i_inline_xattr_size = + cpu_to_le16(DEFAULT_INLINE_XATTR_ADDRS); + need_fix = 1; + } + } + } + } + ofs = get_extra_isize(node_blk); + + if (time_to_inject(FAULT_INODE) || + ((node_blk->i.i_flags & cpu_to_le32(F2FS_CASEFOLD_FL)) && + (!S_ISDIR(le16_to_cpu(node_blk->i.i_mode)) || + !(c.feature & F2FS_FEATURE_CASEFOLD)))) { + ASSERT_MSG("[0x%x] unexpected casefold flag", nid); + if (c.fix_on) { + FIX_MSG("ino[0x%x] clear casefold flag", nid); + i_flags &= ~F2FS_CASEFOLD_FL; + node_blk->i.i_flags = cpu_to_le32(i_flags); + need_fix = 1; + } + } + + if (chk_extended_attributes(sbi, nid, node_blk)) + need_fix = 1; + + if ((node_blk->i.i_inline & F2FS_INLINE_DATA)) { + unsigned int inline_size = MAX_INLINE_DATA(node_blk); + if (cur_qtype != -1) + qf_szchk_type[cur_qtype] = QF_SZCHK_INLINE; + block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs]); + + if (time_to_inject(FAULT_INODE) || + (blkaddr != NULL_ADDR)) { + ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", + nid, blkaddr); + if (c.fix_on) { + FIX_MSG("inline_data has wrong 0'th block = %x", + blkaddr); + node_blk->i.i_addr[ofs] = NULL_ADDR; + node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); + need_fix = 1; + } + } + if (time_to_inject(FAULT_INODE) || + (i_size > inline_size)) { + ASSERT_MSG("[0x%x] wrong inline size:%lu", + nid, (unsigned long)i_size); + if (c.fix_on) { + node_blk->i.i_size = cpu_to_le64(inline_size); + FIX_MSG("inline_data has wrong i_size %lu", + (unsigned long)i_size); + need_fix = 1; + } + } + if (!(node_blk->i.i_inline & F2FS_DATA_EXIST)) { + if (!is_zeroed(inline_data_addr(node_blk), + MAX_INLINE_DATA(node_blk))) { + ASSERT_MSG("[0x%x] junk inline data", nid); + if (c.fix_on) { + FIX_MSG("inline_data has DATA_EXIST"); + node_blk->i.i_inline |= F2FS_DATA_EXIST; + need_fix = 1; + } + } + } + DBG(3, "ino[0x%x] has inline data!\n", nid); + child.state |= FSCK_INLINE_INODE; + goto check; + } + + if ((node_blk->i.i_inline & F2FS_INLINE_DENTRY)) { + block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs]); + + DBG(3, "ino[0x%x] has inline dentry!\n", nid); + if (time_to_inject(FAULT_INODE) || (blkaddr != 0)) { + ASSERT_MSG("[0x%x] wrong inline reserve blkaddr:%u", + nid, blkaddr); + if (c.fix_on) { + FIX_MSG("inline_dentry has wrong 0'th block = %x", + blkaddr); + node_blk->i.i_addr[ofs] = NULL_ADDR; + node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); + need_fix = 1; + } + } + + ret = fsck_chk_inline_dentries(sbi, node_blk, &child); + if (ret < 0) { + if (c.fix_on) + need_fix = 1; + } + child.state |= FSCK_INLINE_INODE; + goto check; + } + + /* check data blocks in inode */ + addrs = ADDRS_PER_INODE(&node_blk->i); + if (cur_qtype != -1) { + u64 addrs_per_blk = (u64)ADDRS_PER_BLOCK(&node_blk->i); + qf_szchk_type[cur_qtype] = QF_SZCHK_REGFILE; + qf_maxsize[cur_qtype] = (u64)(addrs + 2 * addrs_per_blk + + 2 * addrs_per_blk * NIDS_PER_BLOCK + + addrs_per_blk * NIDS_PER_BLOCK * + NIDS_PER_BLOCK) * F2FS_BLKSIZE; + } + + if (is_aliasing) { + struct extent_info ei; + + get_extent_info(&ei, &node_blk->i.i_ext); + for (idx = 0; idx < ei.len; idx++, child.pgofs++) { + block_t blkaddr = ei.blk + idx; + + /* check extent info */ + check_extent_info(&child, blkaddr, 0); + ret = fsck_chk_data_blk(sbi, &node_blk->i, blkaddr, + &child, (i_blocks == *blk_cnt), ftype, nid, + idx, ni->version, node_blk); + if (!ret) { + *blk_cnt = *blk_cnt + 1; + if (cur_qtype != -1) + qf_last_blkofs[cur_qtype] = child.pgofs; + } else if (c.fix_on) { + node_blk->i.i_ext.len = cpu_to_le32(idx); + need_fix = 1; + break; + } + } + + goto check; + } + + for (idx = 0; idx < addrs; idx++, child.pgofs++) { + block_t blkaddr = le32_to_cpu(node_blk->i.i_addr[ofs + idx]); + + /* check extent info */ + check_extent_info(&child, blkaddr, 0); + + if (blkaddr == NULL_ADDR) + continue; + if (blkaddr == COMPRESS_ADDR) { + if (!compressed || (child.pgofs & + (cluster_size - 1)) != 0) { + if (c.fix_on) { + node_blk->i.i_addr[ofs + idx] = + NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] i_addr[%d] = NULL_ADDR", + nid, ofs + idx); + } + continue; + } + if (!compr_rel) { + fsck->chk.valid_blk_cnt++; + *blk_cnt = *blk_cnt + 1; + cbc->cheader_pgofs = child.pgofs; + cbc->cnt++; + } + continue; + } + if (!compr_rel && blkaddr == NEW_ADDR && + child.pgofs - cbc->cheader_pgofs < cluster_size) + cbc->cnt++; + ret = fsck_chk_data_blk(sbi, + &node_blk->i, + blkaddr, + &child, (i_blocks == *blk_cnt), + ftype, nid, idx, ni->version, + node_blk); + if (blkaddr != le32_to_cpu(node_blk->i.i_addr[ofs + idx])) + need_fix = 1; + if (!ret) { + *blk_cnt = *blk_cnt + 1; + if (cur_qtype != -1 && blkaddr != NEW_ADDR) + qf_last_blkofs[cur_qtype] = child.pgofs; + } else if (c.fix_on) { + node_blk->i.i_addr[ofs + idx] = NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] i_addr[%d] = NULL_ADDR", nid, ofs + idx); + } + } + + /* readahead node blocks */ + for (idx = 0; idx < 5; idx++) { + u32 nid = le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, idx)); + fsck_reada_node_block(sbi, nid); + } + + /* check node blocks in inode */ + for (idx = 0; idx < 5; idx++) { + nid_t i_nid = le32_to_cpu(F2FS_INODE_I_NID(&node_blk->i, idx)); + + if (idx == 0 || idx == 1) + ntype = TYPE_DIRECT_NODE; + else if (idx == 2 || idx == 3) + ntype = TYPE_INDIRECT_NODE; + else if (idx == 4) + ntype = TYPE_DOUBLE_INDIRECT_NODE; + else + ASSERT(0); + + if (i_nid == 0x0) + goto skip; + + ret = fsck_chk_node_blk(sbi, &node_blk->i, i_nid, + ftype, ntype, blk_cnt, cbc, &child); + if (!ret) { + *blk_cnt = *blk_cnt + 1; + } else if (ret == -EINVAL) { + if (c.fix_on) { + F2FS_INODE_I_NID(&node_blk->i, idx) = 0; + need_fix = 1; + FIX_MSG("[0x%x] i_nid[%d] = 0", nid, idx); + } +skip: + if (ntype == TYPE_DIRECT_NODE) + child.pgofs += ADDRS_PER_BLOCK(&node_blk->i); + else if (ntype == TYPE_INDIRECT_NODE) + child.pgofs += ADDRS_PER_BLOCK(&node_blk->i) * + NIDS_PER_BLOCK; + else + child.pgofs += ADDRS_PER_BLOCK(&node_blk->i) * + NIDS_PER_BLOCK * NIDS_PER_BLOCK; + } + + } + +check: + /* check uncovered range in the back of extent */ + check_extent_info(&child, 0, 1); + + if (child.state & FSCK_UNMATCHED_EXTENT) { + ASSERT_MSG("ino: 0x%x has wrong ext: [pgofs:%u, blk:%u, len:%u]", + nid, child.ei.fofs, child.ei.blk, child.ei.len); + if (c.fix_on) + need_fix = 1; + } + + if (i_blocks != *blk_cnt) { + ASSERT_MSG("ino: 0x%x has i_blocks: 0x%08"PRIx64", " + "but has 0x%x blocks", + nid, i_blocks, *blk_cnt); + if (c.fix_on) { + node_blk->i.i_blocks = cpu_to_le64(*blk_cnt); + need_fix = 1; + FIX_MSG("[0x%x] i_blocks=0x%08"PRIx64" -> 0x%x", + nid, i_blocks, *blk_cnt); + } + } + + if (compressed && i_compr_blocks != cbc->cnt) { + if (c.fix_on) { + node_blk->i.i_compr_blocks = cpu_to_le64(cbc->cnt); + need_fix = 1; + FIX_MSG("[0x%x] i_compr_blocks=0x%08"PRIx64" -> 0x%x", + nid, i_compr_blocks, cbc->cnt); + } + } + +skip_blkcnt_fix: + en = malloc(F2FS_PRINT_NAMELEN); + ASSERT(en); + + namelen = le32_to_cpu(node_blk->i.i_namelen); + if (namelen > F2FS_NAME_LEN) { + if (child_d && child_d->i_namelen <= F2FS_NAME_LEN) { + ASSERT_MSG("ino: 0x%x has i_namelen: 0x%x, " + "but has %d characters for name", + nid, namelen, child_d->i_namelen); + if (c.fix_on) { + FIX_MSG("[0x%x] i_namelen=0x%x -> 0x%x", nid, namelen, + child_d->i_namelen); + node_blk->i.i_namelen = cpu_to_le32(child_d->i_namelen); + need_fix = 1; + } + namelen = child_d->i_namelen; + } else + namelen = F2FS_NAME_LEN; + } + pretty_print_filename(node_blk->i.i_name, namelen, en, + file_enc_name(&node_blk->i)); + if (ftype == F2FS_FT_ORPHAN) + DBG(1, "Orphan Inode: 0x%x [%s] i_blocks: %u\n\n", + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), + en, (u32)i_blocks); + + if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) + DBG(1, "Quota Inode: 0x%x [%s] i_blocks: %u\n\n", + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), + en, (u32)i_blocks); + + if (ftype == F2FS_FT_DIR) { + DBG(1, "Directory Inode: 0x%x [%s] depth: %d has %d files\n\n", + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), en, + le32_to_cpu(node_blk->i.i_current_depth), + child.files); + + if (i_links != child.links) { + ASSERT_MSG("ino: 0x%x i_links: %u, real links: %u", + nid, i_links, child.links); + if (c.fix_on) { + node_blk->i.i_links = cpu_to_le32(child.links); + need_fix = 1; + FIX_MSG("Dir: 0x%x i_links= 0x%x -> 0x%x", + nid, i_links, child.links); + } + } + if (child.dot == 0 || child.dotdot == 0) { + ASSERT_MSG("ino: 0x%x has no '.' and/or '..' dirents, dot: %u, dotdot: %u", + nid, child.dot, child.dotdot); + if (c.fix_on) { + umode_t mode = le16_to_cpu(node_blk->i.i_mode); + + ret = convert_inline_dentry(sbi, node_blk, + &ni->blk_addr); + FIX_MSG("convert inline dentry ino: %u, pino: %u, ret: %d", + nid, child_d->p_ino, ret); + if (ret) + goto skip_dot_fix; + + if (child.dot == 0) { + char *name = "."; + + ret = f2fs_add_link(sbi, node_blk, + (const unsigned char *)name, + 1, nid, map_de_type(mode), + &ni->blk_addr, 0); + FIX_MSG("add missing '%s' dirent in ino: %u, pino: %u, ret:%d", + name, nid, child_d->p_ino, ret); + if (ret) + goto skip_dot_fix; + } + + if (child.dotdot == 0) { + char *name = ".."; + + ret = f2fs_add_link(sbi, node_blk, + (const unsigned char *)name, + 2, child_d->p_ino, + map_de_type(mode), + &ni->blk_addr, 0); + FIX_MSG("add missing '%s' dirent in ino: %u, pino: %u, ret:%d", + name, nid, child_d->p_ino, ret); + if (ret) + goto skip_dot_fix; + } + + need_fix = 1; + } + } + } +skip_dot_fix: + + i_gc_failures = le16_to_cpu(node_blk->i.i_gc_failures); + + /* + * old kernel initialized i_gc_failures as 0x01, in preen mode 2, + * let's skip repairing. + */ + if (ftype == F2FS_FT_REG_FILE && i_gc_failures && + (c.preen_mode != PREEN_MODE_2 || i_gc_failures != 0x01)) { + + DBG(1, "Regular Inode: 0x%x [%s] depth: %d\n\n", + le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), en, + i_gc_failures); + + if (c.fix_on) { + node_blk->i.i_gc_failures = cpu_to_le16(0); + need_fix = 1; + INFO_MSG("Regular: 0x%x reset i_gc_failures from 0x%x to 0x00", + nid, i_gc_failures); + } + } + + free(en); + + if (ftype == F2FS_FT_SYMLINK && i_size == 0 && + i_blocks == (i_xattr_nid ? 3 : 2)) { + node_blk->i.i_size = cpu_to_le64(F2FS_BLKSIZE); + need_fix = 1; + FIX_MSG("Symlink: recover 0x%x with i_size=%lu", + nid, (unsigned long)F2FS_BLKSIZE); + } + + if (ftype == F2FS_FT_ORPHAN && i_links) { + ASSERT_MSG("ino: 0x%x is orphan inode, but has i_links: %u", + nid, i_links); + if (c.fix_on) { + node_blk->i.i_links = 0; + need_fix = 1; + FIX_MSG("ino: 0x%x orphan_inode, i_links= 0x%x -> 0", + nid, i_links); + } + } + + /* drop extent information to avoid potential wrong access */ + if (need_fix && f2fs_dev_is_writable() && !is_aliasing) + node_blk->i.i_ext.len = 0; + + if ((c.feature & F2FS_FEATURE_INODE_CHKSUM) && + f2fs_has_extra_isize(&node_blk->i)) { + __u32 provided, calculated; + + provided = le32_to_cpu(node_blk->i.i_inode_checksum); + calculated = f2fs_inode_chksum(node_blk); + + if (provided != calculated) { + ASSERT_MSG("ino: 0x%x chksum:0x%x, but calculated one is: 0x%x", + nid, provided, calculated); + if (c.fix_on) { + node_blk->i.i_inode_checksum = + cpu_to_le32(calculated); + need_fix = 1; + FIX_MSG("ino: 0x%x recover, i_inode_checksum= 0x%x -> 0x%x", + nid, provided, calculated); + } + } + } + + if (need_fix && f2fs_dev_is_writable()) { + ret = update_block(sbi, node_blk, &ni->blk_addr, NULL); + ASSERT(ret >= 0); + } +} + +int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, + u32 nid, enum FILE_TYPE ftype, struct f2fs_node *node_blk, + u32 *blk_cnt, struct f2fs_compr_blk_cnt *cbc, + struct child_info *child, struct node_info *ni) +{ + int idx, ret; + int need_fix = 0; + child->p_ino = nid; + child->pp_ino = le32_to_cpu(inode->i_pino); + u32 i_flags = le32_to_cpu(inode->i_flags); + bool compressed = i_flags & F2FS_COMPR_FL; + bool compr_rel = inode->i_inline & F2FS_COMPRESS_RELEASED; + u32 cluster_size = 1 << inode->i_log_cluster_size; + + for (idx = 0; idx < ADDRS_PER_BLOCK(inode); idx++, child->pgofs++) { + block_t blkaddr = le32_to_cpu(node_blk->dn.addr[idx]); + + check_extent_info(child, blkaddr, 0); + + if (blkaddr == NULL_ADDR) + continue; + if (blkaddr == COMPRESS_ADDR) { + if (!compressed || (child->pgofs & + (cluster_size - 1)) != 0) { + if (c.fix_on) { + node_blk->dn.addr[idx] = NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, + idx); + } + continue; + } + if (!compr_rel) { + F2FS_FSCK(sbi)->chk.valid_blk_cnt++; + *blk_cnt = *blk_cnt + 1; + cbc->cheader_pgofs = child->pgofs; + cbc->cnt++; + } + continue; + } + if (!compr_rel && blkaddr == NEW_ADDR && child->pgofs - + cbc->cheader_pgofs < cluster_size) + cbc->cnt++; + ret = fsck_chk_data_blk(sbi, inode, blkaddr, child, + le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype, + nid, idx, ni->version, node_blk); + if (blkaddr != le32_to_cpu(node_blk->dn.addr[idx])) + need_fix = 1; + if (!ret) { + *blk_cnt = *blk_cnt + 1; + if (cur_qtype != -1 && blkaddr != NEW_ADDR) + qf_last_blkofs[cur_qtype] = child->pgofs; + } else if (c.fix_on) { + node_blk->dn.addr[idx] = NULL_ADDR; + need_fix = 1; + FIX_MSG("[0x%x] dn.addr[%d] = 0", nid, idx); + } + } + if (need_fix && f2fs_dev_is_writable()) { + ret = update_block(sbi, node_blk, &ni->blk_addr, NULL); + ASSERT(ret >= 0); + } + return 0; +} + +int fsck_chk_idnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, + enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, + struct f2fs_compr_blk_cnt *cbc, struct child_info *child) +{ + int need_fix = 0, ret; + int i = 0; + + fsck_reada_all_direct_node_blocks(sbi, node_blk); + + for (i = 0; i < NIDS_PER_BLOCK; i++) { + if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) + goto skip; + ret = fsck_chk_node_blk(sbi, inode, + le32_to_cpu(node_blk->in.nid[i]), + ftype, TYPE_DIRECT_NODE, blk_cnt, + cbc, child); + if (!ret) + *blk_cnt = *blk_cnt + 1; + else if (ret == -EINVAL) { + if (!c.fix_on) + printf("should delete in.nid[i] = 0;\n"); + else { + node_blk->in.nid[i] = 0; + need_fix = 1; + FIX_MSG("Set indirect node 0x%x -> 0", i); + } +skip: + child->pgofs += ADDRS_PER_BLOCK(inode); + } + } + + if (need_fix && f2fs_dev_is_writable()) { + struct node_info ni; + nid_t nid = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid); + + get_node_info(sbi, nid, &ni); + ret = update_block(sbi, node_blk, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + } + + return 0; +} + +int fsck_chk_didnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, + enum FILE_TYPE ftype, struct f2fs_node *node_blk, u32 *blk_cnt, + struct f2fs_compr_blk_cnt *cbc, struct child_info *child) +{ + int i = 0; + int need_fix = 0, ret = 0; + + fsck_reada_all_direct_node_blocks(sbi, node_blk); + + for (i = 0; i < NIDS_PER_BLOCK; i++) { + if (le32_to_cpu(node_blk->in.nid[i]) == 0x0) + goto skip; + ret = fsck_chk_node_blk(sbi, inode, + le32_to_cpu(node_blk->in.nid[i]), + ftype, TYPE_INDIRECT_NODE, blk_cnt, cbc, child); + if (!ret) + *blk_cnt = *blk_cnt + 1; + else if (ret == -EINVAL) { + if (!c.fix_on) + printf("should delete in.nid[i] = 0;\n"); + else { + node_blk->in.nid[i] = 0; + need_fix = 1; + FIX_MSG("Set double indirect node 0x%x -> 0", i); + } +skip: + child->pgofs += ADDRS_PER_BLOCK(inode) * NIDS_PER_BLOCK; + } + } + + if (need_fix && f2fs_dev_is_writable()) { + struct node_info ni; + nid_t nid = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid); + + get_node_info(sbi, nid, &ni); + ret = update_block(sbi, node_blk, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + } + + return 0; +} + +static const char *lookup_table = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + +/** + * base64_encode() - + * + * Encodes the input string using characters from the set [A-Za-z0-9+,]. + * The encoded string is roughly 4/3 times the size of the input string. + */ +static int base64_encode(const u8 *src, int len, char *dst) +{ + int i, bits = 0, ac = 0; + char *cp = dst; + + for (i = 0; i < len; i++) { + ac += src[i] << bits; + bits += 8; + do { + *cp++ = lookup_table[ac & 0x3f]; + ac >>= 6; + bits -= 6; + } while (bits >= 6); + } + if (bits) + *cp++ = lookup_table[ac & 0x3f]; + return cp - dst; +} + +void pretty_print_filename(const u8 *raw_name, u32 len, + char out[F2FS_PRINT_NAMELEN], int enc_name) +{ + len = min(len, (u32)F2FS_NAME_LEN); + + if (enc_name) + len = base64_encode(raw_name, len, out); + else + memcpy(out, raw_name, len); + out[len] = 0; +} + +static void print_dentry(struct f2fs_sb_info *sbi, __u8 *name, + u8 *bitmap, struct f2fs_dir_entry *dentry, + int max, int idx, int last_blk, int enc_name) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + u32 depth = fsck->dentry_depth; + int last_de = 0; + int next_idx = 0; + u32 name_len; + unsigned int i; + int bit_offset; + char new[F2FS_PRINT_NAMELEN]; + + if (!c.show_dentry && !c.show_file_map) + return; + + name_len = le16_to_cpu(dentry[idx].name_len); + next_idx = idx + (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; + + bit_offset = find_next_bit_le(bitmap, max, next_idx); + if (bit_offset >= max && last_blk) + last_de = 1; + + if (tree_mark_size <= depth) { + tree_mark_size *= 2; + ASSERT(tree_mark_size != 0); + tree_mark = realloc(tree_mark, tree_mark_size); + ASSERT(tree_mark != NULL); + } + + if (last_de) + tree_mark[depth] = '`'; + else + tree_mark[depth] = '|'; + + if (tree_mark[depth - 1] == '`') + tree_mark[depth - 1] = ' '; + + pretty_print_filename(name, name_len, new, enc_name); + + if (c.show_file_map) { + struct f2fs_dentry *d = fsck->dentry; + + if (dentry[idx].file_type != F2FS_FT_REG_FILE) + return; + + while (d) { + if (d->depth > 1) + printf("/%s", d->name); + d = d->next; + } + printf("/%s", new); + if (dump_node(sbi, le32_to_cpu(dentry[idx].ino), 0, NULL, 0, 0, NULL)) + printf("\33[2K\r"); + } else { + for (i = 1; i < depth; i++) + printf("%c ", tree_mark[i]); + + printf("%c-- %s , \n", + last_de ? '`' : '|', + new, le32_to_cpu(dentry[idx].ino), + enc_name); + } +} + +static int f2fs_check_hash_code(int encoding, int casefolded, + struct f2fs_dir_entry *dentry, + const unsigned char *name, u32 len, int enc_name) +{ + if (time_to_inject(FAULT_DENTRY)) { + ASSERT_MSG("%s is injected.", f2fs_fault_name[FAULT_DENTRY]); + return 1; + } + + /* Casefolded Encrypted names require a key to compute siphash */ + if (enc_name && casefolded) + return 0; + + f2fs_hash_t hash_code = f2fs_dentry_hash(encoding, casefolded, name, len); + /* fix hash_code made by old buggy code */ + if (dentry->hash_code != hash_code) { + char new[F2FS_PRINT_NAMELEN]; + + pretty_print_filename(name, len, new, enc_name); + + ASSERT_MSG("Mismatch hash_code for \"%s\" [%x:%x]", + new, le32_to_cpu(dentry->hash_code), + hash_code); + if (c.fix_on) { + FIX_MSG("Fix hash_code for \"%s\" from %x to %x", + new, le32_to_cpu(dentry->hash_code), + hash_code); + dentry->hash_code = cpu_to_le32(hash_code); + return 1; + } + return 0; + } + return 0; +} + + +static int __get_current_level(int dir_level, u32 pgofs) +{ + unsigned int bidx = 0; + int i; + + for (i = 0; i < MAX_DIR_HASH_DEPTH; i++) { + bidx += dir_buckets(i, dir_level) * bucket_blocks(i); + if (bidx > pgofs) + break; + } + return i; +} + +static int f2fs_check_dirent_position(const struct f2fs_dir_entry *dentry, + const char *printable_name, + u32 pgofs, u8 dir_level, u32 pino) +{ + unsigned int nbucket, nblock; + unsigned int bidx, end_block; + int level; + + level = __get_current_level(dir_level, pgofs); + + nbucket = dir_buckets(level, dir_level); + nblock = bucket_blocks(level); + + bidx = dir_block_index(level, dir_level, + le32_to_cpu(dentry->hash_code) % nbucket); + end_block = bidx + nblock; + + if (pgofs >= bidx && pgofs < end_block) + return 0; + + ASSERT_MSG("Wrong position of dirent pino:%u, name:%s, level:%d, " + "dir_level:%d, pgofs:%u, correct range:[%u, %u]\n", + pino, printable_name, level, dir_level, pgofs, bidx, + end_block - 1); + return 1; +} + +static int __chk_dots_dentries(struct f2fs_sb_info *sbi, + int casefolded, + struct f2fs_dir_entry *dentry, + struct child_info *child, + u8 *name, int len, + __u8 (*filename)[F2FS_SLOT_LEN], + int enc_name) +{ + int fixed = 0; + + if ((name[0] == '.' && len == 1)) { + if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) != child->p_ino)) { + ASSERT_MSG("Bad inode number[0x%x] for '.', parent_ino is [0x%x]\n", + le32_to_cpu(dentry->ino), child->p_ino); + dentry->ino = cpu_to_le32(child->p_ino); + fixed = 1; + } + } + + if (name[0] == '.' && name[1] == '.' && len == 2) { + if (child->p_ino == F2FS_ROOT_INO(sbi)) { + if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) != + F2FS_ROOT_INO(sbi))) { + ASSERT_MSG("Bad inode number[0x%x] for '..'\n", + le32_to_cpu(dentry->ino)); + dentry->ino = cpu_to_le32(F2FS_ROOT_INO(sbi)); + fixed = 1; + } + } else if (time_to_inject(FAULT_DENTRY) || + (le32_to_cpu(dentry->ino) != child->pp_ino)) { + ASSERT_MSG("Bad inode number[0x%x] for '..', parent parent ino is [0x%x]\n", + le32_to_cpu(dentry->ino), child->pp_ino); + dentry->ino = cpu_to_le32(child->pp_ino); + fixed = 1; + } + } + + if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry, name, len, enc_name)) + fixed = 1; + + if (time_to_inject(FAULT_DENTRY) || (name[len] != '\0')) { + ASSERT_MSG("'.' is not NULL terminated\n"); + name[len] = '\0'; + memcpy(*filename, name, len); + fixed = 1; + } + return fixed; +} + +static void nullify_dentry(struct f2fs_dir_entry *dentry, int offs, + __u8 (*filename)[F2FS_SLOT_LEN], u8 **bitmap) +{ + memset(dentry, 0, sizeof(struct f2fs_dir_entry)); + test_and_clear_bit_le(offs, *bitmap); + memset(*filename, 0, F2FS_SLOT_LEN); +} + +static int __chk_dentries(struct f2fs_sb_info *sbi, int casefolded, + struct child_info *child, + u8 *bitmap, struct f2fs_dir_entry *dentry, + __u8 (*filenames)[F2FS_SLOT_LEN], + int max, int last_blk, int enc_name) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + enum FILE_TYPE ftype; + int dentries = 0; + u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; + u8 *name; + char en[F2FS_PRINT_NAMELEN]; + u16 name_len; + int ret = 0; + int fixed = 0; + int i, slots; + + /* readahead inode blocks */ + for (i = 0; i < max; i++) { + u32 ino; + + if (test_bit_le(i, bitmap) == 0) + continue; + + ino = le32_to_cpu(dentry[i].ino); + + if (IS_VALID_NID(sbi, ino)) { + struct node_info ni; + + get_node_info(sbi, ino, &ni); + if (f2fs_is_valid_blkaddr(sbi, ni.blk_addr, + DATA_GENERIC)) { + dev_reada_block(ni.blk_addr); + name_len = le16_to_cpu(dentry[i].name_len); + if (name_len > 0) + i += (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN - 1; + } + } + } + + for (i = 0; i < max;) { + if (test_bit_le(i, bitmap) == 0) { + i++; + continue; + } + if (time_to_inject(FAULT_DENTRY) || + !IS_VALID_NID(sbi, le32_to_cpu(dentry[i].ino))) { + ASSERT_MSG("Bad dentry 0x%x with invalid NID/ino 0x%x", + i, le32_to_cpu(dentry[i].ino)); + if (c.fix_on) { + FIX_MSG("Clear bad dentry 0x%x with bad ino 0x%x", + i, le32_to_cpu(dentry[i].ino)); + test_and_clear_bit_le(i, bitmap); + fixed = 1; + } + i++; + continue; + } + + ftype = dentry[i].file_type; + if (time_to_inject(FAULT_DENTRY) || + (ftype <= F2FS_FT_UNKNOWN || + ftype > F2FS_FT_LAST_FILE_TYPE)) { + ASSERT_MSG("Bad dentry 0x%x with unexpected ftype 0x%x", + le32_to_cpu(dentry[i].ino), ftype); + if (c.fix_on) { + FIX_MSG("Clear bad dentry 0x%x with bad ftype 0x%x", + i, ftype); + test_and_clear_bit_le(i, bitmap); + fixed = 1; + } + i++; + continue; + } + + name_len = le16_to_cpu(dentry[i].name_len); + + if (time_to_inject(FAULT_DENTRY) || + (name_len == 0 || name_len > F2FS_NAME_LEN)) { + ASSERT_MSG("Bad dentry 0x%x with invalid name_len", i); + if (c.fix_on) { + FIX_MSG("Clear bad dentry 0x%x", i); + test_and_clear_bit_le(i, bitmap); + fixed = 1; + } + i++; + continue; + } + name = calloc(name_len + 1, 1); + ASSERT(name); + + memcpy(name, filenames[i], name_len); + slots = (name_len + F2FS_SLOT_LEN - 1) / F2FS_SLOT_LEN; + + /* Becareful. 'dentry.file_type' is not imode. */ + if (ftype == F2FS_FT_DIR) { + enum dot_type dot_type = NON_DOT; + + if (name[0] == '.' && name_len == 1) + dot_type = TYPE_DOT; + else if (name[0] == '.' && name[1] == '.' && + name_len == 2) + dot_type = TYPE_DOTDOT; + + if (dot_type != NON_DOT) { + bool need_del = false; + + DBG(3, "i:%u, dot_type:%u, ino:%u, p:%u, pp:%u\n", + i, dot_type, dentry[i].ino, + child->p_ino, child->pp_ino); + + ret = __chk_dots_dentries(sbi, casefolded, + &dentry[i], child, name, name_len, + &filenames[i], enc_name); + if (ret) + fixed = 1; + + if (dot_type == TYPE_DOT) { + if (child->dot == 0) + child->dot++; + else + need_del = true; + } else if (dot_type == TYPE_DOTDOT) { + if (child->dotdot == 0) + child->dotdot++; + else + need_del = true; + } + + if (need_del) { + ASSERT_MSG("More than one '%s', should delete the extra one, i: %u, ino:%u", + dot_type == TYPE_DOT ? "." : "..", + i, dentry[i].ino); + nullify_dentry(&dentry[i], i, + &filenames[i], &bitmap); + fixed = 1; + } + + i++; + free(name); + continue; + } + } + + if (f2fs_check_hash_code(get_encoding(sbi), casefolded, dentry + i, name, name_len, enc_name)) + fixed = 1; + + pretty_print_filename(name, name_len, en, enc_name); + + if (max == NR_DENTRY_IN_BLOCK) { + ret = f2fs_check_dirent_position(dentry + i, en, + child->pgofs, child->dir_level, + child->p_ino); + if (ret) { + if (c.fix_on) { + FIX_MSG("Clear bad dentry 0x%x", i); + test_and_clear_bit_le(i, bitmap); + fixed = 1; + } + i++; + free(name); + continue; + } + } + + DBG(1, "[%3u]-[0x%x] name[%s] len[0x%x] ino[0x%x] type[0x%x]\n", + fsck->dentry_depth, i, en, name_len, + le32_to_cpu(dentry[i].ino), + dentry[i].file_type); + + print_dentry(sbi, name, bitmap, + dentry, max, i, last_blk, enc_name); + + blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + child->i_namelen = name_len; + ret = fsck_chk_node_blk(sbi, + NULL, le32_to_cpu(dentry[i].ino), + ftype, TYPE_INODE, &blk_cnt, &cbc, child); + + if (ret && c.fix_on) { + int j; + + for (j = 0; j < slots; j++) + test_and_clear_bit_le(i + j, bitmap); + FIX_MSG("Unlink [0x%x] - %s len[0x%x], type[0x%x]", + le32_to_cpu(dentry[i].ino), + en, name_len, + dentry[i].file_type); + fixed = 1; + } else if (ret == 0) { + if (ftype == F2FS_FT_DIR) + child->links++; + dentries++; + child->files++; + } + + i += slots; + free(name); + } + return fixed ? -1 : dentries; +} + +int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk, struct child_info *child) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_dentry *cur_dentry = fsck->dentry_end; + struct f2fs_dentry *new_dentry; + struct f2fs_dentry_ptr d; + void *inline_dentry; + int dentries; + + inline_dentry = inline_data_addr(node_blk); + ASSERT(inline_dentry != NULL); + + make_dentry_ptr(&d, node_blk, inline_dentry, 2); + + fsck->dentry_depth++; + new_dentry = calloc(sizeof(struct f2fs_dentry), 1); + ASSERT(new_dentry != NULL); + + new_dentry->depth = fsck->dentry_depth; + memcpy(new_dentry->name, child->p_name, F2FS_NAME_LEN); + cur_dentry->next = new_dentry; + fsck->dentry_end = new_dentry; + + dentries = __chk_dentries(sbi, IS_CASEFOLDED(&node_blk->i), child, + d.bitmap, d.dentry, d.filename, d.max, 1, + file_is_encrypt(&node_blk->i));// pass through + if (dentries < 0) { + DBG(1, "[%3d] Inline Dentry Block Fixed hash_codes\n\n", + fsck->dentry_depth); + } else { + DBG(1, "[%3d] Inline Dentry Block Done : " + "dentries:%d in %d slots (len:%d)\n\n", + fsck->dentry_depth, dentries, + d.max, F2FS_NAME_LEN); + } + fsck->dentry = cur_dentry; + fsck->dentry_end = cur_dentry; + cur_dentry->next = NULL; + free(new_dentry); + fsck->dentry_depth--; + return dentries; +} + +int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, int casefolded, u32 blk_addr, + struct child_info *child, int last_blk, int enc_name, + struct f2fs_node *node_blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_dentry_block *de_blk; + struct f2fs_dentry *cur_dentry = fsck->dentry_end; + struct f2fs_dentry *new_dentry; + int dentries, ret; + + de_blk = (struct f2fs_dentry_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(de_blk != NULL); + + ret = dev_read_block(de_blk, blk_addr); + ASSERT(ret >= 0); + + fsck->dentry_depth++; + new_dentry = calloc(sizeof(struct f2fs_dentry), 1); + ASSERT(new_dentry != NULL); + new_dentry->depth = fsck->dentry_depth; + memcpy(new_dentry->name, child->p_name, F2FS_NAME_LEN); + cur_dentry->next = new_dentry; + fsck->dentry_end = new_dentry; + + dentries = __chk_dentries(sbi, casefolded, child, + de_blk->dentry_bitmap, + F2FS_DENTRY_BLOCK_DENTRIES(de_blk), F2FS_DENTRY_BLOCK_FILENAMES(de_blk), + NR_DENTRY_IN_BLOCK, last_blk, enc_name); + + if (dentries < 0 && f2fs_dev_is_writable()) { + ret = update_block(sbi, de_blk, &blk_addr, node_blk); + ASSERT(ret >= 0); + DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n", + fsck->dentry_depth, blk_addr); + } else { + DBG(1, "[%3d] Dentry Block [0x%x] Done : " + "dentries:%d in %d slots (len:%d)\n\n", + fsck->dentry_depth, blk_addr, dentries, + NR_DENTRY_IN_BLOCK, F2FS_NAME_LEN); + } + fsck->dentry = cur_dentry; + fsck->dentry_end = cur_dentry; + cur_dentry->next = NULL; + free(new_dentry); + fsck->dentry_depth--; + free(de_blk); + return 0; +} + +int fsck_chk_data_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode, + u32 blk_addr, struct child_info *child, int last_blk, + enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver, + struct f2fs_node *node_blk) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + int casefolded = IS_CASEFOLDED(inode); + int enc_name = file_is_encrypt(inode); + int aliasing = IS_DEVICE_ALIASING(inode); + + /* Is it reserved block? */ + if (blk_addr == NEW_ADDR) { + fsck->chk.valid_blk_cnt++; + return 0; + } + + if (time_to_inject(FAULT_DATA)) { + ASSERT_MSG("%s is injected.", f2fs_fault_name[FAULT_DATA]); + return -EINVAL; + } + + if (!f2fs_is_valid_blkaddr(sbi, blk_addr, DATA_GENERIC)) { + ASSERT_MSG("blkaddress is not valid. [0x%x]", blk_addr); + return -EINVAL; + } + + if (!aliasing && is_valid_ssa_data_blk(sbi, blk_addr, parent_nid, + idx_in_node, ver)) { + ASSERT_MSG("summary data block is not valid. [0x%x]", + parent_nid); + return -EINVAL; + } + + if (f2fs_test_sit_bitmap(sbi, blk_addr) == 0) + ASSERT_MSG("SIT bitmap is 0x0. blk_addr[0x%x]", blk_addr); + + if (f2fs_test_main_bitmap(sbi, blk_addr) != 0) + ASSERT_MSG("Duplicated data [0x%x]. pnid[0x%x] idx[0x%x]", + blk_addr, parent_nid, idx_in_node); + + fsck->chk.valid_blk_cnt++; + + if (ftype == F2FS_FT_DIR) { + f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_HOT_DATA); + return fsck_chk_dentry_blk(sbi, casefolded, blk_addr, child, + last_blk, enc_name, node_blk); + } else { + f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_WARM_DATA); + } + return 0; +} + +int fsck_chk_orphan_node(struct f2fs_sb_info *sbi) +{ + u32 blk_cnt = 0; + struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; + block_t start_blk, orphan_blkaddr, i, j; + struct f2fs_orphan_block *orphan_blk, *new_blk; + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + u32 entry_count; + + if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG)) + return 0; + + start_blk = __start_cp_addr(sbi) + 1 + get_sb(cp_payload); + orphan_blkaddr = __start_sum_addr(sbi) - 1 - get_sb(cp_payload); + + f2fs_ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP); + + orphan_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(orphan_blk); + + new_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(new_blk); + + for (i = 0; i < orphan_blkaddr; i++) { + int ret = dev_read_block(orphan_blk, start_blk + i); + u32 new_entry_count = 0; + + ASSERT(ret >= 0); + entry_count = le32_to_cpu(F2FS_ORPHAN_BLOCK_FOOTER(orphan_blk)->entry_count); + + for (j = 0; j < entry_count; j++) { + nid_t ino = le32_to_cpu(orphan_blk->ino[j]); + DBG(1, "[%3d] ino [0x%x]\n", i, ino); + struct node_info ni; + blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + + if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { + get_node_info(sbi, ino, &ni); + if (!IS_VALID_NID(sbi, ino) || + !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, + DATA_GENERIC)) { + free(orphan_blk); + free(new_blk); + return -EINVAL; + } + + continue; + } + + ret = fsck_chk_node_blk(sbi, NULL, ino, + F2FS_FT_ORPHAN, TYPE_INODE, &blk_cnt, + &cbc, NULL); + if (!ret) + new_blk->ino[new_entry_count++] = + orphan_blk->ino[j]; + else if (ret && c.fix_on) + FIX_MSG("[0x%x] remove from orphan list", ino); + else if (ret) + ASSERT_MSG("[0x%x] wrong orphan inode", ino); + } + if (f2fs_dev_is_writable() && c.fix_on && + entry_count != new_entry_count) { + F2FS_ORPHAN_BLOCK_FOOTER(new_blk)->entry_count = cpu_to_le32(new_entry_count); + ret = dev_write_block(new_blk, start_blk + i, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + memset(orphan_blk, 0, F2FS_BLKSIZE); + memset(new_blk, 0, F2FS_BLKSIZE); + } + free(orphan_blk); + free(new_blk); + + return 0; +} + +int fsck_chk_quota_node(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + enum quota_type qtype; + int ret = 0; + u32 blk_cnt = 0; + struct f2fs_compr_blk_cnt cbc = {0, CHEADER_PGOFS_NONE}; + + for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { + cur_qtype = qtype; + if (sb->qf_ino[qtype] == 0) + continue; + nid_t ino = QUOTA_INO(sb, qtype); + struct node_info ni; + + DBG(1, "qtype [%d] ino [0x%x]\n", qtype, ino); + blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + + if (c.preen_mode == PREEN_MODE_1 && !c.fix_on) { + get_node_info(sbi, ino, &ni); + if (!IS_VALID_NID(sbi, ino) || + !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, + DATA_GENERIC)) + return -EINVAL; + continue; + } + ret = fsck_chk_node_blk(sbi, NULL, ino, + F2FS_FT_REG_FILE, TYPE_INODE, &blk_cnt, + &cbc, NULL); + if (ret) { + ASSERT_MSG("wrong quota inode, qtype [%d] ino [0x%x]", + qtype, ino); + qf_szchk_type[qtype] = QF_SZCHK_ERR; + if (c.fix_on) + f2fs_rebuild_qf_inode(sbi, qtype); + } + } + cur_qtype = -1; + return ret; +} + +static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino, + bool dealloc); + +int fsck_chk_quota_files(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + enum quota_type qtype; + f2fs_ino_t ino; + int ret = 0; + int needs_writeout; + + /* Return if quota feature is disabled */ + if (!fsck->qctx) + return 0; + + for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { + ino = sb->qf_ino[qtype]; + if (!ino) + continue; + + DBG(1, "Checking Quota file ([%3d] ino [0x%x])\n", qtype, ino); + needs_writeout = 0; + ret = quota_compare_and_update(sbi, qtype, &needs_writeout, + c.preserve_limits); + if (ret == 0 && needs_writeout == 0) { + DBG(1, "OK\n"); + continue; + } + + /* Something is wrong */ + if (c.fix_on) { + DBG(0, "Fixing Quota file ([%3d] ino [0x%x])\n", + qtype, ino); + fsck_disconnect_file(sbi, ino, true); + f2fs_rebuild_qf_inode(sbi, qtype); + f2fs_filesize_update(sbi, ino, 0); + ret = quota_write_inode(sbi, qtype); + if (!ret) { + c.quota_fixed = true; + DBG(1, "OK\n"); + } else { + ASSERT_MSG("Unable to write quota file"); + } + } else { + ASSERT_MSG("Quota file is missing or invalid" + " quota file content found."); + } + } + return ret; +} + +void fsck_update_sb_flags(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + u16 flags = get_sb(s_encoding_flags); + + if (c.nolinear_lookup == LINEAR_LOOKUP_DEFAULT) { + MSG(0, "Info: Casefold: linear_lookup [%s]\n", + get_sb(s_encoding_flags) & F2FS_ENC_NO_COMPAT_FALLBACK_FL ? + "disable" : "enable"); + return; + } + + MSG(0, "Info: linear_lookup option: %s\n", + c.nolinear_lookup == LINEAR_LOOKUP_DISABLE ? + "disable" : "enable"); + + if (!(get_sb(feature) & F2FS_FEATURE_CASEFOLD)) { + MSG(0, "Info: Not support Casefold feature\n"); + return; + } + + if (c.nolinear_lookup == LINEAR_LOOKUP_DISABLE) { + if (!(flags & F2FS_ENC_NO_COMPAT_FALLBACK_FL)) { + flags |= F2FS_ENC_NO_COMPAT_FALLBACK_FL; + set_sb(s_encoding_flags, flags); + MSG(0, "Info: Casefold: disable linear lookup\n"); + update_superblock(sbi->raw_super, SB_MASK_ALL); + } + } else if (c.nolinear_lookup == LINEAR_LOOKUP_ENABLE) { + if (flags & F2FS_ENC_NO_COMPAT_FALLBACK_FL) { + flags &= ~F2FS_ENC_NO_COMPAT_FALLBACK_FL; + set_sb(s_encoding_flags, flags); + MSG(0, "Info: Casefold: enable linear lookup\n"); + update_superblock(sbi->raw_super, SB_MASK_ALL); + } + } +} + +int fsck_chk_meta(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct seg_entry *se; + unsigned int sit_valid_segs = 0, sit_node_blks = 0; + unsigned int i; + + /* 1. check sit usage with CP: curseg is lost? */ + for (i = 0; i < MAIN_SEGS(sbi); i++) { + se = get_seg_entry(sbi, i); + if (se->valid_blocks != 0) + sit_valid_segs++; + else if (IS_CUR_SEGNO(sbi, i)) { + /* curseg has not been written back to device */ + MSG(1, "\tInfo: curseg %u is counted in valid segs\n", i); + sit_valid_segs++; + } + if (IS_NODESEG(se->type)) + sit_node_blks += se->valid_blocks; + } + if (fsck->chk.sit_free_segs + sit_valid_segs != + get_usable_seg_count(sbi)) { + ASSERT_MSG("SIT usage does not match: sit_free_segs %u, " + "sit_valid_segs %u, total_segs %u", + fsck->chk.sit_free_segs, sit_valid_segs, + get_usable_seg_count(sbi)); + return -EINVAL; + } + + /* 2. check node count */ + if (fsck->chk.valid_nat_entry_cnt != sit_node_blks) { + ASSERT_MSG("node count does not match: valid_nat_entry_cnt %u," + " sit_node_blks %u", + fsck->chk.valid_nat_entry_cnt, sit_node_blks); + return -EINVAL; + } + + /* 3. check SIT with CP */ + if (fsck->chk.sit_free_segs != le32_to_cpu(cp->free_segment_count)) { + ASSERT_MSG("free segs does not match: sit_free_segs %u, " + "free_segment_count %u", + fsck->chk.sit_free_segs, + le32_to_cpu(cp->free_segment_count)); + return -EINVAL; + } + + /* 4. check NAT with CP */ + if (fsck->chk.valid_nat_entry_cnt != + le32_to_cpu(cp->valid_node_count)) { + ASSERT_MSG("valid node does not match: valid_nat_entry_cnt %u," + " valid_node_count %u", + fsck->chk.valid_nat_entry_cnt, + le32_to_cpu(cp->valid_node_count)); + return -EINVAL; + } + + /* 4. check orphan inode simply */ + if (fsck_chk_orphan_node(sbi)) + return -EINVAL; + + /* 5. check nat entry -- must be done before quota check */ + for (i = 0; i < fsck->nr_nat_entries; i++) { + u32 blk = le32_to_cpu(fsck->entries[i].block_addr); + nid_t ino = le32_to_cpu(fsck->entries[i].ino); + + if (!blk) + /* + * skip entry whose ino is 0, otherwise, we will + * get a negative number by BLKOFF_FROM_MAIN(sbi, blk) + */ + continue; + + if (!f2fs_is_valid_blkaddr(sbi, blk, DATA_GENERIC)) { + MSG(0, "\tError: nat entry[ino %u block_addr 0x%x]" + " is in valid\n", + ino, blk); + return -EINVAL; + } + + if (!f2fs_test_sit_bitmap(sbi, blk)) { + MSG(0, "\tError: nat entry[ino %u block_addr 0x%x]" + " not find it in sit_area_bitmap\n", + ino, blk); + return -EINVAL; + } + + if (!IS_VALID_NID(sbi, ino)) { + MSG(0, "\tError: nat_entry->ino %u exceeds the range" + " of nat entries %u\n", + ino, fsck->nr_nat_entries); + return -EINVAL; + } + + if (!f2fs_test_bit(ino, fsck->nat_area_bitmap)) { + MSG(0, "\tError: nat_entry->ino %u is not set in" + " nat_area_bitmap\n", ino); + return -EINVAL; + } + } + + /* 6. check quota inode simply */ + if (fsck_chk_quota_node(sbi)) + return -EINVAL; + + if (fsck->nat_valid_inode_cnt != le32_to_cpu(cp->valid_inode_count)) { + ASSERT_MSG("valid inode does not match: nat_valid_inode_cnt %u," + " valid_inode_count %u", + fsck->nat_valid_inode_cnt, + le32_to_cpu(cp->valid_inode_count)); + return -EINVAL; + } + + return 0; +} + +void fsck_chk_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + + if (get_cp(ckpt_flags) & CP_LARGE_NAT_BITMAP_FLAG) { + if (get_cp(checksum_offset) != CP_MIN_CHKSUM_OFFSET) { + ASSERT_MSG("Deprecated layout of large_nat_bitmap, " + "chksum_offset:%u", get_cp(checksum_offset)); + c.fix_chksum = 1; + } + } +} + +void fsck_init(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_sm_info *sm_i = SM_I(sbi); + + /* + * We build three bitmap for main/sit/nat so that may check consistency + * of filesystem. + * 1. main_area_bitmap will be used to check whether all blocks of main + * area is used or not. + * 2. nat_area_bitmap has bitmap information of used nid in NAT. + * 3. sit_area_bitmap has bitmap information of used main block. + * At Last sequence, we compare main_area_bitmap with sit_area_bitmap. + */ + fsck->nr_main_blks = sm_i->main_segments << sbi->log_blocks_per_seg; + fsck->main_area_bitmap_sz = (fsck->nr_main_blks + 7) / 8; + fsck->main_area_bitmap = calloc(fsck->main_area_bitmap_sz, 1); + ASSERT(fsck->main_area_bitmap != NULL); + + build_nat_area_bitmap(sbi); + + build_sit_area_bitmap(sbi); + + ASSERT(tree_mark_size != 0); + tree_mark = calloc(tree_mark_size, 1); + ASSERT(tree_mark != NULL); + fsck->dentry = calloc(sizeof(struct f2fs_dentry), 1); + ASSERT(fsck->dentry != NULL); + memcpy(fsck->dentry->name, "/", 1); + fsck->dentry_end = fsck->dentry; + + c.quota_fixed = false; +} + +static void fix_hard_links(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct hard_link_node *tmp, *node; + struct f2fs_node *node_blk = NULL; + struct node_info ni; + int ret; + + if (fsck->hard_link_list_head == NULL) + return; + + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk != NULL); + + node = fsck->hard_link_list_head; + while (node) { + /* Sanity check */ + if (sanity_check_nid(sbi, node->nid, node_blk, + F2FS_FT_MAX, TYPE_INODE, &ni)) + FIX_MSG("Failed to fix, rerun fsck.f2fs"); + + node_blk->i.i_links = cpu_to_le32(node->actual_links); + + FIX_MSG("File: 0x%x i_links= 0x%x -> 0x%x", + node->nid, node->links, node->actual_links); + + ret = update_block(sbi, node_blk, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + tmp = node; + node = node->next; + free(tmp); + } + free(node_blk); +} + +static void fix_nat_entries(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + u32 i; + + for (i = 0; i < fsck->nr_nat_entries; i++) + if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) + nullify_nat_entry(sbi, i); +} + +static void flush_curseg_sit_entries(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sit_block *sit_blk; + int i; + + sit_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sit_blk); + /* update curseg sit entries, since we may change + * a segment type in move_curseg_info + */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + struct f2fs_sit_entry *sit; + struct seg_entry *se; + + se = get_seg_entry(sbi, curseg->segno); + get_current_sit_page(sbi, curseg->segno, sit_blk); + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, curseg->segno)]; + sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) | + se->valid_blocks); + rewrite_current_sit_page(sbi, curseg->segno, sit_blk); + } + + free(sit_blk); +} + +static void fix_checksum(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct sit_info *sit_i = SIT_I(sbi); + void *bitmap_offset; + + if (!c.fix_chksum) + return; + + bitmap_offset = cp->sit_nat_version_bitmap + sizeof(__le32); + + memcpy(bitmap_offset, nm_i->nat_bitmap, nm_i->bitmap_size); + memcpy(bitmap_offset + nm_i->bitmap_size, + sit_i->sit_bitmap, sit_i->bitmap_size); +} + +static void fix_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + unsigned long long cp_blk_no; + u32 flags = c.alloc_failed ? CP_FSCK_FLAG : + (c.roll_forward ? 0 : CP_UMOUNT_FLAG); + block_t orphan_blks = 0; + block_t cp_blocks; + u32 i; + int ret; + uint32_t crc = 0; + + /* should call from fsck */ + ASSERT(c.func == FSCK); + + if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) { + orphan_blks = __start_sum_addr(sbi) - 1; + flags |= CP_ORPHAN_PRESENT_FLAG; + } + if (is_set_ckpt_flags(cp, CP_TRIMMED_FLAG)) + flags |= CP_TRIMMED_FLAG; + if (is_set_ckpt_flags(cp, CP_DISABLED_FLAG)) + flags |= CP_DISABLED_FLAG; + if (is_set_ckpt_flags(cp, CP_LARGE_NAT_BITMAP_FLAG)) { + flags |= CP_LARGE_NAT_BITMAP_FLAG; + set_cp(checksum_offset, CP_MIN_CHKSUM_OFFSET); + } else { + set_cp(checksum_offset, CP_CHKSUM_OFFSET); + } + + if (flags & CP_UMOUNT_FLAG) + cp_blocks = 8; + else + cp_blocks = 5; + + set_cp(cp_pack_total_block_count, cp_blocks + + orphan_blks + get_sb(cp_payload)); + + flags = update_nat_bits_flags(sb, cp, flags); + flags |= CP_NOCRC_RECOVERY_FLAG; + set_cp(ckpt_flags, flags); + + set_cp(free_segment_count, get_free_segments(sbi)); + set_cp(valid_block_count, fsck->chk.valid_blk_cnt); + set_cp(valid_node_count, fsck->chk.valid_node_cnt); + set_cp(valid_inode_count, fsck->chk.valid_inode_cnt); + + crc = f2fs_checkpoint_chksum(cp); + *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + + cp_blk_no = get_sb(cp_blkaddr); + if (sbi->cur_cp == 2) + cp_blk_no += 1 << get_sb(log_blocks_per_seg); + + ret = dev_write_block(cp, cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + for (i = 0; i < get_sb(cp_payload); i++) { + ret = dev_write_block(((unsigned char *)cp) + + (i + 1) * F2FS_BLKSIZE, cp_blk_no++, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + + cp_blk_no += orphan_blks; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + + if (!(flags & CP_UMOUNT_FLAG) && IS_NODESEG(i)) + continue; + + ret = dev_write_block(curseg->sum_blk, cp_blk_no++, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); + + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + ret = dev_write_block(cp, cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + MSG(0, "Info: fix_checkpoint() cur_cp:%d\n", sbi->cur_cp); +} + +static void fix_checkpoints(struct f2fs_sb_info *sbi) +{ + /* copy valid checkpoint to its mirror position */ + duplicate_checkpoint(sbi); + + /* repair checkpoint at CP #0 position */ + sbi->cur_cp = 1; + fix_checkpoint(sbi); +} + +#ifdef HAVE_LINUX_BLKZONED_H + +/* + * Refer valid block map and return offset of the last valid block in the zone. + * Obtain valid block map from SIT and fsync data. + * If there is no valid block in the zone, return -1. + */ +static int last_vblk_off_in_zone(struct f2fs_sb_info *sbi, + unsigned int zone_segno) +{ + int s, b; + unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone; + struct seg_entry *se; + + for (s = segs_per_zone - 1; s >= 0; s--) { + se = get_seg_entry(sbi, zone_segno + s); + + for (b = sbi->blocks_per_seg - 1; b >= 0; b--) + if (f2fs_test_bit(b, (const char *)se->cur_valid_map)) + return b + (s << sbi->log_blocks_per_seg); + } + + return -1; +} + +static int check_curseg_write_pointer(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct blk_zone blkz; + block_t cs_block, wp_block; + uint64_t cs_sector, wp_sector; + int i, ret; + int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; + + if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) + return -EINVAL; + + /* get the device the curseg points to */ + cs_block = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff; + for (i = 0; i < MAX_DEVICES; i++) { + if (!c.devices[i].path) + break; + if (c.devices[i].start_blkaddr <= cs_block && + cs_block <= c.devices[i].end_blkaddr) + break; + } + + if (i >= MAX_DEVICES) + return -EINVAL; + + if (c.devices[i].zoned_model != F2FS_ZONED_HM) + return 0; + + /* get write pointer position of the zone the curseg points to */ + cs_sector = (cs_block - c.devices[i].start_blkaddr) + << log_sectors_per_block; + ret = f2fs_report_zone(i, cs_sector, &blkz); + if (ret) + return ret; + + if (blk_zone_type(&blkz) != BLK_ZONE_TYPE_SEQWRITE_REQ) + return 0; + + /* check consistency between the curseg and the write pointer */ + wp_block = c.devices[i].start_blkaddr + + (blk_zone_wp_sector(&blkz) >> log_sectors_per_block); + wp_sector = blk_zone_wp_sector(&blkz); + + if (cs_sector == wp_sector) { + return 0; + } else if (cs_sector > wp_sector) { + MSG(0, "Inconsistent write pointer with curseg %d: " + "curseg %d[0x%x,0x%x] > wp[0x%x,0x%x]\n", + type, type, curseg->segno, curseg->next_blkoff, + GET_SEGNO(sbi, wp_block), + OFFSET_IN_SEG(sbi, wp_block)); + if (!c.fix_on) + fsck->chk.wp_inconsistent_zones++; + } else { + MSG(0, "Write pointer goes advance from curseg %d: " + "curseg %d[0x%x,0x%x] wp[0x%x,0x%x]\n", + type, type, curseg->segno, curseg->next_blkoff, + GET_SEGNO(sbi, wp_block), OFFSET_IN_SEG(sbi, wp_block)); + } + + return -EINVAL; +} + +#else + +static int check_curseg_write_pointer(struct f2fs_sb_info *UNUSED(sbi), + int UNUSED(type)) +{ + return 0; +} + +#endif + +int check_curseg_offset(struct f2fs_sb_info *sbi, int type, bool check_wp) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct seg_entry *se; + int j, nblocks; + + if ((get_sb(feature) & F2FS_FEATURE_RO) && + type != CURSEG_HOT_DATA && type != CURSEG_HOT_NODE) + return 0; + + if ((curseg->next_blkoff >> 3) >= SIT_VBLOCK_MAP_SIZE) { + ASSERT_MSG("Next block offset:%u is invalid, type:%d", + curseg->next_blkoff, type); + return -EINVAL; + } + se = get_seg_entry(sbi, curseg->segno); + if (f2fs_test_bit(curseg->next_blkoff, + (const char *)se->cur_valid_map)) { + ASSERT_MSG("Next block offset is not free, type:%d", type); + return -EINVAL; + } + if (curseg->alloc_type == SSR) + return 0; + + nblocks = sbi->blocks_per_seg; + for (j = curseg->next_blkoff + 1; j < nblocks; j++) { + if (f2fs_test_bit(j, (const char *)se->cur_valid_map)) { + ASSERT_MSG("For LFS curseg, space after .next_blkoff " + "should be unused, type:%d", type); + return -EINVAL; + } + } + + if (check_wp && c.zoned_model == F2FS_ZONED_HM) + return check_curseg_write_pointer(sbi, type); + + return 0; +} + +int check_curseg_offsets(struct f2fs_sb_info *sbi, bool check_wp) +{ + int i, ret; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + ret = check_curseg_offset(sbi, i, check_wp); + if (ret) + return ret; + } + return 0; +} + +static void fix_curseg_info(struct f2fs_sb_info *sbi, bool check_wp) +{ + int i, need_update = 0; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + if (check_curseg_offset(sbi, i, check_wp)) { + update_curseg_info(sbi, i); + need_update = 1; + } + } + + if (need_update) { + write_curseg_info(sbi); + flush_curseg_sit_entries(sbi); + } +} + +int check_sit_types(struct f2fs_sb_info *sbi) +{ + unsigned int i; + int err = 0; + + for (i = 0; i < MAIN_SEGS(sbi); i++) { + struct seg_entry *se; + + se = get_seg_entry(sbi, i); + if (se->orig_type != se->type) { + if (se->orig_type == CURSEG_COLD_DATA && + se->type <= CURSEG_COLD_DATA) { + se->type = se->orig_type; + } else { + FIX_MSG("Wrong segment type [0x%x] %x -> %x", + i, se->orig_type, se->type); + err = -EINVAL; + } + } + } + return err; +} + +static struct f2fs_node *fsck_get_lpf(struct f2fs_sb_info *sbi) +{ + struct f2fs_node *node; + struct node_info ni; + nid_t lpf_ino; + int err; + + /* read root inode first */ + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + get_node_info(sbi, F2FS_ROOT_INO(sbi), &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + /* lookup lost+found in root directory */ + lpf_ino = f2fs_lookup(sbi, node, (u8 *)LPF, strlen(LPF)); + if (lpf_ino) { /* found */ + get_node_info(sbi, lpf_ino, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + DBG(1, "Found lost+found 0x%x at blkaddr [0x%x]\n", + lpf_ino, ni.blk_addr); + if (!S_ISDIR(le16_to_cpu(node->i.i_mode))) { + ASSERT_MSG("lost+found is not directory [0%o]\n", + le16_to_cpu(node->i.i_mode)); + /* FIXME: give up? */ + goto out; + } + + /* Must convert inline dentry before adding inodes */ + err = convert_inline_dentry(sbi, node, &ni.blk_addr); + if (err) { + MSG(0, "Convert inline dentry for ino=%x failed.\n", + lpf_ino); + goto out; + } + } else { /* not found, create it */ + struct dentry de; + + memset(&de, 0, sizeof(de)); + de.name = (u8 *) LPF; + de.len = strlen(LPF); + de.mode = 0x41c0; + de.pino = F2FS_ROOT_INO(sbi), + de.file_type = F2FS_FT_DIR, + de.uid = getuid(); + de.gid = getgid(); + de.mtime = time(NULL); + + err = f2fs_mkdir(sbi, &de); + if (err) { + ASSERT_MSG("Failed create lost+found"); + goto out; + } + + get_node_info(sbi, de.ino, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + DBG(1, "Create lost+found 0x%x at blkaddr [0x%x]\n", + de.ino, ni.blk_addr); + } + + c.lpf_ino = le32_to_cpu(F2FS_NODE_FOOTER(node)->ino); + return node; +out: + free(node); + return NULL; +} + +static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi, + struct f2fs_node *lpf, + struct f2fs_node *fnode) +{ + char name[80]; + size_t namelen; + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(fnode)->ino); + struct node_info ni; + int ftype, ret; + + namelen = snprintf(name, 80, "%u", ino); + if (namelen >= 80) + /* ignore terminating '\0', should never happen */ + namelen = 79; + + if (f2fs_lookup(sbi, lpf, (u8 *)name, namelen)) { + ASSERT_MSG("Name %s already exist in lost+found", name); + return -EEXIST; + } + + get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(lpf)->ino), &ni); + ftype = map_de_type(le16_to_cpu(fnode->i.i_mode)); + ret = f2fs_add_link(sbi, lpf, (unsigned char *)name, namelen, + ino, ftype, &ni.blk_addr, 0); + if (ret) { + ASSERT_MSG("Failed to add inode [0x%x] to lost+found", ino); + return -EINVAL; + } + + /* update fnode */ + memcpy(fnode->i.i_name, name, namelen); + fnode->i.i_namelen = cpu_to_le32(namelen); + fnode->i.i_pino = c.lpf_ino; + get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(fnode)->ino), &ni); + ret = update_block(sbi, fnode, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + + DBG(1, "Reconnect inode [0x%x] to lost+found\n", ino); + return 0; +} + +static inline void release_inode_cnt(struct f2fs_sb_info *sbi, bool dealloc) +{ + F2FS_FSCK(sbi)->chk.valid_inode_cnt--; + if (dealloc) + sbi->total_valid_inode_count--; +} + +static inline void release_node_cnt(struct f2fs_sb_info *sbi, bool dealloc) +{ + F2FS_FSCK(sbi)->chk.valid_node_cnt--; + if (dealloc) + sbi->total_valid_node_count--; +} + +static inline void release_block_cnt(struct f2fs_sb_info *sbi, bool dealloc) +{ + F2FS_FSCK(sbi)->chk.valid_blk_cnt--; + if (dealloc) + sbi->total_valid_block_count--; +} + +static inline void release_block(struct f2fs_sb_info *sbi, u64 blkaddr, + bool dealloc) +{ + f2fs_clear_main_bitmap(sbi, blkaddr); + if (dealloc) { + struct seg_entry *se; + u64 offset; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr)); + offset = OFFSET_IN_SEG(sbi, blkaddr); + se->valid_blocks--; + f2fs_clear_bit(offset, (char *)se->cur_valid_map); + if (need_fsync_data_record(sbi)) + f2fs_clear_bit(offset, (char *)se->ckpt_valid_map); + se->dirty = 1; + f2fs_clear_sit_bitmap(sbi, blkaddr); + } +} + +static inline void release_nat_entry(struct f2fs_sb_info *sbi, u32 nid) +{ + nullify_nat_entry(sbi, nid); + F2FS_FSCK(sbi)->chk.valid_nat_entry_cnt--; +} + +static void fsck_disconnect_file_dnode(struct f2fs_sb_info *sbi, + struct f2fs_inode *inode, nid_t nid, bool dealloc) +{ + struct f2fs_node *node; + struct node_info ni; + u32 addr; + int i, err; + + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + + get_node_info(sbi, nid, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + release_node_cnt(sbi, dealloc); + release_block_cnt(sbi, dealloc); + release_block(sbi, ni.blk_addr, dealloc); + + for (i = 0; i < ADDRS_PER_BLOCK(inode); i++) { + addr = le32_to_cpu(node->dn.addr[i]); + if (!addr) + continue; + release_block_cnt(sbi, dealloc); + if (addr == NEW_ADDR || addr == COMPRESS_ADDR) + continue; + release_block(sbi, addr, dealloc); + } + + if (dealloc) + release_nat_entry(sbi, nid); + + free(node); +} + +static void fsck_disconnect_file_idnode(struct f2fs_sb_info *sbi, + struct f2fs_inode *inode, nid_t nid, bool dealloc) +{ + struct f2fs_node *node; + struct node_info ni; + nid_t tmp; + int i, err; + + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + + get_node_info(sbi, nid, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + release_node_cnt(sbi, dealloc); + release_block_cnt(sbi, dealloc); + release_block(sbi, ni.blk_addr, dealloc); + + for (i = 0; i < NIDS_PER_BLOCK; i++) { + tmp = le32_to_cpu(node->in.nid[i]); + if (!tmp) + continue; + fsck_disconnect_file_dnode(sbi, inode, tmp, dealloc); + } + + if (dealloc) + release_nat_entry(sbi, nid); + + free(node); +} + +static void fsck_disconnect_file_didnode(struct f2fs_sb_info *sbi, + struct f2fs_inode *inode, nid_t nid, bool dealloc) +{ + struct f2fs_node *node; + struct node_info ni; + nid_t tmp; + int i, err; + + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + + get_node_info(sbi, nid, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + release_node_cnt(sbi, dealloc); + release_block_cnt(sbi, dealloc); + release_block(sbi, ni.blk_addr, dealloc); + + for (i = 0; i < NIDS_PER_BLOCK; i++) { + tmp = le32_to_cpu(node->in.nid[i]); + if (!tmp) + continue; + fsck_disconnect_file_idnode(sbi, inode, tmp, dealloc); + } + + if (dealloc) + release_nat_entry(sbi, nid); + + free(node); +} + +static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino, + bool dealloc) +{ + struct f2fs_node *node; + struct node_info ni; + nid_t nid; + int ofs, i, err; + + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + + get_node_info(sbi, ino, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + /* clear inode counters */ + release_inode_cnt(sbi, dealloc); + release_node_cnt(sbi, dealloc); + release_block_cnt(sbi, dealloc); + release_block(sbi, ni.blk_addr, dealloc); + + /* clear xnid counters */ + if (node->i.i_xattr_nid) { + nid = le32_to_cpu(node->i.i_xattr_nid); + release_node_cnt(sbi, dealloc); + release_block_cnt(sbi, dealloc); + get_node_info(sbi, nid, &ni); + release_block(sbi, ni.blk_addr, dealloc); + + if (dealloc) + release_nat_entry(sbi, nid); + } + + /* clear data counters */ + if (!(node->i.i_inline & (F2FS_INLINE_DATA | F2FS_INLINE_DENTRY))) { + ofs = get_extra_isize(node); + for (i = 0; i < ADDRS_PER_INODE(&node->i); i++) { + block_t addr = le32_to_cpu(node->i.i_addr[ofs + i]); + if (!addr) + continue; + release_block_cnt(sbi, dealloc); + if (addr == NEW_ADDR || addr == COMPRESS_ADDR) + continue; + release_block(sbi, addr, dealloc); + } + } + + for (i = 0; i < 5; i++) { + nid = le32_to_cpu(F2FS_INODE_I_NID(&node->i, i)); + if (!nid) + continue; + + switch (i) { + case 0: /* direct node */ + case 1: + fsck_disconnect_file_dnode(sbi, &node->i, nid, + dealloc); + break; + case 2: /* indirect node */ + case 3: + fsck_disconnect_file_idnode(sbi, &node->i, nid, + dealloc); + break; + case 4: /* double indirect node */ + fsck_disconnect_file_didnode(sbi, &node->i, nid, + dealloc); + break; + } + } + + if (dealloc) + release_nat_entry(sbi, ino); + + free(node); +} + +/* + * Scan unreachable nids and find only regular file inodes. If these files + * are not corrupted, reconnect them to lost+found. + * + * Since all unreachable nodes are already checked, we can allocate new + * blocks safely. + * + * This function returns the number of files been reconnected. + */ +static int fsck_reconnect_file(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_node *lpf_node, *node; + struct node_info ni; + char *reconnect_bitmap; + u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; + nid_t nid; + int err, cnt = 0, ftype; + + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + + reconnect_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); + ASSERT(reconnect_bitmap); + + for (nid = 0; nid < fsck->nr_nat_entries; nid++) { + if (f2fs_test_bit(nid, fsck->nat_area_bitmap)) { + if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) { + DBG(1, "Not support quota inode [0x%x]\n", + nid); + continue; + } + + get_node_info(sbi, nid, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + /* reconnection will restore these nodes if needed */ + if (!IS_INODE(node)) { + DBG(1, "Not support non-inode node [0x%x]\n", + nid); + continue; + } + + if (S_ISDIR(le16_to_cpu(node->i.i_mode))) { + DBG(1, "Not support directory inode [0x%x]\n", + nid); + continue; + } + + ftype = map_de_type(le16_to_cpu(node->i.i_mode)); + if (sanity_check_nid(sbi, nid, node, ftype, + TYPE_INODE, &ni)) { + ASSERT_MSG("Invalid nid [0x%x]\n", nid); + continue; + } + + DBG(1, "Check inode 0x%x\n", nid); + blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + fsck_chk_inode_blk(sbi, nid, ftype, node, + &blk_cnt, &cbc, &ni, NULL); + + f2fs_set_bit(nid, reconnect_bitmap); + } + } + + lpf_node = fsck_get_lpf(sbi); + if (!lpf_node) + goto out; + + for (nid = 0; nid < fsck->nr_nat_entries; nid++) { + if (f2fs_test_bit(nid, reconnect_bitmap)) { + get_node_info(sbi, nid, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + if (fsck_do_reconnect_file(sbi, lpf_node, node)) { + DBG(1, "Failed to reconnect inode [0x%x]\n", + nid); + fsck_disconnect_file(sbi, nid, false); + continue; + } + + quota_add_inode_usage(fsck->qctx, nid, &node->i); + + DBG(1, "Reconnected inode [0x%x] to lost+found\n", nid); + cnt++; + } + } + +out: + free(node); + free(lpf_node); + free(reconnect_bitmap); + return cnt; +} + +#ifdef HAVE_LINUX_BLKZONED_H + +struct write_pointer_check_data { + struct f2fs_sb_info *sbi; + int dev_index; +}; + +static int chk_and_fix_wp_with_sit(int UNUSED(i), void *blkzone, void *opaque) +{ + struct blk_zone *blkz = (struct blk_zone *)blkzone; + struct write_pointer_check_data *wpd = opaque; + struct f2fs_sb_info *sbi = wpd->sbi; + struct device_info *dev = c.devices + wpd->dev_index; + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + block_t zone_block, wp_block, wp_blkoff; + unsigned int zone_segno, wp_segno; + int i, ret, last_valid_blkoff; + int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; + unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone; + + if (blk_zone_conv(blkz)) + return 0; + + zone_block = dev->start_blkaddr + + (blk_zone_sector(blkz) >> log_sectors_per_block); + zone_segno = GET_SEGNO(sbi, zone_block); + if (zone_segno >= MAIN_SEGS(sbi)) + return 0; + + wp_block = dev->start_blkaddr + + (blk_zone_wp_sector(blkz) >> log_sectors_per_block); + wp_segno = GET_SEGNO(sbi, wp_block); + wp_blkoff = wp_block - START_BLOCK(sbi, wp_segno); + + last_valid_blkoff = last_vblk_off_in_zone(sbi, zone_segno); + + /* if a curseg points to the zone, do not finishing zone */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *cs = CURSEG_I(sbi, i); + + if (zone_segno <= cs->segno && + cs->segno < zone_segno + segs_per_zone) { + /* + * When there is no valid block in the zone, check + * write pointer is at zone start. If not, reset + * the write pointer. + */ + if (last_valid_blkoff < 0 && + blk_zone_wp_sector(blkz) != blk_zone_sector(blkz)) { + if (!c.fix_on) { + MSG(0, "Inconsistent write pointer: " + "wp[0x%x,0x%x]\n", + wp_segno, wp_blkoff); + fsck->chk.wp_inconsistent_zones++; + return 0; + } + + FIX_MSG("Reset write pointer of zone at " + "segment 0x%x", zone_segno); + ret = f2fs_reset_zone(wpd->dev_index, blkz); + if (ret) { + printf("[FSCK] Write pointer reset " + "failed: %s\n", dev->path); + return ret; + } + fsck->chk.wp_fixed = 1; + } + return 0; + } + } + + /* + * If valid blocks exist in the zone beyond the write pointer, it + * is a bug. No need to fix because the zone is not selected for the + * write. Just report it. + */ + if (last_valid_blkoff + zone_block > wp_block) { + MSG(0, "Unexpected invalid write pointer: wp[0x%x,0x%x]\n", + wp_segno, wp_blkoff); + if (!c.fix_on) + fsck->chk.wp_inconsistent_zones++; + } + + if (!c.fix_on) + return 0; + + ret = f2fs_finish_zone(wpd->dev_index, blkz); + if (ret) { + u64 fill_sects = blk_zone_length(blkz) - + (blk_zone_wp_sector(blkz) - blk_zone_sector(blkz)); + struct seg_entry *se = get_seg_entry(sbi, wp_segno); + printf("[FSCK] Finishing zone failed: %s\n", dev->path); + ret = dev_fill(NULL, wp_block * F2FS_BLKSIZE, + (fill_sects >> log_sectors_per_block) * F2FS_BLKSIZE, + f2fs_io_type_to_rw_hint(se->type)); + if (ret) + printf("[FSCK] Fill up zone failed: %s\n", dev->path); + } + + if (!ret) + fsck->chk.wp_fixed = 1; + return ret; +} + +static void fix_wp_sit_alignment(struct f2fs_sb_info *sbi) +{ + unsigned int i; + struct write_pointer_check_data wpd = { sbi, 0 }; + + if (c.zoned_model != F2FS_ZONED_HM) + return; + + for (i = 0; i < MAX_DEVICES; i++) { + if (!c.devices[i].path) + break; + if (c.devices[i].zoned_model != F2FS_ZONED_HM) + continue; + + wpd.dev_index = i; + if (f2fs_report_zones(i, chk_and_fix_wp_with_sit, &wpd)) { + printf("[FSCK] Write pointer check failed: %s\n", + c.devices[i].path); + return; + } + } +} + +#else + +static void fix_wp_sit_alignment(struct f2fs_sb_info *UNUSED(sbi)) +{ + return; +} + +#endif + +/* + * Check and fix consistency with write pointers at the beginning of + * fsck so that following writes by fsck do not fail. + */ +void fsck_chk_and_fix_write_pointers(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + if (c.zoned_model != F2FS_ZONED_HM) + return; + + if (c.fix_on) { + flush_nat_journal_entries(sbi); + flush_sit_journal_entries(sbi); + + if (check_curseg_offsets(sbi, true)) + fix_curseg_info(sbi, true); + + fix_wp_sit_alignment(sbi); + fsck->chk.wp_fixed = 1; + } +} + +int fsck_chk_curseg_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct curseg_info *curseg; + struct seg_entry *se; + struct f2fs_summary_block *sum_blk; + int i, ret = 0; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + curseg = CURSEG_I(sbi, i); + se = get_seg_entry(sbi, curseg->segno); + sum_blk = curseg->sum_blk; + + if ((get_sb(feature) & F2FS_FEATURE_RO) && + (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)) + continue; + + if (se->type != i) { + ASSERT_MSG("Incorrect curseg [%d]: segno [0x%x] " + "type(SIT) [%d]", i, curseg->segno, + se->type); + if (c.fix_on || c.preen_mode) + se->type = i; + ret = -1; + } + if (i <= CURSEG_COLD_DATA && IS_SUM_DATA_SEG(sum_blk)) { + continue; + } else if (i > CURSEG_COLD_DATA && IS_SUM_NODE_SEG(sum_blk)) { + continue; + } else { + ASSERT_MSG("Incorrect curseg [%d]: segno [0x%x] " + "type(SSA) [%d]", i, curseg->segno, + F2FS_SUMMARY_BLOCK_FOOTER(sum_blk)->entry_type); + if (c.fix_on || c.preen_mode) + F2FS_SUMMARY_BLOCK_FOOTER(sum_blk)->entry_type = + i <= CURSEG_COLD_DATA ? + SUM_TYPE_DATA : SUM_TYPE_NODE; + ret = -1; + } + } + + return ret; +} + +void print_fault_cnt(struct f2fs_fault_info *ffi) +{ + int i; + + printf("[Fault injection result]\n"); + for (i = 0; i < FAULT_MAX; i++) { + printf("%s: %u", f2fs_fault_name[i], ffi->fault_cnt[i]); + if (i < FAULT_MAX - 1) + printf(", "); + } + printf("\n"); +} + +int fsck_verify(struct f2fs_sb_info *sbi) +{ + unsigned int i = 0; + int ret = 0; + int force = 0; + u32 nr_unref_nid = 0; + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct hard_link_node *node = NULL; + struct f2fs_fault_info *ffi = &c.fault_info; + bool verify_failed = false; + uint64_t max_blks, data_secs, node_secs, free_blks; + + if (c.show_file_map) + return 0; + + if (ffi->inject_rate) + print_fault_cnt(ffi); + + printf("\n"); + + if (c.zoned_model == F2FS_ZONED_HM) { + printf("[FSCK] Write pointers consistency "); + if (fsck->chk.wp_inconsistent_zones == 0x0) { + printf(" [Ok..]\n"); + } else { + printf(" [Fail] [0x%x]\n", + fsck->chk.wp_inconsistent_zones); + verify_failed = true; + } + + if (fsck->chk.wp_fixed && c.fix_on) + force = 1; + } + + if (c.feature & F2FS_FEATURE_LOST_FOUND) { + for (i = 0; i < fsck->nr_nat_entries; i++) + if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) + break; + if (i < fsck->nr_nat_entries) { + i = fsck_reconnect_file(sbi); + printf("[FSCK] Reconnect %u files to lost+found\n", i); + } + } + + for (i = 0; i < fsck->nr_nat_entries; i++) { + if (f2fs_test_bit(i, fsck->nat_area_bitmap) != 0) { + struct node_info ni; + + get_node_info(sbi, i, &ni); + printf("NID[0x%x] is unreachable, blkaddr:0x%x\n", + i, ni.blk_addr); + nr_unref_nid++; + } + } + + if (fsck->hard_link_list_head != NULL) { + node = fsck->hard_link_list_head; + while (node) { + printf("NID[0x%x] has [0x%x] more unreachable links\n", + node->nid, node->links); + node = node->next; + } + c.bug_on = 1; + } + + data_secs = round_up(sbi->total_valid_node_count, BLKS_PER_SEC(sbi)); + node_secs = round_up(sbi->total_valid_block_count - + sbi->total_valid_node_count, BLKS_PER_SEC(sbi)); + free_blks = (sbi->total_sections - data_secs - node_secs) * + BLKS_PER_SEC(sbi); + max_blks = SM_I(sbi)->main_blkaddr + (data_secs + node_secs) * + BLKS_PER_SEC(sbi); + printf("[FSCK] Max image size: %"PRIu64" MB, Free space: %"PRIu64" MB\n", + max_blks >> (20 - F2FS_BLKSIZE_BITS), + free_blks >> (20 - F2FS_BLKSIZE_BITS)); + printf("[FSCK] Unreachable nat entries "); + if (nr_unref_nid == 0x0) { + printf(" [Ok..] [0x%x]\n", nr_unref_nid); + } else { + printf(" [Fail] [0x%x]\n", nr_unref_nid); + verify_failed = true; + } + + printf("[FSCK] SIT valid block bitmap checking "); + if (memcmp(fsck->sit_area_bitmap, fsck->main_area_bitmap, + fsck->sit_area_bitmap_sz) == 0x0) { + printf("[Ok..]\n"); + } else { + printf("[Fail]\n"); + verify_failed = true; + } + + printf("[FSCK] Hard link checking for regular file "); + if (fsck->hard_link_list_head == NULL) { + printf(" [Ok..] [0x%x]\n", fsck->chk.multi_hard_link_files); + } else { + printf(" [Fail] [0x%x]\n", fsck->chk.multi_hard_link_files); + verify_failed = true; + } + + printf("[FSCK] valid_block_count matching with CP "); + if (sbi->total_valid_block_count == fsck->chk.valid_blk_cnt) { + printf(" [Ok..] [0x%x]\n", (u32)fsck->chk.valid_blk_cnt); + } else { + printf(" [Fail] [0x%x, 0x%x]\n", sbi->total_valid_block_count, + (u32)fsck->chk.valid_blk_cnt); + verify_failed = true; + } + + printf("[FSCK] valid_node_count matching with CP (de lookup) "); + if (sbi->total_valid_node_count == fsck->chk.valid_node_cnt) { + printf(" [Ok..] [0x%x]\n", fsck->chk.valid_node_cnt); + } else { + printf(" [Fail] [0x%x, 0x%x]\n", sbi->total_valid_node_count, + fsck->chk.valid_node_cnt); + verify_failed = true; + } + + printf("[FSCK] valid_node_count matching with CP (nat lookup)"); + if (sbi->total_valid_node_count == fsck->chk.valid_nat_entry_cnt) { + printf(" [Ok..] [0x%x]\n", fsck->chk.valid_nat_entry_cnt); + } else { + printf(" [Fail] [0x%x, 0x%x]\n", sbi->total_valid_node_count, + fsck->chk.valid_nat_entry_cnt); + verify_failed = true; + } + + printf("[FSCK] valid_inode_count matched with CP "); + if (sbi->total_valid_inode_count == fsck->chk.valid_inode_cnt) { + printf(" [Ok..] [0x%x]\n", fsck->chk.valid_inode_cnt); + } else { + printf(" [Fail] [0x%x, 0x%x]\n", sbi->total_valid_inode_count, + fsck->chk.valid_inode_cnt); + verify_failed = true; + } + + printf("[FSCK] free segment_count matched with CP "); + if (le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count) == + fsck->chk.sit_free_segs) { + printf(" [Ok..] [0x%x]\n", fsck->chk.sit_free_segs); + } else { + printf(" [Fail] [0x%x, 0x%x]\n", + le32_to_cpu(F2FS_CKPT(sbi)->free_segment_count), + fsck->chk.sit_free_segs); + verify_failed = true; + } + + printf("[FSCK] next block offset is free "); + if (check_curseg_offsets(sbi, false) == 0) { + printf(" [Ok..]\n"); + } else { + printf(" [Fail]\n"); + verify_failed = true; + } + + printf("[FSCK] fixing SIT types\n"); + if (check_sit_types(sbi) != 0) + force = 1; + + printf("[FSCK] other corrupted bugs "); + if (c.bug_on == 0) { + printf(" [Ok..]\n"); + } else { + printf(" [Fail]\n"); + ret = EXIT_ERR_CODE; + } + + if (verify_failed) { + ret = EXIT_ERR_CODE; + c.bug_on = 1; + } + +#ifndef WITH_ANDROID + if (nr_unref_nid && !c.ro) { + char ans[255] = {0}; + int res; + + printf("\nDo you want to restore lost files into ./lost_found/? [Y/N] "); + res = scanf("%s", ans); + ASSERT(res >= 0); + if (!strcasecmp(ans, "y")) { + for (i = 0; i < fsck->nr_nat_entries; i++) { + if (f2fs_test_bit(i, fsck->nat_area_bitmap)) + dump_node(sbi, i, 1, NULL, 1, 0, NULL); + } + } + } +#endif + + /* fix global metadata */ + if (force || (c.fix_on && f2fs_dev_is_writable())) { + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + if (force || c.bug_on || c.bug_nat_bits || c.quota_fixed) { + if (c.zoned_model != F2FS_ZONED_HM) { + /* flush nats to write_nit_bits below */ + flush_journal_entries(sbi); + } + fix_hard_links(sbi); + fix_nat_entries(sbi); + rewrite_sit_area_bitmap(sbi); + if (c.zoned_model == F2FS_ZONED_HM) { + struct curseg_info *curseg; + u64 ssa_blk; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + curseg = CURSEG_I(sbi, i); + ssa_blk = GET_SUM_BLKADDR(sbi, + curseg->segno); + ret = dev_write_block(curseg->sum_blk, + ssa_blk, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + if (c.roll_forward) + restore_curseg_warm_node_info(sbi); + write_curseg_info(sbi); + } else { + fix_curseg_info(sbi, false); + } + fix_checksum(sbi); + fix_checkpoints(sbi); + } else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) || + is_set_ckpt_flags(cp, CP_QUOTA_NEED_FSCK_FLAG)) { + write_checkpoints(sbi); + } + + if (c.invalid_sb & SB_ABNORMAL_STOP) + memset(sb->s_stop_reason, 0, MAX_STOP_REASON); + + if (c.invalid_sb & SB_FS_ERRORS) + memset(sb->s_errors, 0, MAX_F2FS_ERRORS); + + if (c.invalid_sb & (SB_NEED_FIX | SB_ENCODE_FLAG)) + update_superblock(sb, SB_MASK_ALL); + + /* to return FSCK_ERROR_CORRECTED */ + ret = 0; + } + return ret; +} + +void fsck_free(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + if (fsck->qctx) + quota_release_context(&fsck->qctx); + + if (fsck->main_area_bitmap) + free(fsck->main_area_bitmap); + + if (fsck->nat_area_bitmap) + free(fsck->nat_area_bitmap); + + if (fsck->sit_area_bitmap) + free(fsck->sit_area_bitmap); + + if (fsck->entries) + free(fsck->entries); + + if (tree_mark) + free(tree_mark); + + while (fsck->dentry) { + struct f2fs_dentry *dentry = fsck->dentry; + + fsck->dentry = fsck->dentry->next; + free(dentry); + } +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.h new file mode 100644 index 00000000000..40cb6d9a641 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/fsck.h @@ -0,0 +1,364 @@ +/** + * fsck.h + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _FSCK_H_ +#define _FSCK_H_ + +#include "f2fs.h" + +enum { + FSCK_SUCCESS = 0, + FSCK_ERROR_CORRECTED = 1 << 0, + FSCK_SYSTEM_SHOULD_REBOOT = 1 << 1, + FSCK_ERRORS_LEFT_UNCORRECTED = 1 << 2, + FSCK_OPERATIONAL_ERROR = 1 << 3, + FSCK_USAGE_OR_SYNTAX_ERROR = 1 << 4, + FSCK_USER_CANCELLED = 1 << 5, + FSCK_SHARED_LIB_ERROR = 1 << 7, +}; + +struct quota_ctx; + +#define FSCK_UNMATCHED_EXTENT 0x00000001 +#define FSCK_INLINE_INODE 0x00000002 + +enum { + PREEN_MODE_0, + PREEN_MODE_1, + PREEN_MODE_2, + PREEN_MODE_MAX +}; + +enum { + NOERROR, + EWRONG_OPT, + ENEED_ARG, + EUNKNOWN_OPT, + EUNKNOWN_ARG, +}; + +enum SB_ADDR { + SB0_ADDR = 0, + SB1_ADDR, + SB_MAX_ADDR, +}; + +#define SB_MASK(i) (1 << (i)) +#define SB_MASK_ALL (SB_MASK(SB0_ADDR) | SB_MASK(SB1_ADDR)) + +/* fsck.c */ +struct orphan_info { + u32 nr_inodes; + u32 *ino_list; +}; + +struct extent_info { + u32 fofs; /* start offset in a file */ + u32 blk; /* start block address of the extent */ + u32 len; /* length of the extent */ +}; + +struct child_info { + u32 state; + u32 links; + u32 files; + u32 pgofs; + u8 dot; + u8 dotdot; + u8 dir_level; + u32 p_ino; /* parent ino */ + char p_name[F2FS_NAME_LEN + 1]; /* parent name */ + u32 pp_ino; /* parent parent ino*/ + struct extent_info ei; + u32 last_blk; + u32 i_namelen; /* dentry namelen */ +}; + +struct f2fs_dentry { + char name[F2FS_NAME_LEN + 1]; + int depth; + struct f2fs_dentry *next; +}; + +struct f2fs_fsck { + struct f2fs_sb_info sbi; + + struct orphan_info orphani; + struct chk_result { + u64 checked_node_cnt; + u64 valid_blk_cnt; + u32 valid_nat_entry_cnt; + u32 valid_node_cnt; + u32 valid_inode_cnt; + u32 multi_hard_link_files; + u64 sit_valid_blocks; + u32 sit_free_segs; + u32 wp_fixed; + u32 wp_inconsistent_zones; + } chk; + + struct hard_link_node *hard_link_list_head; + + char *main_seg_usage; + char *main_area_bitmap; + char *nat_area_bitmap; + char *sit_area_bitmap; + + u64 main_area_bitmap_sz; + u32 nat_area_bitmap_sz; + u32 sit_area_bitmap_sz; + + u64 nr_main_blks; + u32 nr_nat_entries; + + u32 dentry_depth; + struct f2fs_dentry *dentry; + struct f2fs_dentry *dentry_end; + struct f2fs_nat_entry *entries; + u32 nat_valid_inode_cnt; + + struct quota_ctx *qctx; +}; + +enum NODE_TYPE { + TYPE_INODE = 37, + TYPE_DIRECT_NODE = 43, + TYPE_INDIRECT_NODE = 53, + TYPE_DOUBLE_INDIRECT_NODE = 67, + TYPE_XATTR = 77 +}; + +struct hard_link_node { + u32 nid; + u32 links; + u32 actual_links; + struct hard_link_node *next; +}; + +enum seg_type { + SEG_TYPE_DATA, + SEG_TYPE_CUR_DATA, + SEG_TYPE_NODE, + SEG_TYPE_CUR_NODE, + SEG_TYPE_MAX, +}; + +struct selabel_handle; + +static inline bool need_fsync_data_record(struct f2fs_sb_info *sbi) +{ + return !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG); +} + +extern int fsck_chk_orphan_node(struct f2fs_sb_info *); +extern int fsck_chk_quota_node(struct f2fs_sb_info *); +extern int fsck_chk_quota_files(struct f2fs_sb_info *); +extern int fsck_sanity_check_nid(struct f2fs_sb_info *, u32, + enum FILE_TYPE, enum NODE_TYPE); +extern int fsck_sanity_check_nat(struct f2fs_sb_info *sbi, u32 nid); +extern int fsck_chk_node_blk(struct f2fs_sb_info *, struct f2fs_inode *, u32, + enum FILE_TYPE, enum NODE_TYPE, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *); +extern int fsck_chk_root_inode(struct f2fs_sb_info *); +extern void fsck_chk_inode_blk(struct f2fs_sb_info *, u32, enum FILE_TYPE, + struct f2fs_node *, u32 *, struct f2fs_compr_blk_cnt *, + struct node_info *, struct child_info *); +extern int fsck_chk_dnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, + u32, enum FILE_TYPE, struct f2fs_node *, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *, + struct node_info *); +extern int fsck_chk_idnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, + enum FILE_TYPE, struct f2fs_node *, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *); +extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *, + enum FILE_TYPE, struct f2fs_node *, u32 *, + struct f2fs_compr_blk_cnt *, struct child_info *); +extern int fsck_chk_data_blk(struct f2fs_sb_info *, struct f2fs_inode *, + u32, struct child_info *, int, enum FILE_TYPE, u32, u16, u8, + struct f2fs_node *); +extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, int, + u32, struct child_info *, int, int, struct f2fs_node *); +int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *, + struct child_info *); +void fsck_chk_checkpoint(struct f2fs_sb_info *sbi); +void fsck_update_sb_flags(struct f2fs_sb_info *sbi); +int fsck_chk_meta(struct f2fs_sb_info *sbi); +void fsck_chk_and_fix_write_pointers(struct f2fs_sb_info *); +int fsck_chk_curseg_info(struct f2fs_sb_info *); +void pretty_print_filename(const u8 *raw_name, u32 len, + char out[F2FS_PRINT_NAMELEN], int enc_name); + +extern void update_free_segments(struct f2fs_sb_info *); +void print_cp_state(u32); +extern void print_node_info(struct f2fs_sb_info *, struct f2fs_node *, int); +extern void print_inode_info(struct f2fs_sb_info *, struct f2fs_node *, int); +extern struct seg_entry *get_seg_entry(struct f2fs_sb_info *, unsigned int); +extern struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *, + unsigned int, int *); +extern int get_sum_entry(struct f2fs_sb_info *, u32, struct f2fs_summary *); +extern void update_sum_entry(struct f2fs_sb_info *, block_t, + struct f2fs_summary *); +extern void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *); +extern void nullify_nat_entry(struct f2fs_sb_info *, u32); +extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *); +extern void build_nat_area_bitmap(struct f2fs_sb_info *); +extern void build_sit_area_bitmap(struct f2fs_sb_info *); +extern int f2fs_set_main_bitmap(struct f2fs_sb_info *, u32, int); +extern int f2fs_clear_main_bitmap(struct f2fs_sb_info *, u32); +extern int f2fs_set_sit_bitmap(struct f2fs_sb_info *, u32); +extern int f2fs_clear_sit_bitmap(struct f2fs_sb_info *, u32); +extern void fsck_init(struct f2fs_sb_info *); +extern int fsck_verify(struct f2fs_sb_info *); +extern void fsck_free(struct f2fs_sb_info *); +extern bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type); +extern int f2fs_ra_meta_pages(struct f2fs_sb_info *, block_t, int, int); +extern int f2fs_do_mount(struct f2fs_sb_info *); +extern void f2fs_do_umount(struct f2fs_sb_info *); +extern int f2fs_sparse_initialize_meta(struct f2fs_sb_info *); + +extern void flush_journal_entries(struct f2fs_sb_info *); +extern void update_curseg_info(struct f2fs_sb_info *, int); +extern void zero_journal_entries(struct f2fs_sb_info *); +extern void flush_sit_entries(struct f2fs_sb_info *); +extern void move_curseg_info(struct f2fs_sb_info *, u64, int); +extern void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left, + int i); +extern void write_curseg_info(struct f2fs_sb_info *); +extern void save_curseg_warm_node_info(struct f2fs_sb_info *); +extern void restore_curseg_warm_node_info(struct f2fs_sb_info *); +extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int, bool); +extern void duplicate_checkpoint(struct f2fs_sb_info *); +extern void write_checkpoint(struct f2fs_sb_info *); +extern void write_checkpoints(struct f2fs_sb_info *); +extern void write_raw_cp_blocks(struct f2fs_sb_info *sbi, + struct f2fs_checkpoint *cp, int which); +extern void update_superblock(struct f2fs_super_block *, int); +extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t, + struct f2fs_node *); +extern void update_nat_blkaddr(struct f2fs_sb_info *, nid_t, nid_t, block_t); + +extern void print_raw_sb_info(struct f2fs_super_block *); +extern void print_ckpt_info(struct f2fs_sb_info *); +extern bool is_checkpoint_stop(struct f2fs_super_block *, bool); +extern bool is_inconsistent_error(struct f2fs_super_block *); +extern pgoff_t current_nat_addr(struct f2fs_sb_info *, nid_t, int *); + +extern u32 get_free_segments(struct f2fs_sb_info *); +extern void get_current_sit_page(struct f2fs_sb_info *, + unsigned int, struct f2fs_sit_block *); +extern void rewrite_current_sit_page(struct f2fs_sb_info *, unsigned int, + struct f2fs_sit_block *); + +extern u32 update_nat_bits_flags(struct f2fs_super_block *, + struct f2fs_checkpoint *, u32); +extern void write_nat_bits(struct f2fs_sb_info *, struct f2fs_super_block *, + struct f2fs_checkpoint *, int); +extern unsigned int get_usable_seg_count(struct f2fs_sb_info *); +extern bool is_usable_seg(struct f2fs_sb_info *, unsigned int); + +/* dump.c */ +struct dump_option { + nid_t nid; + nid_t start_nat; + nid_t end_nat; + int start_sit; + int end_sit; + int start_ssa; + int end_ssa; + int32_t blk_addr; + nid_t scan_nid; + int use_root_nid; + char *base_path; +}; + +extern void nat_dump(struct f2fs_sb_info *, nid_t, nid_t); +extern void sit_dump(struct f2fs_sb_info *, unsigned int, unsigned int); +extern void ssa_dump(struct f2fs_sb_info *, int, int); +extern int dump_node(struct f2fs_sb_info *, nid_t, int, char *, int, int, char *); +extern int dump_info_from_blkaddr(struct f2fs_sb_info *, u32); +extern unsigned int start_bidx_of_node(unsigned int, struct f2fs_node *); +extern void dump_node_scan_disk(struct f2fs_sb_info *sbi, nid_t nid); +extern bool is_sit_bitmap_set(struct f2fs_sb_info *sbi, u32 blk_addr); + +/* defrag.c */ +int f2fs_defragment(struct f2fs_sb_info *, u64, u64, u64, int); + +/* resize.c */ +int f2fs_resize(struct f2fs_sb_info *); + +/* sload.c */ +int f2fs_sload(struct f2fs_sb_info *); + +/* segment.c */ +int reserve_new_block(struct f2fs_sb_info *, block_t *, + struct f2fs_summary *, int, bool); +int new_data_block(struct f2fs_sb_info *, void *, + struct dnode_of_data *, int); +int f2fs_build_file(struct f2fs_sb_info *, struct dentry *); +void f2fs_alloc_nid(struct f2fs_sb_info *, nid_t *); +void set_data_blkaddr(struct dnode_of_data *); +block_t new_node_block(struct f2fs_sb_info *, + struct dnode_of_data *, unsigned int); +int f2fs_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype); +int update_block(struct f2fs_sb_info *sbi, void *buf, u32 *blkaddr, + struct f2fs_node *node_blk); + +/* segment.c */ +struct quota_file; +u64 f2fs_quota_size(struct quota_file *); +u64 f2fs_read(struct f2fs_sb_info *, nid_t, u8 *, u64, pgoff_t); +enum wr_addr_type { + WR_NORMAL = 1, + WR_COMPRESS_DATA = 2, + WR_NULL_ADDR = NULL_ADDR, /* 0 */ + WR_NEW_ADDR = NEW_ADDR, /* -1U */ + WR_COMPRESS_ADDR = COMPRESS_ADDR, /* -2U */ +}; +u64 f2fs_write(struct f2fs_sb_info *, nid_t, u8 *, u64, pgoff_t); +u64 f2fs_write_compress_data(struct f2fs_sb_info *, nid_t, u8 *, u64, pgoff_t); +u64 f2fs_write_addrtag(struct f2fs_sb_info *, nid_t, pgoff_t, unsigned int); +void f2fs_filesize_update(struct f2fs_sb_info *, nid_t, u64); + +int get_dnode_of_data(struct f2fs_sb_info *, struct dnode_of_data *, + pgoff_t, int); +void make_dentry_ptr(struct f2fs_dentry_ptr *, struct f2fs_node *, void *, int); +int f2fs_create(struct f2fs_sb_info *, struct dentry *); +int f2fs_mkdir(struct f2fs_sb_info *, struct dentry *); +int f2fs_symlink(struct f2fs_sb_info *, struct dentry *); +int inode_set_selinux(struct f2fs_sb_info *, u32, const char *); +int f2fs_find_path(struct f2fs_sb_info *, char *, nid_t *); +nid_t f2fs_lookup(struct f2fs_sb_info *, struct f2fs_node *, u8 *, int); +int f2fs_add_link(struct f2fs_sb_info *, struct f2fs_node *, + const unsigned char *, int, nid_t, int, block_t *, int); +struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi, + struct dentry *de); + +/* xattr.c */ +void *read_all_xattrs(struct f2fs_sb_info *, struct f2fs_node *, bool); +void write_all_xattrs(struct f2fs_sb_info *sbi, + struct f2fs_node *inode, __u32 hsize, void *txattr_addr); + +/* dir.c */ +int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node, + block_t *p_blkaddr); + +/* node.c */ +int update_inode(struct f2fs_sb_info *sbi, struct f2fs_node *inode, + u32 *blkaddr); + +/* mount.c */ +int flush_nat_journal_entries(struct f2fs_sb_info *sbi); +int flush_sit_journal_entries(struct f2fs_sb_info *sbi); + +/* main.c */ +int is_digits(char *optarg); + +#endif /* _FSCK_H_ */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.c new file mode 100644 index 00000000000..bd6ab848097 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.c @@ -0,0 +1,1108 @@ +/** + * inject.c + * + * Copyright (c) 2024 OPPO Mobile Comm Corp., Ltd. + * http://www.oppo.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include "node.h" +#include "inject.h" + +static void print_raw_nat_entry_info(struct f2fs_nat_entry *ne) +{ + if (!c.dbg_lv) + return; + + DISP_u8(ne, version); + DISP_u32(ne, ino); + DISP_u32(ne, block_addr); +} + +static void print_raw_sit_entry_info(struct f2fs_sit_entry *se) +{ + int i; + + if (!c.dbg_lv) + return; + + DISP_u16(se, vblocks); + if (c.layout) + printf("%-30s ", "valid_map:"); + else + printf("%-30s\t\t[", "valid_map"); + for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) + printf("%02x", se->valid_map[i]); + if (c.layout) + printf("\n"); + else + printf("]\n"); + DISP_u64(se, mtime); +} + +static void print_raw_sum_entry_info(struct f2fs_summary *sum) +{ + if (!c.dbg_lv) + return; + + DISP_u32(sum, nid); + DISP_u8(sum, version); + DISP_u16(sum, ofs_in_node); +} + +static void print_sum_footer_info(struct summary_footer *footer) +{ + if (!c.dbg_lv) + return; + + DISP_u8(footer, entry_type); + DISP_u32(footer, check_sum); +} + +static void print_node_footer_info(struct node_footer *footer) +{ + if (!c.dbg_lv) + return; + + DISP_u32(footer, nid); + DISP_u32(footer, ino); + DISP_u32(footer, flag); + DISP_u64(footer, cp_ver); + DISP_u32(footer, next_blkaddr); +} + +static void print_raw_dentry_info(struct f2fs_dir_entry *dentry) +{ + if (!c.dbg_lv) + return; + + DISP_u32(dentry, hash_code); + DISP_u32(dentry, ino); + DISP_u16(dentry, name_len); + DISP_u8(dentry, file_type); +} + +void inject_usage(void) +{ + MSG(0, "\nUsage: inject.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -V print the version number and exit\n"); + MSG(0, " --mb which member is injected in a struct\n"); + MSG(0, " --val new value to set\n"); + MSG(0, " --str new string to set\n"); + MSG(0, " --idx which slot is injected in an array\n"); + MSG(0, " --nid which nid is injected\n"); + MSG(0, " --blk which blkaddr is injected\n"); + MSG(0, " --sb <0|1|2> --mb [--idx ] --val/str inject superblock\n"); + MSG(0, " --cp <0|1|2> --mb [--idx ] --val inject checkpoint\n"); + MSG(0, " --nat <0|1|2> --mb --nid --val inject nat entry\n"); + MSG(0, " --sit <0|1|2> --mb --blk [--idx ] --val inject sit entry\n"); + MSG(0, " --ssa --mb --blk [--idx ] --val inject summary entry\n"); + MSG(0, " --node --mb --nid [--idx ] --val inject node\n"); + MSG(0, " --dent --mb --nid [--idx ] --val inject ino's dentry\n"); + MSG(0, " --dry-run do not really inject\n"); + + exit(1); +} + +static void inject_sb_usage(void) +{ + MSG(0, "inject.f2fs --sb <0|1|2> --mb [--idx ] --val/str \n"); + MSG(0, "[sb]:\n"); + MSG(0, " 0: auto select the first super block\n"); + MSG(0, " 1: select the first super block\n"); + MSG(0, " 2: select the second super block\n"); + MSG(0, "[mb]:\n"); + MSG(0, " magic: inject magic number\n"); + MSG(0, " s_stop_reason: inject s_stop_reason array selected by --idx \n"); + MSG(0, " s_errors: inject s_errors array selected by --idx \n"); + MSG(0, " devs.path: inject path in devs array selected by --idx specified by --str \n"); +} + +static void inject_cp_usage(void) +{ + MSG(0, "inject.f2fs --cp <0|1|2> --mb [--idx ] --val inject checkpoint\n"); + MSG(0, "[cp]:\n"); + MSG(0, " 0: auto select the current cp pack\n"); + MSG(0, " 1: select the first cp pack\n"); + MSG(0, " 2: select the second cp pack\n"); + MSG(0, "[mb]:\n"); + MSG(0, " checkpoint_ver: inject checkpoint_ver\n"); + MSG(0, " ckpt_flags: inject ckpt_flags\n"); + MSG(0, " cur_node_segno: inject cur_node_segno array selected by --idx \n"); + MSG(0, " cur_node_blkoff: inject cur_node_blkoff array selected by --idx \n"); + MSG(0, " cur_data_segno: inject cur_data_segno array selected by --idx \n"); + MSG(0, " cur_data_blkoff: inject cur_data_blkoff array selected by --idx \n"); +} + +static void inject_nat_usage(void) +{ + MSG(0, "inject.f2fs --nat <0|1|2> --mb --nid --val inject nat entry\n"); + MSG(0, "[nat]:\n"); + MSG(0, " 0: auto select the current nat pack\n"); + MSG(0, " 1: select the first nat pack\n"); + MSG(0, " 2: select the second nat pack\n"); + MSG(0, "[mb]:\n"); + MSG(0, " version: inject nat entry version\n"); + MSG(0, " ino: inject nat entry ino\n"); + MSG(0, " block_addr: inject nat entry block_addr\n"); +} + +static void inject_sit_usage(void) +{ + MSG(0, "inject.f2fs --sit <0|1|2> --mb --blk [--idx ] --val inject sit entry\n"); + MSG(0, "[sit]:\n"); + MSG(0, " 0: auto select the current sit pack\n"); + MSG(0, " 1: select the first sit pack\n"); + MSG(0, " 2: select the second sit pack\n"); + MSG(0, "[mb]:\n"); + MSG(0, " vblocks: inject sit entry vblocks\n"); + MSG(0, " valid_map: inject sit entry valid_map\n"); + MSG(0, " mtime: inject sit entry mtime\n"); +} + +static void inject_ssa_usage(void) +{ + MSG(0, "inject.f2fs --ssa --mb --blk [--idx ] --val inject summary entry\n"); + MSG(0, "[mb]:\n"); + MSG(0, " entry_type: inject summary block footer entry_type\n"); + MSG(0, " check_sum: inject summary block footer check_sum\n"); + MSG(0, " nid: inject summary entry nid selected by --idx --nid [--idx ] --val inject node\n"); + MSG(0, "[mb]:\n"); + MSG(0, " nid: inject node footer nid\n"); + MSG(0, " ino: inject node footer ino\n"); + MSG(0, " flag: inject node footer flag\n"); + MSG(0, " cp_ver: inject node footer cp_ver\n"); + MSG(0, " next_blkaddr: inject node footer next_blkaddr\n"); + MSG(0, " i_mode: inject inode i_mode\n"); + MSG(0, " i_advise: inject inode i_advise\n"); + MSG(0, " i_inline: inject inode i_inline\n"); + MSG(0, " i_links: inject inode i_links\n"); + MSG(0, " i_size: inject inode i_size\n"); + MSG(0, " i_blocks: inject inode i_blocks\n"); + MSG(0, " i_extra_isize: inject inode i_extra_isize\n"); + MSG(0, " i_inode_checksum: inject inode i_inode_checksum\n"); + MSG(0, " i_addr: inject inode i_addr array selected by --idx \n"); + MSG(0, " i_nid: inject inode i_nid array selected by --idx \n"); + MSG(0, " addr: inject {in}direct node nid/addr array selected by --idx \n"); +} + +static void inject_dent_usage(void) +{ + MSG(0, "inject.f2fs --dent --mb --nid [--idx ] --val inject dentry\n"); + MSG(0, "[mb]:\n"); + MSG(0, " d_bitmap: inject dentry block d_bitmap of nid\n"); + MSG(0, " d_hash: inject dentry hash\n"); + MSG(0, " d_ino: inject dentry ino\n"); + MSG(0, " d_ftype: inject dentry ftype\n"); +} + +int inject_parse_options(int argc, char *argv[], struct inject_option *opt) +{ + int o = 0; + const char *pack[] = {"auto", "1", "2"}; + const char *option_string = "d:Vh"; + char *endptr; + struct option long_opt[] = { + {"dry-run", no_argument, 0, 1}, + {"mb", required_argument, 0, 2}, + {"idx", required_argument, 0, 3}, + {"val", required_argument, 0, 4}, + {"str", required_argument, 0, 5}, + {"sb", required_argument, 0, 6}, + {"cp", required_argument, 0, 7}, + {"nat", required_argument, 0, 8}, + {"nid", required_argument, 0, 9}, + {"sit", required_argument, 0, 10}, + {"blk", required_argument, 0, 11}, + {"ssa", no_argument, 0, 12}, + {"node", no_argument, 0, 13}, + {"dent", no_argument, 0, 14}, + {0, 0, 0, 0} + }; + + while ((o = getopt_long(argc, argv, option_string, + long_opt, NULL)) != EOF) { + long nid, blk; + + switch (o) { + case 1: + c.dry_run = 1; + MSG(0, "Info: Dry run\n"); + break; + case 2: + opt->mb = optarg; + MSG(0, "Info: inject member %s\n", optarg); + break; + case 3: + if (!is_digits(optarg)) + return EWRONG_OPT; + opt->idx = atoi(optarg); + MSG(0, "Info: inject slot index %d\n", opt->idx); + break; + case 4: + opt->val = strtoll(optarg, &endptr, 0); + if (opt->val == LLONG_MAX || opt->val == LLONG_MIN || + *endptr != '\0') + return -ERANGE; + MSG(0, "Info: inject value %lld : 0x%llx\n", opt->val, + (unsigned long long)opt->val); + break; + case 5: + opt->str = strdup(optarg); + if (!opt->str) + return -ENOMEM; + MSG(0, "Info: inject string %s\n", opt->str); + break; + case 6: + if (!is_digits(optarg)) + return EWRONG_OPT; + opt->sb = atoi(optarg); + if (opt->sb < 0 || opt->sb > 2) + return -ERANGE; + MSG(0, "Info: inject sb %s\n", pack[opt->sb]); + break; + case 7: + if (!is_digits(optarg)) + return EWRONG_OPT; + opt->cp = atoi(optarg); + if (opt->cp < 0 || opt->cp > 2) + return -ERANGE; + MSG(0, "Info: inject cp pack %s\n", pack[opt->cp]); + break; + case 8: + if (!is_digits(optarg)) + return EWRONG_OPT; + opt->nat = atoi(optarg); + if (opt->nat < 0 || opt->nat > 2) + return -ERANGE; + MSG(0, "Info: inject nat pack %s\n", pack[opt->nat]); + break; + case 9: + nid = strtol(optarg, &endptr, 0); + if (nid >= UINT_MAX || nid < 0 || + *endptr != '\0') + return -ERANGE; + opt->nid = nid; + MSG(0, "Info: inject nid %u : 0x%x\n", opt->nid, opt->nid); + break; + case 10: + if (!is_digits(optarg)) + return EWRONG_OPT; + opt->sit = atoi(optarg); + if (opt->sit < 0 || opt->sit > 2) + return -ERANGE; + MSG(0, "Info: inject sit pack %s\n", pack[opt->sit]); + break; + case 11: + blk = strtol(optarg, &endptr, 0); + if (blk >= UINT_MAX || blk < 0 || + *endptr != '\0') + return -ERANGE; + opt->blk = blk; + MSG(0, "Info: inject blkaddr %u : 0x%x\n", opt->blk, opt->blk); + break; + case 12: + opt->ssa = true; + MSG(0, "Info: inject ssa\n"); + break; + case 13: + opt->node = true; + MSG(0, "Info: inject node\n"); + break; + case 14: + opt->dent = true; + MSG(0, "Info: inject dentry\n"); + break; + case 'd': + if (optarg[0] == '-' || !is_digits(optarg)) + return EWRONG_OPT; + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", c.dbg_lv); + break; + case 'V': + show_version("inject.f2fs"); + exit(0); + case 'h': + default: + if (opt->sb >= 0) { + inject_sb_usage(); + exit(0); + } else if (opt->cp >= 0) { + inject_cp_usage(); + exit(0); + } else if (opt->nat >= 0) { + inject_nat_usage(); + exit(0); + } else if (opt->sit >= 0) { + inject_sit_usage(); + exit(0); + } else if (opt->ssa) { + inject_ssa_usage(); + exit(0); + } else if (opt->node) { + inject_node_usage(); + exit(0); + } else if (opt->dent) { + inject_dent_usage(); + exit(0); + } + return EUNKNOWN_OPT; + } + } + + return 0; +} + +static int inject_sb(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct f2fs_super_block *sb; + char *buf; + int ret; + + buf = calloc(1, F2FS_BLKSIZE); + ASSERT(buf != NULL); + + if (opt->sb == 0) + opt->sb = 1; + + ret = dev_read_block(buf, opt->sb == 1 ? SB0_ADDR : SB1_ADDR); + ASSERT(ret >= 0); + + sb = (struct f2fs_super_block *)(buf + F2FS_SUPER_OFFSET); + + if (!strcmp(opt->mb, "magic")) { + MSG(0, "Info: inject magic of sb %d: 0x%x -> 0x%x\n", + opt->sb, get_sb(magic), (u32)opt->val); + set_sb(magic, (u32)opt->val); + } else if (!strcmp(opt->mb, "s_stop_reason")) { + if (opt->idx >= MAX_STOP_REASON) { + ERR_MSG("invalid index %u of sb->s_stop_reason[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject s_stop_reason[%d] of sb %d: %d -> %d\n", + opt->idx, opt->sb, sb->s_stop_reason[opt->idx], + (u8)opt->val); + sb->s_stop_reason[opt->idx] = (u8)opt->val; + } else if (!strcmp(opt->mb, "s_errors")) { + if (opt->idx >= MAX_F2FS_ERRORS) { + ERR_MSG("invalid index %u of sb->s_errors[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject s_errors[%d] of sb %d: %x -> %x\n", + opt->idx, opt->sb, sb->s_errors[opt->idx], (u8)opt->val); + sb->s_errors[opt->idx] = (u8)opt->val; + } else if (!strcmp(opt->mb, "devs.path")) { + if (opt->idx >= MAX_DEVICES) { + ERR_MSG("invalid index %u of sb->devs[]\n", opt->idx); + ret = -EINVAL; + goto out; + } + if (strlen(opt->str) >= MAX_PATH_LEN) { + ERR_MSG("invalid length of option str\n"); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject devs[%d].path of sb %d: %s -> %s\n", + opt->idx, opt->sb, (char *)sb->devs[opt->idx].path, opt->str); + strcpy((char *)sb->devs[opt->idx].path, opt->str); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + ret = -EINVAL; + goto out; + } + + print_raw_sb_info(sb); + update_superblock(sb, SB_MASK((u32)opt->sb - 1)); + +out: + free(buf); + free(opt->str); + return ret; +} + +static int inject_cp(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct f2fs_checkpoint *cp, *cur_cp = F2FS_CKPT(sbi); + char *buf = NULL; + int ret = 0; + + if (opt->cp == 0) + opt->cp = sbi->cur_cp; + + if (opt->cp != sbi->cur_cp) { + struct f2fs_super_block *sb = sbi->raw_super; + block_t cp_addr; + + buf = calloc(1, F2FS_BLKSIZE); + ASSERT(buf != NULL); + + cp_addr = get_sb(cp_blkaddr); + if (opt->cp == 2) + cp_addr += 1 << get_sb(log_blocks_per_seg); + ret = dev_read_block(buf, cp_addr); + ASSERT(ret >= 0); + + cp = (struct f2fs_checkpoint *)buf; + sbi->ckpt = cp; + sbi->cur_cp = opt->cp; + } else { + cp = cur_cp; + } + + if (!strcmp(opt->mb, "checkpoint_ver")) { + MSG(0, "Info: inject checkpoint_ver of cp %d: 0x%llx -> 0x%"PRIx64"\n", + opt->cp, get_cp(checkpoint_ver), (u64)opt->val); + set_cp(checkpoint_ver, (u64)opt->val); + } else if (!strcmp(opt->mb, "ckpt_flags")) { + MSG(0, "Info: inject ckpt_flags of cp %d: 0x%x -> 0x%x\n", + opt->cp, get_cp(ckpt_flags), (u32)opt->val); + set_cp(ckpt_flags, (u32)opt->val); + } else if (!strcmp(opt->mb, "cur_node_segno")) { + if (opt->idx >= MAX_ACTIVE_NODE_LOGS) { + ERR_MSG("invalid index %u of cp->cur_node_segno[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject cur_node_segno[%d] of cp %d: 0x%x -> 0x%x\n", + opt->idx, opt->cp, get_cp(cur_node_segno[opt->idx]), + (u32)opt->val); + set_cp(cur_node_segno[opt->idx], (u32)opt->val); + } else if (!strcmp(opt->mb, "cur_node_blkoff")) { + if (opt->idx >= MAX_ACTIVE_NODE_LOGS) { + ERR_MSG("invalid index %u of cp->cur_node_blkoff[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject cur_node_blkoff[%d] of cp %d: 0x%x -> 0x%x\n", + opt->idx, opt->cp, get_cp(cur_node_blkoff[opt->idx]), + (u16)opt->val); + set_cp(cur_node_blkoff[opt->idx], (u16)opt->val); + } else if (!strcmp(opt->mb, "cur_data_segno")) { + if (opt->idx >= MAX_ACTIVE_DATA_LOGS) { + ERR_MSG("invalid index %u of cp->cur_data_segno[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject cur_data_segno[%d] of cp %d: 0x%x -> 0x%x\n", + opt->idx, opt->cp, get_cp(cur_data_segno[opt->idx]), + (u32)opt->val); + set_cp(cur_data_segno[opt->idx], (u32)opt->val); + } else if (!strcmp(opt->mb, "cur_data_blkoff")) { + if (opt->idx >= MAX_ACTIVE_DATA_LOGS) { + ERR_MSG("invalid index %u of cp->cur_data_blkoff[]\n", + opt->idx); + ret = -EINVAL; + goto out; + } + MSG(0, "Info: inject cur_data_blkoff[%d] of cp %d: 0x%x -> 0x%x\n", + opt->idx, opt->cp, get_cp(cur_data_blkoff[opt->idx]), + (u16)opt->val); + set_cp(cur_data_blkoff[opt->idx], (u16)opt->val); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + ret = -EINVAL; + goto out; + } + + print_ckpt_info(sbi); + write_raw_cp_blocks(sbi, cp, opt->cp); + +out: + free(buf); + sbi->ckpt = cur_cp; + return ret; +} + +static int inject_nat(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_nat_block *nat_blk; + struct f2fs_nat_entry *ne; + block_t blk_addr; + unsigned int offs; + bool is_set; + int ret; + + if (!IS_VALID_NID(sbi, opt->nid)) { + ERR_MSG("Invalid nid %u range [%u:%"PRIu64"]\n", opt->nid, 0, + NAT_ENTRY_PER_BLOCK * + ((get_sb(segment_count_nat) << 1) << + sbi->log_blocks_per_seg)); + return -EINVAL; + } + + nat_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_blk); + + /* change NAT version bitmap temporarily to select specified pack */ + is_set = f2fs_test_bit(opt->nid, nm_i->nat_bitmap); + if (opt->nat == 0) { + opt->nat = is_set ? 2 : 1; + } else { + if (opt->nat == 1) + f2fs_clear_bit(opt->nid, nm_i->nat_bitmap); + else + f2fs_set_bit(opt->nid, nm_i->nat_bitmap); + } + + blk_addr = current_nat_addr(sbi, opt->nid, NULL); + + ret = dev_read_block(nat_blk, blk_addr); + ASSERT(ret >= 0); + + offs = opt->nid % NAT_ENTRY_PER_BLOCK; + ne = &nat_blk->entries[offs]; + + if (!strcmp(opt->mb, "version")) { + MSG(0, "Info: inject nat entry version of nid %u " + "in pack %d: %d -> %d\n", opt->nid, opt->nat, + ne->version, (u8)opt->val); + ne->version = (u8)opt->val; + } else if (!strcmp(opt->mb, "ino")) { + MSG(0, "Info: inject nat entry ino of nid %u " + "in pack %d: %d -> %d\n", opt->nid, opt->nat, + le32_to_cpu(ne->ino), (nid_t)opt->val); + ne->ino = cpu_to_le32((nid_t)opt->val); + } else if (!strcmp(opt->mb, "block_addr")) { + MSG(0, "Info: inject nat entry block_addr of nid %u " + "in pack %d: 0x%x -> 0x%x\n", opt->nid, opt->nat, + le32_to_cpu(ne->block_addr), (block_t)opt->val); + ne->block_addr = cpu_to_le32((block_t)opt->val); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + free(nat_blk); + return -EINVAL; + } + print_raw_nat_entry_info(ne); + + ret = dev_write_block(nat_blk, blk_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + /* restore NAT version bitmap */ + if (is_set) + f2fs_set_bit(opt->nid, nm_i->nat_bitmap); + else + f2fs_clear_bit(opt->nid, nm_i->nat_bitmap); + + free(nat_blk); + return ret; +} + +static int inject_sit(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sit_block *sit_blk; + struct f2fs_sit_entry *sit; + unsigned int segno, offs; + bool is_set; + + if (!f2fs_is_valid_blkaddr(sbi, opt->blk, DATA_GENERIC)) { + ERR_MSG("Invalid blkaddr 0x%x (valid range [0x%x:0x%lx])\n", + opt->blk, SM_I(sbi)->main_blkaddr, + (unsigned long)le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count)); + return -EINVAL; + } + + sit_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sit_blk); + + segno = GET_SEGNO(sbi, opt->blk); + /* change SIT version bitmap temporarily to select specified pack */ + is_set = f2fs_test_bit(segno, sit_i->sit_bitmap); + if (opt->sit == 0) { + opt->sit = is_set ? 2 : 1; + } else { + if (opt->sit == 1) + f2fs_clear_bit(segno, sit_i->sit_bitmap); + else + f2fs_set_bit(segno, sit_i->sit_bitmap); + } + get_current_sit_page(sbi, segno, sit_blk); + offs = SIT_ENTRY_OFFSET(sit_i, segno); + sit = &sit_blk->entries[offs]; + + if (!strcmp(opt->mb, "vblocks")) { + MSG(0, "Info: inject sit entry vblocks of block 0x%x " + "in pack %d: %u -> %u\n", opt->blk, opt->sit, + le16_to_cpu(sit->vblocks), (u16)opt->val); + sit->vblocks = cpu_to_le16((u16)opt->val); + } else if (!strcmp(opt->mb, "valid_map")) { + if (opt->idx == -1) { + MSG(0, "Info: auto idx = %u\n", offs); + opt->idx = offs; + } + if (opt->idx >= SIT_VBLOCK_MAP_SIZE) { + ERR_MSG("invalid idx %u of valid_map[]\n", opt->idx); + free(sit_blk); + return -ERANGE; + } + MSG(0, "Info: inject sit entry valid_map[%d] of block 0x%x " + "in pack %d: 0x%02x -> 0x%02x\n", opt->idx, opt->blk, + opt->sit, sit->valid_map[opt->idx], (u8)opt->val); + sit->valid_map[opt->idx] = (u8)opt->val; + } else if (!strcmp(opt->mb, "mtime")) { + MSG(0, "Info: inject sit entry mtime of block 0x%x " + "in pack %d: %"PRIu64" -> %"PRIu64"\n", opt->blk, opt->sit, + le64_to_cpu(sit->mtime), (u64)opt->val); + sit->mtime = cpu_to_le64((u64)opt->val); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + free(sit_blk); + return -EINVAL; + } + print_raw_sit_entry_info(sit); + + rewrite_current_sit_page(sbi, segno, sit_blk); + /* restore SIT version bitmap */ + if (is_set) + f2fs_set_bit(segno, sit_i->sit_bitmap); + else + f2fs_clear_bit(segno, sit_i->sit_bitmap); + + free(sit_blk); + return 0; +} + +static int inject_ssa(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct f2fs_summary_block *sum_blk; + struct summary_footer *footer; + struct f2fs_summary *sum; + u32 segno, offset; + block_t ssa_blkaddr; + int type; + int ret; + + if (!f2fs_is_valid_blkaddr(sbi, opt->blk, DATA_GENERIC)) { + ERR_MSG("Invalid blkaddr %#x (valid range [%#x:%#lx])\n", + opt->blk, SM_I(sbi)->main_blkaddr, + (unsigned long)le64_to_cpu(F2FS_RAW_SUPER(sbi)->block_count)); + return -ERANGE; + } + + segno = GET_SEGNO(sbi, opt->blk); + offset = OFFSET_IN_SEG(sbi, opt->blk); + + sum_blk = get_sum_block(sbi, segno, &type); + sum = &sum_blk->entries[offset]; + footer = F2FS_SUMMARY_BLOCK_FOOTER(sum_blk); + + if (!strcmp(opt->mb, "entry_type")) { + MSG(0, "Info: inject summary block footer entry_type of " + "block 0x%x: %d -> %d\n", opt->blk, footer->entry_type, + (unsigned char)opt->val); + footer->entry_type = (unsigned char)opt->val; + } else if (!strcmp(opt->mb, "check_sum")) { + MSG(0, "Info: inject summary block footer check_sum of " + "block 0x%x: 0x%x -> 0x%x\n", opt->blk, + le32_to_cpu(footer->check_sum), (u32)opt->val); + footer->check_sum = cpu_to_le32((u32)opt->val); + } else { + if (opt->idx == -1) { + MSG(0, "Info: auto idx = %u\n", offset); + opt->idx = offset; + } + if (opt->idx >= ENTRIES_IN_SUM) { + ERR_MSG("invalid idx %u of entries[]\n", opt->idx); + ret = -EINVAL; + goto out; + } + sum = &sum_blk->entries[opt->idx]; + if (!strcmp(opt->mb, "nid")) { + MSG(0, "Info: inject summary entry nid of " + "block 0x%x: 0x%x -> 0x%x\n", opt->blk, + le32_to_cpu(sum->nid), (u32)opt->val); + sum->nid = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "version")) { + MSG(0, "Info: inject summary entry version of " + "block 0x%x: %d -> %d\n", opt->blk, + sum->version, (u8)opt->val); + sum->version = (u8)opt->val; + } else if (!strcmp(opt->mb, "ofs_in_node")) { + MSG(0, "Info: inject summary entry ofs_in_node of " + "block 0x%x: %d -> %d\n", opt->blk, + sum->ofs_in_node, (u16)opt->val); + sum->ofs_in_node = cpu_to_le16((u16)opt->val); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + ret = -EINVAL; + goto out; + } + + print_raw_sum_entry_info(sum); + } + + print_sum_footer_info(footer); + + ssa_blkaddr = GET_SUM_BLKADDR(sbi, segno); + ret = dev_write_block(sum_blk, ssa_blkaddr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + +out: + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); + return ret; +} + +static int inject_inode(struct f2fs_sb_info *sbi, struct f2fs_node *node, + struct inject_option *opt) +{ + struct f2fs_inode *inode = &node->i; + + if (!strcmp(opt->mb, "i_mode")) { + MSG(0, "Info: inject inode i_mode of nid %u: 0x%x -> 0x%x\n", + opt->nid, le16_to_cpu(inode->i_mode), (u16)opt->val); + inode->i_mode = cpu_to_le16((u16)opt->val); + } else if (!strcmp(opt->mb, "i_advise")) { + MSG(0, "Info: inject inode i_advise of nid %u: 0x%x -> 0x%x\n", + opt->nid, inode->i_advise, (u8)opt->val); + inode->i_advise = (u8)opt->val; + } else if (!strcmp(opt->mb, "i_inline")) { + MSG(0, "Info: inject inode i_inline of nid %u: 0x%x -> 0x%x\n", + opt->nid, inode->i_inline, (u8)opt->val); + inode->i_inline = (u8)opt->val; + } else if (!strcmp(opt->mb, "i_links")) { + MSG(0, "Info: inject inode i_links of nid %u: %u -> %u\n", + opt->nid, le32_to_cpu(inode->i_links), (u32)opt->val); + inode->i_links = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "i_size")) { + MSG(0, "Info: inject inode i_size of nid %u: %"PRIu64" -> %"PRIu64"\n", + opt->nid, le64_to_cpu(inode->i_size), (u64)opt->val); + inode->i_size = cpu_to_le64((u64)opt->val); + } else if (!strcmp(opt->mb, "i_blocks")) { + MSG(0, "Info: inject inode i_blocks of nid %u: %"PRIu64" -> %"PRIu64"\n", + opt->nid, le64_to_cpu(inode->i_blocks), (u64)opt->val); + inode->i_blocks = cpu_to_le64((u64)opt->val); + } else if (!strcmp(opt->mb, "i_extra_isize")) { + /* do not care if F2FS_EXTRA_ATTR is enabled */ + MSG(0, "Info: inject inode i_extra_isize of nid %u: %d -> %d\n", + opt->nid, le16_to_cpu(inode->i_extra_isize), (u16)opt->val); + inode->i_extra_isize = cpu_to_le16((u16)opt->val); + } else if (!strcmp(opt->mb, "i_inode_checksum")) { + MSG(0, "Info: inject inode i_inode_checksum of nid %u: " + "0x%x -> 0x%x\n", opt->nid, + le32_to_cpu(inode->i_inode_checksum), (u32)opt->val); + inode->i_inode_checksum = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "i_addr")) { + /* do not care if it is inline data */ + if (opt->idx >= DEF_ADDRS_PER_INODE) { + ERR_MSG("invalid index %u of i_addr[]\n", opt->idx); + return -EINVAL; + } + MSG(0, "Info: inject inode i_addr[%d] of nid %u: " + "0x%x -> 0x%x\n", opt->idx, opt->nid, + le32_to_cpu(inode->i_addr[opt->idx]), (u32)opt->val); + inode->i_addr[opt->idx] = cpu_to_le32((block_t)opt->val); + } else if (!strcmp(opt->mb, "i_nid")) { + if (opt->idx >= 5) { + ERR_MSG("invalid index %u of i_nid[]\n", opt->idx); + return -EINVAL; + } + MSG(0, "Info: inject inode i_nid[%d] of nid %u: " + "0x%x -> 0x%x\n", opt->idx, opt->nid, + le32_to_cpu(F2FS_INODE_I_NID(inode, opt->idx)), + (u32)opt->val); + F2FS_INODE_I_NID(inode, opt->idx) = cpu_to_le32((nid_t)opt->val); + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + return -EINVAL; + } + + if (c.dbg_lv > 0) + print_node_info(sbi, node, 1); + + return 0; +} + +static int inject_index_node(struct f2fs_sb_info *sbi, struct f2fs_node *node, + struct inject_option *opt) +{ + struct direct_node *dn = &node->dn; + + if (strcmp(opt->mb, "addr")) { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + return -EINVAL; + } + + if (opt->idx >= DEF_ADDRS_PER_BLOCK) { + ERR_MSG("invalid index %u of nid/addr[]\n", opt->idx); + return -EINVAL; + } + + MSG(0, "Info: inject node nid/addr[%d] of nid %u: 0x%x -> 0x%x\n", + opt->idx, opt->nid, le32_to_cpu(dn->addr[opt->idx]), + (block_t)opt->val); + dn->addr[opt->idx] = cpu_to_le32((block_t)opt->val); + + if (c.dbg_lv > 0) + print_node_info(sbi, node, 1); + + return 0; +} + +static int inject_node(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct f2fs_super_block *sb = sbi->raw_super; + struct node_info ni; + struct f2fs_node *node_blk; + struct node_footer *footer; + int ret; + + if (!IS_VALID_NID(sbi, opt->nid)) { + ERR_MSG("Invalid nid %u range [%u:%"PRIu64"]\n", opt->nid, 0, + NAT_ENTRY_PER_BLOCK * + ((get_sb(segment_count_nat) << 1) << + sbi->log_blocks_per_seg)); + return -EINVAL; + } + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + get_node_info(sbi, opt->nid, &ni); + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + footer = F2FS_NODE_FOOTER(node_blk); + + if (!strcmp(opt->mb, "nid")) { + MSG(0, "Info: inject node footer nid of nid %u: %u -> %u\n", + opt->nid, le32_to_cpu(footer->nid), (u32)opt->val); + footer->nid = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "ino")) { + MSG(0, "Info: inject node footer ino of nid %u: %u -> %u\n", + opt->nid, le32_to_cpu(footer->ino), (u32)opt->val); + footer->ino = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "flag")) { + MSG(0, "Info: inject node footer flag of nid %u: " + "0x%x -> 0x%x\n", opt->nid, le32_to_cpu(footer->flag), + (u32)opt->val); + footer->flag = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "cp_ver")) { + MSG(0, "Info: inject node footer cp_ver of nid %u: " + "0x%"PRIx64" -> 0x%"PRIx64"\n", opt->nid, le64_to_cpu(footer->cp_ver), + (u64)opt->val); + footer->cp_ver = cpu_to_le64((u64)opt->val); + } else if (!strcmp(opt->mb, "next_blkaddr")) { + MSG(0, "Info: inject node footer next_blkaddr of nid %u: " + "0x%x -> 0x%x\n", opt->nid, + le32_to_cpu(footer->next_blkaddr), (u32)opt->val); + footer->next_blkaddr = cpu_to_le32((u32)opt->val); + } else if (ni.nid == ni.ino) { + ret = inject_inode(sbi, node_blk, opt); + } else { + ret = inject_index_node(sbi, node_blk, opt); + } + if (ret) + goto out; + + print_node_footer_info(footer); + + /* + * if i_inode_checksum is injected, should call update_block() to + * avoid recalculate inode checksum + */ + if (ni.nid == ni.ino && strcmp(opt->mb, "i_inode_checksum")) + ret = update_inode(sbi, node_blk, &ni.blk_addr); + else + ret = update_block(sbi, node_blk, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + +out: + free(node_blk); + return ret; +} + +static int find_dir_entry(struct f2fs_dentry_ptr *d, nid_t ino) +{ + struct f2fs_dir_entry *de; + int slot = 0; + + while (slot < d->max) { + if (!test_bit_le(slot, d->bitmap)) { + slot++; + continue; + } + + de = &d->dentry[slot]; + if (le32_to_cpu(de->ino) == ino && de->hash_code != 0) + return slot; + if (de->name_len == 0) { + slot++; + continue; + } + slot += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len)); + } + + return -ENOENT; +} + +static int inject_dentry(struct f2fs_sb_info *sbi, struct inject_option *opt) +{ + struct node_info ni; + struct f2fs_node *node_blk = NULL; + struct f2fs_inode *inode; + struct f2fs_dentry_ptr d; + void *inline_dentry; + struct f2fs_dentry_block *dent_blk = NULL; + block_t addr = 0; + void *buf = NULL; + struct f2fs_dir_entry *dent = NULL; + struct dnode_of_data dn; + nid_t pino; + int slot = -ENOENT, ret; + + node_blk = malloc(F2FS_BLKSIZE); + ASSERT(node_blk != NULL); + + /* get child inode */ + get_node_info(sbi, opt->nid, &ni); + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + pino = le32_to_cpu(node_blk->i.i_pino); + + /* get parent inode */ + get_node_info(sbi, pino, &ni); + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + inode = &node_blk->i; + + /* find child dentry */ + if (inode->i_inline & F2FS_INLINE_DENTRY) { + inline_dentry = inline_data_addr(node_blk); + make_dentry_ptr(&d, node_blk, inline_dentry, 2); + addr = ni.blk_addr; + buf = node_blk; + + slot = find_dir_entry(&d, opt->nid); + if (slot >= 0) + dent = &d.dentry[slot]; + } else { + unsigned int level, dirlevel, nbucket; + unsigned long i, end; + + level = le32_to_cpu(inode->i_current_depth); + dirlevel = le32_to_cpu(inode->i_dir_level); + nbucket = dir_buckets(level, dirlevel); + end = dir_block_index(level, dirlevel, nbucket) + + bucket_blocks(level); + + dent_blk = malloc(F2FS_BLKSIZE); + ASSERT(dent_blk != NULL); + + for (i = 0; i < end; i++) { + memset(&dn, 0, sizeof(dn)); + set_new_dnode(&dn, node_blk, NULL, pino); + ret = get_dnode_of_data(sbi, &dn, i, LOOKUP_NODE); + if (ret < 0) + break; + addr = dn.data_blkaddr; + if (dn.inode_blk != dn.node_blk) + free(dn.node_blk); + if (addr == NULL_ADDR || addr == NEW_ADDR) + continue; + if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC)) { + MSG(0, "invalid blkaddr 0x%x at offset %lu\n", + addr, i); + continue; + } + ret = dev_read_block(dent_blk, addr); + ASSERT(ret >= 0); + + make_dentry_ptr(&d, node_blk, dent_blk, 1); + slot = find_dir_entry(&d, opt->nid); + if (slot >= 0) { + dent = &d.dentry[slot]; + buf = dent_blk; + break; + } + } + } + + if (slot < 0) { + ERR_MSG("dentry of ino %u not found\n", opt->nid); + ret = -ENOENT; + goto out; + } + + if (!strcmp(opt->mb, "d_bitmap")) { + MSG(0, "Info: inject dentry bitmap of nid %u: 1 -> 0\n", + opt->nid); + test_and_clear_bit_le(slot, d.bitmap); + } else if (!strcmp(opt->mb, "d_hash")) { + MSG(0, "Info: inject dentry d_hash of nid %u: " + "0x%x -> 0x%x\n", opt->nid, le32_to_cpu(dent->hash_code), + (u32)opt->val); + dent->hash_code = cpu_to_le32((u32)opt->val); + } else if (!strcmp(opt->mb, "d_ino")) { + MSG(0, "Info: inject dentry d_ino of nid %u: " + "%u -> %u\n", opt->nid, le32_to_cpu(dent->ino), + (nid_t)opt->val); + dent->ino = cpu_to_le32((nid_t)opt->val); + } else if (!strcmp(opt->mb, "d_ftype")) { + MSG(0, "Info: inject dentry d_type of nid %u: " + "%d -> %d\n", opt->nid, dent->file_type, + (u8)opt->val); + dent->file_type = (u8)opt->val; + } else { + ERR_MSG("unknown or unsupported member \"%s\"\n", opt->mb); + ret = -EINVAL; + goto out; + } + + print_raw_dentry_info(dent); + + if (inode->i_inline & F2FS_INLINE_DENTRY) + ret = update_inode(sbi, buf, &addr); + else + ret = update_block(sbi, buf, &addr, NULL); + ASSERT(ret >= 0); + +out: + free(node_blk); + free(dent_blk); + return ret; +} + +int do_inject(struct f2fs_sb_info *sbi) +{ + struct inject_option *opt = (struct inject_option *)c.private; + int ret = -EINVAL; + + if (opt->sb >= 0) + ret = inject_sb(sbi, opt); + else if (opt->cp >= 0) + ret = inject_cp(sbi, opt); + else if (opt->nat >= 0) + ret = inject_nat(sbi, opt); + else if (opt->sit >= 0) + ret = inject_sit(sbi, opt); + else if (opt->ssa) + ret = inject_ssa(sbi, opt); + else if (opt->node) + ret = inject_node(sbi, opt); + else if (opt->dent) + ret = inject_dentry(sbi, opt); + + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.h new file mode 100644 index 00000000000..43c21b56a7e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/inject.h @@ -0,0 +1,41 @@ +/** + * inject.h + * + * Copyright (c) 2024 OPPO Mobile Comm Corp., Ltd. + * http://www.oppo.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _INJECT_H_ +#define _INJECT_H_ + +#include +#include +#include + +#include "f2fs_fs.h" +#include "fsck.h" + +struct inject_option { + const char *mb; /* member name */ + unsigned int idx; /* slot index */ + long long val; /* new value */ + char *str; /* new string */ + nid_t nid; + block_t blk; + int sb; /* which sb */ + int cp; /* which cp */ + int nat; /* which nat pack */ + int sit; /* which sit pack */ + bool ssa; + bool node; + bool dent; +}; + +void inject_usage(void); +int inject_parse_options(int argc, char *argv[], struct inject_option *inject_opt); +int do_inject(struct f2fs_sb_info *sbi); +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/main.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/main.c new file mode 100644 index 00000000000..c5d41597934 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/main.c @@ -0,0 +1,1412 @@ +/** + * main.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * Copyright (c) 2015 Jaegeuk Kim + * : implement defrag.f2fs + * Copyright (C) 2015 Huawei Ltd. + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * : add sload.f2fs + * Copyright (c) 2019 Google Inc. + * Robin Hsu + * : add cache layer + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add sload compression support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include +#include +#include +#include +#include +#include "quotaio.h" +#include "compress.h" +#ifdef WITH_INJECT +#include "inject.h" +#else +static void inject_usage(void) +{ + MSG(0, "\ninject.f2fs not supported\n"); + exit(1); +} +#endif + +struct f2fs_fsck gfsck; + +INIT_FEATURE_TABLE; + +#if defined(WITH_SLOAD) || defined(WITH_DUMP) +static char *absolute_path(const char *file) +{ + char *ret; + char cwd[PATH_MAX]; + + if (file[0] != '/') { + if (getcwd(cwd, PATH_MAX) == NULL) { + fprintf(stderr, "Failed to getcwd\n"); + exit(EXIT_FAILURE); + } + ret = malloc(strlen(cwd) + 1 + strlen(file) + 1); + if (ret) + sprintf(ret, "%s/%s", cwd, file); + } else + ret = strdup(file); + return ret; +} +#endif + +void fsck_usage() +{ + MSG(0, "\nUsage: fsck.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -a check/fix potential corruption, reported by f2fs\n"); + MSG(0, " -c set number of cache entries" + " (default 0)\n"); + MSG(0, " -m set max cache hash collision" + " (default 16)\n"); + MSG(0, " -C encoding[:flag1,flag2] Set options for enabling" + " casefolding\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -f check/fix entire partition\n"); + MSG(0, " -g add default options\n"); + MSG(0, " -H support write hint\n"); + MSG(0, " -l show superblock/checkpoint\n"); + MSG(0, " -M show a file map\n"); + MSG(0, " -O feature1[feature2,feature3,...] e.g. \"encrypt\"\n"); + MSG(0, " -p preen mode [default:0 the same as -a [0|1|2]]\n"); + MSG(0, " -S sparse_mode\n"); + MSG(0, " -t show directory tree\n"); + MSG(0, " -q preserve quota limits\n"); + MSG(0, " -y fix all the time\n"); + MSG(0, " -V print the version number and exit\n"); + MSG(0, " --dry-run do not really fix corruptions\n"); + MSG(0, " --no-kernel-check skips detecting kernel change\n"); + MSG(0, " --kernel-check checks kernel change\n"); + MSG(0, " --debug-cache to debug cache when -c is used\n"); + MSG(0, " --nolinear-lookup=X X=1: disable linear lookup, X=0: enable linear lookup\n"); + MSG(0, " --fault_injection=%%d to enable fault injection with specified injection rate\n"); + MSG(0, " --fault_type=%%d to configure enabled fault injection type\n"); + exit(1); +} + +void dump_usage() +{ + MSG(0, "\nUsage: dump.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -i inode no (hex)\n"); + MSG(0, " -I inode no (hex) scan full disk\n"); + MSG(0, " -n [NAT dump nid from #1~#2 (decimal), for all 0~-1]\n"); + MSG(0, " -M show a block map\n"); + MSG(0, " -s [SIT dump segno from #1~#2 (decimal), for all 0~-1]\n"); + MSG(0, " -S sparse_mode\n"); + MSG(0, " -a [SSA dump segno from #1~#2 (decimal), for all 0~-1]\n"); + MSG(0, " -b blk_addr (in 4KB)\n"); + MSG(0, " -r dump out from the root inode\n"); + MSG(0, " -f do not prompt before dumping\n"); + MSG(0, " -H support write hint\n"); + MSG(0, " -y alias for -f\n"); + MSG(0, " -o dump inodes to the given path\n"); + MSG(0, " -P preserve mode/owner/group for dumped inode\n"); + MSG(0, " -L Preserves symlinks. Otherwise symlinks are dumped as regular files.\n"); + MSG(0, " -V print the version number and exit\n"); + + exit(1); +} + +void defrag_usage() +{ + MSG(0, "\nUsage: defrag.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -H support write hint\n"); + MSG(0, " -s start block address [default: main_blkaddr]\n"); + MSG(0, " -S sparse_mode\n"); + MSG(0, " -l length [default:512 (2MB)]\n"); + MSG(0, " -t target block address [default: main_blkaddr + 2MB]\n"); + MSG(0, " -i set direction as shrink [default: expand]\n"); + MSG(0, " -V print the version number and exit\n"); + exit(1); +} + +void resize_usage() +{ + MSG(0, "\nUsage: resize.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -H support write hint\n"); + MSG(0, " -o overprovision percentage [default:auto]\n"); + MSG(0, " -s safe resize (Does not resize metadata)\n"); + MSG(0, " -t target sectors [default: device size]\n"); + MSG(0, " -V print the version number and exit\n"); + exit(1); +} + +void sload_usage() +{ + MSG(0, "\nUsage: sload.f2fs [options] device\n"); + MSG(0, "[options]:\n"); + MSG(0, " -C fs_config\n"); + MSG(0, " -f source directory [path of the source directory]\n"); + MSG(0, " -p product out directory\n"); + MSG(0, " -s file_contexts\n"); + MSG(0, " -S sparse_mode\n"); + MSG(0, " -t mount point [prefix of target fs path, default:/]\n"); + MSG(0, " -T timestamp\n"); + MSG(0, " -P preserve owner: user and group\n"); + MSG(0, " -c enable compression (default allow policy)\n"); + MSG(0, " ------------ Compression sub-options -----------------\n"); + MSG(0, " -L , default 2\n"); + MSG(0, " -a compression algorithm, default LZ4\n"); + MSG(0, " -x compress files except for these extensions.\n"); + MSG(0, " -i compress files with these extensions only.\n"); + MSG(0, " * -i or -x: use it many times for multiple extensions.\n"); + MSG(0, " * -i and -x cannot be used together..\n"); + MSG(0, " -m min compressed blocks per cluster\n"); + MSG(0, " -r read only (to release unused blocks) for compressed " + "files\n"); + MSG(0, " ------------------------------------------------------\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -V print the version number and exit\n"); + exit(1); +} + +void label_usage() +{ + MSG(0, "\nUsage: f2fslabel [options] device [volume-label]\n"); + MSG(0, "[options]:\n"); + MSG(0, " -V print the version number and exit\n"); + exit(1); +} + +int is_digits(char *optarg) +{ + unsigned int i; + + for (i = 0; i < strlen(optarg); i++) + if (!isdigit(optarg[i])) + break; + return i == strlen(optarg); +} + +static void error_out(char *prog) +{ + if (!strcmp("fsck.f2fs", prog)) + fsck_usage(); + else if (!strcmp("dump.f2fs", prog)) + dump_usage(); + else if (!strcmp("defrag.f2fs", prog)) + defrag_usage(); + else if (!strcmp("resize.f2fs", prog)) + resize_usage(); + else if (!strcmp("sload.f2fs", prog)) + sload_usage(); + else if (!strcmp("f2fslabel", prog)) + label_usage(); + else if (!strcmp("inject.f2fs", prog)) + inject_usage(); + else + MSG(0, "\nWrong program.\n"); +} + +static void add_default_options(void) +{ + switch (c.defset) { + case CONF_ANDROID: + if (c.func == FSCK) { + /* -a */ + c.auto_fix = 1; + } else if (c.func == RESIZE) { + c.force = 1; + } + + /* + * global config for fsck family tools, including dump, + * defrag, resize, sload, label and inject. + */ + + /* disable nat_bits feature by default */ + c.disabled_feature |= F2FS_FEATURE_NAT_BITS; + + /* enable write hitn by default */ + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + } + c.quota_fix = 1; +} + +void f2fs_parse_options(int argc, char *argv[]) +{ + int option = 0; + char *prog = basename(argv[0]); + int err = NOERROR; +#ifdef WITH_ANDROID + int i; + + /* Allow prog names (e.g, sload_f2fs, fsck_f2fs, etc) */ + for (i = 0; i < strlen(prog); i++) { + if (prog[i] == '_') + prog[i] = '.'; + } +#endif + if (argc < 2) { + MSG(0, "\tError: Device not specified\n"); + error_out(prog); + } + + if (!strcmp("fsck.f2fs", prog)) { + const char *option_string = ":aC:c:m:Md:fg:HlO:p:q:StyV"; + int opt = 0, val; + char *token; + struct option long_opt[] = { + {"dry-run", no_argument, 0, 1}, + {"no-kernel-check", no_argument, 0, 2}, + {"kernel-check", no_argument, 0, 3}, + {"debug-cache", no_argument, 0, 4}, + {"nolinear-lookup", required_argument, 0, 5}, + {"fault_injection", required_argument, 0, 6}, + {"fault_type", required_argument, 0, 7}, + {0, 0, 0, 0} + }; + + c.func = FSCK; + c.cache_config.max_hash_collision = 16; + c.cache_config.dbg_en = false; + while ((option = getopt_long(argc, argv, option_string, + long_opt, &opt)) != EOF) { + switch (option) { + case 1: + c.dry_run = 1; + MSG(0, "Info: Dry run\n"); + break; + case 2: + c.no_kernel_check = 1; + MSG(0, "Info: No Kernel Check\n"); + break; + case 3: + c.no_kernel_check = 0; + MSG(0, "Info: Do Kernel Check\n"); + break; + case 4: + c.cache_config.dbg_en = true; + break; + case 5: + if (!optarg || !strcmp(optarg, "0")) + c.nolinear_lookup = LINEAR_LOOKUP_ENABLE; + else + c.nolinear_lookup = LINEAR_LOOKUP_DISABLE; + break; + case 6: + val = atoi(optarg); + if ((unsigned int)val <= 1) { + MSG(0, "\tError: injection rate must be larger " + "than 1: %d\n", val); + fsck_usage(); + } + c.fault_info.inject_rate = val; + c.fault_info.inject_type = F2FS_ALL_FAULT_TYPE; + break; + case 7: + val = atoi(optarg); + if (val >= (1UL << (FAULT_MAX))) { + MSG(0, "\tError: Invalid inject type: %x\n", val); + fsck_usage(); + } + c.fault_info.inject_type = val; + break; + case 'a': + c.auto_fix = 1; + MSG(0, "Info: Automatic fix mode enabled.\n"); + break; + case 'c': + c.cache_config.num_cache_entry = atoi(optarg); + break; + case 'm': + c.cache_config.max_hash_collision = + atoi(optarg); + break; + case 'g': + if (!strcmp(optarg, "android")) { + c.defset = CONF_ANDROID; + MSG(0, "Info: Set conf for android\n"); + } + break; + case 'H': + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + break; + case 'l': + c.layout = 1; + break; + case 'M': + c.show_file_map = 1; + break; + case 'O': + if (parse_feature(feature_table, optarg)) + fsck_usage(); + break; + case 'p': + /* preen mode has different levels: + * 0: default level, the same as -a + * 1: check meta + * 2: same as 0, but will skip some + * check for old kernel + */ + if (optarg[0] == '-' || !is_digits(optarg) || + optind == argc) { + MSG(0, "Info: Use default preen mode\n"); + c.preen_mode = PREEN_MODE_0; + c.auto_fix = 1; + optind--; + break; + } + c.preen_mode = atoi(optarg); + if (c.preen_mode < 0) + c.preen_mode = PREEN_MODE_0; + else if (c.preen_mode >= PREEN_MODE_MAX) + c.preen_mode = PREEN_MODE_MAX - 1; + if (c.preen_mode == PREEN_MODE_0 || + c.preen_mode == PREEN_MODE_2) + c.auto_fix = 1; + MSG(0, "Info: Fix the reported corruption in " + "preen mode %d\n", c.preen_mode); + break; + case 'd': + if (optarg[0] == '-') { + err = ENEED_ARG; + break; + } else if (!is_digits(optarg)) { + err = EWRONG_OPT; + break; + } + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", c.dbg_lv); + break; + case 'f': + case 'y': + c.fix_on = 1; + c.force = 1; + MSG(0, "Info: Force to fix corruption\n"); + break; + case 'q': + c.preserve_limits = atoi(optarg); + MSG(0, "Info: Preserve quota limits = %d\n", + c.preserve_limits); + break; + case 'S': + c.sparse_mode = 1; + break; + case 't': + c.show_dentry = 1; + break; + case ':': + if (optopt == 'p') { + MSG(0, "Info: Use default preen mode\n"); + c.preen_mode = PREEN_MODE_0; + c.auto_fix = 1; + } else { + option = optopt; + err = ENEED_ARG; + break; + } + break; + case 'C': + token = strtok(optarg, ":"); + val = f2fs_str2encoding(token); + if (val < 0) { + MSG(0, "\tError: Unknown encoding %s\n", token); + fsck_usage(); + } + c.s_encoding = val; + token = strtok(NULL, ""); + val = f2fs_str2encoding_flags(&token, &c.s_encoding_flags); + if (val) { + MSG(0, "\tError: Unknown flag %s\n", token); + fsck_usage(); + } + c.feature |= F2FS_FEATURE_CASEFOLD; + break; + case 'V': + show_version(prog); + exit(0); + case '?': + option = optopt; + fallthrough; + default: + err = EUNKNOWN_OPT; + break; + } + if (err != NOERROR) + break; + } + } else if (!strcmp("dump.f2fs", prog)) { +#ifdef WITH_DUMP + const char *option_string = "d:fi:I:n:LMo:Prs:Sa:b:Vy"; + static struct dump_option dump_opt = { + .nid = 0, /* default root ino */ + .start_nat = -1, + .end_nat = -1, + .start_sit = -1, + .end_sit = -1, + .start_ssa = -1, + .end_ssa = -1, + .blk_addr = -1, + .scan_nid = 0, + .use_root_nid = 0, + .base_path = NULL, + }; + + c.func = DUMP; + while ((option = getopt(argc, argv, option_string)) != EOF) { + int ret = 0; + + switch (option) { + case 'd': + if (!is_digits(optarg)) { + err = EWRONG_OPT; + break; + } + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", + c.dbg_lv); + break; + case 'i': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%d", + &dump_opt.nid); + else + ret = sscanf(optarg, "%x", + &dump_opt.nid); + break; + case 'I': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%d", + &dump_opt.scan_nid); + else + ret = sscanf(optarg, "%x", + &dump_opt.scan_nid); + break; + case 'n': + ret = sscanf(optarg, "%d~%d", + &dump_opt.start_nat, + &dump_opt.end_nat); + break; + case 'M': + c.show_file_map = 1; + break; + case 's': + ret = sscanf(optarg, "%d~%d", + &dump_opt.start_sit, + &dump_opt.end_sit); + break; + case 'S': + c.sparse_mode = 1; + break; + case 'a': + ret = sscanf(optarg, "%d~%d", + &dump_opt.start_ssa, + &dump_opt.end_ssa); + break; + case 'b': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%d", + &dump_opt.blk_addr); + else + ret = sscanf(optarg, "%x", + &dump_opt.blk_addr); + break; + case 'y': + case 'f': + c.force = 1; + break; + case 'r': + dump_opt.use_root_nid = 1; + break; + case 'o': + dump_opt.base_path = absolute_path(optarg); + break; + case 'P': +#if defined(__MINGW32__) + MSG(0, "-P not supported for Windows\n"); + err = EWRONG_OPT; +#else + c.preserve_perms = 1; +#endif + break; + case 'L': +#if defined(__MINGW32__) + MSG(0, "-L not supported for Windows\n"); + err = EWRONG_OPT; +#else + c.preserve_symlinks = 1; +#endif + break; + case 'V': + show_version(prog); + exit(0); + default: + err = EUNKNOWN_OPT; + break; + } + ASSERT(ret >= 0); + if (err != NOERROR) + break; + } + + c.private = &dump_opt; +#endif + } else if (!strcmp("defrag.f2fs", prog)) { +#ifdef WITH_DEFRAG + const char *option_string = "d:Hs:Sl:t:iV"; + + c.func = DEFRAG; + while ((option = getopt(argc, argv, option_string)) != EOF) { + int ret = 0; + + switch (option) { + case 'd': + if (!is_digits(optarg)) { + err = EWRONG_OPT; + break; + } + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", + c.dbg_lv); + break; + case 'H': + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + break; + case 's': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%"PRIu64"", + &c.defrag_start); + else + ret = sscanf(optarg, "%"PRIx64"", + &c.defrag_start); + break; + case 'S': + c.sparse_mode = 1; + break; + case 'l': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%"PRIu64"", + &c.defrag_len); + else + ret = sscanf(optarg, "%"PRIx64"", + &c.defrag_len); + break; + case 't': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%"PRIu64"", + &c.defrag_target); + else + ret = sscanf(optarg, "%"PRIx64"", + &c.defrag_target); + break; + case 'i': + c.defrag_shrink = 1; + break; + case 'V': + show_version(prog); + exit(0); + default: + err = EUNKNOWN_OPT; + break; + } + ASSERT(ret >= 0); + if (err != NOERROR) + break; + } +#endif + } else if (!strcmp("resize.f2fs", prog)) { +#ifdef WITH_RESIZE + const char *option_string = "d:fFHst:o:V"; + + c.func = RESIZE; + while ((option = getopt(argc, argv, option_string)) != EOF) { + int ret = 0; + + switch (option) { + case 'd': + if (!is_digits(optarg)) { + err = EWRONG_OPT; + break; + } + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", + c.dbg_lv); + break; + case 'f': + c.ignore_error = 1; + MSG(0, "Info: Ignore errors during resize\n"); + break; + case 'F': + c.force = 1; + MSG(0, "Info: Force to resize\n"); + break; + case 'H': + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + break; + case 's': + c.safe_resize = 1; + break; + case 't': + if (strncmp(optarg, "0x", 2)) + ret = sscanf(optarg, "%"PRIu64"", + &c.target_sectors); + else + ret = sscanf(optarg, "%"PRIx64"", + &c.target_sectors); + break; + case 'o': + c.new_overprovision = atof(optarg); + break; + case 'V': + show_version(prog); + exit(0); + default: + err = EUNKNOWN_OPT; + break; + } + ASSERT(ret >= 0); + if (err != NOERROR) + break; + } +#endif + } else if (!strcmp("sload.f2fs", prog)) { +#ifdef WITH_SLOAD + const char *option_string = "cL:a:i:x:m:rC:d:f:p:s:St:T:VP"; +#ifdef HAVE_LIBSELINUX + int max_nr_opt = (int)sizeof(c.seopt_file) / + sizeof(c.seopt_file[0]); + char *token; +#endif + char *p; + + c.func = SLOAD; + c.compress.cc.log_cluster_size = 2; + c.compress.alg = COMPR_LZ4; + c.compress.min_blocks = 1; + c.compress.filter_ops = &ext_filter; + while ((option = getopt(argc, argv, option_string)) != EOF) { + unsigned int i; + int val; + + switch (option) { + case 'c': /* compression support */ + c.compress.enabled = true; + break; + case 'L': /* compression: log of blocks-per-cluster */ + c.compress.required = true; + val = atoi(optarg); + if (val < MIN_COMPRESS_LOG_SIZE || + val > MAX_COMPRESS_LOG_SIZE) { + MSG(0, "\tError: log of blocks per" + " cluster must be in the range" + " of %d .. %d.\n", + MIN_COMPRESS_LOG_SIZE, + MAX_COMPRESS_LOG_SIZE); + error_out(prog); + } + c.compress.cc.log_cluster_size = val; + break; + case 'a': /* compression: choose algorithm */ + c.compress.required = true; + c.compress.alg = MAX_COMPRESS_ALGS; + for (i = 0; i < MAX_COMPRESS_ALGS; i++) { + if (!strcmp(supported_comp_names[i], + optarg)) { + c.compress.alg = i; + break; + } + } + if (c.compress.alg == MAX_COMPRESS_ALGS) { + MSG(0, "\tError: Unknown compression" + " algorithm %s\n", optarg); + error_out(prog); + } + break; + case 'i': /* compress only these extensions */ + c.compress.required = true; + if (c.compress.filter == COMPR_FILTER_ALLOW) { + MSG(0, "\tError: could not mix option" + " -i and -x\n"); + error_out(prog); + } + c.compress.filter = COMPR_FILTER_DENY; + c.compress.filter_ops->add(optarg); + break; + case 'x': /* compress except for these extensions */ + c.compress.required = true; + if (c.compress.filter == COMPR_FILTER_DENY) { + MSG(0, "\tError: could not mix option" + " -i and -x\n"); + error_out(prog); + } + c.compress.filter = COMPR_FILTER_ALLOW; + c.compress.filter_ops->add(optarg); + break; + case 'm': /* minimum compressed blocks per cluster */ + c.compress.required = true; + val = atoi(optarg); + if (val <= 0) { + MSG(0, "\tError: minimum compressed" + " blocks per cluster must be" + " positive.\n"); + error_out(prog); + } + c.compress.min_blocks = val; + break; + case 'r': /* for setting FI_COMPRESS_RELEASED */ + c.compress.required = true; + c.compress.readonly = true; + break; + case 'C': + c.fs_config_file = absolute_path(optarg); + break; + case 'd': + if (!is_digits(optarg)) { + err = EWRONG_OPT; + break; + } + c.dbg_lv = atoi(optarg); + MSG(0, "Info: Debug level = %d\n", + c.dbg_lv); + break; + case 'f': + c.from_dir = absolute_path(optarg); + break; + case 'p': + c.target_out_dir = absolute_path(optarg); + break; + case 's': +#ifdef HAVE_LIBSELINUX + token = strtok(optarg, ","); + while (token) { + if (c.nr_opt == max_nr_opt) { + MSG(0, "\tError: Expected at most %d selinux opts\n", + max_nr_opt); + error_out(prog); + } + c.seopt_file[c.nr_opt].type = + SELABEL_OPT_PATH; + c.seopt_file[c.nr_opt].value = + absolute_path(token); + c.nr_opt++; + token = strtok(NULL, ","); + } +#else + MSG(0, "Info: Not support selinux opts\n"); +#endif + break; + case 'S': + c.sparse_mode = 1; + break; + case 't': + c.mount_point = (char *)optarg; + break; + case 'T': + c.fixed_time = strtoul(optarg, &p, 0); + break; + case 'V': + show_version(prog); + exit(0); + case 'P': + c.preserve_perms = 1; + break; + default: + err = EUNKNOWN_OPT; + break; + } + if (err != NOERROR) + break; + } + if (c.compress.required && !c.compress.enabled) { + MSG(0, "\tError: compression sub-options are used" + " without the compression enable (-c) option\n" + ); + error_out(prog); + } + if (err == NOERROR && c.compress.enabled) { + c.compress.cc.cluster_size = 1 + << c.compress.cc.log_cluster_size; + if (c.compress.filter == COMPR_FILTER_UNASSIGNED) + c.compress.filter = COMPR_FILTER_ALLOW; + if (c.compress.min_blocks >= + c.compress.cc.cluster_size) { + MSG(0, "\tError: minimum reduced blocks by" + " compression per cluster must be at" + " most one less than blocks per" + " cluster, i.e. %d\n", + c.compress.cc.cluster_size - 1); + error_out(prog); + } + } +#endif /* WITH_SLOAD */ + } else if (!strcmp("f2fslabel", prog)) { +#ifdef WITH_LABEL + const char *option_string = "V"; + + c.func = LABEL; + while ((option = getopt(argc, argv, option_string)) != EOF) { + switch (option) { + case 'V': + show_version(prog); + exit(0); + default: + err = EUNKNOWN_OPT; + break; + } + if (err != NOERROR) + break; + } + + if (argc > (optind + 2)) { /* unknown argument(s) is(are) passed */ + optind += 2; + err = EUNKNOWN_ARG; + } else if (argc == (optind + 2)) { /* change label */ + c.vol_label = argv[optind + 1]; + argc--; + } else { /* print label */ + /* + * Since vol_label was initialized as "", in order to + * distinguish between clear label and print, set + * vol_label as NULL for print case + */ + c.vol_label = NULL; + } +#endif /* WITH_LABEL */ + } else if (!strcmp("inject.f2fs", prog)) { +#ifdef WITH_INJECT + static struct inject_option inject_opt = { + .sb = -1, + .cp = -1, + .nat = -1, + .sit = -1, + .idx = -1, + .nid = -1, + }; + + err = inject_parse_options(argc, argv, &inject_opt); + if (err < 0) { + err = EWRONG_OPT; + } + + c.func = INJECT; + c.private = &inject_opt; +#endif /* WITH_INJECT */ + } + +#if defined(__MINGW32__) + if (c.need_whint) { + MSG(0, "-H not supported for Windows\n"); + err = EWRONG_OPT; + } +#endif + if (err == NOERROR) { + add_default_options(); + + if (optind >= argc) { + MSG(0, "\tError: Device not specified\n"); + error_out(prog); + } + + c.devices[0].path = strdup(argv[optind]); + if (argc > (optind + 1)) { + c.dbg_lv = 0; + err = EUNKNOWN_ARG; + } + if (err == NOERROR) + return; + } + + check_block_struct_sizes(); + /* print out error */ + switch (err) { + case EWRONG_OPT: + MSG(0, "\tError: Wrong option -%c %s\n", option, optarg); + break; + case ENEED_ARG: + MSG(0, "\tError: Need argument for -%c\n", option); + break; + case EUNKNOWN_OPT: + MSG(0, "\tError: Unknown option %c\n", option); + break; + case EUNKNOWN_ARG: + MSG(0, "\tError: Unknown argument %s\n", argv[optind]); + break; + } + error_out(prog); +} + +static int do_fsck(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + u32 flag = le32_to_cpu(ckpt->ckpt_flags); + u32 blk_cnt; + struct f2fs_compr_blk_cnt cbc; + struct child_info child = { 0 }; + errcode_t ret; + + fsck_init(sbi); + + print_cp_state(flag); + + if (c.roll_forward && c.zoned_model == F2FS_ZONED_HM) + save_curseg_warm_node_info(sbi); + + fsck_chk_and_fix_write_pointers(sbi); + + fsck_chk_curseg_info(sbi); + + if (!c.fix_on && !c.bug_on) { + switch (c.preen_mode) { + case PREEN_MODE_1: + if (fsck_chk_meta(sbi)) { + MSG(0, "[FSCK] F2FS metadata [Fail]"); + MSG(0, "\tError: meta does not match, " + "force check all\n"); + } else { + MSG(0, "[FSCK] F2FS metadata [Ok..]"); + fsck_free(sbi); + return FSCK_SUCCESS; + } + + if (!c.ro) + c.fix_on = 1; + break; + } + } else if (c.preen_mode) { + /* + * we can hit this in 3 situations: + * 1. fsck -f, fix_on has already been set to 1 when + * parsing options; + * 2. fsck -a && CP_FSCK_FLAG is set, fix_on has already + * been set to 1 when checking CP_FSCK_FLAG; + * 3. fsck -p 1 && error is detected, then bug_on is set, + * we set fix_on = 1 here, so that fsck can fix errors + * automatically + */ + c.fix_on = 1; + } + + fsck_chk_checkpoint(sbi); + + fsck_chk_quota_node(sbi); + + /* Traverse all block recursively from root inode */ + blk_cnt = 1; + cbc.cnt = 0; + cbc.cheader_pgofs = CHEADER_PGOFS_NONE; + + if (c.feature & F2FS_FEATURE_QUOTA_INO) { + ret = quota_init_context(sbi); + if (ret) { + ASSERT_MSG("quota_init_context failure: %d", ret); + return FSCK_OPERATIONAL_ERROR; + } + } + fsck_chk_orphan_node(sbi); + + if (fsck_sanity_check_nat(sbi, sbi->root_ino_num)) + fsck_chk_root_inode(sbi); + + child.p_ino = sbi->root_ino_num; + fsck_chk_node_blk(sbi, NULL, sbi->root_ino_num, + F2FS_FT_DIR, TYPE_INODE, &blk_cnt, &cbc, &child); + fsck_chk_quota_files(sbi); + + ret = fsck_verify(sbi); + fsck_free(sbi); + + if (!c.bug_on) + return FSCK_SUCCESS; + if (!ret) + return FSCK_ERROR_CORRECTED; + return FSCK_ERRORS_LEFT_UNCORRECTED; +} + +#ifdef WITH_DUMP +static void do_dump(struct f2fs_sb_info *sbi) +{ + struct dump_option *opt = (struct dump_option *)c.private; + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + u32 flag = le32_to_cpu(ckpt->ckpt_flags); + + if (opt->use_root_nid) + opt->nid = sbi->root_ino_num; + + if (opt->end_nat == -1) + opt->end_nat = NM_I(sbi)->max_nid; + if (opt->end_sit == -1) + opt->end_sit = SM_I(sbi)->main_segments; + if (opt->end_ssa == -1) + opt->end_ssa = SM_I(sbi)->main_segments; + if (opt->start_nat != -1) + nat_dump(sbi, opt->start_nat, opt->end_nat); + if (opt->start_sit != -1) + sit_dump(sbi, opt->start_sit, opt->end_sit); + if (opt->start_ssa != -1) + ssa_dump(sbi, opt->start_ssa, opt->end_ssa); + if (opt->blk_addr != -1) + dump_info_from_blkaddr(sbi, opt->blk_addr); + if (opt->nid) + dump_node(sbi, opt->nid, c.force, opt->base_path, 1, 1, NULL); + if (opt->scan_nid) + dump_node_scan_disk(sbi, opt->scan_nid); + + print_cp_state(flag); + +} +#endif + +#ifdef WITH_DEFRAG +static int do_defrag(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + if (get_sb(feature) & F2FS_FEATURE_RO) { + MSG(0, "Not support on readonly image.\n"); + return -1; + } + + if (get_sb(feature) & F2FS_FEATURE_DEVICE_ALIAS) { + MSG(0, "Not support on image with device aliasing feature.\n"); + return -1; + } + + if (c.defrag_start > get_sb(block_count)) + goto out_range; + if (c.defrag_start < SM_I(sbi)->main_blkaddr) + c.defrag_start = SM_I(sbi)->main_blkaddr; + + if (c.defrag_len == 0) + c.defrag_len = sbi->blocks_per_seg; + + if (c.defrag_start + c.defrag_len > get_sb(block_count)) + c.defrag_len = get_sb(block_count) - c.defrag_start; + + if (c.defrag_target == 0) { + c.defrag_target = c.defrag_start - 1; + if (!c.defrag_shrink) + c.defrag_target += c.defrag_len + 1; + } + + if (c.defrag_target < SM_I(sbi)->main_blkaddr || + c.defrag_target > get_sb(block_count)) + goto out_range; + if (c.defrag_target >= c.defrag_start && + c.defrag_target < c.defrag_start + c.defrag_len) + goto out_range; + + if (c.defrag_start > c.defrag_target) + MSG(0, "Info: Move 0x%"PRIx64" <- [0x%"PRIx64"-0x%"PRIx64"]\n", + c.defrag_target, + c.defrag_start, + c.defrag_start + c.defrag_len - 1); + else + MSG(0, "Info: Move [0x%"PRIx64"-0x%"PRIx64"] -> 0x%"PRIx64"\n", + c.defrag_start, + c.defrag_start + c.defrag_len - 1, + c.defrag_target); + + return f2fs_defragment(sbi, c.defrag_start, c.defrag_len, + c.defrag_target, c.defrag_shrink); +out_range: + ASSERT_MSG("Out-of-range [0x%"PRIx64" ~ 0x%"PRIx64"] to 0x%"PRIx64"", + c.defrag_start, + c.defrag_start + c.defrag_len - 1, + c.defrag_target); + return -1; +} +#endif + +#ifdef WITH_RESIZE +static int do_resize(struct f2fs_sb_info *sbi) +{ + char answer[255] = {0}; + int ret; + + if (!c.force) { +retry: + printf("\nResize operation is currently experimental, please " + "backup your data.\nDo you want to continue? [y/n]"); + ret = scanf("%s", answer); + ASSERT(ret >= 0); + if (!strcasecmp(answer, "y")) + printf("Proceeding to resize\n"); + else if (!strcasecmp(answer, "n")) + return 0; + else + goto retry; + } + + if (!c.target_sectors) + c.target_sectors = c.total_sectors; + + if (c.target_sectors > c.total_sectors) { + ASSERT_MSG("Out-of-range Target=0x%"PRIx64" / 0x%"PRIx64"", + c.target_sectors, c.total_sectors); + return -1; + } + + return f2fs_resize(sbi); +} +#endif + +#ifdef WITH_SLOAD +static int init_compr(struct f2fs_sb_info *sbi) +{ + if (!c.compress.enabled) + return 0; + + if (!(sbi->raw_super->feature + & cpu_to_le32(F2FS_FEATURE_COMPRESSION))) { + MSG(0, "Error: Compression (-c) was requested " + "but the file system is not created " + "with such feature.\n"); + return -1; + } + if (!supported_comp_ops[c.compress.alg].init) { + MSG(0, "Error: The selected compression algorithm is not" + " supported\n"); + return -1; + } + c.compress.ops = supported_comp_ops + c.compress.alg; + c.compress.ops->init(&c.compress.cc); + c.compress.ops->reset(&c.compress.cc); + c.compress.cc.rlen = c.compress.cc.cluster_size * F2FS_BLKSIZE; + return 0; +} + +static int do_sload(struct f2fs_sb_info *sbi) +{ + if (!c.from_dir) { + MSG(0, "Info: No source directory, but it's okay.\n"); + return 0; + } + if (!c.mount_point) + c.mount_point = "/"; + + if (init_compr(sbi)) + return -1; + + return f2fs_sload(sbi); +} +#endif + +#ifdef WITH_LABEL +static int do_label(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + if (!c.vol_label) { + char label[MAX_VOLUME_NAME]; + + utf16_to_utf8(label, (const char *)sb->volume_name, + MAX_VOLUME_NAME, MAX_VOLUME_NAME); + MSG(0, "Info: volume label = %s\n", label); + return 0; + } + + if (strlen(c.vol_label) > MAX_VOLUME_NAME) { + ERR_MSG("Label should not exceed %d characters\n", MAX_VOLUME_NAME); + return -1; + } + + utf8_to_utf16((char *)sb->volume_name, (const char *)c.vol_label, + MAX_VOLUME_NAME, strlen(c.vol_label)); + + update_superblock(sb, SB_MASK_ALL); + + MSG(0, "Info: volume label is changed to %s\n", c.vol_label); + + return 0; +} +#endif + +#ifdef HAVE_MACH_TIME_H +static u64 get_boottime_ns() +{ + return mach_absolute_time(); +} +#elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME) +static u64 get_boottime_ns() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_BOOTTIME, &t); + return (u64)t.tv_sec * 1000000000LL + t.tv_nsec; +} +#else +static u64 get_boottime_ns() +{ + return 0; +} +#endif + +int main(int argc, char **argv) +{ + struct f2fs_sb_info *sbi; + int ret = 0, ret2; + u64 start = get_boottime_ns(); + + f2fs_init_configuration(); + + f2fs_parse_options(argc, argv); + + if (c.func != DUMP && (ret = f2fs_devs_are_umounted()) < 0) { + if (ret == -EBUSY) { + ret = -1; + if (c.func == FSCK) + ret = FSCK_OPERATIONAL_ERROR; + goto quick_err; + } + if (!c.ro || c.func == DEFRAG) { + MSG(0, "\tError: Not available on mounted device!\n"); + ret = -1; + if (c.func == FSCK) + ret = FSCK_OPERATIONAL_ERROR; + goto quick_err; + } + + /* allow ro-mounted partition */ + if (c.force) { + MSG(0, "Info: Force to check/repair FS on RO mounted device\n"); + } else { + MSG(0, "Info: Check FS only on RO mounted device\n"); + c.fix_on = 0; + c.auto_fix = 0; + } + } + + /* Get device */ + if (f2fs_get_device_info() < 0 || f2fs_get_f2fs_info() < 0) { + ret = -1; + if (c.func == FSCK) + ret = FSCK_OPERATIONAL_ERROR; + goto quick_err; + } + +fsck_again: + memset(&gfsck, 0, sizeof(gfsck)); + gfsck.sbi.fsck = &gfsck; + sbi = &gfsck.sbi; + + ret = f2fs_do_mount(sbi); + if (ret != 0) { + if (ret == 1) { + MSG(0, "Info: No error was reported\n"); + ret = 0; + } + goto out_err; + } + + switch (c.func) { + case FSCK: + ret = do_fsck(sbi); + break; +#ifdef WITH_DUMP + case DUMP: + do_dump(sbi); + break; +#endif +#ifdef WITH_DEFRAG + case DEFRAG: + ret = do_defrag(sbi); + if (ret) + goto out_err; + break; +#endif +#ifdef WITH_RESIZE + case RESIZE: + if (do_resize(sbi)) + goto out_err; + break; +#endif +#ifdef WITH_SLOAD + case SLOAD: + if (do_sload(sbi)) + goto out_err; + + ret = f2fs_sparse_initialize_meta(sbi); + if (ret < 0) + goto out_err; + + f2fs_do_umount(sbi); + + /* fsck to fix missing quota */ + c.func = FSCK; + c.fix_on = 1; + goto fsck_again; +#endif +#ifdef WITH_LABEL + case LABEL: + if (do_label(sbi)) + goto out_err; + break; +#endif +#ifdef WITH_INJECT + case INJECT: + if (do_inject(sbi)) + goto out_err; + break; +#endif + default: + ERR_MSG("Wrong program name\n"); + ASSERT(0); + } + + f2fs_do_umount(sbi); + + if (c.func == FSCK && c.bug_on) { + if (!c.ro && c.fix_on == 0 && c.auto_fix == 0 && !c.dry_run) { + char ans[255] = {0}; +retry: + printf("Do you want to fix this partition? [Y/N] "); + ret2 = scanf("%s", ans); + ASSERT(ret2 >= 0); + if (!strcasecmp(ans, "y")) + c.fix_on = 1; + else if (!strcasecmp(ans, "n")) + c.fix_on = 0; + else + goto retry; + + if (c.fix_on) + goto fsck_again; + } + } + ret2 = f2fs_finalize_device(); + if (ret2) { + if (c.func == FSCK) + return FSCK_OPERATIONAL_ERROR; + return ret2; + } + + if (c.func == SLOAD) + c.compress.filter_ops->destroy(); + + if (!c.show_file_map) + printf("\nDone: %lf secs\n", (get_boottime_ns() - start) / 1000000000.0); + return ret; + +out_err: + if (sbi->ckpt) + free(sbi->ckpt); + if (sbi->raw_super) + free(sbi->raw_super); +quick_err: + f2fs_release_sparse_resource(); + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mkquota.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mkquota.c new file mode 100644 index 00000000000..3f491d7d10e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mkquota.c @@ -0,0 +1,415 @@ +/* + * mkquota.c --- create quota files for a filesystem + * + * Aditya Kali + * Hyojun Kim - Ported to f2fs-tools + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "quotaio.h" +#include "quotaio_v2.h" +#include "quotaio_tree.h" +#include "common.h" +#include "dict.h" + + +/* Needed for architectures where sizeof(int) != sizeof(void *) */ +#define UINT_TO_VOIDPTR(val) ((void *)(intptr_t)(val)) +#define VOIDPTR_TO_UINT(ptr) ((unsigned int)(intptr_t)(ptr)) + +#if DEBUG_QUOTA +static void print_dquot(const char *desc, struct dquot *dq) +{ + if (desc) + fprintf(stderr, "%s: ", desc); + fprintf(stderr, "%u %lld:%lld:%lld %lld:%lld:%lld\n", + dq->dq_id, (long long) dq->dq_dqb.dqb_curspace, + (long long) dq->dq_dqb.dqb_bsoftlimit, + (long long) dq->dq_dqb.dqb_bhardlimit, + (long long) dq->dq_dqb.dqb_curinodes, + (long long) dq->dq_dqb.dqb_isoftlimit, + (long long) dq->dq_dqb.dqb_ihardlimit); +} +#else +#define print_dquot(...) +#endif + +static int write_dquots(dict_t *dict, struct quota_handle *qh) +{ + dnode_t *n; + struct dquot *dq; + int retval = 0; + + for (n = dict_first(dict); n; n = dict_next(dict, n)) { + dq = dnode_get(n); + if (dq) { + print_dquot("write", dq); + dq->dq_h = qh; + update_grace_times(dq); + if (qh->qh_ops->commit_dquot(dq)) { + retval = -1; + break; + } + } + } + return retval; +} + +errcode_t quota_write_inode(struct f2fs_sb_info *sbi, enum quota_type qtype) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + quota_ctx_t qctx = fsck->qctx; + struct quota_handle *h = NULL; + int retval = 0; + dict_t *dict; + + if ((!qctx) || (!sb->qf_ino[qtype])) + return 0; + + retval = quota_get_mem(sizeof(struct quota_handle), &h); + if (retval) { + log_debug("Unable to allocate quota handle"); + goto out; + } + + dict = qctx->quota_dict[qtype]; + if (dict) { + retval = quota_file_create(sbi, h, qtype); + if (retval) { + log_debug("Cannot initialize io on quotafile"); + } else { + retval = write_dquots(dict, h); + quota_file_close(sbi, h, 1); + } + } +out: + if (h) + quota_free_mem(&h); + return retval; +} + +/******************************************************************/ +/* Helper functions for computing quota in memory. */ +/******************************************************************/ + +static int dict_uint_cmp(const void *a, const void *b) +{ + unsigned int c, d; + + c = VOIDPTR_TO_UINT(a); + d = VOIDPTR_TO_UINT(b); + + if (c == d) + return 0; + else if (c > d) + return 1; + else + return -1; +} + +static inline qid_t get_qid(struct f2fs_inode *inode, enum quota_type qtype) +{ + switch (qtype) { + case USRQUOTA: + return inode->i_uid; + case GRPQUOTA: + return inode->i_gid; + case PRJQUOTA: + return inode->i_projid; + default: + return 0; + } + + return 0; +} + +static void quota_dnode_free(dnode_t *node, void *UNUSED(context)) +{ + void *ptr = node ? dnode_get(node) : 0; + + quota_free_mem(&ptr); + free(node); +} + +/* + * Set up the quota tracking data structures. + */ +errcode_t quota_init_context(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + errcode_t err; + dict_t *dict; + quota_ctx_t ctx; + enum quota_type qtype; + + err = quota_get_mem(sizeof(struct quota_ctx), &ctx); + if (err) { + log_debug("Failed to allocate quota context"); + return err; + } + + memset(ctx, 0, sizeof(struct quota_ctx)); + dict_init(&ctx->linked_inode_dict, DICTCOUNT_T_MAX, dict_uint_cmp); + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + ctx->quota_file[qtype] = NULL; + if (!sb->qf_ino[qtype]) + continue; + err = quota_get_mem(sizeof(dict_t), &dict); + if (err) { + log_debug("Failed to allocate dictionary"); + quota_release_context(&ctx); + return err; + } + ctx->quota_dict[qtype] = dict; + dict_init(dict, DICTCOUNT_T_MAX, dict_uint_cmp); + dict_set_allocator(dict, NULL, quota_dnode_free, NULL); + } + ctx->sbi = sbi; + fsck->qctx = ctx; + return 0; +} + +void quota_release_context(quota_ctx_t *qctx) +{ + dict_t *dict; + enum quota_type qtype; + quota_ctx_t ctx; + + if (!qctx) + return; + + ctx = *qctx; + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dict = ctx->quota_dict[qtype]; + ctx->quota_dict[qtype] = 0; + if (dict) { + dict_free_nodes(dict); + free(dict); + } + } + dict_free_nodes(&ctx->linked_inode_dict); + *qctx = NULL; + free(ctx); +} + +static struct dquot *get_dq(dict_t *dict, __u32 key) +{ + struct dquot *dq; + dnode_t *n; + + n = dict_lookup(dict, UINT_TO_VOIDPTR(key)); + if (n) + dq = dnode_get(n); + else { + if (quota_get_mem(sizeof(struct dquot), &dq)) { + log_err("Unable to allocate dquot"); + return NULL; + } + memset(dq, 0, sizeof(struct dquot)); + dict_alloc_insert(dict, UINT_TO_VOIDPTR(key), dq); + dq->dq_id = key; + } + return dq; +} + +/* + * Called to update the blocks used by a particular inode + */ +void quota_data_add(quota_ctx_t qctx, struct f2fs_inode *inode, qsize_t space) +{ + struct dquot *dq; + dict_t *dict; + enum quota_type qtype; + + if (!qctx) + return; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + if (dq) + dq->dq_dqb.dqb_curspace += space; + } + } +} + +/* + * Called to remove some blocks used by a particular inode + */ +void quota_data_sub(quota_ctx_t qctx, struct f2fs_inode *inode, qsize_t space) +{ + struct dquot *dq; + dict_t *dict; + enum quota_type qtype; + + if (!qctx) + return; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + dq->dq_dqb.dqb_curspace -= space; + } + } +} + +/* + * Called to count the files used by an inode's user/group + */ +void quota_data_inodes(quota_ctx_t qctx, struct f2fs_inode *inode, int adjust) +{ + struct dquot *dq; + dict_t *dict; enum quota_type qtype; + + if (!qctx) + return; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) { + dict = qctx->quota_dict[qtype]; + if (dict) { + dq = get_dq(dict, get_qid(inode, qtype)); + dq->dq_dqb.dqb_curinodes += adjust; + } + } +} + +/* + * Called from fsck to count quota. + */ +void quota_add_inode_usage(quota_ctx_t qctx, f2fs_ino_t ino, + struct f2fs_inode* inode) +{ + if (qctx) { + /* Handle hard linked inodes */ + if (inode->i_links > 1) { + if (dict_lookup(&qctx->linked_inode_dict, + UINT_TO_VOIDPTR(ino))) { + return; + } + dict_alloc_insert(&qctx->linked_inode_dict, + UINT_TO_VOIDPTR(ino), NULL); + } + + qsize_t space = (inode->i_blocks - 1) * F2FS_BLKSIZE; + quota_data_add(qctx, inode, space); + quota_data_inodes(qctx, inode, +1); + } +} + +struct scan_dquots_data { + dict_t *quota_dict; + int update_limits; /* update limits from disk */ + int update_usage; + int usage_is_inconsistent; +}; + +static int scan_dquots_callback(struct dquot *dquot, void *cb_data) +{ + struct scan_dquots_data *scan_data = cb_data; + dict_t *quota_dict = scan_data->quota_dict; + struct dquot *dq; + + dq = get_dq(quota_dict, dquot->dq_id); + dq->dq_id = dquot->dq_id; + dq->dq_flags |= DQF_SEEN; + + print_dquot("mem", dq); + print_dquot("dsk", dquot); + /* Check if there is inconsistency */ + if (dq->dq_dqb.dqb_curspace != dquot->dq_dqb.dqb_curspace || + dq->dq_dqb.dqb_curinodes != dquot->dq_dqb.dqb_curinodes) { + scan_data->usage_is_inconsistent = 1; + log_debug("[QUOTA WARNING] Usage inconsistent for ID %u:" + "actual (%lld, %lld) != expected (%lld, %lld)\n", + dq->dq_id, (long long) dq->dq_dqb.dqb_curspace, + (long long) dq->dq_dqb.dqb_curinodes, + (long long) dquot->dq_dqb.dqb_curspace, + (long long) dquot->dq_dqb.dqb_curinodes); + } + + if (scan_data->update_limits) { + dq->dq_dqb.dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit; + dq->dq_dqb.dqb_isoftlimit = dquot->dq_dqb.dqb_isoftlimit; + dq->dq_dqb.dqb_bhardlimit = dquot->dq_dqb.dqb_bhardlimit; + dq->dq_dqb.dqb_bsoftlimit = dquot->dq_dqb.dqb_bsoftlimit; + } + + if (scan_data->update_usage) { + dq->dq_dqb.dqb_curspace = dquot->dq_dqb.dqb_curspace; + dq->dq_dqb.dqb_curinodes = dquot->dq_dqb.dqb_curinodes; + } + + return 0; +} + +/* + * Compares the measured quota in qctx->quota_dict with that in the quota inode + * on disk and updates the limits in qctx->quota_dict. 'usage_inconsistent' is + * set to 1 if the supplied and on-disk quota usage values are not identical. + */ +errcode_t quota_compare_and_update(struct f2fs_sb_info *sbi, + enum quota_type qtype, int *usage_inconsistent, + int preserve_limits) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + quota_ctx_t qctx = fsck->qctx; + struct quota_handle qh; + struct scan_dquots_data scan_data; + struct dquot *dq; + dnode_t *n; + dict_t *dict = qctx->quota_dict[qtype]; + errcode_t err = 0; + + if (time_to_inject(FAULT_QUOTA)) { + ASSERT_MSG("%s is injected.", f2fs_fault_name[FAULT_QUOTA]); + return -EINVAL; + } + + if (!dict) + goto out; + + err = quota_file_open(sbi, &qh, qtype, 0); + if (err) { + log_debug("Open quota file failed"); + *usage_inconsistent = 1; + goto out; + } + + scan_data.quota_dict = qctx->quota_dict[qtype]; + scan_data.update_limits = preserve_limits; + scan_data.update_usage = 0; + scan_data.usage_is_inconsistent = 0; + err = qh.qh_ops->scan_dquots(&qh, scan_dquots_callback, &scan_data); + if (err) { + log_debug("Error scanning dquots"); + goto out; + } + + for (n = dict_first(dict); n; n = dict_next(dict, n)) { + dq = dnode_get(n); + if (!dq) + continue; + if ((dq->dq_flags & DQF_SEEN) == 0) { + log_debug("[QUOTA WARNING] " + "Missing quota entry ID %d\n", dq->dq_id); + scan_data.usage_is_inconsistent = 1; + } + } + *usage_inconsistent = scan_data.usage_is_inconsistent; + +out: + return err; +} + diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mount.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mount.c new file mode 100644 index 00000000000..a7f16e78bae --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/mount.c @@ -0,0 +1,4312 @@ +/** + * mount.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "node.h" +#include "xattr.h" +#include "quota.h" +#include +#include +#include +#ifdef HAVE_LINUX_POSIX_ACL_H +#include +#endif +#ifdef HAVE_SYS_ACL_H +#include +#endif +#ifdef HAVE_UUID_UUID_H +#include +#endif + +#ifndef ACL_UNDEFINED_TAG +#define ACL_UNDEFINED_TAG (0x00) +#define ACL_USER_OBJ (0x01) +#define ACL_USER (0x02) +#define ACL_GROUP_OBJ (0x04) +#define ACL_GROUP (0x08) +#define ACL_MASK (0x10) +#define ACL_OTHER (0x20) +#endif + +#ifdef HAVE_LINUX_BLKZONED_H + +static int get_device_idx(struct f2fs_sb_info *sbi, uint32_t segno) +{ + block_t seg_start_blkaddr; + int i; + + seg_start_blkaddr = SM_I(sbi)->main_blkaddr + + segno * DEFAULT_BLOCKS_PER_SEGMENT; + for (i = 0; i < c.ndevs; i++) + if (c.devices[i].start_blkaddr <= seg_start_blkaddr && + c.devices[i].end_blkaddr > seg_start_blkaddr) + return i; + return 0; +} + +static int get_zone_idx_from_dev(struct f2fs_sb_info *sbi, + uint32_t segno, uint32_t dev_idx) +{ + block_t seg_start_blkaddr = START_BLOCK(sbi, segno); + + return (seg_start_blkaddr - c.devices[dev_idx].start_blkaddr) / + (sbi->segs_per_sec * sbi->blocks_per_seg); +} + +bool is_usable_seg(struct f2fs_sb_info *sbi, unsigned int segno) +{ + block_t seg_start = START_BLOCK(sbi, segno); + unsigned int dev_idx = get_device_idx(sbi, segno); + unsigned int zone_idx = get_zone_idx_from_dev(sbi, segno, dev_idx); + unsigned int sec_start_blkaddr = START_BLOCK(sbi, + GET_SEG_FROM_SEC(sbi, segno / sbi->segs_per_sec)); + + if (zone_idx < c.devices[dev_idx].nr_rnd_zones) + return true; + + if (c.devices[dev_idx].zoned_model != F2FS_ZONED_HM) + return true; + + return seg_start < sec_start_blkaddr + + c.devices[dev_idx].zone_cap_blocks[zone_idx]; +} + +unsigned int get_usable_seg_count(struct f2fs_sb_info *sbi) +{ + unsigned int i, usable_seg_count = 0; + + for (i = 0; i < MAIN_SEGS(sbi); i++) + if (is_usable_seg(sbi, i)) + usable_seg_count++; + + return usable_seg_count; +} + +#else + +bool is_usable_seg(struct f2fs_sb_info *UNUSED(sbi), unsigned int UNUSED(segno)) +{ + return true; +} + +unsigned int get_usable_seg_count(struct f2fs_sb_info *sbi) +{ + return MAIN_SEGS(sbi); +} + +#endif + +u32 get_free_segments(struct f2fs_sb_info *sbi) +{ + u32 i, free_segs = 0; + + for (i = 0; i < MAIN_SEGS(sbi); i++) { + struct seg_entry *se = get_seg_entry(sbi, i); + + if (se->valid_blocks == 0x0 && !IS_CUR_SEGNO(sbi, i) && + is_usable_seg(sbi, i)) + free_segs++; + } + return free_segs; +} + +void update_free_segments(struct f2fs_sb_info *sbi) +{ + char *progress = "-*|*-"; + static int i = 0; + + if (c.dbg_lv) + return; + + MSG(0, "\r [ %c ] Free segments: 0x%x", progress[i % 5], SM_I(sbi)->free_segments); + fflush(stdout); + i++; +} + +#if defined(HAVE_LINUX_POSIX_ACL_H) || defined(HAVE_SYS_ACL_H) +static void print_acl(const u8 *value, int size) +{ + const struct f2fs_acl_header *hdr = (struct f2fs_acl_header *)value; + const struct f2fs_acl_entry *entry = (struct f2fs_acl_entry *)(hdr + 1); + const u8 *end = value + size; + int i, count; + + if (hdr->a_version != cpu_to_le32(F2FS_ACL_VERSION)) { + MSG(0, "Invalid ACL version [0x%x : 0x%x]\n", + le32_to_cpu(hdr->a_version), F2FS_ACL_VERSION); + return; + } + + count = f2fs_acl_count(size); + if (count <= 0) { + MSG(0, "Invalid ACL value size %d\n", size); + return; + } + + for (i = 0; i < count; i++) { + if ((u8 *)entry > end) { + MSG(0, "Invalid ACL entries count %d\n", count); + return; + } + + switch (le16_to_cpu(entry->e_tag)) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + MSG(0, "tag:0x%x perm:0x%x\n", + le16_to_cpu(entry->e_tag), + le16_to_cpu(entry->e_perm)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry_short)); + break; + case ACL_USER: + MSG(0, "tag:0x%x perm:0x%x uid:%u\n", + le16_to_cpu(entry->e_tag), + le16_to_cpu(entry->e_perm), + le32_to_cpu(entry->e_id)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + case ACL_GROUP: + MSG(0, "tag:0x%x perm:0x%x gid:%u\n", + le16_to_cpu(entry->e_tag), + le16_to_cpu(entry->e_perm), + le32_to_cpu(entry->e_id)); + entry = (struct f2fs_acl_entry *)((char *)entry + + sizeof(struct f2fs_acl_entry)); + break; + default: + MSG(0, "Unknown ACL tag 0x%x\n", + le16_to_cpu(entry->e_tag)); + return; + } + } +} +#endif /* HAVE_LINUX_POSIX_ACL_H || HAVE_SYS_ACL_H */ + +static void print_xattr_entry(const struct f2fs_xattr_entry *ent) +{ + const u8 *value = (const u8 *)&ent->e_name[ent->e_name_len]; + const int size = le16_to_cpu(ent->e_value_size); + char *enc_name = F2FS_XATTR_NAME_ENCRYPTION_CONTEXT; + u32 enc_name_len = strlen(enc_name); + const union fscrypt_context *ctx; + const struct fsverity_descriptor_location *dloc; + int i; + + MSG(0, "\nxattr: e_name_index:%d e_name:", ent->e_name_index); + for (i = 0; i < ent->e_name_len; i++) + MSG(0, "%c", ent->e_name[i]); + MSG(0, " e_name_len:%d e_value_size:%d e_value:\n", + ent->e_name_len, size); + + switch (ent->e_name_index) { +#if defined(HAVE_LINUX_POSIX_ACL_H) || defined(HAVE_SYS_ACL_H) + case F2FS_XATTR_INDEX_POSIX_ACL_ACCESS: + case F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT: + print_acl(value, size); + return; +#endif + case F2FS_XATTR_INDEX_ENCRYPTION: + if (ent->e_name_len != enc_name_len || + memcmp(ent->e_name, enc_name, enc_name_len)) + break; + ctx = (const union fscrypt_context *)value; + if (size == 0 || size != fscrypt_context_size(ctx)) + break; + switch (ctx->version) { + case FSCRYPT_CONTEXT_V1: + MSG(0, "format: %d\n", ctx->version); + MSG(0, "contents_encryption_mode: 0x%x\n", ctx->v1.contents_encryption_mode); + MSG(0, "filenames_encryption_mode: 0x%x\n", ctx->v1.filenames_encryption_mode); + MSG(0, "flags: 0x%x\n", ctx->v1.flags); + MSG(0, "master_key_descriptor: "); + for (i = 0; i < FSCRYPT_KEY_DESCRIPTOR_SIZE; i++) + MSG(0, "%02X", ctx->v1.master_key_descriptor[i]); + MSG(0, "\nnonce: "); + for (i = 0; i < FSCRYPT_FILE_NONCE_SIZE; i++) + MSG(0, "%02X", ctx->v1.nonce[i]); + MSG(0, "\n"); + return; + case FSCRYPT_CONTEXT_V2: + MSG(0, "format: %d\n", ctx->version); + MSG(0, "contents_encryption_mode: 0x%x\n", ctx->v2.contents_encryption_mode); + MSG(0, "filenames_encryption_mode: 0x%x\n", ctx->v2.filenames_encryption_mode); + MSG(0, "flags: 0x%x\n", ctx->v2.flags); + MSG(0, "master_key_identifier: "); + for (i = 0; i < FSCRYPT_KEY_IDENTIFIER_SIZE; i++) + MSG(0, "%02X", ctx->v2.master_key_identifier[i]); + MSG(0, "\nnonce: "); + for (i = 0; i < FSCRYPT_FILE_NONCE_SIZE; i++) + MSG(0, "%02X", ctx->v2.nonce[i]); + MSG(0, "\n"); + return; + } + break; + case F2FS_XATTR_INDEX_VERITY: + dloc = (const struct fsverity_descriptor_location *)value; + if (ent->e_name_len != strlen(F2FS_XATTR_NAME_VERITY) || + memcmp(ent->e_name, F2FS_XATTR_NAME_VERITY, + ent->e_name_len)) + break; + if (size != sizeof(*dloc)) + break; + MSG(0, "version: %u\n", le32_to_cpu(dloc->version)); + MSG(0, "size: %u\n", le32_to_cpu(dloc->size)); + MSG(0, "pos: %"PRIu64"\n", le64_to_cpu(dloc->pos)); + return; + } + for (i = 0; i < size; i++) + MSG(0, "%02X", value[i]); + MSG(0, "\n"); +} + +void print_inode_info(struct f2fs_sb_info *sbi, + struct f2fs_node *node, int name) +{ + struct f2fs_inode *inode = &node->i; + void *xattr_addr; + void *last_base_addr; + struct f2fs_xattr_entry *ent; + char en[F2FS_PRINT_NAMELEN]; + unsigned int i = 0; + u32 namelen = le32_to_cpu(inode->i_namelen); + int enc_name = file_enc_name(inode); + int ofs = get_extra_isize(node); + + pretty_print_filename(inode->i_name, namelen, en, enc_name); + if (name && en[0]) { + MSG(0, " - File name : %s%s\n", en, + enc_name ? " " : ""); + setlocale(LC_ALL, ""); + MSG(0, " - File size : %'" PRIu64 " (bytes)\n", + le64_to_cpu(inode->i_size)); + return; + } + + DISP_u32(inode, i_mode); + DISP_u32(inode, i_advise); + DISP_u32(inode, i_uid); + DISP_u32(inode, i_gid); + DISP_u32(inode, i_links); + DISP_u64(inode, i_size); + DISP_u64(inode, i_blocks); + + DISP_u64(inode, i_atime); + DISP_u32(inode, i_atime_nsec); + DISP_u64(inode, i_ctime); + DISP_u32(inode, i_ctime_nsec); + DISP_u64(inode, i_mtime); + DISP_u32(inode, i_mtime_nsec); + + DISP_u32(inode, i_generation); + DISP_u32(inode, i_current_depth); + DISP_u32(inode, i_xattr_nid); + DISP_u32(inode, i_flags); + DISP_u32(inode, i_inline); + DISP_u32(inode, i_pino); + DISP_u32(inode, i_dir_level); + + if (en[0]) { + DISP_u32(inode, i_namelen); + printf("%-30s\t\t[%s]\n", "i_name", en); + + printf("%-30s\t\t[", "i_name(hex)"); + for (i = 0; i < F2FS_NAME_LEN && en[i]; i++) + printf("0x%x ", (unsigned char)en[i]); + printf("0x%x]\n", (unsigned char)en[i]); + } + + printf("i_ext: fofs:%x blkaddr:%x len:%x\n", + le32_to_cpu(inode->i_ext.fofs), + le32_to_cpu(inode->i_ext.blk_addr), + le32_to_cpu(inode->i_ext.len)); + + if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { + DISP_u16(inode, i_extra_isize); + if (c.feature & F2FS_FEATURE_FLEXIBLE_INLINE_XATTR) + DISP_u16(inode, i_inline_xattr_size); + if (c.feature & F2FS_FEATURE_PRJQUOTA) + DISP_u32(inode, i_projid); + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + DISP_u32(inode, i_inode_checksum); + if (c.feature & F2FS_FEATURE_INODE_CRTIME) { + DISP_u64(inode, i_crtime); + DISP_u32(inode, i_crtime_nsec); + } + if (c.feature & F2FS_FEATURE_COMPRESSION) { + DISP_u64(inode, i_compr_blocks); + DISP_u8(inode, i_compress_algorithm); + DISP_u8(inode, i_log_cluster_size); + DISP_u16(inode, i_compress_flag); + } + } + + for (i = 0; i < ADDRS_PER_INODE(inode); i++) { + block_t blkaddr; + char *flag = ""; + + if (i + ofs >= DEF_ADDRS_PER_INODE) + break; + + blkaddr = le32_to_cpu(inode->i_addr[i + ofs]); + + if (blkaddr == 0x0) + continue; + if (blkaddr == COMPRESS_ADDR) + flag = "cluster flag"; + else if (blkaddr == NEW_ADDR) + flag = "reserved flag"; + printf("i_addr[0x%x] %-16s\t\t[0x%8x : %u]\n", i + ofs, flag, + blkaddr, blkaddr); + } + + DISP_u32(F2FS_INODE_NIDS(inode), i_nid[0]); /* direct */ + DISP_u32(F2FS_INODE_NIDS(inode), i_nid[1]); /* direct */ + DISP_u32(F2FS_INODE_NIDS(inode), i_nid[2]); /* indirect */ + DISP_u32(F2FS_INODE_NIDS(inode), i_nid[3]); /* indirect */ + DISP_u32(F2FS_INODE_NIDS(inode), i_nid[4]); /* double indirect */ + + xattr_addr = read_all_xattrs(sbi, node, true); + if (!xattr_addr) + goto out; + + last_base_addr = (void *)xattr_addr + XATTR_SIZE(&node->i); + + list_for_each_xattr(ent, xattr_addr) { + if ((void *)(ent) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(ent) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + break; + } + print_xattr_entry(ent); + } + free(xattr_addr); + +out: + printf("\n"); +} + +void print_node_info(struct f2fs_sb_info *sbi, + struct f2fs_node *node_block, int verbose) +{ + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(node_block)->ino); + nid_t nid = le32_to_cpu(F2FS_NODE_FOOTER(node_block)->nid); + /* Is this inode? */ + if (ino == nid) { + DBG(verbose, "Node ID [0x%x:%u] is inode\n", nid, nid); + print_inode_info(sbi, node_block, verbose); + } else { + int i; + u32 *dump_blk = (u32 *)node_block; + DBG(verbose, + "Node ID [0x%x:%u] is direct node or indirect node.\n", + nid, nid); + for (i = 0; i < DEF_ADDRS_PER_BLOCK; i++) + MSG(verbose, "[%d]\t\t\t[0x%8x : %d]\n", + i, dump_blk[i], dump_blk[i]); + } +} + +void print_extention_list(struct f2fs_super_block *sb, int cold) +{ + int start, end, i; + + if (cold) { + DISP_u32(sb, extension_count); + + start = 0; + end = le32_to_cpu(sb->extension_count); + } else { + DISP_u8(sb, hot_ext_count); + + start = le32_to_cpu(sb->extension_count); + end = start + sb->hot_ext_count; + } + + printf("%s file extentsions\n", cold ? "cold" : "hot"); + + for (i = 0; i < end - start; i++) { + if (c.layout) { + printf("%-30s %-8.8s\n", "extension_list", + sb->extension_list[start + i]); + } else { + if (i % 4 == 0) + printf("%-30s\t\t[", ""); + + printf("%-8.8s", sb->extension_list[start + i]); + + if (i % 4 == 4 - 1) + printf("]\n"); + } + } + + for (; i < round_up(end - start, 4) * 4; i++) { + printf("%-8.8s", ""); + if (i % 4 == 4 - 1) + printf("]\n"); + } +} + +static void DISP_label(const char *name) +{ + char buffer[MAX_VOLUME_NAME]; + + utf16_to_utf8(buffer, name, MAX_VOLUME_NAME, MAX_VOLUME_NAME); + if (c.layout) + printf("%-30s %s\n", "Filesystem volume name:", buffer); + else + printf("%-30s" "\t\t[%s]\n", "volum_name", buffer); +} + +void print_sb_debug_info(struct f2fs_super_block *sb); +void print_raw_sb_info(struct f2fs_super_block *sb) +{ +#ifdef HAVE_LIBUUID + char uuid[40]; + char encrypt_pw_salt[40]; +#endif + int i; + + if (c.layout) + goto printout; + if (!c.dbg_lv) + return; + + printf("\n"); + printf("+--------------------------------------------------------+\n"); + printf("| Super block |\n"); + printf("+--------------------------------------------------------+\n"); +printout: + DISP_u32(sb, magic); + DISP_u32(sb, major_ver); + + DISP_u32(sb, minor_ver); + DISP_u32(sb, log_sectorsize); + DISP_u32(sb, log_sectors_per_block); + + DISP_u32(sb, log_blocksize); + DISP_u32(sb, log_blocks_per_seg); + DISP_u32(sb, segs_per_sec); + DISP_u32(sb, secs_per_zone); + DISP_u32(sb, checksum_offset); + DISP_u64(sb, block_count); + + DISP_u32(sb, section_count); + DISP_u32(sb, segment_count); + DISP_u32(sb, segment_count_ckpt); + DISP_u32(sb, segment_count_sit); + DISP_u32(sb, segment_count_nat); + + DISP_u32(sb, segment_count_ssa); + DISP_u32(sb, segment_count_main); + DISP_u32(sb, segment0_blkaddr); + + DISP_u32(sb, cp_blkaddr); + DISP_u32(sb, sit_blkaddr); + DISP_u32(sb, nat_blkaddr); + DISP_u32(sb, ssa_blkaddr); + DISP_u32(sb, main_blkaddr); + + DISP_u32(sb, root_ino); + DISP_u32(sb, node_ino); + DISP_u32(sb, meta_ino); + +#ifdef HAVE_LIBUUID + uuid_unparse(sb->uuid, uuid); + DISP_raw_str("%-.36s", uuid); +#endif + + DISP_label((const char *)sb->volume_name); + + print_extention_list(sb, 1); + print_extention_list(sb, 0); + + DISP_u32(sb, cp_payload); + + DISP_str("%-.252s", sb, version); + DISP_str("%-.252s", sb, init_version); + + DISP_u32(sb, feature); + DISP_u8(sb, encryption_level); + +#ifdef HAVE_LIBUUID + uuid_unparse(sb->encrypt_pw_salt, encrypt_pw_salt); + DISP_raw_str("%-.36s", encrypt_pw_salt); +#endif + + for (i = 0; i < MAX_DEVICES; i++) { + if (!sb->devs[i].path[0]) + break; + DISP_str("%s", sb, devs[i].path); + DISP_u32(sb, devs[i].total_segments); + } + + DISP_u32(sb, qf_ino[USRQUOTA]); + DISP_u32(sb, qf_ino[GRPQUOTA]); + DISP_u32(sb, qf_ino[PRJQUOTA]); + + DISP_u16(sb, s_encoding); + DISP_u16(sb, s_encoding_flags); + DISP_u32(sb, crc); + + print_sb_debug_info(sb); + + printf("\n"); +} + +void print_chksum(struct f2fs_checkpoint *cp) +{ + unsigned int crc = le32_to_cpu(*(__le32 *)((unsigned char *)cp + + get_cp(checksum_offset))); + + printf("%-30s" "\t\t[0x%8x : %u]\n", "checksum", crc, crc); +} + +void print_version_bitmap(struct f2fs_sb_info *sbi) +{ + char str[41]; + int i, j; + + for (i = NAT_BITMAP; i <= SIT_BITMAP; i++) { + unsigned int *bitmap = __bitmap_ptr(sbi, i); + unsigned int size = round_up(__bitmap_size(sbi, i), 4); + + for (j = 0; j < size; j++) { + snprintf(str, 40, "%s[%d]", i == NAT_BITMAP ? + "nat_version_bitmap" : + "sit_version_bitmap", j); + printf("%-30s" "\t\t[0x%8x : %u]\n", str, + bitmap[i], bitmap[i]); + } + } +} + +void print_ckpt_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + + if (c.layout) + goto printout; + if (!c.dbg_lv) + return; + + printf("\n"); + printf("+--------------------------------------------------------+\n"); + printf("| Checkpoint |\n"); + printf("+--------------------------------------------------------+\n"); +printout: + DISP_u64(cp, checkpoint_ver); + DISP_u64(cp, user_block_count); + DISP_u64(cp, valid_block_count); + DISP_u32(cp, rsvd_segment_count); + DISP_u32(cp, overprov_segment_count); + DISP_u32(cp, free_segment_count); + + DISP_u32(cp, alloc_type[CURSEG_HOT_NODE]); + DISP_u32(cp, alloc_type[CURSEG_WARM_NODE]); + DISP_u32(cp, alloc_type[CURSEG_COLD_NODE]); + DISP_u32(cp, cur_node_segno[0]); + DISP_u32(cp, cur_node_segno[1]); + DISP_u32(cp, cur_node_segno[2]); + + DISP_u32(cp, cur_node_blkoff[0]); + DISP_u32(cp, cur_node_blkoff[1]); + DISP_u32(cp, cur_node_blkoff[2]); + + + DISP_u32(cp, alloc_type[CURSEG_HOT_DATA]); + DISP_u32(cp, alloc_type[CURSEG_WARM_DATA]); + DISP_u32(cp, alloc_type[CURSEG_COLD_DATA]); + DISP_u32(cp, cur_data_segno[0]); + DISP_u32(cp, cur_data_segno[1]); + DISP_u32(cp, cur_data_segno[2]); + + DISP_u32(cp, cur_data_blkoff[0]); + DISP_u32(cp, cur_data_blkoff[1]); + DISP_u32(cp, cur_data_blkoff[2]); + + DISP_u32(cp, ckpt_flags); + DISP_u32(cp, cp_pack_total_block_count); + DISP_u32(cp, cp_pack_start_sum); + DISP_u32(cp, valid_node_count); + DISP_u32(cp, valid_inode_count); + DISP_u32(cp, next_free_nid); + DISP_u32(cp, sit_ver_bitmap_bytesize); + DISP_u32(cp, nat_ver_bitmap_bytesize); + DISP_u32(cp, checksum_offset); + DISP_u64(cp, elapsed_time); + + print_chksum(cp); + print_version_bitmap(sbi); + + printf("\n\n"); +} + +void print_cp_state(u32 flag) +{ + if (c.show_file_map) + return; + + MSG(0, "Info: checkpoint state = %x : ", flag); + if (flag & CP_QUOTA_NEED_FSCK_FLAG) + MSG(0, "%s", " quota_need_fsck"); + if (flag & CP_LARGE_NAT_BITMAP_FLAG) + MSG(0, "%s", " large_nat_bitmap"); + if (flag & CP_NOCRC_RECOVERY_FLAG) + MSG(0, "%s", " allow_nocrc"); + if (flag & CP_TRIMMED_FLAG) + MSG(0, "%s", " trimmed"); + if (flag & CP_NAT_BITS_FLAG) + MSG(0, "%s", " nat_bits"); + if (flag & CP_CRC_RECOVERY_FLAG) + MSG(0, "%s", " crc"); + if (flag & CP_FASTBOOT_FLAG) + MSG(0, "%s", " fastboot"); + if (flag & CP_FSCK_FLAG) + MSG(0, "%s", " fsck"); + if (flag & CP_ERROR_FLAG) + MSG(0, "%s", " error"); + if (flag & CP_COMPACT_SUM_FLAG) + MSG(0, "%s", " compacted_summary"); + if (flag & CP_ORPHAN_PRESENT_FLAG) + MSG(0, "%s", " orphan_inodes"); + if (flag & CP_DISABLED_FLAG) + MSG(0, "%s", " disabled"); + if (flag & CP_RESIZEFS_FLAG) + MSG(0, "%s", " resizefs"); + if (flag & CP_UMOUNT_FLAG) + MSG(0, "%s", " unmount"); + else + MSG(0, "%s", " sudden-power-off"); + MSG(0, "\n"); +} + +extern struct feature feature_table[]; +void print_sb_state(struct f2fs_super_block *sb) +{ + unsigned int f = get_sb(feature); + char *name; + int i; + + MSG(0, "Info: superblock features = %x : ", f); + + for (i = 0; i < MAX_NR_FEATURE; i++) { + unsigned int bit = 1 << i; + + if (!(f & bit)) + continue; + + name = feature_name(feature_table, bit); + if (!name) + continue; + + MSG(0, " %s", name); + } + + MSG(0, "\n"); + MSG(0, "Info: superblock encrypt level = %d, salt = ", + sb->encryption_level); + for (i = 0; i < 16; i++) + MSG(0, "%02x", sb->encrypt_pw_salt[i]); + MSG(0, "\n"); +} + +static char *stop_reason_str[] = { + [STOP_CP_REASON_SHUTDOWN] = "shutdown", + [STOP_CP_REASON_FAULT_INJECT] = "fault_inject", + [STOP_CP_REASON_META_PAGE] = "meta_page", + [STOP_CP_REASON_WRITE_FAIL] = "write_fail", + [STOP_CP_REASON_CORRUPTED_SUMMARY] = "corrupted_summary", + [STOP_CP_REASON_UPDATE_INODE] = "update_inode", + [STOP_CP_REASON_FLUSH_FAIL] = "flush_fail", + [STOP_CP_REASON_NO_SEGMENT] = "no_segment", + [STOP_CP_REASON_CORRUPTED_FREE_BITMAP] = "corrupted_free_bitmap", +}; + +void print_sb_stop_reason(struct f2fs_super_block *sb) +{ + u8 *reason = sb->s_stop_reason; + int i; + + if (!(c.invalid_sb & SB_FORCE_STOP)) + return; + + MSG(0, "Info: checkpoint stop reason: "); + + for (i = 0; i < STOP_CP_REASON_MAX; i++) { + if (reason[i]) + MSG(0, "%s(%d) ", stop_reason_str[i], reason[i]); + } + + MSG(0, "\n"); +} + +static char *errors_str[] = { + [ERROR_CORRUPTED_CLUSTER] = "corrupted_cluster", + [ERROR_FAIL_DECOMPRESSION] = "fail_decompression", + [ERROR_INVALID_BLKADDR] = "invalid_blkaddr", + [ERROR_CORRUPTED_DIRENT] = "corrupted_dirent", + [ERROR_CORRUPTED_INODE] = "corrupted_inode", + [ERROR_INCONSISTENT_SUMMARY] = "inconsistent_summary", + [ERROR_INCONSISTENT_FOOTER] = "inconsistent_footer", + [ERROR_INCONSISTENT_SUM_TYPE] = "inconsistent_sum_type", + [ERROR_CORRUPTED_JOURNAL] = "corrupted_journal", + [ERROR_INCONSISTENT_NODE_COUNT] = "inconsistent_node_count", + [ERROR_INCONSISTENT_BLOCK_COUNT] = "inconsistent_block_count", + [ERROR_INVALID_CURSEG] = "invalid_curseg", + [ERROR_INCONSISTENT_SIT] = "inconsistent_sit", + [ERROR_CORRUPTED_VERITY_XATTR] = "corrupted_verity_xattr", + [ERROR_CORRUPTED_XATTR] = "corrupted_xattr", + [ERROR_INVALID_NODE_REFERENCE] = "invalid_node_reference", + [ERROR_INCONSISTENT_NAT] = "inconsistent_nat", +}; + +void print_sb_errors(struct f2fs_super_block *sb) +{ + u8 *errors = sb->s_errors; + int i; + + if (!(c.invalid_sb & SB_FS_ERRORS)) + return; + + MSG(0, "Info: fs errors: "); + + for (i = 0; i < ERROR_MAX; i++) { + if (test_bit_le(i, errors)) + MSG(0, "%s ", errors_str[i]); + } + + MSG(0, "\n"); +} + +void print_sb_debug_info(struct f2fs_super_block *sb) +{ + u8 *reason = sb->s_stop_reason; + u8 *errors = sb->s_errors; + int i; + + for (i = 0; i < STOP_CP_REASON_MAX; i++) { + if (!reason[i]) + continue; + if (c.layout) + printf("%-30s %s(%s, %d)\n", "", "stop_reason", + stop_reason_str[i], reason[i]); + else + printf("%-30s\t\t[%-20s : %u]\n", "", + stop_reason_str[i], reason[i]); + } + + for (i = 0; i < ERROR_MAX; i++) { + if (!test_bit_le(i, errors)) + continue; + if (c.layout) + printf("%-30s %s(%s)\n", "", "errors", errors_str[i]); + else + printf("%-30s\t\t[%-20s]\n", "", errors_str[i]); + } +} + +bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, + block_t blkaddr, int type) +{ + switch (type) { + case META_NAT: + break; + case META_SIT: + if (blkaddr >= SIT_BLK_CNT(sbi)) + return 0; + break; + case META_SSA: + if (blkaddr >= MAIN_BLKADDR(sbi) || + blkaddr < SM_I(sbi)->ssa_blkaddr) + return 0; + break; + case META_CP: + if (blkaddr >= SIT_I(sbi)->sit_base_addr || + blkaddr < __start_cp_addr(sbi)) + return 0; + break; + case META_POR: + case DATA_GENERIC: + if (blkaddr >= MAX_BLKADDR(sbi) || + blkaddr < MAIN_BLKADDR(sbi)) + return 0; + break; + default: + ASSERT(0); + } + + return 1; +} + +static inline block_t current_sit_addr(struct f2fs_sb_info *sbi, + unsigned int start); + +/* + * Readahead CP/NAT/SIT/SSA pages + */ +int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, + int type) +{ + block_t blkno = start; + block_t blkaddr, start_blk = 0, len = 0; + + for (; nrpages-- > 0; blkno++) { + + if (!f2fs_is_valid_blkaddr(sbi, blkno, type)) + goto out; + + switch (type) { + case META_NAT: + if (blkno >= NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid)) + blkno = 0; + /* get nat block addr */ + blkaddr = current_nat_addr(sbi, + blkno * NAT_ENTRY_PER_BLOCK, NULL); + break; + case META_SIT: + /* get sit block addr */ + blkaddr = current_sit_addr(sbi, + blkno * SIT_ENTRY_PER_BLOCK); + break; + case META_SSA: + case META_CP: + case META_POR: + blkaddr = blkno; + break; + default: + ASSERT(0); + } + + if (!len) { + start_blk = blkaddr; + len = 1; + } else if (start_blk + len == blkaddr) { + len++; + } else { + dev_readahead(start_blk << F2FS_BLKSIZE_BITS, + len << F2FS_BLKSIZE_BITS); + } + } +out: + if (len) + dev_readahead(start_blk << F2FS_BLKSIZE_BITS, + len << F2FS_BLKSIZE_BITS); + return blkno - start; +} + +void update_superblock(struct f2fs_super_block *sb, int sb_mask) +{ + int addr, ret; + uint8_t *buf; + u32 old_crc, new_crc; + + buf = calloc(F2FS_BLKSIZE, 1); + ASSERT(buf); + + if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) { + old_crc = get_sb(crc); + new_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, sb, + SB_CHKSUM_OFFSET); + set_sb(crc, new_crc); + MSG(1, "Info: SB CRC is updated (0x%x -> 0x%x)\n", + old_crc, new_crc); + } + + memcpy(buf + F2FS_SUPER_OFFSET, sb, sizeof(*sb)); + for (addr = SB0_ADDR; addr < SB_MAX_ADDR; addr++) { + if (SB_MASK(addr) & sb_mask) { + ret = dev_write_block(buf, addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + } + + free(buf); + DBG(0, "Info: Done to update superblock\n"); +} + +static inline int sanity_check_area_boundary(struct f2fs_super_block *sb, + enum SB_ADDR sb_addr) +{ + u32 segment0_blkaddr = get_sb(segment0_blkaddr); + u32 cp_blkaddr = get_sb(cp_blkaddr); + u32 sit_blkaddr = get_sb(sit_blkaddr); + u32 nat_blkaddr = get_sb(nat_blkaddr); + u32 ssa_blkaddr = get_sb(ssa_blkaddr); + u32 main_blkaddr = get_sb(main_blkaddr); + u32 segment_count_ckpt = get_sb(segment_count_ckpt); + u32 segment_count_sit = get_sb(segment_count_sit); + u32 segment_count_nat = get_sb(segment_count_nat); + u32 segment_count_ssa = get_sb(segment_count_ssa); + u32 segment_count_main = get_sb(segment_count_main); + u32 segment_count = get_sb(segment_count); + u32 log_blocks_per_seg = get_sb(log_blocks_per_seg); + u64 main_end_blkaddr = main_blkaddr + + (segment_count_main << log_blocks_per_seg); + u64 seg_end_blkaddr = segment0_blkaddr + + (segment_count << log_blocks_per_seg); + + if (segment0_blkaddr != cp_blkaddr) { + MSG(0, "\tMismatch segment0(%u) cp_blkaddr(%u)\n", + segment0_blkaddr, cp_blkaddr); + return -1; + } + + if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) != + sit_blkaddr) { + MSG(0, "\tWrong CP boundary, start(%u) end(%u) blocks(%u)\n", + cp_blkaddr, sit_blkaddr, + segment_count_ckpt << log_blocks_per_seg); + return -1; + } + + if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) != + nat_blkaddr) { + MSG(0, "\tWrong SIT boundary, start(%u) end(%u) blocks(%u)\n", + sit_blkaddr, nat_blkaddr, + segment_count_sit << log_blocks_per_seg); + return -1; + } + + if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) != + ssa_blkaddr) { + MSG(0, "\tWrong NAT boundary, start(%u) end(%u) blocks(%u)\n", + nat_blkaddr, ssa_blkaddr, + segment_count_nat << log_blocks_per_seg); + return -1; + } + + if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) != + main_blkaddr) { + MSG(0, "\tWrong SSA boundary, start(%u) end(%u) blocks(%u)\n", + ssa_blkaddr, main_blkaddr, + segment_count_ssa << log_blocks_per_seg); + return -1; + } + + if (main_end_blkaddr > seg_end_blkaddr) { + MSG(0, "\tWrong MAIN_AREA, start(%u) end(%u) block(%u)\n", + main_blkaddr, + segment0_blkaddr + + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + return -1; + } else if (main_end_blkaddr < seg_end_blkaddr) { + set_sb(segment_count, (main_end_blkaddr - + segment0_blkaddr) >> log_blocks_per_seg); + + update_superblock(sb, SB_MASK(sb_addr)); + MSG(0, "Info: Fix alignment: start(%u) end(%u) block(%u)\n", + main_blkaddr, + segment0_blkaddr + + (segment_count << log_blocks_per_seg), + segment_count_main << log_blocks_per_seg); + } + return 0; +} + +static int verify_sb_chksum(struct f2fs_super_block *sb) +{ + if (SB_CHKSUM_OFFSET != get_sb(checksum_offset)) { + MSG(0, "\tInvalid SB CRC offset: %u\n", + get_sb(checksum_offset)); + return -1; + } + if (f2fs_crc_valid(get_sb(crc), sb, + get_sb(checksum_offset))) { + MSG(0, "\tInvalid SB CRC: 0x%x\n", get_sb(crc)); + return -1; + } + return 0; +} + +int sanity_check_raw_super(struct f2fs_super_block *sb, enum SB_ADDR sb_addr) +{ + unsigned int blocksize; + unsigned int segment_count, segs_per_sec, secs_per_zone, segs_per_zone; + unsigned int total_sections, blocks_per_seg; + + if (F2FS_SUPER_MAGIC != get_sb(magic)) { + MSG(0, "Magic Mismatch, valid(0x%x) - read(0x%x)\n", + F2FS_SUPER_MAGIC, get_sb(magic)); + return -1; + } + + if ((get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) && + verify_sb_chksum(sb)) + return -1; + + blocksize = 1 << get_sb(log_blocksize); + if (c.sparse_mode && F2FS_BLKSIZE != blocksize) { + MSG(0, "Invalid blocksize (%u), does not equal sparse file blocksize (%u)", + F2FS_BLKSIZE, blocksize); + } + if (blocksize < F2FS_MIN_BLKSIZE || blocksize > F2FS_MAX_BLKSIZE) { + MSG(0, "Invalid blocksize (%u), must be between 4KB and 16KB\n", + blocksize); + return -1; + } + c.blksize_bits = get_sb(log_blocksize); + c.blksize = blocksize; + c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size; + check_block_struct_sizes(); + + /* check log blocks per segment */ + if (get_sb(log_blocks_per_seg) != 9) { + MSG(0, "Invalid log blocks per segment (%u)\n", + get_sb(log_blocks_per_seg)); + return -1; + } + + /* Currently, support powers of 2 from 512 to BLOCK SIZE bytes sector size */ + if (get_sb(log_sectorsize) > F2FS_MAX_LOG_SECTOR_SIZE || + get_sb(log_sectorsize) < F2FS_MIN_LOG_SECTOR_SIZE) { + MSG(0, "Invalid log sectorsize (%u)\n", get_sb(log_sectorsize)); + return -1; + } + + if (get_sb(log_sectors_per_block) + get_sb(log_sectorsize) != + F2FS_MAX_LOG_SECTOR_SIZE) { + MSG(0, "Invalid log sectors per block(%u) log sectorsize(%u)\n", + get_sb(log_sectors_per_block), + get_sb(log_sectorsize)); + return -1; + } + + segment_count = get_sb(segment_count); + segs_per_sec = get_sb(segs_per_sec); + secs_per_zone = get_sb(secs_per_zone); + total_sections = get_sb(section_count); + segs_per_zone = segs_per_sec * secs_per_zone; + + /* blocks_per_seg should be 512, given the above check */ + blocks_per_seg = 1 << get_sb(log_blocks_per_seg); + + if (segment_count > F2FS_MAX_SEGMENT || + segment_count < F2FS_MIN_SEGMENTS) { + MSG(0, "\tInvalid segment count (%u)\n", segment_count); + return -1; + } + + if (!(get_sb(feature) & F2FS_FEATURE_RO) && + (total_sections > segment_count || + total_sections < F2FS_MIN_SEGMENTS || + segs_per_sec > segment_count || !segs_per_sec)) { + MSG(0, "\tInvalid segment/section count (%u, %u x %u)\n", + segment_count, total_sections, segs_per_sec); + return 1; + } + + if ((segment_count / segs_per_sec) < total_sections) { + MSG(0, "Small segment_count (%u < %u * %u)\n", + segment_count, segs_per_sec, total_sections); + return 1; + } + + if (segment_count > (get_sb(block_count) >> 9)) { + MSG(0, "Wrong segment_count / block_count (%u > %llu)\n", + segment_count, get_sb(block_count)); + return 1; + } + + if (sb->devs[0].path[0]) { + unsigned int dev_segs = le32_to_cpu(sb->devs[0].total_segments); + int i = 1; + + while (i < MAX_DEVICES && sb->devs[i].path[0]) { + dev_segs += le32_to_cpu(sb->devs[i].total_segments); + i++; + } + if (segment_count != dev_segs / segs_per_zone * segs_per_zone) { + MSG(0, "Segment count (%u) mismatch with total segments from devices (%u)", + segment_count, dev_segs); + return 1; + } + } + + if (secs_per_zone > total_sections || !secs_per_zone) { + MSG(0, "Wrong secs_per_zone / total_sections (%u, %u)\n", + secs_per_zone, total_sections); + return 1; + } + if (get_sb(extension_count) > F2FS_MAX_EXTENSION || + sb->hot_ext_count > F2FS_MAX_EXTENSION || + get_sb(extension_count) + + sb->hot_ext_count > F2FS_MAX_EXTENSION) { + MSG(0, "Corrupted extension count (%u + %u > %u)\n", + get_sb(extension_count), + sb->hot_ext_count, + F2FS_MAX_EXTENSION); + return 1; + } + + if (get_sb(cp_payload) > (blocks_per_seg - F2FS_CP_PACKS)) { + MSG(0, "Insane cp_payload (%u > %u)\n", + get_sb(cp_payload), blocks_per_seg - F2FS_CP_PACKS); + return 1; + } + + /* check reserved ino info */ + if (get_sb(node_ino) != 1 || get_sb(meta_ino) != 2 || + get_sb(root_ino) != 3) { + MSG(0, "Invalid Fs Meta Ino: node(%u) meta(%u) root(%u)\n", + get_sb(node_ino), get_sb(meta_ino), get_sb(root_ino)); + return -1; + } + + /* Check zoned block device feature */ + if (c.devices[0].zoned_model != F2FS_ZONED_NONE && + !(get_sb(feature) & F2FS_FEATURE_BLKZONED)) { + MSG(0, "\tMissing zoned block device feature\n"); + return -1; + } + + if (sanity_check_area_boundary(sb, sb_addr)) + return -1; + return 0; +} + +#define CHECK_PERIOD (3600 * 24 * 30) // one month by default + +int validate_super_block(struct f2fs_sb_info *sbi, enum SB_ADDR sb_addr) +{ + char buf[F2FS_BLKSIZE]; + + sbi->raw_super = malloc(sizeof(struct f2fs_super_block)); + if (!sbi->raw_super) + return -ENOMEM; + + if (dev_read_block(buf, sb_addr)) + return -1; + + memcpy(sbi->raw_super, buf + F2FS_SUPER_OFFSET, + sizeof(struct f2fs_super_block)); + + if (!sanity_check_raw_super(sbi->raw_super, sb_addr)) { + /* get kernel version */ + if (c.kd >= 0) { + dev_read_version(c.version, 0, VERSION_NAME_LEN); + get_kernel_version(c.version); + } else { + get_kernel_uname_version(c.version); + } + + /* build sb version */ + memcpy(c.sb_version, sbi->raw_super->version, VERSION_NAME_LEN); + get_kernel_version(c.sb_version); + memcpy(c.init_version, sbi->raw_super->init_version, + VERSION_NAME_LEN); + get_kernel_version(c.init_version); + + if (is_checkpoint_stop(sbi->raw_super, false)) + c.invalid_sb |= SB_FORCE_STOP; + if (is_checkpoint_stop(sbi->raw_super, true)) + c.invalid_sb |= SB_ABNORMAL_STOP; + if (is_inconsistent_error(sbi->raw_super)) + c.invalid_sb |= SB_FS_ERRORS; + + MSG(0, "Info: MKFS version\n \"%s\"\n", c.init_version); + MSG(0, "Info: FSCK version\n from \"%s\"\n to \"%s\"\n", + c.sb_version, c.version); + print_sb_state(sbi->raw_super); + print_sb_stop_reason(sbi->raw_super); + print_sb_errors(sbi->raw_super); + return 0; + } + + free(sbi->raw_super); + sbi->raw_super = NULL; + c.invalid_sb |= SB_INVALID; + MSG(0, "\tCan't find a valid F2FS superblock at 0x%x\n", sb_addr); + + return -EINVAL; +} + +int init_sb_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + u64 total_sectors; + int i; + + sbi->log_sectors_per_block = get_sb(log_sectors_per_block); + sbi->log_blocksize = get_sb(log_blocksize); + sbi->blocksize = 1 << sbi->log_blocksize; + sbi->log_blocks_per_seg = get_sb(log_blocks_per_seg); + sbi->blocks_per_seg = 1 << sbi->log_blocks_per_seg; + sbi->segs_per_sec = get_sb(segs_per_sec); + sbi->secs_per_zone = get_sb(secs_per_zone); + sbi->total_sections = get_sb(section_count); + sbi->total_node_count = (get_sb(segment_count_nat) / 2) * + sbi->blocks_per_seg * NAT_ENTRY_PER_BLOCK; + sbi->root_ino_num = get_sb(root_ino); + sbi->node_ino_num = get_sb(node_ino); + sbi->meta_ino_num = get_sb(meta_ino); + sbi->cur_victim_sec = NULL_SEGNO; + + for (i = 0; i < MAX_DEVICES; i++) { + if (!sb->devs[i].path[0]) + break; + + if (i) { + c.devices[i].path = strdup((char *)sb->devs[i].path); + if (get_device_info(i)) + ASSERT(0); + } else if (c.func != INJECT) { + ASSERT(!strcmp((char *)sb->devs[i].path, + (char *)c.devices[i].path)); + } + + c.devices[i].total_segments = + le32_to_cpu(sb->devs[i].total_segments); + if (i) + c.devices[i].start_blkaddr = + c.devices[i - 1].end_blkaddr + 1; + c.devices[i].end_blkaddr = c.devices[i].start_blkaddr + + c.devices[i].total_segments * + c.blks_per_seg - 1; + if (i == 0) + c.devices[i].end_blkaddr += get_sb(segment0_blkaddr); + + if (c.zoned_model == F2FS_ZONED_NONE) { + if (c.devices[i].zoned_model == F2FS_ZONED_HM) + c.zoned_model = F2FS_ZONED_HM; + else if (c.devices[i].zoned_model == F2FS_ZONED_HA && + c.zoned_model != F2FS_ZONED_HM) + c.zoned_model = F2FS_ZONED_HA; + } + + c.ndevs = i + 1; + MSG(0, "Info: Device[%d] : %s blkaddr = %"PRIx64"--%"PRIx64"\n", + i, c.devices[i].path, + c.devices[i].start_blkaddr, + c.devices[i].end_blkaddr); + } + + total_sectors = get_sb(block_count) << sbi->log_sectors_per_block; + MSG(0, "Info: Segments per section = %d\n", sbi->segs_per_sec); + MSG(0, "Info: Sections per zone = %d\n", sbi->secs_per_zone); + MSG(0, "Info: total FS sectors = %"PRIu64" (%"PRIu64" MB)\n", + total_sectors, total_sectors >> + (20 - get_sb(log_sectorsize))); + return 0; +} + +static int verify_checksum_chksum(struct f2fs_checkpoint *cp) +{ + unsigned int chksum_offset = get_cp(checksum_offset); + unsigned int crc, cal_crc; + + if (chksum_offset < CP_MIN_CHKSUM_OFFSET || + chksum_offset > CP_CHKSUM_OFFSET) { + MSG(0, "\tInvalid CP CRC offset: %u\n", chksum_offset); + return -1; + } + + crc = le32_to_cpu(*(__le32 *)((unsigned char *)cp + chksum_offset)); + cal_crc = f2fs_checkpoint_chksum(cp); + if (cal_crc != crc) { + MSG(0, "\tInvalid CP CRC: offset:%u, crc:0x%x, calc:0x%x\n", + chksum_offset, crc, cal_crc); + return -1; + } + return 0; +} + +static void *get_checkpoint_version(block_t cp_addr) +{ + void *cp_page; + + cp_page = malloc(F2FS_BLKSIZE); + ASSERT(cp_page); + + if (dev_read_block(cp_page, cp_addr) < 0) + ASSERT(0); + + if (verify_checksum_chksum((struct f2fs_checkpoint *)cp_page)) + goto out; + return cp_page; +out: + free(cp_page); + return NULL; +} + +void *validate_checkpoint(struct f2fs_sb_info *sbi, block_t cp_addr, + unsigned long long *version) +{ + void *cp_page_1, *cp_page_2; + struct f2fs_checkpoint *cp; + unsigned long long cur_version = 0, pre_version = 0; + + /* Read the 1st cp block in this CP pack */ + cp_page_1 = get_checkpoint_version(cp_addr); + if (!cp_page_1) + return NULL; + + cp = (struct f2fs_checkpoint *)cp_page_1; + if (get_cp(cp_pack_total_block_count) > sbi->blocks_per_seg) + goto invalid_cp1; + + pre_version = get_cp(checkpoint_ver); + + /* Read the 2nd cp block in this CP pack */ + cp_addr += get_cp(cp_pack_total_block_count) - 1; + cp_page_2 = get_checkpoint_version(cp_addr); + if (!cp_page_2) + goto invalid_cp1; + + cp = (struct f2fs_checkpoint *)cp_page_2; + cur_version = get_cp(checkpoint_ver); + + if (cur_version == pre_version) { + *version = cur_version; + free(cp_page_2); + return cp_page_1; + } + + free(cp_page_2); +invalid_cp1: + free(cp_page_1); + return NULL; +} + +int get_valid_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + void *cp1, *cp2, *cur_page; + unsigned long blk_size = sbi->blocksize; + unsigned long long cp1_version = 0, cp2_version = 0, version; + unsigned long long cp_start_blk_no; + unsigned int cp_payload, cp_blks; + int ret; + + cp_payload = get_sb(cp_payload); + if (cp_payload > F2FS_BLK_ALIGN(MAX_CP_PAYLOAD)) + return -EINVAL; + + cp_blks = 1 + cp_payload; + sbi->ckpt = malloc(cp_blks * blk_size); + if (!sbi->ckpt) + return -ENOMEM; + /* + * Finding out valid cp block involves read both + * sets( cp pack1 and cp pack 2) + */ + cp_start_blk_no = get_sb(cp_blkaddr); + cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version); + + /* The second checkpoint pack should start at the next segment */ + cp_start_blk_no += 1 << get_sb(log_blocks_per_seg); + cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version); + + if (cp1 && cp2) { + if (ver_after(cp2_version, cp1_version)) { + cur_page = cp2; + sbi->cur_cp = 2; + version = cp2_version; + } else { + cur_page = cp1; + sbi->cur_cp = 1; + version = cp1_version; + } + } else if (cp1) { + cur_page = cp1; + sbi->cur_cp = 1; + version = cp1_version; + } else if (cp2) { + cur_page = cp2; + sbi->cur_cp = 2; + version = cp2_version; + } else + goto fail_no_cp; + + MSG(0, "Info: CKPT version = %llx\n", version); + + memcpy(sbi->ckpt, cur_page, blk_size); + + if (cp_blks > 1) { + unsigned int i; + unsigned long long cp_blk_no; + + cp_blk_no = get_sb(cp_blkaddr); + if (cur_page == cp2) + cp_blk_no += 1 << get_sb(log_blocks_per_seg); + + /* copy sit bitmap */ + for (i = 1; i < cp_blks; i++) { + unsigned char *ckpt = (unsigned char *)sbi->ckpt; + ret = dev_read_block(cur_page, cp_blk_no + i); + ASSERT(ret >= 0); + memcpy(ckpt + i * blk_size, cur_page, blk_size); + } + } + if (cp1) + free(cp1); + if (cp2) + free(cp2); + return 0; + +fail_no_cp: + free(sbi->ckpt); + sbi->ckpt = NULL; + return -EINVAL; +} + +bool is_checkpoint_stop(struct f2fs_super_block *sb, bool abnormal) +{ + int i; + + for (i = 0; i < STOP_CP_REASON_MAX; i++) { + if (abnormal && i == STOP_CP_REASON_SHUTDOWN) + continue; + if (sb->s_stop_reason[i]) + return true; + } + + return false; +} + +bool is_inconsistent_error(struct f2fs_super_block *sb) +{ + int i; + + for (i = 0; i < MAX_F2FS_ERRORS; i++) { + if (sb->s_errors[i]) + return true; + } + + return false; +} + +/* + * For a return value of 1, caller should further check for c.fix_on state + * and take appropriate action. + */ +static int f2fs_should_proceed(struct f2fs_super_block *sb, u32 flag) +{ + if (!c.fix_on && (c.auto_fix || c.preen_mode)) { + if (flag & CP_FSCK_FLAG || + flag & CP_DISABLED_FLAG || + flag & CP_QUOTA_NEED_FSCK_FLAG || + c.invalid_sb & SB_NEED_FIX || + (exist_qf_ino(sb) && (flag & CP_ERROR_FLAG))) { + c.fix_on = 1; + } else if (!c.preen_mode) { + print_cp_state(flag); + return 0; + } + } + return 1; +} + +int sanity_check_ckpt(struct f2fs_sb_info *sbi) +{ + unsigned int total, fsmeta; + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + unsigned int flag = get_cp(ckpt_flags); + unsigned int ovp_segments, reserved_segments; + unsigned int main_segs, blocks_per_seg; + unsigned int sit_segs, nat_segs; + unsigned int sit_bitmap_size, nat_bitmap_size; + unsigned int log_blocks_per_seg; + unsigned int segment_count_main; + unsigned int cp_pack_start_sum, cp_payload; + block_t user_block_count; + int i; + + total = get_sb(segment_count); + fsmeta = get_sb(segment_count_ckpt); + sit_segs = get_sb(segment_count_sit); + fsmeta += sit_segs; + nat_segs = get_sb(segment_count_nat); + fsmeta += nat_segs; + fsmeta += get_cp(rsvd_segment_count); + fsmeta += get_sb(segment_count_ssa); + + if (fsmeta >= total) + return 1; + + ovp_segments = get_cp(overprov_segment_count); + reserved_segments = get_cp(rsvd_segment_count); + + if (!(get_sb(feature) & F2FS_FEATURE_RO) && + (fsmeta < F2FS_MIN_SEGMENT || ovp_segments == 0 || + reserved_segments == 0)) { + MSG(0, "\tWrong layout: check mkfs.f2fs version\n"); + return 1; + } + + user_block_count = get_cp(user_block_count); + segment_count_main = get_sb(segment_count_main) + + ((get_sb(feature) & F2FS_FEATURE_RO) ? 1 : 0); + log_blocks_per_seg = get_sb(log_blocks_per_seg); + if (!user_block_count || user_block_count >= + segment_count_main << log_blocks_per_seg) { + ASSERT_MSG("\tWrong user_block_count(%u)\n", user_block_count); + + if (!f2fs_should_proceed(sb, flag)) + return 1; + if (!c.fix_on) + return 1; + + if (flag & (CP_FSCK_FLAG | CP_RESIZEFS_FLAG)) { + u32 valid_user_block_cnt; + u32 seg_cnt_main = get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat) + + get_sb(segment_count_ssa)); + + /* validate segment_count_main in sb first */ + if (seg_cnt_main != get_sb(segment_count_main)) { + MSG(0, "Inconsistent segment_cnt_main %u in sb\n", + segment_count_main << log_blocks_per_seg); + return 1; + } + valid_user_block_cnt = ((get_sb(segment_count_main) - + get_cp(overprov_segment_count)) * c.blks_per_seg); + MSG(0, "Info: Fix wrong user_block_count in CP: (%u) -> (%u)\n", + user_block_count, valid_user_block_cnt); + set_cp(user_block_count, valid_user_block_cnt); + c.bug_on = 1; + } + } + + main_segs = get_sb(segment_count_main); + blocks_per_seg = sbi->blocks_per_seg; + + for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { + if (get_cp(cur_node_segno[i]) >= main_segs || + get_cp(cur_node_blkoff[i]) >= blocks_per_seg) + return 1; + } + for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { + if (get_cp(cur_data_segno[i]) >= main_segs || + get_cp(cur_data_blkoff[i]) >= blocks_per_seg) + return 1; + } + + sit_bitmap_size = get_cp(sit_ver_bitmap_bytesize); + nat_bitmap_size = get_cp(nat_ver_bitmap_bytesize); + + if (sit_bitmap_size != ((sit_segs / 2) << log_blocks_per_seg) / 8 || + nat_bitmap_size != ((nat_segs / 2) << log_blocks_per_seg) / 8) { + MSG(0, "\tWrong bitmap size: sit(%u), nat(%u)\n", + sit_bitmap_size, nat_bitmap_size); + return 1; + } + + cp_pack_start_sum = __start_sum_addr(sbi); + cp_payload = __cp_payload(sbi); + if (cp_pack_start_sum < cp_payload + 1 || + cp_pack_start_sum > blocks_per_seg - 1 - + NR_CURSEG_TYPE) { + MSG(0, "\tWrong cp_pack_start_sum(%u) or cp_payload(%u)\n", + cp_pack_start_sum, cp_payload); + if (get_sb(feature) & F2FS_FEATURE_SB_CHKSUM) + return 1; + set_sb(cp_payload, cp_pack_start_sum - 1); + update_superblock(sb, SB_MASK_ALL); + } + + return 0; +} + +pgoff_t current_nat_addr(struct f2fs_sb_info *sbi, nid_t start, int *pack) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + pgoff_t block_off; + pgoff_t block_addr; + int seg_off; + + block_off = NAT_BLOCK_OFFSET(start); + seg_off = block_off >> sbi->log_blocks_per_seg; + + block_addr = (pgoff_t)(nm_i->nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) -1))); + if (pack) + *pack = 1; + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) { + block_addr += sbi->blocks_per_seg; + if (pack) + *pack = 2; + } + + return block_addr; +} + +/* will not init nid_bitmap from nat */ +static int f2fs_early_init_nid_bitmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + int nid_bitmap_size = (nm_i->max_nid + BITS_PER_BYTE - 1) / BITS_PER_BYTE; + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_summary_block *sum = curseg->sum_blk; + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(sum); + nid_t nid; + int i; + + if (!(c.func == SLOAD || c.func == FSCK)) + return 0; + + nm_i->nid_bitmap = (char *)calloc(nid_bitmap_size, 1); + if (!nm_i->nid_bitmap) + return -ENOMEM; + + /* arbitrarily set 0 bit */ + f2fs_set_bit(0, nm_i->nid_bitmap); + + if (nats_in_cursum(journal) > NAT_JOURNAL_ENTRIES) { + MSG(0, "\tError: f2fs_init_nid_bitmap truncate n_nats(%u) to " + "NAT_JOURNAL_ENTRIES(%zu)\n", + nats_in_cursum(journal), NAT_JOURNAL_ENTRIES); + journal->n_nats = cpu_to_le16(NAT_JOURNAL_ENTRIES); + c.fix_on = 1; + } + + for (i = 0; i < nats_in_cursum(journal); i++) { + block_t addr; + + addr = le32_to_cpu(nat_in_journal(journal, i).block_addr); + if (addr != NULL_ADDR && + !f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC)) { + MSG(0, "\tError: f2fs_init_nid_bitmap: addr(%u) is invalid!!!\n", addr); + journal->n_nats = cpu_to_le16(i); + c.fix_on = 1; + continue; + } + + nid = le32_to_cpu(nid_in_journal(journal, i)); + if (!IS_VALID_NID(sbi, nid)) { + MSG(0, "\tError: f2fs_init_nid_bitmap: nid(%u) is invalid!!!\n", nid); + journal->n_nats = cpu_to_le16(i); + c.fix_on = 1; + continue; + } + if (addr != NULL_ADDR) + f2fs_set_bit(nid, nm_i->nid_bitmap); + } + return 0; +} + +/* will init nid_bitmap from nat */ +static int f2fs_late_init_nid_bitmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct f2fs_nat_block *nat_block; + block_t start_blk; + nid_t nid; + + if (!(c.func == SLOAD || c.func == FSCK)) + return 0; + + nat_block = malloc(F2FS_BLKSIZE); + if (!nat_block) { + free(nm_i->nid_bitmap); + return -ENOMEM; + } + + f2fs_ra_meta_pages(sbi, 0, NAT_BLOCK_OFFSET(nm_i->max_nid), + META_NAT); + for (nid = 0; nid < nm_i->max_nid; nid++) { + if (!(nid % NAT_ENTRY_PER_BLOCK)) { + int ret; + + start_blk = current_nat_addr(sbi, nid, NULL); + ret = dev_read_block(nat_block, start_blk); + ASSERT(ret >= 0); + } + + if (nat_block->entries[nid % NAT_ENTRY_PER_BLOCK].block_addr) + f2fs_set_bit(nid, nm_i->nid_bitmap); + } + + free(nat_block); + return 0; +} + +u32 update_nat_bits_flags(struct f2fs_super_block *sb, + struct f2fs_checkpoint *cp, u32 flags) +{ + uint32_t nat_bits_bytes, nat_bits_blocks; + + nat_bits_bytes = get_sb(segment_count_nat) << 5; + nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + + F2FS_BLKSIZE - 1); + if (!(c.disabled_feature & F2FS_FEATURE_NAT_BITS) && + get_cp(cp_pack_total_block_count) <= + (1 << get_sb(log_blocks_per_seg)) - nat_bits_blocks) + flags |= CP_NAT_BITS_FLAG; + else + flags &= (~CP_NAT_BITS_FLAG); + + return flags; +} + +/* should call flush_journal_entries() bfore this */ +void write_nat_bits(struct f2fs_sb_info *sbi, + struct f2fs_super_block *sb, struct f2fs_checkpoint *cp, int set) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + uint32_t nat_blocks = get_sb(segment_count_nat) << + (get_sb(log_blocks_per_seg) - 1); + uint32_t nat_bits_bytes = nat_blocks >> 3; + uint32_t nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + + 8 + F2FS_BLKSIZE - 1); + unsigned char *nat_bits, *full_nat_bits, *empty_nat_bits; + struct f2fs_nat_block *nat_block; + uint32_t i, j; + block_t blkaddr; + int ret; + + nat_bits = calloc(F2FS_BLKSIZE, nat_bits_blocks); + ASSERT(nat_bits); + + nat_block = malloc(F2FS_BLKSIZE); + ASSERT(nat_block); + + full_nat_bits = nat_bits + 8; + empty_nat_bits = full_nat_bits + nat_bits_bytes; + + memset(full_nat_bits, 0, nat_bits_bytes); + memset(empty_nat_bits, 0, nat_bits_bytes); + + for (i = 0; i < nat_blocks; i++) { + int seg_off = i >> get_sb(log_blocks_per_seg); + int valid = 0; + + blkaddr = (pgoff_t)(get_sb(nat_blkaddr) + + (seg_off << get_sb(log_blocks_per_seg) << 1) + + (i & ((1 << get_sb(log_blocks_per_seg)) - 1))); + + /* + * Should consider new nat_blocks is larger than old + * nm_i->nat_blocks, since nm_i->nat_bitmap is based on + * old one. + */ + if (i < nm_i->nat_blocks && f2fs_test_bit(i, nm_i->nat_bitmap)) + blkaddr += (1 << get_sb(log_blocks_per_seg)); + + ret = dev_read_block(nat_block, blkaddr); + ASSERT(ret >= 0); + + for (j = 0; j < NAT_ENTRY_PER_BLOCK; j++) { + if ((i == 0 && j == 0) || + nat_block->entries[j].block_addr != NULL_ADDR) + valid++; + } + if (valid == 0) + test_and_set_bit_le(i, empty_nat_bits); + else if (valid == NAT_ENTRY_PER_BLOCK) + test_and_set_bit_le(i, full_nat_bits); + } + *(__le64 *)nat_bits = get_cp_crc(cp); + free(nat_block); + + blkaddr = get_sb(segment0_blkaddr) + (set << + get_sb(log_blocks_per_seg)) - nat_bits_blocks; + + DBG(1, "\tWriting NAT bits pages, at offset 0x%08x\n", blkaddr); + + for (i = 0; i < nat_bits_blocks; i++) { + if (dev_write_block(nat_bits + i * F2FS_BLKSIZE, blkaddr + i, + WRITE_LIFE_NONE)) + ASSERT_MSG("\tError: write NAT bits to disk!!!\n"); + } + MSG(0, "Info: Write valid nat_bits in checkpoint\n"); + + free(nat_bits); +} + +static int check_nat_bits(struct f2fs_sb_info *sbi, + struct f2fs_super_block *sb, struct f2fs_checkpoint *cp) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + uint32_t nat_blocks = get_sb(segment_count_nat) << + (get_sb(log_blocks_per_seg) - 1); + uint32_t nat_bits_bytes = nat_blocks >> 3; + uint32_t nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + + 8 + F2FS_BLKSIZE - 1); + unsigned char *nat_bits, *full_nat_bits, *empty_nat_bits; + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + uint32_t i, j; + block_t blkaddr; + int err = 0; + + nat_bits = calloc(F2FS_BLKSIZE, nat_bits_blocks); + ASSERT(nat_bits); + + full_nat_bits = nat_bits + 8; + empty_nat_bits = full_nat_bits + nat_bits_bytes; + + blkaddr = get_sb(segment0_blkaddr) + (sbi->cur_cp << + get_sb(log_blocks_per_seg)) - nat_bits_blocks; + + for (i = 0; i < nat_bits_blocks; i++) { + if (dev_read_block(nat_bits + i * F2FS_BLKSIZE, blkaddr + i)) + ASSERT_MSG("\tError: read NAT bits to disk!!!\n"); + } + + if (*(__le64 *)nat_bits != get_cp_crc(cp) || nats_in_cursum(journal)) { + /* + * if there is a journal, f2fs was not shutdown cleanly. Let's + * flush them with nat_bits. + */ + if (c.fix_on) + err = -1; + /* Otherwise, kernel will disable nat_bits */ + goto out; + } + + for (i = 0; i < nat_blocks; i++) { + uint32_t start_nid = i * NAT_ENTRY_PER_BLOCK; + uint32_t valid = 0; + int empty = test_bit_le(i, empty_nat_bits); + int full = test_bit_le(i, full_nat_bits); + + for (j = 0; j < NAT_ENTRY_PER_BLOCK; j++) { + if (f2fs_test_bit(start_nid + j, nm_i->nid_bitmap)) + valid++; + } + if (valid == 0) { + if (!empty || full) { + err = -1; + goto out; + } + } else if (valid == NAT_ENTRY_PER_BLOCK) { + if (empty || !full) { + err = -1; + goto out; + } + } else { + if (empty || full) { + err = -1; + goto out; + } + } + } +out: + free(nat_bits); + if (!err) { + MSG(0, "Info: Checked valid nat_bits in checkpoint\n"); + } else { + c.bug_nat_bits = 1; + MSG(0, "Info: Corrupted valid nat_bits in checkpoint\n"); + } + return err; +} + +int init_node_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + unsigned char *version_bitmap; + unsigned int nat_segs; + + nm_i->nat_blkaddr = get_sb(nat_blkaddr); + + /* segment_count_nat includes pair segment so divide to 2. */ + nat_segs = get_sb(segment_count_nat) >> 1; + nm_i->nat_blocks = nat_segs << get_sb(log_blocks_per_seg); + nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nm_i->nat_blocks; + nm_i->fcnt = 0; + nm_i->nat_cnt = 0; + nm_i->init_scan_nid = get_cp(next_free_nid); + nm_i->next_scan_nid = get_cp(next_free_nid); + + nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP); + + nm_i->nat_bitmap = malloc(nm_i->bitmap_size); + if (!nm_i->nat_bitmap) + return -ENOMEM; + version_bitmap = __bitmap_ptr(sbi, NAT_BITMAP); + if (!version_bitmap) + return -EFAULT; + + /* copy version bitmap */ + memcpy(nm_i->nat_bitmap, version_bitmap, nm_i->bitmap_size); + return f2fs_early_init_nid_bitmap(sbi); +} + +int build_node_manager(struct f2fs_sb_info *sbi) +{ + int err; + sbi->nm_info = malloc(sizeof(struct f2fs_nm_info)); + if (!sbi->nm_info) + return -ENOMEM; + + err = init_node_manager(sbi); + if (err) + return err; + + return 0; +} + +int build_sit_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct sit_info *sit_i; + unsigned int sit_segs; + int start; + char *src_bitmap, *dst_bitmap; + unsigned char *bitmap; + unsigned int bitmap_size; + + sit_i = malloc(sizeof(struct sit_info)); + if (!sit_i) { + MSG(1, "\tError: Malloc failed for build_sit_info!\n"); + return -ENOMEM; + } + + SM_I(sbi)->sit_info = sit_i; + + sit_i->sentries = calloc(MAIN_SEGS(sbi) * sizeof(struct seg_entry), 1); + if (!sit_i->sentries) { + MSG(1, "\tError: Calloc failed for build_sit_info!\n"); + goto free_sit_info; + } + + bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE; + + if (need_fsync_data_record(sbi)) + bitmap_size += bitmap_size; + + sit_i->bitmap = calloc(bitmap_size, 1); + if (!sit_i->bitmap) { + MSG(1, "\tError: Calloc failed for build_sit_info!!\n"); + goto free_sentries; + } + + bitmap = sit_i->bitmap; + + for (start = 0; start < MAIN_SEGS(sbi); start++) { + sit_i->sentries[start].cur_valid_map = bitmap; + bitmap += SIT_VBLOCK_MAP_SIZE; + + if (need_fsync_data_record(sbi)) { + sit_i->sentries[start].ckpt_valid_map = bitmap; + bitmap += SIT_VBLOCK_MAP_SIZE; + } + } + + sit_segs = get_sb(segment_count_sit) >> 1; + bitmap_size = __bitmap_size(sbi, SIT_BITMAP); + src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP); + + dst_bitmap = malloc(bitmap_size); + if (!dst_bitmap) { + MSG(1, "\tError: Malloc failed for build_sit_info!!\n"); + goto free_validity_maps; + } + + memcpy(dst_bitmap, src_bitmap, bitmap_size); + + sit_i->sit_base_addr = get_sb(sit_blkaddr); + sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg; + sit_i->written_valid_blocks = get_cp(valid_block_count); + sit_i->sit_bitmap = dst_bitmap; + sit_i->bitmap_size = bitmap_size; + sit_i->dirty_sentries = 0; + sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK; + sit_i->elapsed_time = get_cp(elapsed_time); + return 0; + +free_validity_maps: + free(sit_i->bitmap); +free_sentries: + free(sit_i->sentries); +free_sit_info: + free(sit_i); + + return -ENOMEM; +} + +void reset_curseg(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct summary_footer *sum_footer; + struct seg_entry *se; + + sum_footer = F2FS_SUMMARY_BLOCK_FOOTER(curseg->sum_blk); + memset(sum_footer, 0, sizeof(struct summary_footer)); + if (IS_DATASEG(type)) + SET_SUM_TYPE(curseg->sum_blk, SUM_TYPE_DATA); + if (IS_NODESEG(type)) + SET_SUM_TYPE(curseg->sum_blk, SUM_TYPE_NODE); + se = get_seg_entry(sbi, curseg->segno); + se->type = se->orig_type = type; + se->dirty = 1; +} + +static void read_compacted_summaries(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg; + unsigned int i, j, offset; + block_t start; + char *kaddr; + int ret; + + start = start_sum_block(sbi); + + kaddr = malloc(F2FS_BLKSIZE); + ASSERT(kaddr); + + ret = dev_read_block(kaddr, start++); + ASSERT(ret >= 0); + + curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + memcpy(&F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk)->n_nats, kaddr, SUM_JOURNAL_SIZE); + + curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + memcpy(&F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk)->n_sits, kaddr + SUM_JOURNAL_SIZE, + SUM_JOURNAL_SIZE); + + offset = 2 * SUM_JOURNAL_SIZE; + for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { + unsigned short blk_off; + struct curseg_info *curseg = CURSEG_I(sbi, i); + + reset_curseg(sbi, i); + + if (curseg->alloc_type == SSR) + blk_off = sbi->blocks_per_seg; + else + blk_off = curseg->next_blkoff; + + ASSERT(blk_off <= ENTRIES_IN_SUM); + + for (j = 0; j < blk_off; j++) { + struct f2fs_summary *s; + s = (struct f2fs_summary *)(kaddr + offset); + curseg->sum_blk->entries[j] = *s; + offset += SUMMARY_SIZE; + if (offset + SUMMARY_SIZE <= + F2FS_BLKSIZE - SUM_FOOTER_SIZE) + continue; + memset(kaddr, 0, F2FS_BLKSIZE); + ret = dev_read_block(kaddr, start++); + ASSERT(ret >= 0); + offset = 0; + } + } + free(kaddr); +} + +static void restore_node_summary(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_summary_block *sum_blk) +{ + struct f2fs_node *node_blk; + struct f2fs_summary *sum_entry; + block_t addr; + unsigned int i; + int ret; + + node_blk = malloc(F2FS_BLKSIZE); + ASSERT(node_blk); + + /* scan the node segment */ + addr = START_BLOCK(sbi, segno); + sum_entry = &sum_blk->entries[0]; + + for (i = 0; i < sbi->blocks_per_seg; i++, sum_entry++) { + ret = dev_read_block(node_blk, addr); + ASSERT(ret >= 0); + sum_entry->nid = F2FS_NODE_FOOTER(node_blk)->nid; + addr++; + } + free(node_blk); +} + +static void read_normal_summaries(struct f2fs_sb_info *sbi, int type) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_summary_block *sum_blk; + struct curseg_info *curseg; + unsigned int segno = 0; + block_t blk_addr = 0; + int ret; + + if (IS_DATASEG(type)) { + segno = get_cp(cur_data_segno[type]); + if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) + blk_addr = sum_blk_addr(sbi, NR_CURSEG_TYPE, type); + else + blk_addr = sum_blk_addr(sbi, NR_CURSEG_DATA_TYPE, type); + } else { + segno = get_cp(cur_node_segno[type - CURSEG_HOT_NODE]); + if (is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) + blk_addr = sum_blk_addr(sbi, NR_CURSEG_NODE_TYPE, + type - CURSEG_HOT_NODE); + else + blk_addr = GET_SUM_BLKADDR(sbi, segno); + } + + sum_blk = malloc(F2FS_BLKSIZE); + ASSERT(sum_blk); + + ret = dev_read_block(sum_blk, blk_addr); + ASSERT(ret >= 0); + + if (IS_NODESEG(type) && !is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) + restore_node_summary(sbi, segno, sum_blk); + + curseg = CURSEG_I(sbi, type); + memcpy(curseg->sum_blk, sum_blk, F2FS_BLKSIZE); + reset_curseg(sbi, type); + free(sum_blk); +} + +void update_sum_entry(struct f2fs_sb_info *sbi, block_t blk_addr, + struct f2fs_summary *sum) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_summary_block *sum_blk; + u32 segno, offset; + int type, ret; + struct seg_entry *se; + + if (get_sb(feature) & F2FS_FEATURE_RO) + return; + + segno = GET_SEGNO(sbi, blk_addr); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + se = get_seg_entry(sbi, segno); + + sum_blk = get_sum_block(sbi, segno, &type); + memcpy(&sum_blk->entries[offset], sum, sizeof(*sum)); + F2FS_SUMMARY_BLOCK_FOOTER(sum_blk)->entry_type = IS_NODESEG(se->type) ? SUM_TYPE_NODE : + SUM_TYPE_DATA; + + /* write SSA all the time */ + ret = dev_write_block(sum_blk, GET_SUM_BLKADDR(sbi, segno), + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); +} + +static void restore_curseg_summaries(struct f2fs_sb_info *sbi) +{ + int type = CURSEG_HOT_DATA; + + if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) { + read_compacted_summaries(sbi); + type = CURSEG_HOT_NODE; + } + + for (; type <= CURSEG_COLD_NODE; type++) + read_normal_summaries(sbi, type); +} + +static int build_curseg(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct curseg_info *array; + unsigned short blk_off; + unsigned int segno; + int i; + + array = malloc(sizeof(*array) * NR_CURSEG_TYPE); + if (!array) { + MSG(1, "\tError: Malloc failed for build_curseg!\n"); + return -ENOMEM; + } + + SM_I(sbi)->curseg_array = array; + + for (i = 0; i < NR_CURSEG_TYPE; i++) { + array[i].sum_blk = calloc(F2FS_BLKSIZE, 1); + if (!array[i].sum_blk) { + MSG(1, "\tError: Calloc failed for build_curseg!!\n"); + goto seg_cleanup; + } + + if (i <= CURSEG_COLD_DATA) { + blk_off = get_cp(cur_data_blkoff[i]); + segno = get_cp(cur_data_segno[i]); + } + if (i > CURSEG_COLD_DATA) { + blk_off = get_cp(cur_node_blkoff[i - CURSEG_HOT_NODE]); + segno = get_cp(cur_node_segno[i - CURSEG_HOT_NODE]); + } + ASSERT(segno < MAIN_SEGS(sbi)); + ASSERT(blk_off < DEFAULT_BLOCKS_PER_SEGMENT); + + array[i].segno = segno; + array[i].zone = GET_ZONENO_FROM_SEGNO(sbi, segno); + array[i].next_segno = NULL_SEGNO; + array[i].next_blkoff = blk_off; + array[i].alloc_type = cp->alloc_type[i]; + } + restore_curseg_summaries(sbi); + return 0; + +seg_cleanup: + for(--i ; i >=0; --i) + free(array[i].sum_blk); + free(array); + + return -ENOMEM; +} + +static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) +{ + unsigned int end_segno = SM_I(sbi)->segment_count - 1; + ASSERT(segno <= end_segno); +} + +static inline block_t current_sit_addr(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int offset = SIT_BLOCK_OFFSET(sit_i, segno); + block_t blk_addr = sit_i->sit_base_addr + offset; + + check_seg_range(sbi, segno); + + /* calculate sit block address */ + if (f2fs_test_bit(offset, sit_i->sit_bitmap)) + blk_addr += sit_i->sit_blocks; + + return blk_addr; +} + +void get_current_sit_page(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_sit_block *sit_blk) +{ + block_t blk_addr = current_sit_addr(sbi, segno); + + ASSERT(dev_read_block(sit_blk, blk_addr) >= 0); +} + +void rewrite_current_sit_page(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_sit_block *sit_blk) +{ + block_t blk_addr = current_sit_addr(sbi, segno); + + ASSERT(dev_write_block(sit_blk, blk_addr, WRITE_LIFE_NONE) >= 0); +} + +void check_block_count(struct f2fs_sb_info *sbi, + unsigned int segno, struct f2fs_sit_entry *raw_sit) +{ + struct f2fs_sm_info *sm_info = SM_I(sbi); + unsigned int end_segno = sm_info->segment_count - 1; + int valid_blocks = 0; + unsigned int i; + + /* check segment usage */ + if (GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg) + ASSERT_MSG("Invalid SIT vblocks: segno=0x%x, %u", + segno, GET_SIT_VBLOCKS(raw_sit)); + + /* check boundary of a given segment number */ + if (segno > end_segno) + ASSERT_MSG("Invalid SEGNO: 0x%x", segno); + + /* check bitmap with valid block count */ + for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) + valid_blocks += get_bits_in_byte(raw_sit->valid_map[i]); + + if (GET_SIT_VBLOCKS(raw_sit) != valid_blocks) + ASSERT_MSG("Wrong SIT valid blocks: segno=0x%x, %u vs. %u", + segno, GET_SIT_VBLOCKS(raw_sit), valid_blocks); + + if (GET_SIT_TYPE(raw_sit) >= NO_CHECK_TYPE) + ASSERT_MSG("Wrong SIT type: segno=0x%x, %u", + segno, GET_SIT_TYPE(raw_sit)); +} + +void __seg_info_from_raw_sit(struct seg_entry *se, + struct f2fs_sit_entry *raw_sit) +{ + se->valid_blocks = GET_SIT_VBLOCKS(raw_sit); + memcpy(se->cur_valid_map, raw_sit->valid_map, SIT_VBLOCK_MAP_SIZE); + se->type = GET_SIT_TYPE(raw_sit); + se->orig_type = GET_SIT_TYPE(raw_sit); + se->mtime = le64_to_cpu(raw_sit->mtime); +} + +void seg_info_from_raw_sit(struct f2fs_sb_info *sbi, struct seg_entry *se, + struct f2fs_sit_entry *raw_sit) +{ + __seg_info_from_raw_sit(se, raw_sit); + + if (!need_fsync_data_record(sbi)) + return; + se->ckpt_valid_blocks = se->valid_blocks; + memcpy(se->ckpt_valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + se->ckpt_type = se->type; +} + +struct seg_entry *get_seg_entry(struct f2fs_sb_info *sbi, + unsigned int segno) +{ + struct sit_info *sit_i = SIT_I(sbi); + return &sit_i->sentries[segno]; +} + +unsigned short get_seg_vblocks(struct f2fs_sb_info *sbi, struct seg_entry *se) +{ + if (!need_fsync_data_record(sbi)) + return se->valid_blocks; + else + return se->ckpt_valid_blocks; +} + +unsigned char *get_seg_bitmap(struct f2fs_sb_info *sbi, struct seg_entry *se) +{ + if (!need_fsync_data_record(sbi)) + return se->cur_valid_map; + else + return se->ckpt_valid_map; +} + +unsigned char get_seg_type(struct f2fs_sb_info *sbi, struct seg_entry *se) +{ + if (!need_fsync_data_record(sbi)) + return se->type; + else + return se->ckpt_type; +} + +struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *sbi, + unsigned int segno, int *ret_type) +{ + struct f2fs_summary_block *sum_blk; + struct curseg_info *curseg; + int type, ret; + u64 ssa_blk; + + *ret_type= SEG_TYPE_MAX; + + ssa_blk = GET_SUM_BLKADDR(sbi, segno); + for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) { + curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type); + if (segno == curseg->segno) { + if (!IS_SUM_NODE_SEG(curseg->sum_blk)) { + ASSERT_MSG("segno [0x%x] indicates a data " + "segment, but should be node", + segno); + *ret_type = -SEG_TYPE_CUR_NODE; + } else { + *ret_type = SEG_TYPE_CUR_NODE; + } + return curseg->sum_blk; + } + } + + for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) { + curseg = CURSEG_I(sbi, type); + if (segno == curseg->segno) { + if (IS_SUM_NODE_SEG(curseg->sum_blk)) { + ASSERT_MSG("segno [0x%x] indicates a node " + "segment, but should be data", + segno); + *ret_type = -SEG_TYPE_CUR_DATA; + } else { + *ret_type = SEG_TYPE_CUR_DATA; + } + return curseg->sum_blk; + } + } + + sum_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sum_blk); + + ret = dev_read_block(sum_blk, ssa_blk); + ASSERT(ret >= 0); + + if (IS_SUM_NODE_SEG(sum_blk)) + *ret_type = SEG_TYPE_NODE; + else if (IS_SUM_DATA_SEG(sum_blk)) + *ret_type = SEG_TYPE_DATA; + + return sum_blk; +} + +int get_sum_entry(struct f2fs_sb_info *sbi, u32 blk_addr, + struct f2fs_summary *sum_entry) +{ + struct f2fs_summary_block *sum_blk; + u32 segno, offset; + int type; + + segno = GET_SEGNO(sbi, blk_addr); + offset = OFFSET_IN_SEG(sbi, blk_addr); + + sum_blk = get_sum_block(sbi, segno, &type); + memcpy(sum_entry, &(sum_blk->entries[offset]), + sizeof(struct f2fs_summary)); + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) + free(sum_blk); + return type; +} + +static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid, + struct f2fs_nat_entry *raw_nat) +{ + struct f2fs_nat_block *nat_block; + pgoff_t block_addr; + int entry_off; + int ret; + + if (lookup_nat_in_journal(sbi, nid, raw_nat) >= 0) + return; + + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); + + entry_off = nid % NAT_ENTRY_PER_BLOCK; + block_addr = current_nat_addr(sbi, nid, NULL); + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + memcpy(raw_nat, &nat_block->entries[entry_off], + sizeof(struct f2fs_nat_entry)); + free(nat_block); +} + +void update_data_blkaddr(struct f2fs_sb_info *sbi, nid_t nid, + u16 ofs_in_node, block_t newaddr, struct f2fs_node *node_blk) +{ + struct node_info ni; + block_t oldaddr, startaddr, endaddr; + bool node_blk_alloced = false; + int ret; + + if (node_blk == NULL) { + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + get_node_info(sbi, nid, &ni); + + /* read node_block */ + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + node_blk_alloced = true; + } + + /* check its block address */ + if (IS_INODE(node_blk)) { + int ofs = get_extra_isize(node_blk); + + oldaddr = le32_to_cpu(node_blk->i.i_addr[ofs + ofs_in_node]); + node_blk->i.i_addr[ofs + ofs_in_node] = cpu_to_le32(newaddr); + if (node_blk_alloced) { + ret = update_inode(sbi, node_blk, &ni.blk_addr); + ASSERT(ret >= 0); + } + } else { + oldaddr = le32_to_cpu(node_blk->dn.addr[ofs_in_node]); + node_blk->dn.addr[ofs_in_node] = cpu_to_le32(newaddr); + if (node_blk_alloced) { + ret = update_block(sbi, node_blk, &ni.blk_addr, NULL); + ASSERT(ret >= 0); + } + + /* change node_blk with inode to update extent cache entry */ + get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), + &ni); + + /* read inode block */ + if (!node_blk_alloced) { + node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + node_blk_alloced = true; + } + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + } + + /* check extent cache entry */ + startaddr = le32_to_cpu(node_blk->i.i_ext.blk_addr); + endaddr = startaddr + le32_to_cpu(node_blk->i.i_ext.len); + if (oldaddr >= startaddr && oldaddr < endaddr) { + node_blk->i.i_ext.len = 0; + + /* update inode block */ + if (node_blk_alloced) + ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0); + } + + if (node_blk_alloced) + free(node_blk); +} + +void update_nat_blkaddr(struct f2fs_sb_info *sbi, nid_t ino, + nid_t nid, block_t newaddr) +{ + struct f2fs_nat_block *nat_block = NULL; + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct f2fs_nat_entry *entry; + pgoff_t block_addr; + int entry_off; + int ret, i; + + for (i = 0; i < nats_in_cursum(journal); i++) { + if (le32_to_cpu(nid_in_journal(journal, i)) == nid) { + entry = &nat_in_journal(journal, i); + entry->block_addr = cpu_to_le32(newaddr); + if (ino) + entry->ino = cpu_to_le32(ino); + MSG(0, "update nat(nid:%d) blkaddr [0x%x] in journal\n", + nid, newaddr); + goto update_cache; + } + } + + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); + + entry_off = nid % NAT_ENTRY_PER_BLOCK; + block_addr = current_nat_addr(sbi, nid, NULL); + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + entry = &nat_block->entries[entry_off]; + if (ino) + entry->ino = cpu_to_le32(ino); + entry->block_addr = cpu_to_le32(newaddr); + + ret = dev_write_block(nat_block, block_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); +update_cache: + if (c.func == FSCK) + F2FS_FSCK(sbi)->entries[nid] = *entry; + + if (nat_block) + free(nat_block); +} + +void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni) +{ + struct f2fs_nat_entry raw_nat; + + ni->nid = nid; + if (c.func == FSCK && F2FS_FSCK(sbi)->nr_nat_entries) { + node_info_from_raw_nat(ni, &(F2FS_FSCK(sbi)->entries[nid])); + if (ni->blk_addr) + return; + /* nat entry is not cached, read it */ + } + + get_nat_entry(sbi, nid, &raw_nat); + node_info_from_raw_nat(ni, &raw_nat); +} + +static int build_sit_entries(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct f2fs_sit_block *sit_blk; + struct seg_entry *se; + struct f2fs_sit_entry sit; + int sit_blk_cnt = SIT_BLK_CNT(sbi); + unsigned int i, segno, end; + unsigned int readed, start_blk = 0; + + sit_blk = calloc(F2FS_BLKSIZE, 1); + if (!sit_blk) { + MSG(1, "\tError: Calloc failed for build_sit_entries!\n"); + return -ENOMEM; + } + + do { + readed = f2fs_ra_meta_pages(sbi, start_blk, MAX_RA_BLOCKS, + META_SIT); + + segno = start_blk * sit_i->sents_per_block; + end = (start_blk + readed) * sit_i->sents_per_block; + + for (; segno < end && segno < MAIN_SEGS(sbi); segno++) { + se = &sit_i->sentries[segno]; + + get_current_sit_page(sbi, segno, sit_blk); + sit = sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; + + check_block_count(sbi, segno, &sit); + seg_info_from_raw_sit(sbi, se, &sit); + if (se->valid_blocks == 0x0 && + is_usable_seg(sbi, segno) && + !IS_CUR_SEGNO(sbi, segno)) + SM_I(sbi)->free_segments++; + } + start_blk += readed; + } while (start_blk < sit_blk_cnt); + + + free(sit_blk); + + if (sits_in_cursum(journal) > SIT_JOURNAL_ENTRIES) { + MSG(0, "\tError: build_sit_entries truncate n_sits(%u) to " + "SIT_JOURNAL_ENTRIES(%zu)\n", + sits_in_cursum(journal), SIT_JOURNAL_ENTRIES); + journal->n_sits = cpu_to_le16(SIT_JOURNAL_ENTRIES); + c.fix_on = 1; + } + + for (i = 0; i < sits_in_cursum(journal); i++) { + segno = le32_to_cpu(segno_in_journal(journal, i)); + + if (segno >= MAIN_SEGS(sbi)) { + MSG(0, "\tError: build_sit_entries: segno(%u) is invalid!!!\n", segno); + journal->n_sits = cpu_to_le16(i); + c.fix_on = 1; + continue; + } + + se = &sit_i->sentries[segno]; + sit = sit_in_journal(journal, i); + + check_block_count(sbi, segno, &sit); + seg_info_from_raw_sit(sbi, se, &sit); + } + return 0; +} + +static int early_build_segment_manager(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_sm_info *sm_info; + + sm_info = malloc(sizeof(struct f2fs_sm_info)); + if (!sm_info) { + MSG(1, "\tError: Malloc failed for build_segment_manager!\n"); + return -ENOMEM; + } + + /* init sm info */ + sbi->sm_info = sm_info; + sm_info->seg0_blkaddr = get_sb(segment0_blkaddr); + sm_info->main_blkaddr = get_sb(main_blkaddr); + sm_info->segment_count = get_sb(segment_count); + sm_info->reserved_segments = get_cp(rsvd_segment_count); + sm_info->ovp_segments = get_cp(overprov_segment_count); + sm_info->main_segments = get_sb(segment_count_main); + sm_info->ssa_blkaddr = get_sb(ssa_blkaddr); + sm_info->free_segments = 0; + + if (build_sit_info(sbi) || build_curseg(sbi)) { + free(sm_info); + return -ENOMEM; + } + + return 0; +} + +static int late_build_segment_manager(struct f2fs_sb_info *sbi) +{ + if (sbi->seg_manager_done) + return 1; /* this function was already called */ + + sbi->seg_manager_done = true; + if (build_sit_entries(sbi)) { + free (sbi->sm_info); + return -ENOMEM; + } + + return 0; +} + +void build_sit_area_bitmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_sm_info *sm_i = SM_I(sbi); + unsigned int segno = 0; + char *ptr = NULL; + u32 sum_vblocks = 0; + u32 free_segs = 0; + struct seg_entry *se; + + fsck->sit_area_bitmap_sz = sm_i->main_segments * SIT_VBLOCK_MAP_SIZE; + fsck->sit_area_bitmap = calloc(1, fsck->sit_area_bitmap_sz); + ASSERT(fsck->sit_area_bitmap); + ptr = fsck->sit_area_bitmap; + + ASSERT(fsck->sit_area_bitmap_sz == fsck->main_area_bitmap_sz); + + for (segno = 0; segno < MAIN_SEGS(sbi); segno++) { + se = get_seg_entry(sbi, segno); + + memcpy(ptr, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + ptr += SIT_VBLOCK_MAP_SIZE; + + if (se->valid_blocks == 0x0 && is_usable_seg(sbi, segno)) { + if (!IS_CUR_SEGNO(sbi, segno)) + free_segs++; + } else { + sum_vblocks += se->valid_blocks; + } + } + fsck->chk.sit_valid_blocks = sum_vblocks; + fsck->chk.sit_free_segs = free_segs; + + DBG(1, "Blocks [0x%x : %d] Free Segs [0x%x : %d]\n\n", + sum_vblocks, sum_vblocks, + free_segs, free_segs); +} + +void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sit_block *sit_blk; + unsigned int segno = 0; + struct f2fs_summary_block *sum = curseg->sum_blk; + char *ptr = NULL; + + sit_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sit_blk); + /* remove sit journal */ + F2FS_SUMMARY_BLOCK_JOURNAL(sum)->n_sits = 0; + + ptr = fsck->main_area_bitmap; + + for (segno = 0; segno < MAIN_SEGS(sbi); segno++) { + struct f2fs_sit_entry *sit; + struct seg_entry *se; + u16 valid_blocks = 0; + u16 type; + int i; + + get_current_sit_page(sbi, segno, sit_blk); + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; + memcpy(sit->valid_map, ptr, SIT_VBLOCK_MAP_SIZE); + + /* update valid block count */ + for (i = 0; i < SIT_VBLOCK_MAP_SIZE; i++) + valid_blocks += get_bits_in_byte(sit->valid_map[i]); + + se = get_seg_entry(sbi, segno); + memcpy(se->cur_valid_map, ptr, SIT_VBLOCK_MAP_SIZE); + se->valid_blocks = valid_blocks; + type = se->type; + if (type >= NO_CHECK_TYPE) { + ASSERT_MSG("Invalid type and valid blocks=%x,%x", + segno, valid_blocks); + type = 0; + } + sit->vblocks = cpu_to_le16((type << SIT_VBLOCKS_SHIFT) | + valid_blocks); + rewrite_current_sit_page(sbi, segno, sit_blk); + + ptr += SIT_VBLOCK_MAP_SIZE; + } + + free(sit_blk); +} + +int flush_sit_journal_entries(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sit_block *sit_blk; + unsigned int segno; + int i; + + sit_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sit_blk); + for (i = 0; i < sits_in_cursum(journal); i++) { + struct f2fs_sit_entry *sit; + struct seg_entry *se; + + segno = segno_in_journal(journal, i); + se = get_seg_entry(sbi, segno); + + get_current_sit_page(sbi, segno, sit_blk); + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; + + memcpy(sit->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) | + se->valid_blocks); + sit->mtime = cpu_to_le64(se->mtime); + + rewrite_current_sit_page(sbi, segno, sit_blk); + } + + free(sit_blk); + journal->n_sits = 0; + return i; +} + +int flush_nat_journal_entries(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct f2fs_nat_block *nat_block; + pgoff_t block_addr; + int entry_off; + nid_t nid; + int ret; + int i = 0; + + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); +next: + if (i >= nats_in_cursum(journal)) { + free(nat_block); + journal->n_nats = 0; + return i; + } + + nid = le32_to_cpu(nid_in_journal(journal, i)); + + entry_off = nid % NAT_ENTRY_PER_BLOCK; + block_addr = current_nat_addr(sbi, nid, NULL); + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + memcpy(&nat_block->entries[entry_off], &nat_in_journal(journal, i), + sizeof(struct f2fs_nat_entry)); + + ret = dev_write_block(nat_block, block_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + i++; + goto next; +} + +void flush_journal_entries(struct f2fs_sb_info *sbi) +{ + int n_nats = flush_nat_journal_entries(sbi); + int n_sits = flush_sit_journal_entries(sbi); + + if (n_nats || n_sits) { + MSG(0, "Info: flush_journal_entries() n_nats: %d, n_sits: %d\n", + n_nats, n_sits); + write_checkpoints(sbi); + } +} + +void flush_sit_entries(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sit_block *sit_blk; + unsigned int segno = 0; + + sit_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(sit_blk); + /* update free segments */ + for (segno = 0; segno < MAIN_SEGS(sbi); segno++) { + struct f2fs_sit_entry *sit; + struct seg_entry *se; + + se = get_seg_entry(sbi, segno); + + if (!se->dirty) + continue; + + get_current_sit_page(sbi, segno, sit_blk); + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno)]; + memcpy(sit->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) | + se->valid_blocks); + rewrite_current_sit_page(sbi, segno, sit_blk); + } + + free(sit_blk); +} + +int relocate_curseg_offset(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + struct seg_entry *se = get_seg_entry(sbi, curseg->segno); + unsigned int i; + + if (c.zoned_model == F2FS_ZONED_HM) + return -EINVAL; + + for (i = 0; i < sbi->blocks_per_seg; i++) { + if (!f2fs_test_bit(i, (const char *)se->cur_valid_map)) + break; + } + + if (i == sbi->blocks_per_seg) + return -EINVAL; + + DBG(1, "Update curseg[%d].next_blkoff %u -> %u, alloc_type %s -> SSR\n", + type, curseg->next_blkoff, i, + curseg->alloc_type == LFS ? "LFS" : "SSR"); + + curseg->next_blkoff = i; + curseg->alloc_type = SSR; + + return 0; +} + +void set_section_type(struct f2fs_sb_info *sbi, unsigned int segno, int type) +{ + unsigned int i; + + if (sbi->segs_per_sec == 1) + return; + + for (i = 0; i < sbi->segs_per_sec; i++) { + struct seg_entry *se = get_seg_entry(sbi, segno + i); + + se->type = se->orig_type = type; + se->dirty = 1; + } +} + +#ifdef HAVE_LINUX_BLKZONED_H + +static bool write_pointer_at_zone_start(struct f2fs_sb_info *sbi, + unsigned int zone_segno) +{ + uint64_t sector; + struct blk_zone blkz; + block_t block = START_BLOCK(sbi, zone_segno); + int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT; + int ret, j; + + for (j = 0; j < MAX_DEVICES; j++) { + if (!c.devices[j].path) + break; + if (c.devices[j].start_blkaddr <= block && + block <= c.devices[j].end_blkaddr) + break; + } + + if (j >= MAX_DEVICES) + return false; + + if (c.devices[j].zoned_model != F2FS_ZONED_HM) + return true; + + sector = (block - c.devices[j].start_blkaddr) << log_sectors_per_block; + ret = f2fs_report_zone(j, sector, &blkz); + if (ret) + return false; + + if (blk_zone_type(&blkz) != BLK_ZONE_TYPE_SEQWRITE_REQ) + return true; + + return blk_zone_sector(&blkz) == blk_zone_wp_sector(&blkz); +} + +#else + +static bool write_pointer_at_zone_start(struct f2fs_sb_info *UNUSED(sbi), + unsigned int UNUSED(zone_segno)) +{ + return true; +} + +#endif + +static void zero_journal_entries_with_type(struct f2fs_sb_info *sbi, int type) +{ + struct f2fs_journal *journal = + F2FS_SUMMARY_BLOCK_JOURNAL(CURSEG_I(sbi, type)->sum_blk); + + if (type == CURSEG_HOT_DATA) + journal->n_nats = 0; + else if (type == CURSEG_COLD_DATA) + journal->n_sits = 0; +} + +int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left, + int want_type, bool new_sec) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct seg_entry *se; + u32 segno; + u32 offset; + int not_enough = 0; + u64 end_blkaddr = (get_sb(segment_count_main) << + get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr); + + if (c.zoned_model == F2FS_ZONED_HM && !new_sec) { + struct curseg_info *curseg = CURSEG_I(sbi, want_type); + unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone; + char buf[F2FS_BLKSIZE]; + u64 ssa_blk; + int ret; + + *to = NEXT_FREE_BLKADDR(sbi, curseg); + curseg->next_blkoff++; + + if (curseg->next_blkoff == sbi->blocks_per_seg) { + segno = curseg->segno + 1; + if (!(segno % segs_per_zone)) { + u64 new_blkaddr = SM_I(sbi)->main_blkaddr; + + ret = find_next_free_block(sbi, &new_blkaddr, 0, + want_type, true); + if (ret) + return ret; + segno = GET_SEGNO(sbi, new_blkaddr); + } + + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_write_block(curseg->sum_blk, ssa_blk, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + curseg->segno = segno; + curseg->next_blkoff = 0; + curseg->alloc_type = LFS; + + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_read_block(&buf, ssa_blk); + ASSERT(ret >= 0); + + memcpy(curseg->sum_blk, &buf, SUM_ENTRIES_SIZE); + + reset_curseg(sbi, want_type); + zero_journal_entries_with_type(sbi, want_type); + } + + return 0; + } + + if (*to > 0) + *to -= left; + if (SM_I(sbi)->free_segments <= SM_I(sbi)->reserved_segments + 1) + not_enough = 1; + + while (*to >= SM_I(sbi)->main_blkaddr && *to < end_blkaddr) { + unsigned short vblocks; + unsigned char *bitmap; + unsigned char type; + + segno = GET_SEGNO(sbi, *to); + offset = OFFSET_IN_SEG(sbi, *to); + + se = get_seg_entry(sbi, segno); + + vblocks = get_seg_vblocks(sbi, se); + bitmap = get_seg_bitmap(sbi, se); + type = get_seg_type(sbi, se); + + if (vblocks == sbi->blocks_per_seg) { +next_segment: + *to = left ? START_BLOCK(sbi, segno) - 1: + START_BLOCK(sbi, segno + 1); + continue; + } + if (!(get_sb(feature) & F2FS_FEATURE_RO) && + IS_CUR_SEGNO(sbi, segno)) + goto next_segment; + if (vblocks == 0 && not_enough) + goto next_segment; + + if (vblocks == 0 && !(segno % sbi->segs_per_sec)) { + struct seg_entry *se2; + unsigned int i; + + for (i = 1; i < sbi->segs_per_sec; i++) { + se2 = get_seg_entry(sbi, segno + i); + if (get_seg_vblocks(sbi, se2)) + break; + } + + if (i == sbi->segs_per_sec && + write_pointer_at_zone_start(sbi, segno)) { + set_section_type(sbi, segno, want_type); + return 0; + } + } + + if (type != want_type) + goto next_segment; + else if (!new_sec && + !f2fs_test_bit(offset, (const char *)bitmap)) + return 0; + + *to = left ? *to - 1: *to + 1; + } + return -1; +} + +void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left, + int i) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct curseg_info *curseg = CURSEG_I(sbi, i); + char buf[F2FS_BLKSIZE]; + u32 old_segno; + u64 ssa_blk, to; + int ret; + + if ((get_sb(feature) & F2FS_FEATURE_RO)) { + if (i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE) + return; + + if (i == CURSEG_HOT_DATA) { + left = 0; + from = SM_I(sbi)->main_blkaddr; + } else { + left = 1; + from = __end_block_addr(sbi); + } + goto bypass_ssa; + } + + /* update original SSA too */ + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_write_block(curseg->sum_blk, ssa_blk, WRITE_LIFE_NONE); + ASSERT(ret >= 0); +bypass_ssa: + to = from; + ret = find_next_free_block(sbi, &to, left, i, + c.zoned_model == F2FS_ZONED_HM); + ASSERT(ret == 0); + + old_segno = curseg->segno; + curseg->segno = GET_SEGNO(sbi, to); + curseg->next_blkoff = OFFSET_IN_SEG(sbi, to); + curseg->alloc_type = c.zoned_model == F2FS_ZONED_HM ? LFS : SSR; + + /* update new segno */ + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_read_block(buf, ssa_blk); + ASSERT(ret >= 0); + + memcpy(curseg->sum_blk, buf, SUM_ENTRIES_SIZE); + + /* update se->types */ + reset_curseg(sbi, i); + if (c.zoned_model == F2FS_ZONED_HM) + zero_journal_entries_with_type(sbi, i); + + FIX_MSG("Move curseg[%d] %x -> %x after %"PRIx64"\n", + i, old_segno, curseg->segno, from); +} + +void move_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left) +{ + int i; + + /* update summary blocks having nullified journal entries */ + for (i = 0; i < NO_CHECK_TYPE; i++) + move_one_curseg_info(sbi, from, left, i); +} + +void update_curseg_info(struct f2fs_sb_info *sbi, int type) +{ + if (!relocate_curseg_offset(sbi, type)) + return; + move_one_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0, type); +} + +void zero_journal_entries(struct f2fs_sb_info *sbi) +{ + int i; + + for (i = 0; i < NO_CHECK_TYPE; i++) + F2FS_SUMMARY_BLOCK_JOURNAL(CURSEG_I(sbi, i)->sum_blk)->n_nats = 0; +} + +void write_curseg_info(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + int i; + + for (i = 0; i < NO_CHECK_TYPE; i++) { + cp->alloc_type[i] = CURSEG_I(sbi, i)->alloc_type; + if (i < CURSEG_HOT_NODE) { + set_cp(cur_data_segno[i], CURSEG_I(sbi, i)->segno); + set_cp(cur_data_blkoff[i], + CURSEG_I(sbi, i)->next_blkoff); + } else { + int n = i - CURSEG_HOT_NODE; + + set_cp(cur_node_segno[n], CURSEG_I(sbi, i)->segno); + set_cp(cur_node_blkoff[n], + CURSEG_I(sbi, i)->next_blkoff); + } + } +} + +void save_curseg_warm_node_info(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + struct curseg_info *saved_curseg = &SM_I(sbi)->saved_curseg_warm_node; + + saved_curseg->alloc_type = curseg->alloc_type; + saved_curseg->segno = curseg->segno; + saved_curseg->next_blkoff = curseg->next_blkoff; +} + +void restore_curseg_warm_node_info(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + struct curseg_info *saved_curseg = &SM_I(sbi)->saved_curseg_warm_node; + + curseg->alloc_type = saved_curseg->alloc_type; + curseg->segno = saved_curseg->segno; + curseg->next_blkoff = saved_curseg->next_blkoff; +} + +int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid, + struct f2fs_nat_entry *raw_nat) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + int i = 0; + + for (i = 0; i < nats_in_cursum(journal); i++) { + if (le32_to_cpu(nid_in_journal(journal, i)) == nid) { + memcpy(raw_nat, &nat_in_journal(journal, i), + sizeof(struct f2fs_nat_entry)); + DBG(3, "==> Found nid [0x%x] in nat cache\n", nid); + return i; + } + } + return -1; +} + +void nullify_nat_entry(struct f2fs_sb_info *sbi, u32 nid) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct f2fs_nat_block *nat_block; + pgoff_t block_addr; + int entry_off; + int ret; + int i = 0; + + if (c.func == FSCK) + F2FS_FSCK(sbi)->entries[nid].block_addr = 0; + + /* check in journal */ + for (i = 0; i < nats_in_cursum(journal); i++) { + if (le32_to_cpu(nid_in_journal(journal, i)) == nid) { + memset(&nat_in_journal(journal, i), 0, + sizeof(struct f2fs_nat_entry)); + FIX_MSG("Remove nid [0x%x] in nat journal", nid); + return; + } + } + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); + + entry_off = nid % NAT_ENTRY_PER_BLOCK; + block_addr = current_nat_addr(sbi, nid, NULL); + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + if (nid == F2FS_NODE_INO(sbi) || nid == F2FS_META_INO(sbi)) { + FIX_MSG("nid [0x%x] block_addr= 0x%x -> 0x1", nid, + le32_to_cpu(nat_block->entries[entry_off].block_addr)); + nat_block->entries[entry_off].block_addr = cpu_to_le32(0x1); + } else { + memset(&nat_block->entries[entry_off], 0, + sizeof(struct f2fs_nat_entry)); + FIX_MSG("Remove nid [0x%x] in NAT", nid); + } + + ret = dev_write_block(nat_block, block_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + free(nat_block); +} + +void duplicate_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + unsigned long long dst, src; + void *buf; + unsigned int seg_size = 1 << get_sb(log_blocks_per_seg); + int ret; + + if (sbi->cp_backuped) + return; + + buf = malloc(F2FS_BLKSIZE * seg_size); + ASSERT(buf); + + if (sbi->cur_cp == 1) { + src = get_sb(cp_blkaddr); + dst = src + seg_size; + } else { + dst = get_sb(cp_blkaddr); + src = dst + seg_size; + } + + ret = dev_read(buf, src << F2FS_BLKSIZE_BITS, + seg_size << F2FS_BLKSIZE_BITS); + ASSERT(ret >= 0); + + ret = dev_write(buf, dst << F2FS_BLKSIZE_BITS, + seg_size << F2FS_BLKSIZE_BITS, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + free(buf); + + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + sbi->cp_backuped = 1; + + MSG(0, "Info: Duplicate valid checkpoint to mirror position " + "%llu -> %llu\n", src, dst); +} + +void write_checkpoint(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + block_t orphan_blks = 0; + unsigned long long cp_blk_no; + u32 flags = c.roll_forward ? 0 : CP_UMOUNT_FLAG; + int i, ret; + uint32_t crc = 0; + + if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) { + orphan_blks = __start_sum_addr(sbi) - 1; + flags |= CP_ORPHAN_PRESENT_FLAG; + } + if (is_set_ckpt_flags(cp, CP_TRIMMED_FLAG)) + flags |= CP_TRIMMED_FLAG; + if (is_set_ckpt_flags(cp, CP_DISABLED_FLAG)) + flags |= CP_DISABLED_FLAG; + if (is_set_ckpt_flags(cp, CP_LARGE_NAT_BITMAP_FLAG)) { + flags |= CP_LARGE_NAT_BITMAP_FLAG; + set_cp(checksum_offset, CP_MIN_CHKSUM_OFFSET); + } else { + set_cp(checksum_offset, CP_CHKSUM_OFFSET); + } + + set_cp(free_segment_count, get_free_segments(sbi)); + if (c.func == FSCK) { + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + + set_cp(valid_block_count, fsck->chk.valid_blk_cnt); + set_cp(valid_node_count, fsck->chk.valid_node_cnt); + set_cp(valid_inode_count, fsck->chk.valid_inode_cnt); + } else { + set_cp(valid_block_count, sbi->total_valid_block_count); + set_cp(valid_node_count, sbi->total_valid_node_count); + set_cp(valid_inode_count, sbi->total_valid_inode_count); + } + set_cp(cp_pack_total_block_count, 8 + orphan_blks + get_sb(cp_payload)); + + flags = update_nat_bits_flags(sb, cp, flags); + set_cp(ckpt_flags, flags); + + crc = f2fs_checkpoint_chksum(cp); + *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + + cp_blk_no = get_sb(cp_blkaddr); + if (sbi->cur_cp == 2) + cp_blk_no += 1 << get_sb(log_blocks_per_seg); + + /* write the first cp */ + ret = dev_write_block(cp, cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + /* skip payload */ + cp_blk_no += get_sb(cp_payload); + /* skip orphan blocks */ + cp_blk_no += orphan_blks; + + /* update summary blocks having nullified journal entries */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + u64 ssa_blk; + + if (!(flags & CP_UMOUNT_FLAG) && IS_NODESEG(i)) + continue; + + ret = dev_write_block(curseg->sum_blk, cp_blk_no++, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + if (!(get_sb(feature) & F2FS_FEATURE_RO)) { + /* update original SSA too */ + ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno); + ret = dev_write_block(curseg->sum_blk, ssa_blk, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + } + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); + + /* in case of sudden power off */ + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + /* write the last cp */ + ret = dev_write_block(cp, cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + ret = f2fs_fsync_device(); + ASSERT(ret >= 0); + + MSG(0, "Info: write_checkpoint() cur_cp:%d\n", sbi->cur_cp); +} + +void write_checkpoints(struct f2fs_sb_info *sbi) +{ + /* copy valid checkpoint to its mirror position */ + duplicate_checkpoint(sbi); + + /* repair checkpoint at CP #0 position */ + sbi->cur_cp = 1; + write_checkpoint(sbi); +} + +void write_raw_cp_blocks(struct f2fs_sb_info *sbi, + struct f2fs_checkpoint *cp, int which) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + uint32_t crc; + block_t cp_blkaddr; + int ret; + + crc = f2fs_checkpoint_chksum(cp); + *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + + cp_blkaddr = get_sb(cp_blkaddr); + if (which == 2) + cp_blkaddr += 1 << get_sb(log_blocks_per_seg); + + /* write the first cp block in this CP pack */ + ret = dev_write_block(cp, cp_blkaddr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + /* write the second cp block in this CP pack */ + cp_blkaddr += get_cp(cp_pack_total_block_count) - 1; + ret = dev_write_block(cp, cp_blkaddr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); +} + +void build_nat_area_bitmap(struct f2fs_sb_info *sbi) +{ + struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA); + struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk); + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + struct f2fs_nat_block *nat_block; + struct node_info ni; + u32 nid, nr_nat_blks; + pgoff_t block_off; + pgoff_t block_addr; + int seg_off; + int ret; + unsigned int i; + + nat_block = (struct f2fs_nat_block *)calloc(F2FS_BLKSIZE, 1); + ASSERT(nat_block); + + /* Alloc & build nat entry bitmap */ + nr_nat_blks = (get_sb(segment_count_nat) / 2) << + sbi->log_blocks_per_seg; + + fsck->nr_nat_entries = nr_nat_blks * NAT_ENTRY_PER_BLOCK; + fsck->nat_area_bitmap_sz = (fsck->nr_nat_entries + 7) / 8; + fsck->nat_area_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); + ASSERT(fsck->nat_area_bitmap); + + fsck->entries = calloc(sizeof(struct f2fs_nat_entry), + fsck->nr_nat_entries); + ASSERT(fsck->entries); + + for (block_off = 0; block_off < nr_nat_blks; block_off++) { + + seg_off = block_off >> sbi->log_blocks_per_seg; + block_addr = (pgoff_t)(nm_i->nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) + block_addr += sbi->blocks_per_seg; + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + nid = block_off * NAT_ENTRY_PER_BLOCK; + for (i = 0; i < NAT_ENTRY_PER_BLOCK; i++) { + ni.nid = nid + i; + + if ((nid + i) == F2FS_NODE_INO(sbi) || + (nid + i) == F2FS_META_INO(sbi)) { + /* + * block_addr of node/meta inode should be 0x1. + * Set this bit, and fsck_verify will fix it. + */ + if (le32_to_cpu(nat_block->entries[i].block_addr) != 0x1) { + ASSERT_MSG("\tError: ino[0x%x] block_addr[0x%x] is invalid\n", + nid + i, le32_to_cpu(nat_block->entries[i].block_addr)); + f2fs_set_bit(nid + i, fsck->nat_area_bitmap); + } + continue; + } + + node_info_from_raw_nat(&ni, &nat_block->entries[i]); + if (ni.blk_addr == 0x0) + continue; + if (ni.ino == 0x0) { + ASSERT_MSG("\tError: ino[0x%8x] or blk_addr[0x%16x]" + " is invalid\n", ni.ino, ni.blk_addr); + } + if (ni.ino == (nid + i)) { + fsck->nat_valid_inode_cnt++; + DBG(3, "ino[0x%8x] maybe is inode\n", ni.ino); + } + if (nid + i == 0) { + /* + * nat entry [0] must be null. If + * it is corrupted, set its bit in + * nat_area_bitmap, fsck_verify will + * nullify it + */ + ASSERT_MSG("Invalid nat entry[0]: " + "blk_addr[0x%x]\n", ni.blk_addr); + fsck->chk.valid_nat_entry_cnt--; + } + + DBG(3, "nid[0x%8x] addr[0x%16x] ino[0x%8x]\n", + nid + i, ni.blk_addr, ni.ino); + f2fs_set_bit(nid + i, fsck->nat_area_bitmap); + fsck->chk.valid_nat_entry_cnt++; + + fsck->entries[nid + i] = nat_block->entries[i]; + } + } + + /* Traverse nat journal, update the corresponding entries */ + for (i = 0; i < nats_in_cursum(journal); i++) { + struct f2fs_nat_entry raw_nat; + nid = le32_to_cpu(nid_in_journal(journal, i)); + ni.nid = nid; + + DBG(3, "==> Found nid [0x%x] in nat cache, update it\n", nid); + + /* Clear the original bit and count */ + if (fsck->entries[nid].block_addr != 0x0) { + fsck->chk.valid_nat_entry_cnt--; + f2fs_clear_bit(nid, fsck->nat_area_bitmap); + if (fsck->entries[nid].ino == nid) + fsck->nat_valid_inode_cnt--; + } + + /* Use nat entries in journal */ + memcpy(&raw_nat, &nat_in_journal(journal, i), + sizeof(struct f2fs_nat_entry)); + node_info_from_raw_nat(&ni, &raw_nat); + if (ni.blk_addr != 0x0) { + if (ni.ino == 0x0) + ASSERT_MSG("\tError: ino[0x%8x] or blk_addr[0x%16x]" + " is invalid\n", ni.ino, ni.blk_addr); + if (ni.ino == nid) { + fsck->nat_valid_inode_cnt++; + DBG(3, "ino[0x%8x] maybe is inode\n", ni.ino); + } + f2fs_set_bit(nid, fsck->nat_area_bitmap); + fsck->chk.valid_nat_entry_cnt++; + DBG(3, "nid[0x%x] in nat cache\n", nid); + } + fsck->entries[nid] = raw_nat; + } + free(nat_block); + + DBG(1, "valid nat entries (block_addr != 0x0) [0x%8x : %u]\n", + fsck->chk.valid_nat_entry_cnt, + fsck->chk.valid_nat_entry_cnt); +} + +static int check_sector_size(struct f2fs_super_block *sb) +{ + uint32_t log_sectorsize, log_sectors_per_block; + + log_sectorsize = log_base_2(c.sector_size); + log_sectors_per_block = log_base_2(c.sectors_per_blk); + + if (log_sectorsize == get_sb(log_sectorsize) && + log_sectors_per_block == get_sb(log_sectors_per_block)) + return 0; + + set_sb(log_sectorsize, log_sectorsize); + set_sb(log_sectors_per_block, log_sectors_per_block); + + update_superblock(sb, SB_MASK_ALL); + return 0; +} + +static int tune_sb_features(struct f2fs_sb_info *sbi) +{ + int sb_changed = 0; + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + if (!(get_sb(feature) & F2FS_FEATURE_ENCRYPT) && + c.feature & F2FS_FEATURE_ENCRYPT) { + sb->feature = cpu_to_le32(get_sb(feature) | + F2FS_FEATURE_ENCRYPT); + MSG(0, "Info: Set Encryption feature\n"); + sb_changed = 1; + } + if (!(get_sb(feature) & F2FS_FEATURE_CASEFOLD) && + c.feature & F2FS_FEATURE_CASEFOLD) { + if (!c.s_encoding) { + ERR_MSG("ERROR: Must specify encoding to enable casefolding.\n"); + return -1; + } + sb->feature = cpu_to_le32(get_sb(feature) | + F2FS_FEATURE_CASEFOLD); + MSG(0, "Info: Set Casefold feature\n"); + sb_changed = 1; + } + /* TODO: quota needs to allocate inode numbers */ + + c.feature = get_sb(feature); + if (!sb_changed) + return 0; + + update_superblock(sb, SB_MASK_ALL); + return 0; +} + +static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, + nid_t ino) +{ + struct fsync_inode_entry *entry; + + list_for_each_entry(entry, head, list) + if (entry->ino == ino) + return entry; + + return NULL; +} + +static struct fsync_inode_entry *add_fsync_inode(struct list_head *head, + nid_t ino) +{ + struct fsync_inode_entry *entry; + + entry = calloc(sizeof(struct fsync_inode_entry), 1); + if (!entry) + return NULL; + entry->ino = ino; + list_add_tail(&entry->list, head); + return entry; +} + +static void del_fsync_inode(struct fsync_inode_entry *entry) +{ + list_del(&entry->list); + free(entry); +} + +static void destroy_fsync_dnodes(struct list_head *head) +{ + struct fsync_inode_entry *entry, *tmp; + + list_for_each_entry_safe(entry, tmp, head, list) + del_fsync_inode(entry); +} + +static int loop_node_chain_fix(block_t blkaddr_fast, + struct f2fs_node *node_blk_fast, + block_t blkaddr, struct f2fs_node *node_blk) +{ + block_t blkaddr_entry, blkaddr_tmp; + enum rw_hint whint; + int err; + + /* find the entry point of the looped node chain */ + while (blkaddr_fast != blkaddr) { + err = dev_read_block(node_blk_fast, blkaddr_fast); + if (err) + return err; + blkaddr_fast = next_blkaddr_of_node(node_blk_fast); + + err = dev_read_block(node_blk, blkaddr); + if (err) + return err; + blkaddr = next_blkaddr_of_node(node_blk); + } + blkaddr_entry = blkaddr; + + /* find the last node of the chain */ + do { + blkaddr_tmp = blkaddr; + err = dev_read_block(node_blk, blkaddr); + if (err) + return err; + blkaddr = next_blkaddr_of_node(node_blk); + } while (blkaddr != blkaddr_entry); + + /* fix the blkaddr of last node with NULL_ADDR. */ + F2FS_NODE_FOOTER(node_blk)->next_blkaddr = NULL_ADDR; + whint = f2fs_io_type_to_rw_hint(CURSEG_WARM_NODE); + if (IS_INODE(node_blk)) + err = write_inode(node_blk, blkaddr_tmp, whint); + else + err = dev_write_block(node_blk, blkaddr_tmp, whint); + if (!err) + FIX_MSG("Fix looped node chain on blkaddr %u\n", + blkaddr_tmp); + return err; +} + +/* Detect looped node chain with Floyd's cycle detection algorithm. */ +static int sanity_check_node_chain(struct f2fs_sb_info *sbi, + block_t *blkaddr_fast, struct f2fs_node *node_blk_fast, + block_t blkaddr, struct f2fs_node *node_blk, + bool *is_detecting) +{ + int i, err; + + if (!*is_detecting) + return 0; + + for (i = 0; i < 2; i++) { + if (!f2fs_is_valid_blkaddr(sbi, *blkaddr_fast, META_POR)) { + *is_detecting = false; + return 0; + } + + err = dev_read_block(node_blk_fast, *blkaddr_fast); + if (err) + return err; + + if (!is_recoverable_dnode(sbi, node_blk_fast)) { + *is_detecting = false; + return 0; + } + + *blkaddr_fast = next_blkaddr_of_node(node_blk_fast); + } + + if (*blkaddr_fast != blkaddr) + return 0; + + ASSERT_MSG("\tdetect looped node chain, blkaddr:%u\n", blkaddr); + + /* return -ELOOP will coninue fsck rather than exiting directly */ + if (!c.fix_on) + return -ELOOP; + + err = loop_node_chain_fix(NEXT_FREE_BLKADDR(sbi, + CURSEG_I(sbi, CURSEG_WARM_NODE)), + node_blk_fast, blkaddr, node_blk); + if (err) + return err; + + /* Since we call get_fsync_inode() to ensure there are no + * duplicate inodes in the inode_list even if there are + * duplicate blkaddr, we can continue running after fixing the + * looped node chain. + */ + *is_detecting = false; + + return 0; +} + +static int find_fsync_inode(struct f2fs_sb_info *sbi, struct list_head *head) +{ + struct curseg_info *curseg; + struct f2fs_node *node_blk, *node_blk_fast; + block_t blkaddr, blkaddr_fast; + bool is_detecting = true; + int err = 0; + + node_blk = calloc(F2FS_BLKSIZE, 1); + node_blk_fast = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk && node_blk_fast); + + /* get node pages in the current segment */ + curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + blkaddr_fast = blkaddr; + + while (1) { + struct fsync_inode_entry *entry; + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) + break; + + err = dev_read_block(node_blk, blkaddr); + if (err) + break; + + if (!is_recoverable_dnode(sbi, node_blk)) + break; + + if (!is_fsync_dnode(node_blk)) + goto next; + + entry = get_fsync_inode(head, ino_of_node(node_blk)); + if (!entry) { + entry = add_fsync_inode(head, ino_of_node(node_blk)); + if (!entry) { + err = -1; + break; + } + } + entry->blkaddr = blkaddr; + + if (IS_INODE(node_blk) && is_dent_dnode(node_blk)) + entry->last_dentry = blkaddr; +next: + blkaddr = next_blkaddr_of_node(node_blk); + + err = sanity_check_node_chain(sbi, &blkaddr_fast, + node_blk_fast, blkaddr, node_blk, + &is_detecting); + if (err) + break; + } + + free(node_blk_fast); + free(node_blk); + return err; +} + +static int do_record_fsync_data(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk, + block_t blkaddr) +{ + unsigned int segno, offset; + struct seg_entry *se; + unsigned int ofs_in_node = 0; + unsigned int start, end; + int err = 0, recorded = 0; + + segno = GET_SEGNO(sbi, blkaddr); + se = get_seg_entry(sbi, segno); + offset = OFFSET_IN_SEG(sbi, blkaddr); + + if (f2fs_test_bit(offset, (char *)se->cur_valid_map)) + return 1; + + if (f2fs_test_bit(offset, (char *)se->ckpt_valid_map)) + return 1; + + if (!se->ckpt_valid_blocks) + se->ckpt_type = CURSEG_WARM_NODE; + + se->ckpt_valid_blocks++; + f2fs_set_bit(offset, (char *)se->ckpt_valid_map); + + MSG(1, "do_record_fsync_data: [node] ino = %u, nid = %u, blkaddr = %u\n", + ino_of_node(node_blk), ofs_of_node(node_blk), blkaddr); + + /* inline data */ + if (IS_INODE(node_blk) && (node_blk->i.i_inline & F2FS_INLINE_DATA)) + return 0; + /* xattr node */ + if (ofs_of_node(node_blk) == XATTR_NODE_OFFSET) + return 0; + + /* step 3: recover data indices */ + start = start_bidx_of_node(ofs_of_node(node_blk), node_blk); + end = start + ADDRS_PER_PAGE(sbi, node_blk, NULL); + + for (; start < end; start++, ofs_in_node++) { + blkaddr = datablock_addr(node_blk, ofs_in_node); + + if (!is_valid_data_blkaddr(blkaddr)) + continue; + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) { + err = -1; + goto out; + } + + segno = GET_SEGNO(sbi, blkaddr); + se = get_seg_entry(sbi, segno); + offset = OFFSET_IN_SEG(sbi, blkaddr); + + if (f2fs_test_bit(offset, (char *)se->cur_valid_map)) + continue; + if (f2fs_test_bit(offset, (char *)se->ckpt_valid_map)) + continue; + + if (!se->ckpt_valid_blocks) + se->ckpt_type = CURSEG_WARM_DATA; + + se->ckpt_valid_blocks++; + f2fs_set_bit(offset, (char *)se->ckpt_valid_map); + + MSG(1, "do_record_fsync_data: [data] ino = %u, nid = %u, blkaddr = %u\n", + ino_of_node(node_blk), ofs_of_node(node_blk), blkaddr); + + recorded++; + } +out: + MSG(1, "recover_data: ino = %u, nid = %u, recorded = %d, err = %d\n", + ino_of_node(node_blk), ofs_of_node(node_blk), + recorded, err); + return err; +} + +static int traverse_dnodes(struct f2fs_sb_info *sbi, + struct list_head *inode_list) +{ + struct curseg_info *curseg; + struct f2fs_node *node_blk; + block_t blkaddr; + int err = 0; + + /* get node pages in the current segment */ + curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); + blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + while (1) { + struct fsync_inode_entry *entry; + + if (!f2fs_is_valid_blkaddr(sbi, blkaddr, META_POR)) + break; + + err = dev_read_block(node_blk, blkaddr); + if (err) + break; + + if (!is_recoverable_dnode(sbi, node_blk)) + break; + + entry = get_fsync_inode(inode_list, + ino_of_node(node_blk)); + if (!entry) + goto next; + + err = do_record_fsync_data(sbi, node_blk, blkaddr); + if (err) { + if (err > 0) + err = 0; + break; + } + + if (entry->blkaddr == blkaddr) + del_fsync_inode(entry); +next: + blkaddr = next_blkaddr_of_node(node_blk); + } + + free(node_blk); + return err; +} + +static int record_fsync_data(struct f2fs_sb_info *sbi) +{ + struct list_head inode_list = LIST_HEAD_INIT(inode_list); + int ret; + + if (!need_fsync_data_record(sbi)) + return 0; + + ret = find_fsync_inode(sbi, &inode_list); + if (ret) + goto out; + + if (c.func == FSCK && inode_list.next != &inode_list) + c.roll_forward = 1; + + ret = late_build_segment_manager(sbi); + if (ret < 0) { + ERR_MSG("late_build_segment_manager failed\n"); + goto out; + } + + ret = traverse_dnodes(sbi, &inode_list); +out: + destroy_fsync_dnodes(&inode_list); + return ret; +} + +int f2fs_do_mount(struct f2fs_sb_info *sbi) +{ + struct f2fs_checkpoint *cp = NULL; + struct f2fs_super_block *sb = NULL; + int num_cache_entry = c.cache_config.num_cache_entry; + int ret; + + /* Must not initiate cache until block size is known */ + c.cache_config.num_cache_entry = 0; + + sbi->active_logs = NR_CURSEG_TYPE; + ret = validate_super_block(sbi, SB0_ADDR); + if (ret) { + if (!c.sparse_mode) { + /* Assuming 4K Block Size */ + c.blksize_bits = 12; + c.blksize = 1 << c.blksize_bits; + MSG(0, "Looking for secondary superblock assuming 4K Block Size\n"); + } + ret = validate_super_block(sbi, SB1_ADDR); + if (ret && !c.sparse_mode) { + /* Trying 16K Block Size */ + c.blksize_bits = 14; + c.blksize = 1 << c.blksize_bits; + MSG(0, "Looking for secondary superblock assuming 16K Block Size\n"); + ret = validate_super_block(sbi, SB1_ADDR); + } + if (ret) + return -1; + } + sb = F2FS_RAW_SUPER(sbi); + c.cache_config.num_cache_entry = num_cache_entry; + + ret = check_sector_size(sb); + if (ret) + return -1; + + print_raw_sb_info(sb); + + init_sb_info(sbi); + + ret = get_valid_checkpoint(sbi); + if (ret) { + ERR_MSG("Can't find valid checkpoint\n"); + return -1; + } + + c.bug_on = 0; + + if (sanity_check_ckpt(sbi)) { + ERR_MSG("Checkpoint is polluted\n"); + return -1; + } + cp = F2FS_CKPT(sbi); + + if (c.func != FSCK && c.func != DUMP && c.func != INJECT && + !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) { + ERR_MSG("Mount unclean image to replay log first\n"); + return -1; + } + + if (c.func == FSCK) { +#if defined(__APPLE__) + if (!c.no_kernel_check && + memcmp(c.sb_version, c.version, VERSION_NAME_LEN)) { + c.auto_fix = 0; + c.fix_on = 1; + memcpy(sbi->raw_super->version, + c.version, VERSION_NAME_LEN); + update_superblock(sbi->raw_super, SB_MASK_ALL); + } +#else + fsck_update_sb_flags(sbi); + + if (!c.no_kernel_check) { + u32 prev_time, cur_time, time_diff; + __le32 *ver_ts_ptr = (__le32 *)(sbi->raw_super->version + + VERSION_NAME_LEN); + + cur_time = (u32)get_cp(elapsed_time); + prev_time = le32_to_cpu(*ver_ts_ptr); + + MSG(0, "Info: version timestamp cur: %u, prev: %u\n", + cur_time, prev_time); + if (!memcmp(c.sb_version, c.version, + VERSION_NAME_LEN)) { + /* valid prev_time */ + if (prev_time != 0 && cur_time > prev_time) { + time_diff = cur_time - prev_time; + if (time_diff < CHECK_PERIOD) + goto out; + c.auto_fix = 0; + c.fix_on = 1; + } + } else { + memcpy(sbi->raw_super->version, + c.version, VERSION_NAME_LEN); + } + + *ver_ts_ptr = cpu_to_le32(cur_time); + update_superblock(sbi->raw_super, SB_MASK_ALL); + } +#endif + } +out: + print_ckpt_info(sbi); + + if (c.quota_fix) { + if (get_cp(ckpt_flags) & CP_QUOTA_NEED_FSCK_FLAG) + c.fix_on = 1; + } + if (c.layout) + return 1; + + if (tune_sb_features(sbi)) + return -1; + + /* precompute checksum seed for metadata */ + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + c.chksum_seed = f2fs_cal_crc32(~0, sb->uuid, sizeof(sb->uuid)); + + sbi->total_valid_node_count = get_cp(valid_node_count); + sbi->total_valid_inode_count = get_cp(valid_inode_count); + sbi->user_block_count = get_cp(user_block_count); + sbi->total_valid_block_count = get_cp(valid_block_count); + sbi->last_valid_block_count = sbi->total_valid_block_count; + sbi->alloc_valid_block_count = 0; + + if (early_build_segment_manager(sbi)) { + ERR_MSG("early_build_segment_manager failed\n"); + return -1; + } + + if (build_node_manager(sbi)) { + ERR_MSG("build_node_manager failed\n"); + return -1; + } + + ret = record_fsync_data(sbi); + if (ret) { + ERR_MSG("record_fsync_data failed\n"); + if (ret != -ELOOP) + return -1; + } + + if (!f2fs_should_proceed(sb, get_cp(ckpt_flags))) + return 1; + + if (late_build_segment_manager(sbi) < 0) { + ERR_MSG("late_build_segment_manager failed\n"); + return -1; + } + + if (f2fs_late_init_nid_bitmap(sbi)) { + ERR_MSG("f2fs_late_init_nid_bitmap failed\n"); + return -1; + } + + /* Check nat_bits */ + if (c.func == FSCK && is_set_ckpt_flags(cp, CP_NAT_BITS_FLAG)) { + if (check_nat_bits(sbi, sb, cp) && c.fix_on) + write_nat_bits(sbi, sb, cp, sbi->cur_cp); + } + return 0; +} + +void f2fs_do_umount(struct f2fs_sb_info *sbi) +{ + struct sit_info *sit_i = SIT_I(sbi); + struct f2fs_sm_info *sm_i = SM_I(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + unsigned int i; + + /* free nm_info */ + if (c.func == SLOAD || c.func == FSCK) + free(nm_i->nid_bitmap); + free(nm_i->nat_bitmap); + free(sbi->nm_info); + + /* free sit_info */ + free(sit_i->bitmap); + free(sit_i->sit_bitmap); + free(sit_i->sentries); + free(sm_i->sit_info); + + /* free sm_info */ + for (i = 0; i < NR_CURSEG_TYPE; i++) + free(sm_i->curseg_array[i].sum_blk); + + free(sm_i->curseg_array); + free(sbi->sm_info); + + free(sbi->ckpt); + free(sbi->raw_super); +} + +#ifdef WITH_ANDROID +int f2fs_sparse_initialize_meta(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = sbi->raw_super; + uint32_t sit_seg_count, sit_size; + uint32_t nat_seg_count, nat_size; + uint64_t sit_seg_addr, nat_seg_addr, payload_addr; + uint32_t seg_size = 1 << get_sb(log_blocks_per_seg); + int ret; + + if (!c.sparse_mode) + return 0; + + sit_seg_addr = get_sb(sit_blkaddr); + sit_seg_count = get_sb(segment_count_sit); + sit_size = sit_seg_count * seg_size; + + DBG(1, "\tSparse: filling sit area at block offset: 0x%08"PRIx64" len: %u\n", + sit_seg_addr, sit_size); + ret = dev_fill(NULL, sit_seg_addr * F2FS_BLKSIZE, + sit_size * F2FS_BLKSIZE, WRITE_LIFE_NONE); + if (ret) { + MSG(1, "\tError: While zeroing out the sit area " + "on disk!!!\n"); + return -1; + } + + nat_seg_addr = get_sb(nat_blkaddr); + nat_seg_count = get_sb(segment_count_nat); + nat_size = nat_seg_count * seg_size; + + DBG(1, "\tSparse: filling nat area at block offset 0x%08"PRIx64" len: %u\n", + nat_seg_addr, nat_size); + ret = dev_fill(NULL, nat_seg_addr * F2FS_BLKSIZE, + nat_size * F2FS_BLKSIZE, WRITE_LIFE_NONE); + if (ret) { + MSG(1, "\tError: While zeroing out the nat area " + "on disk!!!\n"); + return -1; + } + + payload_addr = get_sb(segment0_blkaddr) + 1; + + DBG(1, "\tSparse: filling bitmap area at block offset 0x%08"PRIx64" len: %u\n", + payload_addr, get_sb(cp_payload)); + ret = dev_fill(NULL, payload_addr * F2FS_BLKSIZE, + get_sb(cp_payload) * F2FS_BLKSIZE, WRITE_LIFE_NONE); + if (ret) { + MSG(1, "\tError: While zeroing out the nat/sit bitmap area " + "on disk!!!\n"); + return -1; + } + + payload_addr += seg_size; + + DBG(1, "\tSparse: filling bitmap area at block offset 0x%08"PRIx64" len: %u\n", + payload_addr, get_sb(cp_payload)); + ret = dev_fill(NULL, payload_addr * F2FS_BLKSIZE, + get_sb(cp_payload) * F2FS_BLKSIZE, WRITE_LIFE_NONE); + if (ret) { + MSG(1, "\tError: While zeroing out the nat/sit bitmap area " + "on disk!!!\n"); + return -1; + } + return 0; +} +#else +int f2fs_sparse_initialize_meta(struct f2fs_sb_info *sbi) { return 0; } +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.c new file mode 100644 index 00000000000..8d4479c543d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.c @@ -0,0 +1,343 @@ +/** + * node.c + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "node.h" + +void f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + nid_t i; + + for (i = 0; i < nm_i->max_nid; i++) + if(f2fs_test_bit(i, nm_i->nid_bitmap) == 0) + break; + + ASSERT(i < nm_i->max_nid); + f2fs_set_bit(i, nm_i->nid_bitmap); + *nid = i; +} + +void f2fs_release_nid(struct f2fs_sb_info *sbi, nid_t nid) +{ + struct f2fs_nm_info *nm_i = NM_I(sbi); + + ASSERT(nid < nm_i->max_nid); + ASSERT(f2fs_test_bit(nid, nm_i->nid_bitmap)); + + f2fs_clear_bit(nid, nm_i->nid_bitmap); +} + +int f2fs_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype) +{ + struct f2fs_node *raw_node = NULL; + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct f2fs_summary sum; + struct node_info ni; + nid_t ino = QUOTA_INO(sb, qtype); + block_t blkaddr = NULL_ADDR; + __u64 cp_ver = cur_cp_version(ckpt); + int ret = 0; + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); + return -ENOMEM; + } + f2fs_init_inode(sb, raw_node, + le32_to_cpu(sb->qf_ino[qtype]), time(NULL), 0x8180); + + raw_node->i.i_size = cpu_to_le64(1024 * 6); + raw_node->i.i_blocks = cpu_to_le64(1); + raw_node->i.i_flags = cpu_to_le32(F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL); + + if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) + cp_ver |= (cur_cp_crc(ckpt) << 32); + F2FS_NODE_FOOTER(raw_node)->cp_ver = cpu_to_le64(cp_ver); + + get_node_info(sbi, ino, &ni); + if (ni.ino != ino) + ni.version = 0; + set_summary(&sum, ino, 0, ni.version); + ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE, 1); + if (ret) { + MSG(1, "\tError: Failed to reserve new block!\n"); + goto err_out; + } + + ret = write_inode(raw_node, blkaddr, f2fs_io_type_to_rw_hint(CURSEG_HOT_NODE)); + if (ret < 0) { + MSG(1, "\tError: While rebuilding the quota inode to disk!\n"); + goto err_out; + } + update_nat_blkaddr(sbi, ino, ino, blkaddr); + + f2fs_clear_bit(ino, F2FS_FSCK(sbi)->nat_area_bitmap); + f2fs_set_bit(ino, NM_I(sbi)->nid_bitmap); + DBG(1, "Rebuild quota inode ([%3d] ino [0x%x]) at offset:0x%x\n", + qtype, ino, blkaddr); +err_out: + free(raw_node); + return ret; +} + +void set_data_blkaddr(struct dnode_of_data *dn) +{ + __le32 *addr_array; + struct f2fs_node *node_blk = dn->node_blk; + unsigned int ofs_in_node = dn->ofs_in_node; + + addr_array = blkaddr_in_node(node_blk); + addr_array[ofs_in_node] = cpu_to_le32(dn->data_blkaddr); + if (dn->node_blk != dn->inode_blk) + dn->ndirty = 1; + else + dn->idirty = 1; +} + +/* + * In this function, we get a new node blk, and write back + * node_blk would be sloadd in RAM, linked by dn->node_blk + */ +block_t new_node_block(struct f2fs_sb_info *sbi, + struct dnode_of_data *dn, unsigned int ofs) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_node *f2fs_inode; + struct f2fs_node *node_blk; + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + struct f2fs_summary sum; + struct node_info ni; + block_t blkaddr = NULL_ADDR; + int type; + int ret; + + f2fs_inode = dn->inode_blk; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + F2FS_NODE_FOOTER(node_blk)->nid = cpu_to_le32(dn->nid); + F2FS_NODE_FOOTER(node_blk)->ino = F2FS_NODE_FOOTER(f2fs_inode)->ino; + F2FS_NODE_FOOTER(node_blk)->flag = cpu_to_le32(ofs << OFFSET_BIT_SHIFT); + F2FS_NODE_FOOTER(node_blk)->cp_ver = ckpt->checkpoint_ver; + set_cold_node(node_blk, S_ISDIR(le16_to_cpu(f2fs_inode->i.i_mode))); + + type = CURSEG_COLD_NODE; + if (IS_DNODE(node_blk)) { + if (S_ISDIR(le16_to_cpu(f2fs_inode->i.i_mode))) + type = CURSEG_HOT_NODE; + else + type = CURSEG_WARM_NODE; + } + + if ((get_sb(feature) & F2FS_FEATURE_RO) && + type != CURSEG_HOT_NODE) + type = CURSEG_HOT_NODE; + + get_node_info(sbi, dn->nid, &ni); + set_summary(&sum, dn->nid, 0, ni.version); + ret = reserve_new_block(sbi, &blkaddr, &sum, type, !ofs); + if (ret) { + free(node_blk); + return 0; + } + + /* update nat info */ + update_nat_blkaddr(sbi, le32_to_cpu(F2FS_NODE_FOOTER(f2fs_inode)->ino), + dn->nid, blkaddr); + + dn->node_blk = node_blk; + inc_inode_blocks(dn); + return blkaddr; +} + +/* + * get_node_path - Get the index path of pgoff_t block + * @offset: offset in the current index node block. + * @noffset: NO. of the index block within a file. + * return: depth of the index path. + * + * By default, it sets inline_xattr and inline_data + */ +static int get_node_path(struct f2fs_node *node, long block, + int offset[4], unsigned int noffset[4]) +{ + const long direct_index = ADDRS_PER_INODE(&node->i); + const long direct_blks = ADDRS_PER_BLOCK(&node->i); + const long dptrs_per_blk = NIDS_PER_BLOCK; + const long indirect_blks = ADDRS_PER_BLOCK(&node->i) * NIDS_PER_BLOCK; + const long dindirect_blks = indirect_blks * NIDS_PER_BLOCK; + int n = 0; + int level = 0; + + noffset[0] = 0; + if (block < direct_index) { + offset[n] = block; + goto got; + } + + block -= direct_index; + if (block < direct_blks) { + offset[n++] = NODE_DIR1_BLOCK; + noffset[n]= 1; + offset[n] = block; + level = 1; + goto got; + } + block -= direct_blks; + if (block < direct_blks) { + offset[n++] = NODE_DIR2_BLOCK; + noffset[n] = 2; + offset[n] = block; + level = 1; + goto got; + } + block -= direct_blks; + if (block < indirect_blks) { + offset[n++] = NODE_IND1_BLOCK; + noffset[n] = 3; + offset[n++] = block / direct_blks; + noffset[n] = 4 + offset[n - 1]; + offset[n] = block % direct_blks; + level = 2; + goto got; + } + block -= indirect_blks; + if (block < indirect_blks) { + offset[n++] = NODE_IND2_BLOCK; + noffset[n] = 4 + dptrs_per_blk; + offset[n++] = block / direct_blks; + noffset[n] = 5 + dptrs_per_blk + offset[n - 1]; + offset[n] = block % direct_blks; + level = 2; + goto got; + } + block -= indirect_blks; + if (block < dindirect_blks) { + offset[n++] = NODE_DIND_BLOCK; + noffset[n] = 5 + (dptrs_per_blk * 2); + offset[n++] = block / indirect_blks; + noffset[n] = 6 + (dptrs_per_blk * 2) + + offset[n - 1] * (dptrs_per_blk + 1); + offset[n++] = (block / direct_blks) % dptrs_per_blk; + noffset[n] = 7 + (dptrs_per_blk * 2) + + offset[n - 2] * (dptrs_per_blk + 1) + + offset[n - 1]; + offset[n] = block % direct_blks; + level = 3; + goto got; + } else { + ASSERT(0); + } +got: + return level; +} + +int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn, + pgoff_t index, int mode) +{ + int offset[4]; + unsigned int noffset[4]; + struct f2fs_node *parent = NULL; + nid_t nids[4]; + block_t nblk[4]; + struct node_info ni; + int level, i; + bool parent_alloced = false; + int ret; + + level = get_node_path(dn->inode_blk, index, offset, noffset); + + nids[0] = dn->nid; + parent = dn->inode_blk; + if (level != 0) + nids[1] = get_nid(parent, offset[0], 1); + else + dn->node_blk = dn->inode_blk; + + get_node_info(sbi, nids[0], &ni); + nblk[0] = ni.blk_addr; + + for (i = 1; i <= level; i++) { + if (!nids[i] && mode == ALLOC_NODE) { + f2fs_alloc_nid(sbi, &nids[i]); + + dn->nid = nids[i]; + set_nid(parent, offset[i - 1], nids[i], i == 1); + + /* Parent node has changed */ + if (!parent_alloced) + ret = update_block(sbi, parent, &nblk[i - 1], NULL); + else { + struct seg_entry *se; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, nblk[i - 1])); + ret = dev_write_block(parent, nblk[i - 1], + f2fs_io_type_to_rw_hint(se->type)); + } + ASSERT(ret >= 0); + + /* Function new_node_blk get a new f2fs_node blk and update*/ + /* We should make sure that dn->node_blk == NULL*/ + nblk[i] = new_node_block(sbi, dn, noffset[i]); + if (!nblk[i]) { + f2fs_release_nid(sbi, nids[i]); + c.alloc_failed = 1; + return -EINVAL; + } + + parent_alloced = true; + if (i == level) + dn->alloced = 1; + } else { + /* If Sparse file no read API, */ + struct node_info ni; + + get_node_info(sbi, nids[i], &ni); + dn->node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(dn->node_blk); + + ret = dev_read_block(dn->node_blk, ni.blk_addr); + ASSERT(ret >= 0); + + nblk[i] = ni.blk_addr; + } + + if (i != 1) + free(parent); + + if (i < level) { + parent = dn->node_blk; + nids[i + 1] = get_nid(parent, offset[i], 0); + } + } + + dn->nid = nids[level]; + dn->ofs_in_node = offset[level]; + dn->data_blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node); + dn->node_blkaddr = nblk[level]; + return 0; +} + +int update_inode(struct f2fs_sb_info *sbi, struct f2fs_node *inode, + u32 *blkaddr) +{ + if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM)) + inode->i.i_inode_checksum = + cpu_to_le32(f2fs_inode_chksum(inode)); + return update_block(sbi, inode, blkaddr, NULL); +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.h new file mode 100644 index 00000000000..19f1e571d85 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/node.h @@ -0,0 +1,179 @@ +/** + * node.h + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _NODE_H_ +#define _NODE_H_ + +#include "fsck.h" + +static inline bool IS_INODE(struct f2fs_node *node) +{ + return F2FS_NODE_FOOTER(node)->nid == F2FS_NODE_FOOTER(node)->ino; +} + +static inline unsigned int ADDRS_PER_PAGE(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk, struct f2fs_node *inode_blk) +{ + nid_t ino = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino); + unsigned int nblocks; + + if (IS_INODE(node_blk)) + return ADDRS_PER_INODE(&node_blk->i); + + if (!inode_blk) { + struct node_info ni; + + inode_blk = calloc(F2FS_BLKSIZE, 2); + ASSERT(inode_blk); + + get_node_info(sbi, ino, &ni); + ASSERT(dev_read_block(inode_blk, ni.blk_addr) >= 0); + nblocks = ADDRS_PER_BLOCK(&inode_blk->i); + free(inode_blk); + } else { + nblocks = ADDRS_PER_BLOCK(&inode_blk->i); + } + return nblocks; +} + +static inline __le32 *blkaddr_in_inode(struct f2fs_node *node) +{ + return node->i.i_addr + get_extra_isize(node); +} + +static inline __le32 *blkaddr_in_node(struct f2fs_node *node) +{ + return IS_INODE(node) ? blkaddr_in_inode(node) : node->dn.addr; +} + +static inline block_t datablock_addr(struct f2fs_node *node_page, + unsigned int offset) +{ + __le32 *addr_array; + + ASSERT(node_page); + addr_array = blkaddr_in_node(node_page); + return le32_to_cpu(addr_array[offset]); +} + +static inline void set_nid(struct f2fs_node * rn, int off, nid_t nid, int i) +{ + if (i) + F2FS_INODE_I_NID(&rn->i, off - NODE_DIR1_BLOCK) = cpu_to_le32(nid); + else + rn->in.nid[off] = cpu_to_le32(nid); +} + +static inline nid_t get_nid(struct f2fs_node * rn, int off, int i) +{ + if (i) + return le32_to_cpu(F2FS_INODE_I_NID(&rn->i, off - NODE_DIR1_BLOCK)); + else + return le32_to_cpu(rn->in.nid[off]); +} + +enum { + ALLOC_NODE, /* allocate a new node page if needed */ + LOOKUP_NODE, /* lookup up a node without readahead */ + LOOKUP_NODE_RA, +}; + +static inline void set_new_dnode(struct dnode_of_data *dn, + struct f2fs_node *iblk, struct f2fs_node *nblk, nid_t nid) +{ + memset(dn, 0, sizeof(*dn)); + dn->inode_blk = iblk; + dn->node_blk = nblk; + dn->nid = nid; + dn->idirty = 0; + dn->ndirty = 0; + dn->alloced = 0; +} + +static inline void inc_inode_blocks(struct dnode_of_data *dn) +{ + u64 blocks = le64_to_cpu(dn->inode_blk->i.i_blocks); + + dn->inode_blk->i.i_blocks = cpu_to_le64(blocks + 1); + dn->idirty = 1; +} + +static inline int IS_DNODE(struct f2fs_node *node_page) +{ + unsigned int ofs = ofs_of_node(node_page); + + if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK || + ofs == 5 + 2 * NIDS_PER_BLOCK) + return 0; + + if (ofs >= 6 + 2 * NIDS_PER_BLOCK) { + ofs -= 6 + 2 * NIDS_PER_BLOCK; + if (!((long int)ofs % (NIDS_PER_BLOCK + 1))) + return 0; + } + return 1; +} + +static inline nid_t ino_of_node(struct f2fs_node *node_blk) +{ + return le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino); +} + +static inline __u64 cpver_of_node(struct f2fs_node *node_blk) +{ + return le64_to_cpu(F2FS_NODE_FOOTER(node_blk)->cp_ver); +} + +static inline bool is_recoverable_dnode(struct f2fs_sb_info *sbi, + struct f2fs_node *node_blk) +{ + struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); + __u64 cp_ver = cur_cp_version(ckpt); + + /* Don't care crc part, if fsck.f2fs sets it. */ + if (is_set_ckpt_flags(ckpt, CP_NOCRC_RECOVERY_FLAG)) + return (cp_ver << 32) == (cpver_of_node(node_blk) << 32); + + if (is_set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG)) + cp_ver |= (cur_cp_crc(ckpt) << 32); + + return cp_ver == cpver_of_node(node_blk); +} + +static inline block_t next_blkaddr_of_node(struct f2fs_node *node_blk) +{ + return le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->next_blkaddr); +} + +static inline int is_node(struct f2fs_node *node_blk, int type) +{ + return le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->flag) & (1 << type); +} + +static inline void set_cold_node(struct f2fs_node *rn, bool is_dir) +{ + unsigned int flag = le32_to_cpu(F2FS_NODE_FOOTER(rn)->flag); + + if (is_dir) + flag &= ~(0x1 << COLD_BIT_SHIFT); + else + flag |= (0x1 << COLD_BIT_SHIFT); + F2FS_NODE_FOOTER(rn)->flag = cpu_to_le32(flag); +} + +#define is_fsync_dnode(node_blk) is_node(node_blk, FSYNC_BIT_SHIFT) +#define is_dent_dnode(node_blk) is_node(node_blk, DENT_BIT_SHIFT) + +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.c new file mode 100644 index 00000000000..d02475287c9 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.c @@ -0,0 +1,232 @@ +/** quotaio.c + * + * Generic IO operations on quotafiles + * Jan Kara - sponsored by SuSE CR + * Aditya Kali - Ported to e2fsprogs + * Hyojun Kim - Ported to f2fs-tools + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "quotaio.h" + +static const char * const extensions[MAXQUOTAS] = { + [USRQUOTA] = "user", + [GRPQUOTA] = "group", + [PRJQUOTA] = "project", +}; + +/* Header in all newer quotafiles */ +struct disk_dqheader { + __le32 dqh_magic; + __le32 dqh_version; +}; + +static_assert(sizeof(struct disk_dqheader) == 8, ""); + +int cur_qtype = -1; +u32 qf_last_blkofs[MAXQUOTAS] = {0, 0, 0}; +enum qf_szchk_type_t qf_szchk_type[MAXQUOTAS] = +{ + QF_SZCHK_NONE, QF_SZCHK_NONE, QF_SZCHK_NONE +}; +u64 qf_maxsize[MAXQUOTAS]; + +/** + * Convert type of quota to written representation + */ +const char *quota_type2name(enum quota_type qtype) +{ + if (qtype >= MAXQUOTAS) + return "unknown"; + return extensions[qtype]; +} + +/* + * Set grace time if needed + */ +void update_grace_times(struct dquot *q) +{ + time_t now; + + time(&now); + if (q->dq_dqb.dqb_bsoftlimit && toqb(q->dq_dqb.dqb_curspace) > + q->dq_dqb.dqb_bsoftlimit) { + if (!q->dq_dqb.dqb_btime) + q->dq_dqb.dqb_btime = + now + q->dq_h->qh_info.dqi_bgrace; + } else { + q->dq_dqb.dqb_btime = 0; + } + + if (q->dq_dqb.dqb_isoftlimit && q->dq_dqb.dqb_curinodes > + q->dq_dqb.dqb_isoftlimit) { + if (!q->dq_dqb.dqb_itime) + q->dq_dqb.dqb_itime = + now + q->dq_h->qh_info.dqi_igrace; + } else { + q->dq_dqb.dqb_itime = 0; + } +} + +/* Functions to read/write quota file. */ +static unsigned int quota_write_nomount(struct quota_file *qf, + long offset, + void *buf, unsigned int size) +{ + unsigned int written; + + written = f2fs_write(qf->sbi, qf->ino, buf, size, offset); + if (qf->filesize < offset + written) + qf->filesize = offset + written; + if (written != size) + return -EIO; + return written; +} + +static unsigned int quota_read_nomount(struct quota_file *qf, long offset, + void *buf, unsigned int size) +{ + return f2fs_read(qf->sbi, qf->ino, buf, size, offset); +} + +/* + * Detect quota format and initialize quota IO + */ +errcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype, int flags) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + quota_ctx_t qctx = fsck->qctx; + f2fs_ino_t qf_ino; + errcode_t err = 0; + int allocated_handle = 0; + + if (qtype >= MAXQUOTAS) + return EINVAL; + + qf_ino = sb->qf_ino[qtype]; + + if (!h) { + if (qctx->quota_file[qtype]) { + h = qctx->quota_file[qtype]; + (void) quota_file_close(sbi, h, 0); + } + err = quota_get_mem(sizeof(struct quota_handle), &h); + if (err) { + log_err("Unable to allocate quota handle"); + return err; + } + allocated_handle = 1; + } + + h->qh_qf.sbi = sbi; + h->qh_qf.ino = qf_ino; + h->write = quota_write_nomount; + h->read = quota_read_nomount; + h->qh_file_flags = flags; + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = QFMT_VFS_V1; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->check_file && + (h->qh_ops->check_file(h, qtype) == 0)) { + log_err("qh_ops->check_file failed"); + err = EIO; + goto errout; + } + + if (h->qh_ops->init_io && (h->qh_ops->init_io(h, qtype) < 0)) { + log_err("qh_ops->init_io failed"); + err = EIO; + goto errout; + } + if (allocated_handle) + qctx->quota_file[qtype] = h; +errout: + return err; +} + +/* + * Create new quotafile of specified format on given filesystem + */ +errcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + f2fs_ino_t qf_inum = sb->qf_ino[qtype]; + errcode_t err = 0; + + memset(&h->qh_qf, 0, sizeof(h->qh_qf)); + h->qh_qf.sbi = sbi; + h->qh_qf.ino = qf_inum; + h->write = quota_write_nomount; + h->read = quota_read_nomount; + + log_debug("Creating quota ino=%u, type=%d", qf_inum, qtype); + h->qh_io_flags = 0; + h->qh_type = qtype; + h->qh_fmt = QFMT_VFS_V1; + memset(&h->qh_info, 0, sizeof(h->qh_info)); + h->qh_ops = "afile_ops_2; + + if (h->qh_ops->new_io && (h->qh_ops->new_io(h) < 0)) { + log_err("qh_ops->new_io failed"); + err = EIO; + } + + return err; +} + +/* + * Close quotafile and release handle + */ +errcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h, + int update_filesize) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + quota_ctx_t qctx = fsck->qctx; + + if (h->qh_io_flags & IOFL_INFODIRTY) { + if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0) + return EIO; + h->qh_io_flags &= ~IOFL_INFODIRTY; + } + if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0) + return EIO; + if (update_filesize) { + f2fs_filesize_update(sbi, h->qh_qf.ino, h->qh_qf.filesize); + } + if (qctx->quota_file[h->qh_type] == h) + quota_free_mem(&qctx->quota_file[h->qh_type]); + return 0; +} + +/* + * Create empty quota structure + */ +struct dquot *get_empty_dquot(void) +{ + struct dquot *dquot; + + if (quota_get_memzero(sizeof(struct dquot), &dquot)) { + log_err("Failed to allocate dquot"); + return NULL; + } + + dquot->dq_id = -1; + return dquot; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.h new file mode 100644 index 00000000000..fc40f98e874 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio.h @@ -0,0 +1,264 @@ +/** quotaio.h + * + * Interface to the quota library. + * + * The quota library provides interface for creating and updating the quota + * files and the ext4 superblock fields. It supports the new VFS_V1 quota + * format. The quota library also provides support for keeping track of quotas + * in memory. + * + * Aditya Kali + * Header of IO operations for quota utilities + * + * Jan Kara + * + * Hyojun Kim - Ported to f2fs-tools + */ + +#ifndef GUARD_QUOTAIO_H +#define GUARD_QUOTAIO_H + +#include +#include +#include + +#include "dict.h" +#include "f2fs_fs.h" +#include "f2fs.h" +#include "node.h" +#include "fsck.h" + +#include "dqblk_v2.h" + +typedef int64_t qsize_t; /* Type in which we store size limitations */ +typedef int32_t f2fs_ino_t; +typedef int errcode_t; + +enum quota_type { + USRQUOTA = 0, + GRPQUOTA = 1, + PRJQUOTA = 2, + MAXQUOTAS = 3, +}; + +#if MAXQUOTAS > 32 +#error "cannot have more than 32 quota types to fit in qtype_bits" +#endif + +enum qf_szchk_type_t { + QF_SZCHK_NONE, + QF_SZCHK_ERR, + QF_SZCHK_INLINE, + QF_SZCHK_REGFILE, +}; + +extern int cur_qtype; +extern u32 qf_last_blkofs[]; +extern enum qf_szchk_type_t qf_szchk_type[]; +extern u64 qf_maxsize[]; + +#define QUOTA_USR_BIT (1 << USRQUOTA) +#define QUOTA_GRP_BIT (1 << GRPQUOTA) +#define QUOTA_PRJ_BIT (1 << PRJQUOTA) +#define QUOTA_ALL_BIT (QUOTA_USR_BIT | QUOTA_GRP_BIT | QUOTA_PRJ_BIT) + +typedef struct quota_ctx *quota_ctx_t; + +struct quota_ctx { + struct f2fs_sb_info *sbi; + struct dict_t *quota_dict[MAXQUOTAS]; + struct quota_handle *quota_file[MAXQUOTAS]; + struct dict_t linked_inode_dict; +}; + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927, /* GRPQUOTA */\ + 0xd9c03f14 /* PRJQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* Quota format type IDs */ +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 +#define QFMT_VFS_V1 4 + +/* + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define IOFL_INFODIRTY 0x01 /* Did info change? */ + +struct quotafile_ops; + +/* Generic information about quotafile */ +struct util_dqinfo { + time_t dqi_bgrace; /* Block grace time for given quotafile */ + time_t dqi_igrace; /* Inode grace time for given quotafile */ + union { + struct v2_mem_dqinfo v2_mdqi; + } u; /* Format specific info about quotafile */ +}; + +struct quota_file { + struct f2fs_sb_info *sbi; + f2fs_ino_t ino; + int64_t filesize; +}; + +/* Structure for one opened quota file */ +struct quota_handle { + enum quota_type qh_type; /* Type of quotafile */ + int qh_fmt; /* Quotafile format */ + int qh_file_flags; + int qh_io_flags; /* IO flags for file */ + struct quota_file qh_qf; + unsigned int (*read)(struct quota_file *qf, long offset, + void *buf, unsigned int size); + unsigned int (*write)(struct quota_file *qf, long offset, + void *buf, unsigned int size); + struct quotafile_ops *qh_ops; /* Operations on quotafile */ + struct util_dqinfo qh_info; /* Generic quotafile info */ +}; + +/* Utility quota block */ +struct util_dqblk { + qsize_t dqb_ihardlimit; + qsize_t dqb_isoftlimit; + qsize_t dqb_curinodes; + qsize_t dqb_bhardlimit; + qsize_t dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; + union { + struct v2_mem_dqblk v2_mdqb; + } u; /* Format specific dquot information */ +}; + +/* Structure for one loaded quota */ +struct dquot { + struct dquot *dq_next; /* Pointer to next dquot in the list */ + qid_t dq_id; /* ID dquot belongs to */ + int dq_flags; /* Some flags for utils */ + struct quota_handle *dq_h; /* Handle of quotafile for this dquot */ + struct util_dqblk dq_dqb; /* Parsed data of dquot */ +}; + +#define DQF_SEEN 0x0001 + +/* Structure of quotafile operations */ +struct quotafile_ops { + /* Check whether quotafile is in our format */ + int (*check_file) (struct quota_handle *h, int type); + /* Open quotafile */ + int (*init_io) (struct quota_handle *h, enum quota_type qtype); + /* Create new quotafile */ + int (*new_io) (struct quota_handle *h); + /* Write all changes and close quotafile */ + int (*end_io) (struct quota_handle *h); + /* Write info about quotafile */ + int (*write_info) (struct quota_handle *h); + /* Read dquot into memory */ + struct dquot *(*read_dquot) (struct quota_handle *h, qid_t id); + /* Write given dquot to disk */ + int (*commit_dquot) (struct dquot *dquot); + /* Scan quotafile and call callback on every structure */ + int (*scan_dquots) (struct quota_handle *h, + int (*process_dquot) (struct dquot *dquot, + void *data), + void *data); + /* Function to print format specific file information */ + int (*report) (struct quota_handle *h, int verbose); +}; + +#ifdef __CHECKER__ +# ifndef __bitwise +# define __bitwise __attribute__((bitwise)) +# endif +#define __force __attribute__((force)) +#else +# ifndef __bitwise +# define __bitwise +# endif +#define __force +#endif + +/* Open existing quotafile of given type (and verify its format) on given + * filesystem. */ +errcode_t quota_file_open(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype, int flags); + +/* Create new quotafile of specified format on given filesystem */ +errcode_t quota_file_create(struct f2fs_sb_info *sbi, struct quota_handle *h, + enum quota_type qtype); + +/* Close quotafile */ +errcode_t quota_file_close(struct f2fs_sb_info *sbi, struct quota_handle *h, + int update_filesize); + +/* Get empty quota structure */ +struct dquot *get_empty_dquot(void); +const char *quota_type2name(enum quota_type qtype); +void update_grace_times(struct dquot *q); + +/* In mkquota.c */ +errcode_t quota_init_context(struct f2fs_sb_info *sbi); +void quota_data_inodes(quota_ctx_t qctx, struct f2fs_inode *inode, int adjust); +void quota_data_add(quota_ctx_t qctx, struct f2fs_inode *inode, qsize_t space); +void quota_data_sub(quota_ctx_t qctx, struct f2fs_inode *inode, qsize_t space); +errcode_t quota_write_inode(struct f2fs_sb_info *sbi, enum quota_type qtype); +void quota_add_inode_usage(quota_ctx_t qctx, f2fs_ino_t ino, + struct f2fs_inode* inode); +void quota_release_context(quota_ctx_t *qctx); +errcode_t quota_compare_and_update(struct f2fs_sb_info *sbi, + enum quota_type qtype, int *usage_inconsistent, + int preserve_limits); + +static inline errcode_t quota_get_mem(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return -1; + memcpy(ptr, &pp, sizeof (pp)); + return 0; +} + +static inline errcode_t quota_get_memzero(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return -1; + memset(pp, 0, size); + memcpy(ptr, &pp, sizeof(pp)); + return 0; +} + +static inline errcode_t quota_free_mem(void *ptr) +{ + void *p; + + memcpy(&p, ptr, sizeof(p)); + free(p); + p = 0; + memcpy(ptr, &p, sizeof(p)); + return 0; +} + +#endif /* GUARD_QUOTAIO_H */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.c new file mode 100644 index 00000000000..40521c54c43 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.c @@ -0,0 +1,687 @@ +/* + * Implementation of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + * Hyojun Kim - Ported to f2fs-tools + */ + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "quotaio_tree.h" +#include "quotaio.h" + +typedef char *dqbuf_t; + +#define freedqbuf(buf) quota_free_mem(&buf) + +static inline dqbuf_t getdqbuf(void) +{ + dqbuf_t buf; + if (quota_get_memzero(QT_BLKSIZE, &buf)) { + log_err("Failed to allocate dqbuf"); + return NULL; + } + + return buf; +} + +/* Is given dquot empty? */ +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk) +{ + unsigned int i; + + for (i = 0; i < info->dqi_entry_size; i++) + if (disk[i]) + return 0; + return 1; +} + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info) +{ + return (QT_BLKSIZE - sizeof(struct qt_disk_dqdbheader)) / + info->dqi_entry_size; +} + +static int get_index(qid_t id, int depth) +{ + return (id >> ((QT_TREEDEPTH - depth - 1) * 8)) & 0xff; +} + +static inline void mark_quotafile_info_dirty(struct quota_handle *h) +{ + h->qh_io_flags |= IOFL_INFODIRTY; +} + +/* Read given block */ +static void read_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +{ + int err; + + err = h->read(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, + QT_BLKSIZE); + if (err < 0) + log_err("Cannot read block %u: %s", blk, strerror(errno)); + else if (err != QT_BLKSIZE) + memset(buf + err, 0, QT_BLKSIZE - err); +} + +/* Write block */ +static int write_blk(struct quota_handle *h, unsigned int blk, dqbuf_t buf) +{ + int err; + + err = h->write(&h->qh_qf, blk << QT_BLKSIZE_BITS, buf, + QT_BLKSIZE); + if (err < 0 && errno != ENOSPC) + log_err("Cannot write block (%u): %s", blk, strerror(errno)); + if (err != QT_BLKSIZE) + return -ENOSPC; + return 0; +} + +/* Get free block in file (either from free list or create new one) */ +static int get_free_dqblk(struct quota_handle *h) +{ + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + int blk; + + if (!buf) + return -ENOMEM; + + if (info->dqi_free_blk) { + blk = info->dqi_free_blk; + read_blk(h, blk, buf); + info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); + } else { + memset(buf, 0, QT_BLKSIZE); + /* Assure block allocation... */ + if (write_blk(h, info->dqi_blocks, buf) < 0) { + freedqbuf(buf); + log_err("Cannot allocate new quota block " + "(out of disk space)."); + return -ENOSPC; + } + blk = info->dqi_blocks++; + } + mark_quotafile_info_dirty(h); + freedqbuf(buf); + return blk; +} + +/* Put given block to free list */ +static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk); + dh->dqdh_prev_free = cpu_to_le32(0); + dh->dqdh_entries = cpu_to_le16(0); + info->dqi_free_blk = blk; + mark_quotafile_info_dirty(h); + write_blk(h, blk, buf); +} + +/* Remove given block from the list of blocks with free entries */ +static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + unsigned int nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = + le32_to_cpu(dh->dqdh_prev_free); + + if (!tmpbuf) + return; + + if (nextblk) { + read_blk(h, nextblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = + dh->dqdh_prev_free; + write_blk(h, nextblk, tmpbuf); + } + if (prevblk) { + read_blk(h, prevblk, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_next_free = + dh->dqdh_next_free; + write_blk(h, prevblk, tmpbuf); + } else { + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = nextblk; + mark_quotafile_info_dirty(h); + } + freedqbuf(tmpbuf); + dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0); + write_blk(h, blk, buf); /* No matter whether write succeeds + * block is out of list */ +} + +/* Insert given block to the beginning of list with free entries */ +static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, + unsigned int blk) +{ + dqbuf_t tmpbuf = getdqbuf(); + struct qt_disk_dqdbheader *dh = (struct qt_disk_dqdbheader *)buf; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + + if (!tmpbuf) + return; + + dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry); + dh->dqdh_prev_free = cpu_to_le32(0); + write_blk(h, blk, buf); + if (info->dqi_free_entry) { + read_blk(h, info->dqi_free_entry, tmpbuf); + ((struct qt_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = + cpu_to_le32(blk); + write_blk(h, info->dqi_free_entry, tmpbuf); + } + freedqbuf(tmpbuf); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); +} + +/* Find space for dquot */ +static unsigned int find_free_dqentry(struct quota_handle *h, + struct dquot *dquot, int *err) +{ + int blk, i; + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + char *ddquot; + dqbuf_t buf; + + *err = 0; + buf = getdqbuf(); + if (!buf) { + *err = -ENOMEM; + return 0; + } + + dh = (struct qt_disk_dqdbheader *)buf; + if (info->dqi_free_entry) { + blk = info->dqi_free_entry; + read_blk(h, blk, buf); + } else { + blk = get_free_dqblk(h); + if (blk < 0) { + freedqbuf(buf); + *err = blk; + return 0; + } + memset(buf, 0, QT_BLKSIZE); + info->dqi_free_entry = blk; + mark_quotafile_info_dirty(h); + } + + /* Block will be full? */ + if (le16_to_cpu(dh->dqdh_entries) + 1 >= + qtree_dqstr_in_blk(info)) + remove_free_dqentry(h, buf, blk); + + dh->dqdh_entries = + cpu_to_le16(le16_to_cpu(dh->dqdh_entries) + 1); + /* Find free structure in block */ + ddquot = buf + sizeof(struct qt_disk_dqdbheader); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !qtree_entry_unused(info, ddquot); + i++) + ddquot += info->dqi_entry_size; + + if (i == qtree_dqstr_in_blk(info)) + log_err("find_free_dqentry(): Data block full unexpectedly."); + + write_blk(h, blk, buf); + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; + freedqbuf(buf); + return blk; +} + +/* Insert reference to structure into the trie */ +static int do_insert_tree(struct quota_handle *h, struct dquot *dquot, + unsigned int * treeblk, int depth) +{ + dqbuf_t buf; + int newson = 0, newact = 0; + __le32 *ref; + unsigned int newblk; + int ret = 0; + + log_debug("inserting in tree: treeblk=%u, depth=%d", *treeblk, depth); + buf = getdqbuf(); + if (!buf) + return -ENOMEM; + + if (!*treeblk) { + ret = get_free_dqblk(h); + if (ret < 0) + goto out_buf; + *treeblk = ret; + memset(buf, 0, QT_BLKSIZE); + newact = 1; + } else { + read_blk(h, *treeblk, buf); + } + + ref = (__le32 *) buf; + newblk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!newblk) + newson = 1; + if (depth == QT_TREEDEPTH - 1) { + if (newblk) + log_err("Inserting already present quota entry " + "(block %u).", + ref[get_index(dquot->dq_id, depth)]); + newblk = find_free_dqentry(h, dquot, &ret); + } else { + ret = do_insert_tree(h, dquot, &newblk, depth + 1); + } + + if (newson && ret >= 0) { + ref[get_index(dquot->dq_id, depth)] = + cpu_to_le32(newblk); + ret = write_blk(h, *treeblk, buf); + if (ret) + goto out_buf; + } else if (newact && ret < 0) { + put_free_dqblk(h, buf, *treeblk); + } + +out_buf: + freedqbuf(buf); + return ret; +} + +/* Wrapper for inserting quota structure into tree */ +static int dq_insert_tree(struct quota_handle *h, struct dquot *dquot) +{ + unsigned int tmp = QT_TREEOFF; + int err; + + err = do_insert_tree(h, dquot, &tmp, 0); + if (err < 0) + log_err("Cannot write quota (id %u): %s", + (unsigned int) dquot->dq_id, strerror(errno)); + return err; +} + +/* Write dquot to file */ +int qtree_write_dquot(struct dquot *dquot) +{ + errcode_t retval; + unsigned int ret; + char *ddquot; + struct quota_handle *h = dquot->dq_h; + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + + log_debug("writing ddquot 1: off=%llu, info->dqi_entry_size=%u", + dquot->dq_dqb.u.v2_mdqb.dqb_off, + info->dqi_entry_size); + retval = quota_get_mem(info->dqi_entry_size, &ddquot); + if (retval) { + log_err("Quota write failed (id %u): %s", + (unsigned int)dquot->dq_id, strerror(errno)); + return -ENOMEM; + } + memset(ddquot, 0, info->dqi_entry_size); + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) { + if (dq_insert_tree(dquot->dq_h, dquot)) { + quota_free_mem(&ddquot); + return -EIO; + } + } + info->dqi_ops->mem2disk_dqblk(ddquot, dquot); + log_debug("writing ddquot 2: off=%llu, info->dqi_entry_size=%u", + dquot->dq_dqb.u.v2_mdqb.dqb_off, + info->dqi_entry_size); + ret = h->write(&h->qh_qf, dquot->dq_dqb.u.v2_mdqb.dqb_off, ddquot, + info->dqi_entry_size); + + if (ret != info->dqi_entry_size) { + log_err("Quota write failed (id %u): %s", + (unsigned int)dquot->dq_id, strerror(errno)); + quota_free_mem(&ddquot); + return ret; + } + quota_free_mem(&ddquot); + return 0; +} + +/* Free dquot entry in data block */ +static void free_dqentry(struct quota_handle *h, struct dquot *dquot, + unsigned int blk) +{ + struct qt_disk_dqdbheader *dh; + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + + if (!buf) + return; + + if (dquot->dq_dqb.u.v2_mdqb.dqb_off >> QT_BLKSIZE_BITS != blk) + log_err("Quota structure has offset to other block (%u) " + "than it should (%u).", blk, + (unsigned int) (dquot->dq_dqb.u.v2_mdqb.dqb_off >> + QT_BLKSIZE_BITS)); + + read_blk(h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + dh->dqdh_entries = + cpu_to_le16(le16_to_cpu(dh->dqdh_entries) - 1); + + if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ + remove_free_dqentry(h, buf, blk); + put_free_dqblk(h, buf, blk); + } else { + memset(buf + (dquot->dq_dqb.u.v2_mdqb.dqb_off & + ((1 << QT_BLKSIZE_BITS) - 1)), + 0, info->dqi_entry_size); + + /* First free entry? */ + if (le16_to_cpu(dh->dqdh_entries) == + qtree_dqstr_in_blk(info) - 1) + /* This will also write data block */ + insert_free_dqentry(h, buf, blk); + else + write_blk(h, blk, buf); + } + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + freedqbuf(buf); +} + +/* Remove reference to dquot from tree */ +static void remove_tree(struct quota_handle *h, struct dquot *dquot, + unsigned int * blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + unsigned int newblk; + __le32 *ref = (__le32 *) buf; + + if (!buf) + return; + + read_blk(h, *blk, buf); + newblk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (depth == QT_TREEDEPTH - 1) { + free_dqentry(h, dquot, newblk); + newblk = 0; + } else { + remove_tree(h, dquot, &newblk, depth + 1); + } + + if (!newblk) { + int i; + + ref[get_index(dquot->dq_id, depth)] = cpu_to_le32(0); + + /* Block got empty? */ + for (i = 0; i < QT_BLKSIZE && !buf[i]; i++); + + /* Don't put the root block into the free block list */ + if (i == QT_BLKSIZE && *blk != QT_TREEOFF) { + put_free_dqblk(h, buf, *blk); + *blk = 0; + } else { + write_blk(h, *blk, buf); + } + } + freedqbuf(buf); +} + +/* Delete dquot from tree */ +void qtree_delete_dquot(struct dquot *dquot) +{ + unsigned int tmp = QT_TREEOFF; + + if (!dquot->dq_dqb.u.v2_mdqb.dqb_off) /* Even not allocated? */ + return; + remove_tree(dquot->dq_h, dquot, &tmp, 0); +} + +/* Find entry in block */ +static long find_block_dqentry(struct quota_handle *h, + struct dquot *dquot, unsigned int blk) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + int i; + char *ddquot = buf + sizeof(struct qt_disk_dqdbheader); + + if (!buf) + return -ENOMEM; + + read_blk(h, blk, buf); + for (i = 0; + i < qtree_dqstr_in_blk(info) && !info->dqi_ops->is_id(ddquot, dquot); + i++) + ddquot += info->dqi_entry_size; + + if (i == qtree_dqstr_in_blk(info)) + log_err("Quota for id %u referenced but not present.", + dquot->dq_id); + freedqbuf(buf); + return (blk << QT_BLKSIZE_BITS) + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; +} + +/* Find entry for given id in the tree */ +static long find_tree_dqentry(struct quota_handle *h, + struct dquot *dquot, + unsigned int blk, int depth) +{ + dqbuf_t buf = getdqbuf(); + long ret = 0; + __le32 *ref = (__le32 *) buf; + + if (!buf) + return -ENOMEM; + + read_blk(h, blk, buf); + ret = 0; + blk = le32_to_cpu(ref[get_index(dquot->dq_id, depth)]); + if (!blk) /* No reference? */ + goto out_buf; + if (depth < QT_TREEDEPTH - 1) + ret = find_tree_dqentry(h, dquot, blk, depth + 1); + else + ret = find_block_dqentry(h, dquot, blk); +out_buf: + freedqbuf(buf); + return ret; +} + +/* Find entry for given id in the tree - wrapper function */ +static inline long find_dqentry(struct quota_handle *h, + struct dquot *dquot) +{ + return find_tree_dqentry(h, dquot, QT_TREEOFF, 0); +} + +/* + * Read dquot from disk. + */ +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id) +{ + struct qtree_mem_dqinfo *info = &h->qh_info.u.v2_mdqi.dqi_qtree; + long offset; + unsigned int ret; + char *ddquot; + struct dquot *dquot = get_empty_dquot(); + + if (!dquot) + return NULL; + if (quota_get_mem(info->dqi_entry_size, &ddquot)) { + quota_free_mem(&dquot); + return NULL; + } + + dquot->dq_id = id; + dquot->dq_h = h; + dquot->dq_dqb.u.v2_mdqb.dqb_off = 0; + memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk)); + + offset = find_dqentry(h, dquot); + if (offset > 0) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = offset; + ret = h->read(&h->qh_qf, offset, ddquot, + info->dqi_entry_size); + if (ret != info->dqi_entry_size) { + if (ret > 0) + errno = EIO; + log_err("Cannot read quota structure for id %u: %s", + dquot->dq_id, strerror(errno)); + } + info->dqi_ops->disk2mem_dqblk(dquot, ddquot); + } + quota_free_mem(&ddquot); + return dquot; +} + +/* + * Scan all dquots in file and call callback on each + */ +#define set_bit(bmp, ind) ((bmp)[(ind) >> 3] |= (1 << ((ind) & 7))) +#define get_bit(bmp, ind) ((bmp)[(ind) >> 3] & (1 << ((ind) & 7))) + +static int report_block(struct dquot *dquot, unsigned int blk, char *bitmap, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + dqbuf_t buf = getdqbuf(); + struct qt_disk_dqdbheader *dh; + char *ddata; + int entries, i; + + if (!buf) + return -1; + + set_bit(bitmap, blk); + read_blk(dquot->dq_h, blk, buf); + dh = (struct qt_disk_dqdbheader *)buf; + ddata = buf + sizeof(struct qt_disk_dqdbheader); + entries = le16_to_cpu(dh->dqdh_entries); + for (i = 0; i < qtree_dqstr_in_blk(info); + i++, ddata += info->dqi_entry_size) + if (!qtree_entry_unused(info, ddata)) { + dquot->dq_dqb.u.v2_mdqb.dqb_off = + (blk << QT_BLKSIZE_BITS) + + sizeof(struct qt_disk_dqdbheader) + + i * info->dqi_entry_size; + info->dqi_ops->disk2mem_dqblk(dquot, ddata); + if (process_dquot(dquot, data) < 0) + break; + } + freedqbuf(buf); + return entries; +} + +static int check_reference(struct quota_handle *h, unsigned int blk) +{ + if (blk >= h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks) { + log_err("Illegal reference (%u >= %u) in %s quota file", + blk, + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks, + quota_type2name(h->qh_type)); + return -1; + } + return 0; +} + +/* Return 0 for successful run */ +static int report_tree(struct dquot *dquot, unsigned int blk, int depth, + char *bitmap, int *entries, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + int i; + dqbuf_t buf = getdqbuf(); + __le32 *ref = (__le32 *) buf; + + if (!buf) + return -1; + + read_blk(dquot->dq_h, blk, buf); + for (i = 0; i < QT_BLKSIZE >> 2; i++) { + blk = le32_to_cpu(ref[i]); + if (blk == 0) + continue; + + if (check_reference(dquot->dq_h, blk)) + break; + + if (depth == QT_TREEDEPTH - 1) { + if (!get_bit(bitmap, blk)) { + int num_entry = report_block(dquot, blk, bitmap, + process_dquot, data); + if (num_entry < 0) + break; + *entries += num_entry; + } + } else { + if (report_tree(dquot, blk, depth + 1, bitmap, entries, + process_dquot, data)) + break; + } + } + freedqbuf(buf); + return (i < QT_BLKSIZE >> 2) ? -1 : 0; +} + +static unsigned int find_set_bits(char *bmp, int blocks) +{ + unsigned int used = 0; + int i; + + for (i = 0; i < blocks; i++) + if (get_bit(bmp, i)) + used++; + return used; +} + +int qtree_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + struct v2_mem_dqinfo *v2info = &h->qh_info.u.v2_mdqi; + struct qtree_mem_dqinfo *info = &v2info->dqi_qtree; + struct dquot *dquot = get_empty_dquot(); + char *bitmap = NULL; + int ret = -1; + int entries = 0; + + if (!dquot) + return -1; + + dquot->dq_h = h; + if (quota_get_memzero((info->dqi_blocks + 7) >> 3, &bitmap)) + goto out; + if (report_tree(dquot, QT_TREEOFF, 0, bitmap, &entries, process_dquot, + data)) + goto out; + + v2info->dqi_used_entries = entries; + v2info->dqi_data_blocks = find_set_bits(bitmap, info->dqi_blocks); + ret = 0; + +out: + if (bitmap) + quota_free_mem(&bitmap); + if (dquot) + quota_free_mem(&dquot); + + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.h new file mode 100644 index 00000000000..8072c6e188f --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_tree.h @@ -0,0 +1,72 @@ +/* + * Definitions of structures for vfsv0 quota format + */ + +#ifndef _LINUX_QUOTA_TREE_H +#define _LINUX_QUOTA_TREE_H + +#include +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#include + +#include + +typedef __u32 qid_t; /* Type in which we store ids in memory */ + +#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ +#define QT_TREEDEPTH 4 /* Depth of quota tree */ +#define QT_BLKSIZE_BITS 10 +#define QT_BLKSIZE (1 << QT_BLKSIZE_BITS) /* Size of block with quota + * structures */ + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes + * so there will be space for exactly 21 quota-entries in a block + */ +struct qt_disk_dqdbheader { + __le32 dqdh_next_free; /* Number of next block with free + * entry */ + __le32 dqdh_prev_free; /* Number of previous block with free + * entry */ + __le16 dqdh_entries; /* Number of valid entries in block */ + __le16 dqdh_pad1; + __le32 dqdh_pad2; +}; + +static_assert(sizeof(struct qt_disk_dqdbheader) == 16, ""); + +struct dquot; +struct quota_handle; + +/* Operations */ +struct qtree_fmt_operations { + /* Convert given entry from in memory format to disk one */ + void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); + /* Convert given entry from disk format to in memory one */ + void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); + /* Is this structure for given id? */ + int (*is_id)(void *disk, struct dquot *dquot); +}; + +/* Inmemory copy of version specific information */ +struct qtree_mem_dqinfo { + unsigned int dqi_blocks; /* # of blocks in quota file */ + unsigned int dqi_free_blk; /* First block in list of free blocks */ + unsigned int dqi_free_entry; /* First block with free entry */ + unsigned int dqi_entry_size; /* Size of quota entry in quota file */ + struct qtree_fmt_operations *dqi_ops; /* Operations for entry + * manipulation */ +}; + +int qtree_write_dquot(struct dquot *dquot); +struct dquot *qtree_read_dquot(struct quota_handle *h, qid_t id); +void qtree_delete_dquot(struct dquot *dquot); +int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); +int qtree_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), void *data); + +int qtree_dqstr_in_blk(struct qtree_mem_dqinfo *info); + +#endif /* _LINUX_QUOTAIO_TREE_H */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.c new file mode 100644 index 00000000000..e19f303d96e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.c @@ -0,0 +1,328 @@ +/* + * Implementation of new quotafile format + * + * Jan Kara - sponsored by SuSE CR + * Hyojun Kim - Ported to f2fs-tools + */ + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#include "quotaio_v2.h" +#include "dqblk_v2.h" +#include "quotaio_tree.h" + +static int v2_check_file(struct quota_handle *h, int type); +static int v2_init_io(struct quota_handle *h, enum quota_type qtype); +static int v2_new_io(struct quota_handle *h); +static int v2_write_info(struct quota_handle *h); +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id); +static int v2_commit_dquot(struct dquot *dquot); +static int v2_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *dquot, + void *data), + void *data); +static int v2_report(struct quota_handle *h, int verbose); + +struct quotafile_ops quotafile_ops_2 = { + .check_file = v2_check_file, + .init_io = v2_init_io, + .new_io = v2_new_io, + .write_info = v2_write_info, + .read_dquot = v2_read_dquot, + .commit_dquot = v2_commit_dquot, + .scan_dquots = v2_scan_dquots, + .report = v2_report, +}; + +/* + * Copy dquot from disk to memory + */ +static void v2r1_disk2memdqblk(struct dquot *dquot, void *dp) +{ + struct util_dqblk *m = &dquot->dq_dqb; + struct v2r1_disk_dqblk *d = dp, empty; + + dquot->dq_id = le32_to_cpu(d->dqb_id); + m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit); + m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit); + m->dqb_bhardlimit = le64_to_cpu(d->dqb_bhardlimit); + m->dqb_bsoftlimit = le64_to_cpu(d->dqb_bsoftlimit); + m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes); + m->dqb_curspace = le64_to_cpu(d->dqb_curspace); + m->dqb_itime = le64_to_cpu(d->dqb_itime); + m->dqb_btime = le64_to_cpu(d->dqb_btime); + + memset(&empty, 0, sizeof(struct v2r1_disk_dqblk)); + empty.dqb_itime = cpu_to_le64(1); + if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk))) + m->dqb_itime = 0; +} + +/* + * Copy dquot from memory to disk + */ +static void v2r1_mem2diskdqblk(void *dp, struct dquot *dquot) +{ + struct util_dqblk *m = &dquot->dq_dqb; + struct v2r1_disk_dqblk *d = dp; + + d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit); + d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit); + d->dqb_bhardlimit = cpu_to_le64(m->dqb_bhardlimit); + d->dqb_bsoftlimit = cpu_to_le64(m->dqb_bsoftlimit); + d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes); + d->dqb_curspace = cpu_to_le64(m->dqb_curspace); + d->dqb_itime = cpu_to_le64(m->dqb_itime); + d->dqb_btime = cpu_to_le64(m->dqb_btime); + d->dqb_id = cpu_to_le32(dquot->dq_id); + if (qtree_entry_unused(&dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree, dp)) + d->dqb_itime = cpu_to_le64(1); +} + +static int v2r1_is_id(void *dp, struct dquot *dquot) +{ + struct v2r1_disk_dqblk *d = dp; + struct qtree_mem_dqinfo *info = + &dquot->dq_h->qh_info.u.v2_mdqi.dqi_qtree; + + if (qtree_entry_unused(info, dp)) + return 0; + return le32_to_cpu(d->dqb_id) == dquot->dq_id; +} + +static struct qtree_fmt_operations v2r1_fmt_ops = { + .mem2disk_dqblk = v2r1_mem2diskdqblk, + .disk2mem_dqblk = v2r1_disk2memdqblk, + .is_id = v2r1_is_id, +}; + +/* + * Copy dqinfo from disk to memory + */ +static inline void v2_disk2memdqinfo(struct util_dqinfo *m, + struct v2_disk_dqinfo *d) +{ + m->dqi_bgrace = le32_to_cpu(d->dqi_bgrace); + m->dqi_igrace = le32_to_cpu(d->dqi_igrace); + m->u.v2_mdqi.dqi_flags = le32_to_cpu(d->dqi_flags) & V2_DQF_MASK; + m->u.v2_mdqi.dqi_qtree.dqi_blocks = le32_to_cpu(d->dqi_blocks); + m->u.v2_mdqi.dqi_qtree.dqi_free_blk = + le32_to_cpu(d->dqi_free_blk); + m->u.v2_mdqi.dqi_qtree.dqi_free_entry = + le32_to_cpu(d->dqi_free_entry); +} + +/* + * Copy dqinfo from memory to disk + */ +static inline void v2_mem2diskdqinfo(struct v2_disk_dqinfo *d, + struct util_dqinfo *m) +{ + d->dqi_bgrace = cpu_to_le32(m->dqi_bgrace); + d->dqi_igrace = cpu_to_le32(m->dqi_igrace); + d->dqi_flags = cpu_to_le32(m->u.v2_mdqi.dqi_flags & V2_DQF_MASK); + d->dqi_blocks = cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_blocks); + d->dqi_free_blk = + cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_blk); + d->dqi_free_entry = + cpu_to_le32(m->u.v2_mdqi.dqi_qtree.dqi_free_entry); +} + +static int v2_read_header(struct quota_handle *h, struct v2_disk_dqheader *dqh) +{ + if (h->read(&h->qh_qf, 0, dqh, sizeof(struct v2_disk_dqheader)) != + sizeof(struct v2_disk_dqheader)) + return 0; + + return 1; +} + +/* + * Check whether given quota file is in our format + */ +static int v2_check_file(struct quota_handle *h, int type) +{ + struct v2_disk_dqheader dqh; + int file_magics[] = INITQMAGICS; + int be_magic; + + if (!v2_read_header(h, &dqh)) + return 0; + + be_magic = be32_to_cpu((__force __be32)dqh.dqh_magic); + if (be_magic == file_magics[type]) { + log_err("Your quota file is stored in wrong endianity"); + return 0; + } + if (V2_VERSION != le32_to_cpu(dqh.dqh_version)) + return 0; + return 1; +} + +/* + * Open quotafile + */ +static int v2_init_io(struct quota_handle *h, enum quota_type qtype) +{ + struct v2_disk_dqinfo ddqinfo; + struct v2_mem_dqinfo *info; + u64 filesize; + struct quota_file *qf = &h->qh_qf; + u32 last_blkofs = qf_last_blkofs[qtype]; + + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; + + /* Read information about quotafile */ + if (h->read(qf, V2_DQINFOOFF, &ddqinfo, + sizeof(ddqinfo)) != sizeof(ddqinfo)) + return -1; + v2_disk2memdqinfo(&h->qh_info, &ddqinfo); + + /* Check to make sure quota file info is sane */ + info = &h->qh_info.u.v2_mdqi; + filesize = qf->filesize = f2fs_quota_size(qf); + if (qf_szchk_type[qtype] == QF_SZCHK_REGFILE && + ((filesize + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS < + last_blkofs + 1 || filesize > qf_maxsize[qtype])) { + /* + * reqular: qf_szchk is now the last block index, + * including the hole's index + */ + log_err("Quota inode %u corrupted: file size %" PRIu64 + " does not match page offset %" PRIu32, + h->qh_qf.ino, + filesize, + last_blkofs); + filesize = (last_blkofs + 1) << F2FS_BLKSIZE_BITS; + f2fs_filesize_update(qf->sbi, qf->ino, filesize); + } + + if ((info->dqi_qtree.dqi_blocks > + (filesize + QT_BLKSIZE - 1) >> QT_BLKSIZE_BITS)) { + log_err("Quota inode %u corrupted: file size %" PRId64 "; " + "dqi_blocks %u", h->qh_qf.ino, + filesize, info->dqi_qtree.dqi_blocks); + return -1; + } + if (info->dqi_qtree.dqi_free_blk >= info->dqi_qtree.dqi_blocks) { + log_err("Quota inode %u corrupted: free_blk %u;" + " dqi_blocks %u", + h->qh_qf.ino, info->dqi_qtree.dqi_free_blk, + info->dqi_qtree.dqi_blocks); + return -1; + } + if (info->dqi_qtree.dqi_free_entry >= info->dqi_qtree.dqi_blocks) { + log_err("Quota inode %u corrupted: free_entry %u; " + "dqi_blocks %u", h->qh_qf.ino, + info->dqi_qtree.dqi_free_entry, + info->dqi_qtree.dqi_blocks); + return -1; + } + return 0; +} + +/* + * Initialize new quotafile + */ +static int v2_new_io(struct quota_handle *h) +{ + int file_magics[] = INITQMAGICS; + struct v2_disk_dqheader ddqheader; + struct v2_disk_dqinfo ddqinfo; + + if (h->qh_fmt != QFMT_VFS_V1) + return -1; + + /* Write basic quota header */ + ddqheader.dqh_magic = cpu_to_le32(file_magics[h->qh_type]); + ddqheader.dqh_version = cpu_to_le32(V2_VERSION); + if (h->write(&h->qh_qf, 0, &ddqheader, sizeof(ddqheader)) != + sizeof(ddqheader)) + return -1; + + /* Write information about quotafile */ + h->qh_info.dqi_bgrace = MAX_DQ_TIME; + h->qh_info.dqi_igrace = MAX_IQ_TIME; + h->qh_info.u.v2_mdqi.dqi_flags = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_blocks = QT_TREEOFF + 1; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_blk = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_free_entry = 0; + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_entry_size = + sizeof(struct v2r1_disk_dqblk); + h->qh_info.u.v2_mdqi.dqi_qtree.dqi_ops = &v2r1_fmt_ops; + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + if (h->write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, + sizeof(ddqinfo)) != + sizeof(ddqinfo)) + return -1; + + return 0; +} + +/* + * Write information (grace times to file) + */ +static int v2_write_info(struct quota_handle *h) +{ + struct v2_disk_dqinfo ddqinfo; + + v2_mem2diskdqinfo(&ddqinfo, &h->qh_info); + if (h->write(&h->qh_qf, V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)) != + sizeof(ddqinfo)) + return -1; + + return 0; +} + +/* + * Read dquot from disk + */ +static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id) +{ + return qtree_read_dquot(h, id); +} + +/* + * Commit changes of dquot to disk - it might also mean deleting it when quota + * became fake one and user has no blocks. + * User can process use 'errno' to detect errstr. + */ +static int v2_commit_dquot(struct dquot *dquot) +{ + struct util_dqblk *b = &dquot->dq_dqb; + + if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && + !b->dqb_isoftlimit && !b->dqb_bhardlimit && !b->dqb_ihardlimit) + { + qtree_delete_dquot(dquot); + } else { + return qtree_write_dquot(dquot); + } + return 0; +} + +static int v2_scan_dquots(struct quota_handle *h, + int (*process_dquot) (struct dquot *, void *), + void *data) +{ + return qtree_scan_dquots(h, process_dquot, data); +} + +/* Report information about quotafile. + * TODO: Not used right now, but we should be able to use this when we add + * support to debugfs to read quota files. + */ +static int v2_report(struct quota_handle *UNUSED(h), int UNUSED(verbose)) +{ + log_err("Not Implemented."); + return -1; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.h new file mode 100644 index 00000000000..b054422f5a6 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/quotaio_v2.h @@ -0,0 +1,60 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef GUARD_QUOTAIO_V2_H +#define GUARD_QUOTAIO_V2_H + +#include +#include "quotaio.h" + +/* Offset of info header in file */ +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) +/* Supported version of quota-tree format */ +#define V2_VERSION 1 + +struct v2_disk_dqheader { + __le32 dqh_magic; /* Magic number identifying file */ + __le32 dqh_version; /* File version */ +}; + +static_assert(sizeof(struct v2_disk_dqheader) == 8, ""); + +/* Flags for version specific files */ +#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + __le32 dqi_bgrace; /* Time before block soft limit becomes + * hard limit */ + __le32 dqi_igrace; /* Time before inode soft limit becomes + * hard limit */ + __le32 dqi_flags; /* Flags for quotafile (DQF_*) */ + __le32 dqi_blocks; /* Number of blocks in file */ + __le32 dqi_free_blk; /* Number of first free block in the list */ + __le32 dqi_free_entry; /* Number of block with at least one + * free entry */ +}; + +static_assert(sizeof(struct v2_disk_dqinfo) == 24, ""); + +struct v2r1_disk_dqblk { + __le32 dqb_id; /* id this quota applies to */ + __le32 dqb_pad; + __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __le64 dqb_isoftlimit; /* preferred inode limit */ + __le64 dqb_curinodes; /* current # allocated inodes */ + __le64 dqb_bhardlimit; /* absolute limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_bsoftlimit; /* preferred limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_curspace; /* current space occupied (in bytes) */ + __le64 dqb_btime; /* time limit for excessive disk use */ + __le64 dqb_itime; /* time limit for excessive inode use */ +}; + +static_assert(sizeof(struct v2r1_disk_dqblk) == 72, ""); + +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/resize.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/resize.c new file mode 100644 index 00000000000..58914ec2ab8 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/resize.c @@ -0,0 +1,778 @@ +/** + * resize.c + * + * Copyright (c) 2015 Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" + +static int get_new_sb(struct f2fs_super_block *sb) +{ + uint32_t zone_size_bytes; + uint64_t zone_align_start_offset; + uint32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa; + uint32_t sit_segments, nat_segments, diff, total_meta_segments; + uint32_t total_valid_blks_available; + uint32_t sit_bitmap_size, max_sit_bitmap_size; + uint32_t max_nat_bitmap_size, max_nat_segments; + uint32_t segment_size_bytes = 1 << (get_sb(log_blocksize) + + get_sb(log_blocks_per_seg)); + uint32_t blks_per_seg = 1 << get_sb(log_blocks_per_seg); + uint32_t segs_per_zone = get_sb(segs_per_sec) * get_sb(secs_per_zone); + + set_sb(block_count, c.target_sectors >> + get_sb(log_sectors_per_block)); + + zone_size_bytes = segment_size_bytes * segs_per_zone; + zone_align_start_offset = + ((uint64_t) c.start_sector * DEFAULT_SECTOR_SIZE + + 2 * F2FS_BLKSIZE + zone_size_bytes - 1) / + zone_size_bytes * zone_size_bytes - + (uint64_t) c.start_sector * DEFAULT_SECTOR_SIZE; + + set_sb(segment_count, (c.target_sectors * c.sector_size - + zone_align_start_offset) / segment_size_bytes / + c.segs_per_sec * c.segs_per_sec); + + if (c.safe_resize) + goto safe_resize; + + blocks_for_sit = SIZE_ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK); + sit_segments = SEG_ALIGN(blocks_for_sit); + set_sb(segment_count_sit, sit_segments * 2); + set_sb(nat_blkaddr, get_sb(sit_blkaddr) + + get_sb(segment_count_sit) * blks_per_seg); + + total_valid_blks_available = (get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit))) * blks_per_seg; + blocks_for_nat = SIZE_ALIGN(total_valid_blks_available, + NAT_ENTRY_PER_BLOCK); + + if (c.large_nat_bitmap) { + nat_segments = SEG_ALIGN(blocks_for_nat) * + DEFAULT_NAT_ENTRY_RATIO / 100; + set_sb(segment_count_nat, nat_segments ? nat_segments : 1); + + max_nat_bitmap_size = (get_sb(segment_count_nat) << + get_sb(log_blocks_per_seg)) / 8; + set_sb(segment_count_nat, get_sb(segment_count_nat) * 2); + } else { + set_sb(segment_count_nat, SEG_ALIGN(blocks_for_nat)); + max_nat_bitmap_size = 0; + } + + sit_bitmap_size = ((get_sb(segment_count_sit) / 2) << + get_sb(log_blocks_per_seg)) / 8; + if (sit_bitmap_size > MAX_SIT_BITMAP_SIZE) + max_sit_bitmap_size = MAX_SIT_BITMAP_SIZE; + else + max_sit_bitmap_size = sit_bitmap_size; + + if (c.large_nat_bitmap) { + /* use cp_payload if free space of f2fs_checkpoint is not enough */ + if (max_sit_bitmap_size + max_nat_bitmap_size > + MAX_BITMAP_SIZE_IN_CKPT) { + uint32_t diff = max_sit_bitmap_size + + max_nat_bitmap_size - + MAX_BITMAP_SIZE_IN_CKPT; + set_sb(cp_payload, F2FS_BLK_ALIGN(diff)); + } else { + set_sb(cp_payload, 0); + } + } else { + /* + * It should be reserved minimum 1 segment for nat. + * When sit is too large, we should expand cp area. + * It requires more pages for cp. + */ + if (max_sit_bitmap_size > MAX_SIT_BITMAP_SIZE_IN_CKPT) { + max_nat_bitmap_size = MAX_BITMAP_SIZE_IN_CKPT; + set_sb(cp_payload, F2FS_BLK_ALIGN(max_sit_bitmap_size)); + } else { + max_nat_bitmap_size = MAX_BITMAP_SIZE_IN_CKPT - + max_sit_bitmap_size; + set_sb(cp_payload, 0); + } + + max_nat_segments = (max_nat_bitmap_size * 8) >> + get_sb(log_blocks_per_seg); + + if (get_sb(segment_count_nat) > max_nat_segments) + set_sb(segment_count_nat, max_nat_segments); + + set_sb(segment_count_nat, get_sb(segment_count_nat) * 2); + } + + set_sb(ssa_blkaddr, get_sb(nat_blkaddr) + + get_sb(segment_count_nat) * blks_per_seg); + + total_valid_blks_available = (get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat))) * blks_per_seg; + + blocks_for_ssa = total_valid_blks_available / blks_per_seg + 1; + + set_sb(segment_count_ssa, SEG_ALIGN(blocks_for_ssa)); + + total_meta_segments = get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat) + + get_sb(segment_count_ssa); + + diff = total_meta_segments % segs_per_zone; + if (diff) + set_sb(segment_count_ssa, get_sb(segment_count_ssa) + + (segs_per_zone - diff)); + + set_sb(main_blkaddr, get_sb(ssa_blkaddr) + get_sb(segment_count_ssa) * + blks_per_seg); + +safe_resize: + set_sb(segment_count_main, get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat) + + get_sb(segment_count_ssa))); + + set_sb(section_count, get_sb(segment_count_main) / + get_sb(segs_per_sec)); + + set_sb(segment_count_main, get_sb(section_count) * + get_sb(segs_per_sec)); + + /* Let's determine the best reserved and overprovisioned space */ + if (c.new_overprovision == 0) + c.new_overprovision = get_best_overprovision(sb); + + c.new_reserved_segments = + (100 / c.new_overprovision + 1 + NR_CURSEG_TYPE) * + get_sb(segs_per_sec); + + if ((get_sb(segment_count_main) - 2) < c.new_reserved_segments || + get_sb(segment_count_main) * blks_per_seg > + get_sb(block_count)) { + MSG(0, "\tError: Device size is not sufficient for F2FS volume, " + "more segment needed =%u", + c.new_reserved_segments - + (get_sb(segment_count_main) - 2)); + return -1; + } + return 0; +} + +static void migrate_main(struct f2fs_sb_info *sbi, unsigned int offset) +{ + void *raw = calloc(F2FS_BLKSIZE, 1); + struct seg_entry *se; + block_t from, to; + int i, j, ret; + struct f2fs_summary sum; + + ASSERT(raw != NULL); + + for (i = MAIN_SEGS(sbi) - 1; i >= 0; i--) { + se = get_seg_entry(sbi, i); + if (!se->valid_blocks) + continue; + + for (j = sbi->blocks_per_seg - 1; j >= 0; j--) { + if (!f2fs_test_bit(j, (const char *)se->cur_valid_map)) + continue; + + from = START_BLOCK(sbi, i) + j; + ret = dev_read_block(raw, from); + ASSERT(ret >= 0); + + to = from + offset; + ret = dev_write_block(raw, to, + f2fs_io_type_to_rw_hint(se->type)); + ASSERT(ret >= 0); + + get_sum_entry(sbi, from, &sum); + + if (IS_DATASEG(se->type)) + update_data_blkaddr(sbi, le32_to_cpu(sum.nid), + le16_to_cpu(sum.ofs_in_node), to, NULL); + else + update_nat_blkaddr(sbi, 0, + le32_to_cpu(sum.nid), to); + } + } + free(raw); + DBG(0, "Info: Done to migrate Main area: main_blkaddr = 0x%x -> 0x%x\n", + START_BLOCK(sbi, 0), + START_BLOCK(sbi, 0) + offset); +} + +static void move_ssa(struct f2fs_sb_info *sbi, unsigned int segno, + block_t new_sum_blk_addr) +{ + struct f2fs_summary_block *sum_blk; + int type; + + sum_blk = get_sum_block(sbi, segno, &type); + if (type < SEG_TYPE_MAX) { + int ret; + + ret = dev_write_block(sum_blk, new_sum_blk_addr, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + DBG(1, "Write summary block: (%d) segno=%x/%x --> (%d) %x\n", + type, segno, GET_SUM_BLKADDR(sbi, segno), + IS_SUM_NODE_SEG(sum_blk), + new_sum_blk_addr); + } + if (type == SEG_TYPE_NODE || type == SEG_TYPE_DATA || + type == SEG_TYPE_MAX) { + free(sum_blk); + } + DBG(1, "Info: Done to migrate SSA blocks\n"); +} + +static void migrate_ssa(struct f2fs_sb_info *sbi, + struct f2fs_super_block *new_sb, unsigned int offset) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + block_t old_sum_blkaddr = get_sb(ssa_blkaddr); + block_t new_sum_blkaddr = get_newsb(ssa_blkaddr); + block_t end_sum_blkaddr = get_newsb(main_blkaddr); + block_t expand_sum_blkaddr = new_sum_blkaddr + + MAIN_SEGS(sbi) - offset; + block_t blkaddr; + int ret; + void *zero_block = calloc(F2FS_BLKSIZE, 1); + ASSERT(zero_block); + + if (offset && new_sum_blkaddr < old_sum_blkaddr + offset) { + blkaddr = new_sum_blkaddr; + while (blkaddr < end_sum_blkaddr) { + if (blkaddr < expand_sum_blkaddr) { + move_ssa(sbi, offset++, blkaddr++); + } else { + ret = dev_write_block(zero_block, blkaddr++, + WRITE_LIFE_NONE); + ASSERT(ret >=0); + } + } + } else { + blkaddr = end_sum_blkaddr - 1; + offset = MAIN_SEGS(sbi) - 1; + while (blkaddr >= new_sum_blkaddr) { + if (blkaddr >= expand_sum_blkaddr) { + ret = dev_write_block(zero_block, blkaddr--, + WRITE_LIFE_NONE); + ASSERT(ret >=0); + } else { + move_ssa(sbi, offset--, blkaddr--); + } + } + } + + DBG(0, "Info: Done to migrate SSA blocks: sum_blkaddr = 0x%x -> 0x%x\n", + old_sum_blkaddr, new_sum_blkaddr); + free(zero_block); +} + +static int shrink_nats(struct f2fs_sb_info *sbi, + struct f2fs_super_block *new_sb) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + block_t old_nat_blkaddr = get_sb(nat_blkaddr); + unsigned int nat_blocks; + void *nat_block, *zero_block; + int nid, ret, new_max_nid; + pgoff_t block_off; + pgoff_t block_addr; + int seg_off; + + nat_block = malloc(F2FS_BLKSIZE); + ASSERT(nat_block); + zero_block = calloc(F2FS_BLKSIZE, 1); + ASSERT(zero_block); + + nat_blocks = get_newsb(segment_count_nat) >> 1; + nat_blocks = nat_blocks << get_sb(log_blocks_per_seg); + new_max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; + + for (nid = nm_i->max_nid - 1; nid > new_max_nid; nid -= NAT_ENTRY_PER_BLOCK) { + block_off = nid / NAT_ENTRY_PER_BLOCK; + seg_off = block_off >> sbi->log_blocks_per_seg; + block_addr = (pgoff_t)(old_nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) + block_addr += sbi->blocks_per_seg; + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + if (memcmp(zero_block, nat_block, F2FS_BLKSIZE)) { + ret = -1; + goto not_avail; + } + } + ret = 0; + nm_i->max_nid = new_max_nid; +not_avail: + free(nat_block); + free(zero_block); + return ret; +} + +static void migrate_nat(struct f2fs_sb_info *sbi, + struct f2fs_super_block *new_sb) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_nm_info *nm_i = NM_I(sbi); + block_t old_nat_blkaddr = get_sb(nat_blkaddr); + block_t new_nat_blkaddr = get_newsb(nat_blkaddr); + unsigned int nat_blocks; + void *nat_block; + int nid, ret, new_max_nid; + pgoff_t block_off; + pgoff_t block_addr; + int seg_off; + + nat_block = malloc(F2FS_BLKSIZE); + ASSERT(nat_block); + + for (nid = nm_i->max_nid - 1; nid >= 0; nid -= NAT_ENTRY_PER_BLOCK) { + block_off = nid / NAT_ENTRY_PER_BLOCK; + seg_off = block_off >> sbi->log_blocks_per_seg; + block_addr = (pgoff_t)(old_nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + /* move to set #0 */ + if (f2fs_test_bit(block_off, nm_i->nat_bitmap)) { + block_addr += sbi->blocks_per_seg; + f2fs_clear_bit(block_off, nm_i->nat_bitmap); + } + + ret = dev_read_block(nat_block, block_addr); + ASSERT(ret >= 0); + + block_addr = (pgoff_t)(new_nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + + /* new bitmap should be zeros */ + ret = dev_write_block(nat_block, block_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + /* zero out newly assigned nids */ + memset(nat_block, 0, F2FS_BLKSIZE); + nat_blocks = get_newsb(segment_count_nat) >> 1; + nat_blocks = nat_blocks << get_sb(log_blocks_per_seg); + new_max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks; + + DBG(1, "Write NAT block: %x->%x, max_nid=%x->%x\n", + old_nat_blkaddr, new_nat_blkaddr, + get_sb(segment_count_nat), + get_newsb(segment_count_nat)); + + for (nid = nm_i->max_nid; nid < new_max_nid; + nid += NAT_ENTRY_PER_BLOCK) { + block_off = nid / NAT_ENTRY_PER_BLOCK; + seg_off = block_off >> sbi->log_blocks_per_seg; + block_addr = (pgoff_t)(new_nat_blkaddr + + (seg_off << sbi->log_blocks_per_seg << 1) + + (block_off & ((1 << sbi->log_blocks_per_seg) - 1))); + ret = dev_write_block(nat_block, block_addr, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + DBG(3, "Write NAT: %lx\n", block_addr); + } + free(nat_block); + DBG(0, "Info: Done to migrate NAT blocks: nat_blkaddr = 0x%x -> 0x%x\n", + old_nat_blkaddr, new_nat_blkaddr); +} + +static void migrate_sit(struct f2fs_sb_info *sbi, + struct f2fs_super_block *new_sb, unsigned int offset) +{ + struct sit_info *sit_i = SIT_I(sbi); + unsigned int ofs = 0, pre_ofs = 0; + unsigned int segno, index; + struct f2fs_sit_block *sit_blk = calloc(F2FS_BLKSIZE, 1); + block_t sit_blks = get_newsb(segment_count_sit) << + (sbi->log_blocks_per_seg - 1); + struct seg_entry *se; + block_t blk_addr = 0; + int ret; + + ASSERT(sit_blk); + + /* initialize with zeros */ + for (index = 0; index < sit_blks; index++) { + ret = dev_write_block(sit_blk, get_newsb(sit_blkaddr) + index, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + DBG(3, "Write zero sit: %x\n", get_newsb(sit_blkaddr) + index); + } + + for (segno = 0; segno < MAIN_SEGS(sbi); segno++) { + struct f2fs_sit_entry *sit; + + se = get_seg_entry(sbi, segno); + if (segno < offset) { + ASSERT(se->valid_blocks == 0); + continue; + } + + ofs = SIT_BLOCK_OFFSET(sit_i, segno - offset); + + if (ofs != pre_ofs) { + blk_addr = get_newsb(sit_blkaddr) + pre_ofs; + ret = dev_write_block(sit_blk, blk_addr, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + DBG(1, "Write valid sit: %x\n", blk_addr); + + pre_ofs = ofs; + memset(sit_blk, 0, F2FS_BLKSIZE); + } + + sit = &sit_blk->entries[SIT_ENTRY_OFFSET(sit_i, segno - offset)]; + memcpy(sit->valid_map, se->cur_valid_map, SIT_VBLOCK_MAP_SIZE); + sit->vblocks = cpu_to_le16((se->type << SIT_VBLOCKS_SHIFT) | + se->valid_blocks); + } + blk_addr = get_newsb(sit_blkaddr) + ofs; + ret = dev_write_block(sit_blk, blk_addr, WRITE_LIFE_NONE); + DBG(1, "Write valid sit: %x\n", blk_addr); + ASSERT(ret >= 0); + + free(sit_blk); + DBG(0, "Info: Done to restore new SIT blocks: 0x%x\n", + get_newsb(sit_blkaddr)); +} + +static void rebuild_checkpoint(struct f2fs_sb_info *sbi, + struct f2fs_super_block *new_sb, unsigned int offset) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + unsigned long long cp_ver = get_cp(checkpoint_ver); + struct f2fs_checkpoint *new_cp; + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + unsigned int free_segment_count, new_segment_count; + block_t new_cp_blks = 1 + get_newsb(cp_payload); + block_t orphan_blks = 0; + block_t new_cp_blk_no, old_cp_blk_no; + uint32_t crc = 0; + u32 flags; + void *buf; + int i, ret; + + new_cp = calloc(new_cp_blks * F2FS_BLKSIZE, 1); + ASSERT(new_cp); + + buf = malloc(F2FS_BLKSIZE); + ASSERT(buf); + + /* ovp / free segments */ + set_cp(rsvd_segment_count, c.new_reserved_segments); + set_cp(overprov_segment_count, (get_newsb(segment_count_main) - + get_cp(rsvd_segment_count)) * + c.new_overprovision / 100); + + /* give 2 sections (DATA and NODE) to trigger GC in advance */ + if (get_cp(overprov_segment_count) < get_cp(rsvd_segment_count)) + set_cp(overprov_segment_count, get_cp(rsvd_segment_count)); + + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + + 2 * get_sb(segs_per_sec)); + + DBG(0, "Info: Overprovision ratio = %.3lf%%\n", c.new_overprovision); + DBG(0, "Info: Overprovision segments = %u (GC reserved = %u)\n", + get_cp(overprov_segment_count), + c.new_reserved_segments); + + free_segment_count = get_free_segments(sbi); + new_segment_count = get_newsb(segment_count_main) - + get_sb(segment_count_main); + + set_cp(free_segment_count, free_segment_count + new_segment_count); + set_cp(user_block_count, ((get_newsb(segment_count_main) - + get_cp(overprov_segment_count)) * c.blks_per_seg)); + + if (is_set_ckpt_flags(cp, CP_ORPHAN_PRESENT_FLAG)) + orphan_blks = __start_sum_addr(sbi) - 1; + + set_cp(cp_pack_start_sum, 1 + get_newsb(cp_payload)); + set_cp(cp_pack_total_block_count, 8 + orphan_blks + get_newsb(cp_payload)); + + /* cur->segno - offset */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + if (i < CURSEG_HOT_NODE) { + set_cp(cur_data_segno[i], + CURSEG_I(sbi, i)->segno - offset); + } else { + int n = i - CURSEG_HOT_NODE; + + set_cp(cur_node_segno[n], + CURSEG_I(sbi, i)->segno - offset); + } + } + + /* sit / nat ver bitmap bytesize */ + set_cp(sit_ver_bitmap_bytesize, + ((get_newsb(segment_count_sit) / 2) << + get_newsb(log_blocks_per_seg)) / 8); + set_cp(nat_ver_bitmap_bytesize, + ((get_newsb(segment_count_nat) / 2) << + get_newsb(log_blocks_per_seg)) / 8); + + /* update nat_bits flag */ + flags = update_nat_bits_flags(new_sb, cp, get_cp(ckpt_flags)); + if (flags & CP_COMPACT_SUM_FLAG) + flags &= ~CP_COMPACT_SUM_FLAG; + if (flags & CP_LARGE_NAT_BITMAP_FLAG) + set_cp(checksum_offset, CP_MIN_CHKSUM_OFFSET); + else + set_cp(checksum_offset, CP_CHKSUM_OFFSET); + + set_cp(ckpt_flags, flags); + + memcpy(new_cp, cp, (unsigned char *)cp->sit_nat_version_bitmap - + (unsigned char *)cp); + if (c.safe_resize) + memcpy((void *)new_cp + CP_BITMAP_OFFSET, + (void *)cp + CP_BITMAP_OFFSET, + F2FS_BLKSIZE - CP_BITMAP_OFFSET); + + new_cp->checkpoint_ver = cpu_to_le64(cp_ver + 1); + + crc = f2fs_checkpoint_chksum(new_cp); + *((__le32 *)((unsigned char *)new_cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + + /* Write a new checkpoint in the other set */ + new_cp_blk_no = old_cp_blk_no = get_sb(cp_blkaddr); + if (sbi->cur_cp == 2) + old_cp_blk_no += 1 << get_sb(log_blocks_per_seg); + else + new_cp_blk_no += 1 << get_sb(log_blocks_per_seg); + + /* write first cp */ + ret = dev_write_block(new_cp, new_cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + memset(buf, 0, F2FS_BLKSIZE); + for (i = 0; i < get_newsb(cp_payload); i++) { + ret = dev_write_block(buf, new_cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + + for (i = 0; i < orphan_blks; i++) { + block_t orphan_blk_no = old_cp_blk_no + 1 + get_sb(cp_payload); + + ret = dev_read_block(buf, orphan_blk_no++); + ASSERT(ret >= 0); + + ret = dev_write_block(buf, new_cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + + /* update summary blocks having nullified journal entries */ + for (i = 0; i < NO_CHECK_TYPE; i++) { + struct curseg_info *curseg = CURSEG_I(sbi, i); + + ret = dev_write_block(curseg->sum_blk, new_cp_blk_no++, + WRITE_LIFE_NONE); + ASSERT(ret >= 0); + } + + /* write the last cp */ + ret = dev_write_block(new_cp, new_cp_blk_no++, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + /* Write nat bits */ + if (flags & CP_NAT_BITS_FLAG) + write_nat_bits(sbi, new_sb, new_cp, sbi->cur_cp == 1 ? 2 : 1); + + /* disable old checkpoint */ + memset(buf, 0, F2FS_BLKSIZE); + ret = dev_write_block(buf, old_cp_blk_no, WRITE_LIFE_NONE); + ASSERT(ret >= 0); + + free(buf); + free(new_cp); + DBG(0, "Info: Done to rebuild checkpoint blocks\n"); +} + +static int f2fs_resize_check(struct f2fs_sb_info *sbi, struct f2fs_super_block *new_sb) +{ + struct f2fs_checkpoint *cp = F2FS_CKPT(sbi); + block_t user_block_count; + unsigned int overprov_segment_count; + + overprov_segment_count = (get_newsb(segment_count_main) - + c.new_reserved_segments) * + c.new_overprovision / 100; + + overprov_segment_count += 2 * get_newsb(segs_per_sec); + + user_block_count = (get_newsb(segment_count_main) - + overprov_segment_count) * c.blks_per_seg; + + if (get_cp(valid_block_count) > user_block_count) + return -1; + + return 0; +} + +static int f2fs_resize_grow(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_super_block new_sb_raw; + struct f2fs_super_block *new_sb = &new_sb_raw; + block_t end_blkaddr, old_main_blkaddr, new_main_blkaddr; + unsigned int offset; + unsigned int offset_seg = 0; + int err = -1; + + /* flush NAT/SIT journal entries */ + flush_journal_entries(sbi); + + memcpy(new_sb, F2FS_RAW_SUPER(sbi), sizeof(*new_sb)); + if (get_new_sb(new_sb)) + return -1; + + if (f2fs_resize_check(sbi, new_sb) < 0) + return -1; + + /* check nat availability */ + if (get_sb(segment_count_nat) > get_newsb(segment_count_nat)) { + err = shrink_nats(sbi, new_sb); + if (err) { + MSG(0, "\tError: Failed to shrink NATs\n"); + return err; + } + } + + old_main_blkaddr = get_sb(main_blkaddr); + new_main_blkaddr = get_newsb(main_blkaddr); + offset = new_main_blkaddr - old_main_blkaddr; + end_blkaddr = (get_sb(segment_count_main) << + get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr); + + err = -EAGAIN; + if (new_main_blkaddr < end_blkaddr) { + err = f2fs_defragment(sbi, old_main_blkaddr, offset, + new_main_blkaddr, 0); + if (!err) + offset_seg = offset >> get_sb(log_blocks_per_seg); + MSG(0, "Try to do defragement: %s\n", err ? "Skip": "Done"); + } + /* move whole data region */ + if (err) + migrate_main(sbi, offset); + + migrate_ssa(sbi, new_sb, offset_seg); + migrate_nat(sbi, new_sb); + migrate_sit(sbi, new_sb, offset_seg); + rebuild_checkpoint(sbi, new_sb, offset_seg); + update_superblock(new_sb, SB_MASK_ALL); + print_raw_sb_info(sb); + print_raw_sb_info(new_sb); + + return 0; +} + +static int f2fs_resize_shrink(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_super_block new_sb_raw; + struct f2fs_super_block *new_sb = &new_sb_raw; + block_t old_end_blkaddr, old_main_blkaddr; + block_t new_end_blkaddr, new_main_blkaddr, tmp_end_blkaddr; + unsigned int offset; + int err = -1; + + /* flush NAT/SIT journal entries */ + flush_journal_entries(sbi); + + memcpy(new_sb, F2FS_RAW_SUPER(sbi), sizeof(*new_sb)); + if (get_new_sb(new_sb)) + return -1; + + if (f2fs_resize_check(sbi, new_sb) < 0) + return -1; + + /* check nat availability */ + if (get_sb(segment_count_nat) > get_newsb(segment_count_nat)) { + err = shrink_nats(sbi, new_sb); + if (err) { + MSG(0, "\tError: Failed to shrink NATs\n"); + return err; + } + } + + old_main_blkaddr = get_sb(main_blkaddr); + new_main_blkaddr = get_newsb(main_blkaddr); + offset = old_main_blkaddr - new_main_blkaddr; + old_end_blkaddr = (get_sb(segment_count_main) << + get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr); + new_end_blkaddr = (get_newsb(segment_count_main) << + get_newsb(log_blocks_per_seg)) + get_newsb(main_blkaddr); + + tmp_end_blkaddr = new_end_blkaddr + offset; + err = f2fs_defragment(sbi, tmp_end_blkaddr, + old_end_blkaddr - tmp_end_blkaddr, + tmp_end_blkaddr, 1); + MSG(0, "Try to do defragement: %s\n", err ? "Insufficient Space": "Done"); + + if (err) { + return -ENOSPC; + } + + update_superblock(new_sb, SB_MASK_ALL); + rebuild_checkpoint(sbi, new_sb, 0); + /*if (!c.safe_resize) { + migrate_sit(sbi, new_sb, offset_seg); + migrate_nat(sbi, new_sb); + migrate_ssa(sbi, new_sb, offset_seg); + }*/ + + /* move whole data region */ + //if (err) + // migrate_main(sbi, offset); + print_raw_sb_info(sb); + print_raw_sb_info(new_sb); + + return 0; +} + +int f2fs_resize(struct f2fs_sb_info *sbi) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + + /* may different sector size */ + if ((c.target_sectors * c.sector_size >> + get_sb(log_blocksize)) < get_sb(block_count)) { + if (!c.safe_resize) { + ASSERT_MSG("Nothing to resize, now only supports resizing with safe resize flag\n"); + return -1; + } else { + return f2fs_resize_shrink(sbi); + } + } else if (((c.target_sectors * c.sector_size >> + get_sb(log_blocksize)) > get_sb(block_count)) || + c.ignore_error) { + if (c.safe_resize) { + ASSERT_MSG("Expanding resize doesn't support safe resize flag"); + return -1; + } + return f2fs_resize_grow(sbi); + } else { + MSG(0, "Nothing to resize.\n"); + return 0; + } +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/segment.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/segment.c new file mode 100644 index 00000000000..96de22a380c --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/segment.c @@ -0,0 +1,826 @@ +/** + * segment.c + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add sload compression support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "node.h" +#include "quotaio.h" + +int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to, + struct f2fs_summary *sum, int type, bool is_inode) +{ + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); + struct seg_entry *se; + u64 blkaddr, offset; + u64 old_blkaddr = *to; + bool is_node = IS_NODESEG(type); + int left = 0; + + if (old_blkaddr == NULL_ADDR) { + if (c.func == FSCK) { + if (fsck->chk.valid_blk_cnt >= sbi->user_block_count) { + ERR_MSG("Not enough space\n"); + return -ENOSPC; + } + if (is_node && fsck->chk.valid_node_cnt >= + sbi->total_node_count) { + ERR_MSG("Not enough space for node block\n"); + return -ENOSPC; + } + } else { + if (sbi->total_valid_block_count >= + sbi->user_block_count) { + ERR_MSG("Not enough space\n"); + return -ENOSPC; + } + if (is_node && sbi->total_valid_node_count >= + sbi->total_node_count) { + ERR_MSG("Not enough space for node block\n"); + return -ENOSPC; + } + } + } + + blkaddr = SM_I(sbi)->main_blkaddr; + + if (le32_to_cpu(sbi->raw_super->feature) & F2FS_FEATURE_RO) { + if (IS_NODESEG(type)) { + type = CURSEG_HOT_NODE; + blkaddr = __end_block_addr(sbi); + left = 1; + } else if (IS_DATASEG(type)) { + type = CURSEG_HOT_DATA; + blkaddr = SM_I(sbi)->main_blkaddr; + left = 0; + } + } + + if (find_next_free_block(sbi, &blkaddr, left, type, false)) { + ERR_MSG("Can't find free block"); + ASSERT(0); + } + + se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr)); + offset = OFFSET_IN_SEG(sbi, blkaddr); + se->type = se->orig_type = type; + if (se->valid_blocks == 0) + SM_I(sbi)->free_segments--; + se->valid_blocks++; + f2fs_set_bit(offset, (char *)se->cur_valid_map); + if (need_fsync_data_record(sbi)) { + se->ckpt_type = type; + se->ckpt_valid_blocks++; + f2fs_set_bit(offset, (char *)se->ckpt_valid_map); + } + if (c.func == FSCK) { + f2fs_set_main_bitmap(sbi, blkaddr, type); + f2fs_set_sit_bitmap(sbi, blkaddr); + } + + if (old_blkaddr == NULL_ADDR) { + sbi->total_valid_block_count++; + if (is_node) { + sbi->total_valid_node_count++; + if (is_inode) + sbi->total_valid_inode_count++; + } + if (c.func == FSCK) { + fsck->chk.valid_blk_cnt++; + if (is_node) { + fsck->chk.valid_nat_entry_cnt++; + fsck->chk.valid_node_cnt++; + if (is_inode) + fsck->chk.valid_inode_cnt++; + } + } + } + se->dirty = 1; + + /* read/write SSA */ + *to = (block_t)blkaddr; + update_sum_entry(sbi, *to, sum); + + return 0; +} + +int new_data_block(struct f2fs_sb_info *sbi, void *block, + struct dnode_of_data *dn, int type) +{ + struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi); + struct f2fs_summary sum; + struct node_info ni; + unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node); + int ret; + + if ((get_sb(feature) & F2FS_FEATURE_RO) && + type != CURSEG_HOT_DATA) + type = CURSEG_HOT_DATA; + + ASSERT(dn->node_blk); + memset(block, 0, F2FS_BLKSIZE); + + get_node_info(sbi, dn->nid, &ni); + set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); + + dn->data_blkaddr = blkaddr; + ret = reserve_new_block(sbi, &dn->data_blkaddr, &sum, type, 0); + if (ret) { + c.alloc_failed = 1; + return ret; + } + + if (blkaddr == NULL_ADDR) + inc_inode_blocks(dn); + else if (blkaddr == NEW_ADDR) + dn->idirty = 1; + set_data_blkaddr(dn); + return 0; +} + +u64 f2fs_quota_size(struct quota_file *qf) +{ + struct node_info ni; + struct f2fs_node *inode; + u64 filesize; + + inode = (struct f2fs_node *) calloc(F2FS_BLKSIZE, 1); + ASSERT(inode); + + /* Read inode */ + get_node_info(qf->sbi, qf->ino, &ni); + ASSERT(dev_read_block(inode, ni.blk_addr) >= 0); + ASSERT(S_ISREG(le16_to_cpu(inode->i.i_mode))); + + filesize = le64_to_cpu(inode->i.i_size); + free(inode); + return filesize; +} + +u64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer, + u64 count, pgoff_t offset) +{ + struct dnode_of_data dn; + struct node_info ni; + struct f2fs_node *inode; + char *blk_buffer; + u64 filesize; + u64 off_in_blk; + u64 len_in_blk; + u64 read_count; + u64 remained_blkentries; + block_t blkaddr; + void *index_node = NULL; + + memset(&dn, 0, sizeof(dn)); + + /* Memory allocation for block buffer and inode. */ + blk_buffer = calloc(F2FS_BLKSIZE, 2); + ASSERT(blk_buffer); + inode = (struct f2fs_node*)(blk_buffer + F2FS_BLKSIZE); + + /* Read inode */ + get_node_info(sbi, ino, &ni); + ASSERT(dev_read_block(inode, ni.blk_addr) >= 0); + ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode))); + ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode))); + + /* Adjust count with file length. */ + filesize = le64_to_cpu(inode->i.i_size); + if (offset > filesize) + count = 0; + else if (count + offset > filesize) + count = filesize - offset; + + /* Main loop for file blocks */ + read_count = remained_blkentries = 0; + while (count > 0) { + if (remained_blkentries == 0) { + set_new_dnode(&dn, inode, NULL, ino); + get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset), + LOOKUP_NODE); + if (index_node) + free(index_node); + index_node = (dn.node_blk == dn.inode_blk) ? + NULL : dn.node_blk; + remained_blkentries = ADDRS_PER_PAGE(sbi, + dn.node_blk, dn.inode_blk); + } + ASSERT(remained_blkentries > 0); + + blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node); + if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) + break; + + off_in_blk = offset % F2FS_BLKSIZE; + len_in_blk = F2FS_BLKSIZE - off_in_blk; + if (len_in_blk > count) + len_in_blk = count; + + /* Read data from single block. */ + if (len_in_blk < F2FS_BLKSIZE) { + ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0); + memcpy(buffer, blk_buffer + off_in_blk, len_in_blk); + } else { + /* Direct read */ + ASSERT(dev_read_block(buffer, blkaddr) >= 0); + } + + offset += len_in_blk; + count -= len_in_blk; + buffer += len_in_blk; + read_count += len_in_blk; + + dn.ofs_in_node++; + remained_blkentries--; + } + if (index_node) + free(index_node); + free(blk_buffer); + + return read_count; +} + +/* + * Do not call this function directly. Instead, call one of the following: + * u64 f2fs_write(); + * u64 f2fs_write_compress_data(); + * u64 f2fs_write_addrtag(); + */ +static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer, + u64 count, pgoff_t offset, enum wr_addr_type addr_type) +{ + struct dnode_of_data dn; + struct node_info ni; + struct f2fs_node *inode; + char *blk_buffer; + void *wbuf; + u64 off_in_blk; + u64 len_in_blk; + u64 written_count; + u64 remained_blkentries; + block_t blkaddr; + void* index_node = NULL; + int idirty = 0; + int err, ret; + bool datablk_alloced = false; + bool has_data = (addr_type == WR_NORMAL + || addr_type == WR_COMPRESS_DATA); + + if (count == 0) + return 0; + + /* + * Enforce calling from f2fs_write(), f2fs_write_compress_data(), + * and f2fs_write_addrtag(). Beside, check if is properly called. + */ + ASSERT((!has_data && buffer == NULL) || (has_data && buffer != NULL)); + if (addr_type != WR_NORMAL) + ASSERT(offset % F2FS_BLKSIZE == 0); /* block boundary only */ + + /* Memory allocation for block buffer and inode. */ + blk_buffer = calloc(F2FS_BLKSIZE, 2); + ASSERT(blk_buffer); + inode = (struct f2fs_node*)(blk_buffer + F2FS_BLKSIZE); + + /* Read inode */ + get_node_info(sbi, ino, &ni); + ASSERT(dev_read_block(inode, ni.blk_addr) >= 0); + ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode))); + ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode))); + + /* Main loop for file blocks */ + written_count = remained_blkentries = 0; + while (count > 0) { + if (remained_blkentries == 0) { + set_new_dnode(&dn, inode, NULL, ino); + err = get_dnode_of_data(sbi, &dn, + F2FS_BYTES_TO_BLK(offset), ALLOC_NODE); + if (err) + break; + idirty |= dn.idirty; + free(index_node); + index_node = (dn.node_blk == dn.inode_blk) ? + NULL : dn.node_blk; + remained_blkentries = ADDRS_PER_PAGE(sbi, + dn.node_blk, dn.inode_blk) - + dn.ofs_in_node; + } + ASSERT(remained_blkentries > 0); + + if (!has_data) { + struct seg_entry *se; + + se = get_seg_entry(sbi, GET_SEGNO(sbi, dn.node_blkaddr)); + dn.data_blkaddr = addr_type; + set_data_blkaddr(&dn); + idirty |= dn.idirty; + if (dn.ndirty) { + ret = dn.alloced ? dev_write_block(dn.node_blk, + dn.node_blkaddr, + f2fs_io_type_to_rw_hint(se->type)) : + update_block(sbi, dn.node_blk, + &dn.node_blkaddr, NULL); + ASSERT(ret >= 0); + } + written_count = 0; + break; + } + + datablk_alloced = false; + blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node); + if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) { + err = new_data_block(sbi, blk_buffer, + &dn, CURSEG_WARM_DATA); + if (err) + break; + blkaddr = dn.data_blkaddr; + idirty |= dn.idirty; + datablk_alloced = true; + } + + off_in_blk = offset % F2FS_BLKSIZE; + len_in_blk = F2FS_BLKSIZE - off_in_blk; + if (len_in_blk > count) + len_in_blk = count; + + /* Write data to single block. */ + if (len_in_blk < F2FS_BLKSIZE) { + ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0); + memcpy(blk_buffer + off_in_blk, buffer, len_in_blk); + wbuf = blk_buffer; + } else { + /* Direct write */ + wbuf = buffer; + } + + if (c.zoned_model == F2FS_ZONED_HM) { + if (datablk_alloced) { + ret = dev_write_block(wbuf, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_WARM_DATA)); + } else { + ret = update_block(sbi, wbuf, &blkaddr, + dn.node_blk); + if (dn.inode_blk == dn.node_blk) + idirty = 1; + else + dn.ndirty = 1; + } + } else { + ret = dev_write_block(wbuf, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_WARM_DATA)); + } + ASSERT(ret >= 0); + + offset += len_in_blk; + count -= len_in_blk; + buffer += len_in_blk; + written_count += len_in_blk; + + dn.ofs_in_node++; + if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty)) { + struct seg_entry *se; + se = get_seg_entry(sbi, GET_SEGNO(sbi, dn.node_blkaddr)); + ret = dn.alloced ? + dev_write_block(dn.node_blk, dn.node_blkaddr, + f2fs_io_type_to_rw_hint(se->type)) : + update_block(sbi, dn.node_blk, &dn.node_blkaddr, NULL); + ASSERT(ret >= 0); + } + } + + if (addr_type == WR_NORMAL && offset > le64_to_cpu(inode->i.i_size)) { + inode->i.i_size = cpu_to_le64(offset); + idirty = 1; + } + if (idirty) { + get_node_info(sbi, ino, &ni); + ASSERT(inode == dn.inode_blk); + ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0); + } + + free(index_node); + free(blk_buffer); + + return written_count; +} + +u64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer, + u64 count, pgoff_t offset) +{ + return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_NORMAL); +} + +u64 f2fs_write_compress_data(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer, + u64 count, pgoff_t offset) +{ + return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_COMPRESS_DATA); +} + +u64 f2fs_write_addrtag(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset, + unsigned int addrtag) +{ + ASSERT(addrtag == COMPRESS_ADDR || addrtag == NEW_ADDR + || addrtag == NULL_ADDR); + return f2fs_write_ex(sbi, ino, NULL, F2FS_BLKSIZE, offset, addrtag); +} + +/* This function updates only inode->i.i_size */ +void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize) +{ + struct node_info ni; + struct f2fs_node *inode; + + inode = calloc(F2FS_BLKSIZE, 1); + ASSERT(inode); + get_node_info(sbi, ino, &ni); + + ASSERT(dev_read_block(inode, ni.blk_addr) >= 0); + ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode))); + ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode))); + + inode->i.i_size = cpu_to_le64(filesize); + + ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0); + free(inode); +} + +#define MAX_BULKR_RETRY 5 +int bulkread(int fd, void *rbuf, size_t rsize, bool *eof) +{ + int n = 0; + int retry = MAX_BULKR_RETRY; + int cur; + + if (!rsize) + return 0; + + if (eof != NULL) + *eof = false; + while (rsize && (cur = read(fd, rbuf, rsize)) != 0) { + if (cur == -1) { + if (errno == EINTR && retry--) + continue; + return -1; + } + retry = MAX_BULKR_RETRY; + + rsize -= cur; + n += cur; + } + if (eof != NULL) + *eof = (cur == 0); + return n; +} + +u64 f2fs_fix_mutable(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset, + unsigned int compressed) +{ + unsigned int i; + u64 wlen; + + if (c.compress.readonly) + return 0; + + for (i = 0; i < compressed - 1; i++) { + wlen = f2fs_write_addrtag(sbi, ino, + offset + (i << F2FS_BLKSIZE_BITS), NEW_ADDR); + if (wlen) + return wlen; + } + return 0; +} + +static inline int is_consecutive(u32 prev_addr, u32 cur_addr) +{ + if (is_valid_data_blkaddr(cur_addr) && (cur_addr == prev_addr + 1)) + return 1; + return 0; +} + +static inline void copy_extent_info(struct extent_info *t_ext, + struct extent_info *s_ext) +{ + t_ext->fofs = s_ext->fofs; + t_ext->blk = s_ext->blk; + t_ext->len = s_ext->len; +} + +static inline void update_extent_info(struct f2fs_node *inode, + struct extent_info *ext) +{ + inode->i.i_ext.fofs = cpu_to_le32(ext->fofs); + inode->i.i_ext.blk_addr = cpu_to_le32(ext->blk); + inode->i.i_ext.len = cpu_to_le32(ext->len); +} + +static void update_largest_extent(struct f2fs_sb_info *sbi, nid_t ino) +{ + struct dnode_of_data dn; + struct node_info ni; + struct f2fs_node *inode; + u32 blkaddr, prev_blkaddr, cur_blk = 0, end_blk; + struct extent_info largest_ext = { 0, }, cur_ext = { 0, }; + u64 remained_blkentries = 0; + u32 cluster_size; + int count; + void *index_node = NULL; + + memset(&dn, 0, sizeof(dn)); + largest_ext.len = cur_ext.len = 0; + + inode = (struct f2fs_node *) calloc(F2FS_BLKSIZE, 1); + ASSERT(inode); + + /* Read inode info */ + get_node_info(sbi, ino, &ni); + ASSERT(dev_read_block(inode, ni.blk_addr) >= 0); + cluster_size = 1 << inode->i.i_log_cluster_size; + + if (inode->i.i_inline & F2FS_INLINE_DATA) + goto exit; + + end_blk = f2fs_max_file_offset(&inode->i) >> F2FS_BLKSIZE_BITS; + + while (cur_blk <= end_blk) { + if (remained_blkentries == 0) { + set_new_dnode(&dn, inode, NULL, ino); + get_dnode_of_data(sbi, &dn, cur_blk, LOOKUP_NODE); + if (index_node) + free(index_node); + index_node = (dn.node_blk == dn.inode_blk) ? + NULL : dn.node_blk; + remained_blkentries = ADDRS_PER_PAGE(sbi, + dn.node_blk, dn.inode_blk); + } + ASSERT(remained_blkentries > 0); + + blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node); + if (cur_ext.len > 0) { + if (is_consecutive(prev_blkaddr, blkaddr)) + cur_ext.len++; + else { + if (cur_ext.len > largest_ext.len) + copy_extent_info(&largest_ext, + &cur_ext); + cur_ext.len = 0; + } + } + + if (cur_ext.len == 0 && is_valid_data_blkaddr(blkaddr)) { + cur_ext.fofs = cur_blk; + cur_ext.len = 1; + cur_ext.blk = blkaddr; + } + + prev_blkaddr = blkaddr; + count = blkaddr == COMPRESS_ADDR ? cluster_size : 1; + cur_blk += count; + dn.ofs_in_node += count; + remained_blkentries -= count; + } + +exit: + if (cur_ext.len > largest_ext.len) + copy_extent_info(&largest_ext, &cur_ext); + if (largest_ext.len > 0) { + update_extent_info(inode, &largest_ext); + ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0); + } + + if (index_node) + free(index_node); + free(inode); +} + +int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de) +{ + int fd, n = -1; + pgoff_t off = 0; + u8 buffer[F2FS_BLKSIZE]; + struct node_info ni; + struct f2fs_node *node_blk; + + if (de->ino == 0) + return -1; + + if (de->from_devino) { + struct hardlink_cache_entry *found_hardlink; + + found_hardlink = f2fs_search_hardlink(sbi, de); + if (found_hardlink && found_hardlink->to_ino && + found_hardlink->nbuild) + return 0; + + found_hardlink->nbuild++; + } + + fd = open(de->full_path, O_RDONLY); + if (fd < 0) { + MSG(0, "Skip: Fail to open %s\n", de->full_path); + return -1; + } + + /* inline_data support */ + if (de->size <= DEF_MAX_INLINE_DATA) { + int ret; + + get_node_info(sbi, de->ino, &ni); + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + ret = dev_read_block(node_blk, ni.blk_addr); + ASSERT(ret >= 0); + + node_blk->i.i_inline |= F2FS_INLINE_DATA; + node_blk->i.i_inline |= F2FS_DATA_EXIST; + + if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { + node_blk->i.i_inline |= F2FS_EXTRA_ATTR; + node_blk->i.i_extra_isize = + cpu_to_le16(calc_extra_isize()); + } + n = read(fd, buffer, F2FS_BLKSIZE); + ASSERT((unsigned long)n == de->size); + memcpy(inline_data_addr(node_blk), buffer, de->size); + node_blk->i.i_size = cpu_to_le64(de->size); + ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0); + free(node_blk); +#ifdef WITH_SLOAD + } else if (c.func == SLOAD && c.compress.enabled && + c.compress.filter_ops->filter(de->full_path)) { + bool eof = false; + u8 *rbuf = c.compress.cc.rbuf; + unsigned int cblocks = 0; + + node_blk = calloc(F2FS_BLKSIZE, 1); + ASSERT(node_blk); + + /* read inode */ + get_node_info(sbi, de->ino, &ni); + ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0); + /* update inode meta */ + node_blk->i.i_compress_algorithm = c.compress.alg; + node_blk->i.i_log_cluster_size = + c.compress.cc.log_cluster_size; + node_blk->i.i_flags = cpu_to_le32(F2FS_COMPR_FL); + if (c.compress.readonly) + node_blk->i.i_inline |= F2FS_COMPRESS_RELEASED; + ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0); + + while (!eof && (n = bulkread(fd, rbuf, c.compress.cc.rlen, + &eof)) > 0) { + int ret = c.compress.ops->compress(&c.compress.cc); + u64 wlen; + u32 csize = ALIGN_UP(c.compress.cc.clen + + COMPRESS_HEADER_SIZE, F2FS_BLKSIZE); + unsigned int cur_cblk; + + if (ret || n < c.compress.cc.rlen || + n < (int)(csize + F2FS_BLKSIZE * + c.compress.min_blocks)) { + wlen = f2fs_write(sbi, de->ino, rbuf, n, off); + ASSERT((int)wlen == n); + } else { + wlen = f2fs_write_addrtag(sbi, de->ino, off, + WR_COMPRESS_ADDR); + ASSERT(!wlen); + wlen = f2fs_write_compress_data(sbi, de->ino, + (u8 *)c.compress.cc.cbuf, + csize, off + F2FS_BLKSIZE); + ASSERT(wlen == csize); + c.compress.ops->reset(&c.compress.cc); + cur_cblk = (c.compress.cc.rlen - csize) / + F2FS_BLKSIZE; + cblocks += cur_cblk; + wlen = f2fs_fix_mutable(sbi, de->ino, + off + F2FS_BLKSIZE + csize, + cur_cblk); + ASSERT(!wlen); + } + off += n; + } + if (n == -1) { + fprintf(stderr, "Load file '%s' failed: ", + de->full_path); + perror(NULL); + } + /* read inode */ + get_node_info(sbi, de->ino, &ni); + ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0); + /* update inode meta */ + node_blk->i.i_size = cpu_to_le64(off); + if (!c.compress.readonly) { + node_blk->i.i_compr_blocks = cpu_to_le64(cblocks); + node_blk->i.i_blocks += cpu_to_le64(cblocks); + } + ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0); + free(node_blk); + + if (!c.compress.readonly) { + sbi->total_valid_block_count += cblocks; + if (sbi->total_valid_block_count >= + sbi->user_block_count) { + ERR_MSG("Not enough space\n"); + ASSERT(0); + } + } +#endif + } else { + while ((n = read(fd, buffer, F2FS_BLKSIZE)) > 0) { + f2fs_write(sbi, de->ino, buffer, n, off); + off += n; + } + } + + close(fd); + if (n < 0) + return -1; + + if (!c.compress.enabled || (c.feature & F2FS_FEATURE_RO)) + update_largest_extent(sbi, de->ino); + update_free_segments(sbi); + + MSG(1, "Info: Create %s -> %s\n" + " -- ino=%x, type=%x, mode=%x, uid=%x, " + "gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n", + de->full_path, de->path, + de->ino, de->file_type, de->mode, + de->uid, de->gid, de->capabilities, de->size, de->pino); + return 0; +} + +int update_block(struct f2fs_sb_info *sbi, void *buf, u32 *blkaddr, + struct f2fs_node *node_blk) +{ + struct seg_entry *se; + struct f2fs_summary sum; + u64 new_blkaddr, old_blkaddr = *blkaddr, offset; + int ret, type; + + if (c.zoned_model != F2FS_ZONED_HM) + return dev_write_block(buf, old_blkaddr, WRITE_LIFE_NONE); + + /* update sit bitmap & valid_blocks && se->type for old block*/ + se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr)); + offset = OFFSET_IN_SEG(sbi, old_blkaddr); + type = se->type; + se->valid_blocks--; + f2fs_clear_bit(offset, (char *)se->cur_valid_map); + if (need_fsync_data_record(sbi)) + f2fs_clear_bit(offset, (char *)se->ckpt_valid_map); + se->dirty = 1; + f2fs_clear_main_bitmap(sbi, old_blkaddr); + f2fs_clear_sit_bitmap(sbi, old_blkaddr); + + new_blkaddr = SM_I(sbi)->main_blkaddr; + if (find_next_free_block(sbi, &new_blkaddr, 0, type, false)) { + ERR_MSG("Can't find free block for the update"); + ASSERT(0); + } + + ret = dev_write_block(buf, new_blkaddr, f2fs_io_type_to_rw_hint(type)); + ASSERT(ret >= 0); + + *blkaddr = new_blkaddr; + + /* update sit bitmap & valid_blocks && se->type for new block */ + se = get_seg_entry(sbi, GET_SEGNO(sbi, new_blkaddr)); + offset = OFFSET_IN_SEG(sbi, new_blkaddr); + se->type = se->orig_type = type; + se->valid_blocks++; + f2fs_set_bit(offset, (char *)se->cur_valid_map); + if (need_fsync_data_record(sbi)) + f2fs_set_bit(offset, (char *)se->ckpt_valid_map); + se->dirty = 1; + f2fs_set_main_bitmap(sbi, new_blkaddr, type); + f2fs_set_sit_bitmap(sbi, new_blkaddr); + + /* update SSA */ + get_sum_entry(sbi, old_blkaddr, &sum); + update_sum_entry(sbi, new_blkaddr, &sum); + + if (IS_DATASEG(type)) { + update_data_blkaddr(sbi, le32_to_cpu(sum.nid), + le16_to_cpu(sum.ofs_in_node), new_blkaddr, node_blk); + } else + update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), new_blkaddr); + + DBG(1, "Update %s block %"PRIx64" -> %"PRIx64"\n", + IS_DATASEG(type) ? "data" : "node", old_blkaddr, new_blkaddr); + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/sload.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/sload.c new file mode 100644 index 00000000000..ae18c046d56 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/sload.c @@ -0,0 +1,388 @@ +/** + * sload.c + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define _GNU_SOURCE +#include "fsck.h" +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif + +#ifdef HAVE_LIBSELINUX +static struct selabel_handle *sehnd = NULL; +#endif + +typedef void (*fs_config_f)(const char *path, int dir, + const char *target_out_path, + unsigned *uid, unsigned *gid, + unsigned *mode, uint64_t *capabilities); + +#ifndef _WIN32 +static fs_config_f fs_config_func = NULL; + +#ifdef HAVE_SELINUX_ANDROID_H +#include +#include +#include +#include +#endif + +static int filter_dot(const struct dirent *d) +{ + return (strcmp(d->d_name, "..") && strcmp(d->d_name, ".")); +} + +static int f2fs_make_directory(struct f2fs_sb_info *sbi, + int entries, struct dentry *de) +{ + int ret = 0; + int i = 0; + + for (i = 0; i < entries; i++) { + if (de[i].file_type == F2FS_FT_DIR) + ret = f2fs_mkdir(sbi, de + i); + else if (de[i].file_type == F2FS_FT_REG_FILE) + ret = f2fs_create(sbi, de + i); + else if (de[i].file_type == F2FS_FT_SYMLINK) + ret = f2fs_symlink(sbi, de + i); + + if (ret) + break; + } + + return ret; +} +#endif + +#ifdef HAVE_LIBSELINUX +static int set_selinux_xattr(struct f2fs_sb_info *sbi, const char *path, + nid_t ino, int mode) +{ + char *secontext = NULL; + char *mnt_path = NULL; + + if (!sehnd) + return 0; + + if (asprintf(&mnt_path, "%s%s", c.mount_point, path) <= 0) { + ERR_MSG("cannot allocate security path for %s%s\n", + c.mount_point, path); + return -ENOMEM; + } + + /* set root inode selinux context */ + if (selabel_lookup(sehnd, &secontext, mnt_path, mode) < 0) { + ERR_MSG("cannot lookup security context for %s\n", mnt_path); + free(mnt_path); + return -EINVAL; + } + + if (secontext) { + MSG(2, "%s (%d) -> SELinux context = %s\n", + mnt_path, ino, secontext); + inode_set_selinux(sbi, ino, secontext); + } + freecon(secontext); + free(mnt_path); + return 0; +} +#else +#define set_selinux_xattr(...) 0 +#endif + +#ifndef _WIN32 +static int set_perms_and_caps(struct dentry *de) +{ + uint64_t capabilities = 0; + unsigned int uid = 0, gid = 0, imode = 0; + char *mnt_path = NULL; + char *mount_path = c.mount_point; + + /* + * de->path already has "/" in the beginning of it. + * Need to remove "/" when c.mount_point is "/", not to add it twice. + */ + if (strlen(c.mount_point) == 1 && c.mount_point[0] == '/') + mount_path = ""; + + if (asprintf(&mnt_path, "%s%s", mount_path, de->path) <= 0) { + ERR_MSG("cannot allocate mount path for %s%s\n", + mount_path, de->path); + return -ENOMEM; + } + + /* Permissions */ + if (fs_config_func != NULL) { + fs_config_func(mnt_path, de->file_type == F2FS_FT_DIR, + c.target_out_dir, &uid, &gid, &imode, + &capabilities); + de->uid = uid & 0xffff; + de->gid = gid & 0xffff; + de->mode = (de->mode & S_IFMT) | (imode & 0xffff); + de->capabilities = capabilities; + } + MSG(2, "%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, " + "capabilities = 0x%"PRIx64"\n", + mnt_path, de->mode, de->uid, de->gid, de->capabilities); + free(mnt_path); + return 0; +} + +static void set_inode_metadata(struct dentry *de) +{ + struct stat stat; + int ret; + + ret = lstat(de->full_path, &stat); + if (ret < 0) { + ERR_MSG("lstat failure\n"); + ASSERT(0); + } + + if (S_ISREG(stat.st_mode)) { + if (stat.st_nlink > 1) { + /* + * This file might have multiple links to it, so remember + * device and inode. + */ + de->from_devino = stat.st_dev; + de->from_devino <<= 32; + de->from_devino |= stat.st_ino; + } + de->file_type = F2FS_FT_REG_FILE; + } else if (S_ISDIR(stat.st_mode)) { + de->file_type = F2FS_FT_DIR; + } else if (S_ISCHR(stat.st_mode)) { + de->file_type = F2FS_FT_CHRDEV; + } else if (S_ISBLK(stat.st_mode)) { + de->file_type = F2FS_FT_BLKDEV; + } else if (S_ISFIFO(stat.st_mode)) { + de->file_type = F2FS_FT_FIFO; + } else if (S_ISSOCK(stat.st_mode)) { + de->file_type = F2FS_FT_SOCK; + } else if (S_ISLNK(stat.st_mode)) { + de->file_type = F2FS_FT_SYMLINK; + de->link = calloc(F2FS_BLKSIZE, 1); + ASSERT(de->link); + ret = readlink(de->full_path, de->link, F2FS_BLKSIZE - 1); + ASSERT(ret >= 0); + } else { + ERR_MSG("unknown file type on %s", de->path); + ASSERT(0); + } + + de->size = stat.st_size; + de->mode = stat.st_mode & + (S_IFMT|S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); + if (c.fixed_time == -1 && c.from_dir) + de->mtime = stat.st_mtime; + else + de->mtime = c.fixed_time; + + if (c.preserve_perms) { + de->uid = stat.st_uid; + de->gid = stat.st_gid; + } + + set_perms_and_caps(de); +} + +static int build_directory(struct f2fs_sb_info *sbi, const char *full_path, + const char *dir_path, const char *target_out_dir, + nid_t dir_ino) +{ + int entries = 0; + struct dentry *dentries; + struct dirent **namelist = NULL; + int i = 0, ret = 0; + + entries = scandir(full_path, &namelist, filter_dot, (void *)alphasort); + if (entries < 0) { + ERR_MSG("No entries in %s\n", full_path); + return -ENOENT; + } + + dentries = calloc(entries, sizeof(struct dentry)); + ASSERT(dentries); + + for (i = 0; i < entries; i++) { + dentries[i].name = (unsigned char *)strdup(namelist[i]->d_name); + if (dentries[i].name == NULL) { + ERR_MSG("Skip: ENOMEM\n"); + continue; + } + dentries[i].len = strlen((char *)dentries[i].name); + + ret = asprintf(&dentries[i].path, "%s%s", + dir_path, namelist[i]->d_name); + ASSERT(ret > 0); + ret = asprintf(&dentries[i].full_path, "%s/%s", + full_path, namelist[i]->d_name); + ASSERT(ret > 0); + free(namelist[i]); + + set_inode_metadata(dentries + i); + + dentries[i].pino = dir_ino; + } + + free(namelist); + + ret = f2fs_make_directory(sbi, entries, dentries); + if (ret) + goto out_free; + + for (i = 0; i < entries; i++) { + if (dentries[i].file_type == F2FS_FT_REG_FILE) { + f2fs_build_file(sbi, dentries + i); + } else if (dentries[i].file_type == F2FS_FT_DIR) { + char *subdir_full_path = NULL; + char *subdir_dir_path = NULL; + + ret = asprintf(&subdir_full_path, "%s", + dentries[i].full_path); + ASSERT(ret > 0); + ret = asprintf(&subdir_dir_path, "%s/", + dentries[i].path); + ASSERT(ret > 0); + + ret = build_directory(sbi, subdir_full_path, + subdir_dir_path, + target_out_dir, + dentries[i].ino); + free(subdir_full_path); + free(subdir_dir_path); + + if (ret) + goto out_free; + } else if (dentries[i].file_type == F2FS_FT_SYMLINK) { + /* + * It is already done in f2fs_make_directory + * f2fs_make_symlink(sbi, dir_ino, &dentries[i]); + */ + } else { + MSG(1, "Error unknown file type\n"); + } + + ret = set_selinux_xattr(sbi, dentries[i].path, + dentries[i].ino, dentries[i].mode); + if (ret) + goto out_free; + + free(dentries[i].path); + free(dentries[i].full_path); + free((void *)dentries[i].name); + } +out_free: + for (; i < entries; i++) { + free(dentries[i].path); + free(dentries[i].full_path); + free((void *)dentries[i].name); + } + + free(dentries); + return 0; +} +#else +static int build_directory(struct f2fs_sb_info *sbi, const char *full_path, + const char *dir_path, const char *target_out_dir, + nid_t dir_ino) +{ + return -1; +} +#endif + +static int configure_files(void) +{ +#ifdef HAVE_LIBSELINUX + if (!c.nr_opt) + goto skip; +#if !defined(__ANDROID__) + sehnd = selabel_open(SELABEL_CTX_FILE, c.seopt_file, c.nr_opt); + if (!sehnd) { + ERR_MSG("Failed to open file contexts \"%s\"", + c.seopt_file[0].value); + return -EINVAL; + } +#else + sehnd = selinux_android_file_context_handle(); + if (!sehnd) { + ERR_MSG("Failed to get android file_contexts\n"); + return -EINVAL; + } +#endif +skip: +#endif +#ifdef HAVE_SELINUX_ANDROID_H + /* Load the FS config */ + if (c.fs_config_file) { + int ret = load_canned_fs_config(c.fs_config_file); + + if (ret < 0) { + ERR_MSG("Failed to load fs_config \"%s\"", + c.fs_config_file); + return ret; + } + fs_config_func = canned_fs_config; + } else { + fs_config_func = fs_config; + } +#endif + return 0; +} + +int f2fs_sload(struct f2fs_sb_info *sbi) +{ + int ret = 0; + + /* this requires for the below sanity checks */ + fsck_init(sbi); + + ret = configure_files(); + if (ret) { + ERR_MSG("Failed to configure files\n"); + return ret; + } + + /* flush NAT/SIT journal entries */ + flush_journal_entries(sbi); + + /* initialize empty hardlink cache */ + sbi->hardlink_cache = 0; + + ret = build_directory(sbi, c.from_dir, "/", + c.target_out_dir, F2FS_ROOT_INO(sbi)); + if (ret) { + ERR_MSG("Failed to build due to %d\n", ret); + return ret; + } + + ret = set_selinux_xattr(sbi, c.mount_point, + F2FS_ROOT_INO(sbi), S_IFDIR); + if (ret) { + ERR_MSG("Failed to set selinux for root: %d\n", ret); + return ret; + } + + /* update curseg info; can update sit->types */ + move_curseg_info(sbi, SM_I(sbi)->main_blkaddr, 0); + zero_journal_entries(sbi); + write_curseg_info(sbi); + + /* flush dirty sit entries */ + flush_sit_entries(sbi); + + write_checkpoint(sbi); + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.c new file mode 100644 index 00000000000..6373c0633d0 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.c @@ -0,0 +1,272 @@ +/** + * xattr.c + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "fsck.h" +#include "node.h" +#include "xattr.h" + +void *read_all_xattrs(struct f2fs_sb_info *sbi, struct f2fs_node *inode, + bool sanity_check) +{ + struct f2fs_xattr_header *header; + void *txattr_addr; + u64 inline_size = inline_xattr_size(&inode->i); + nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid); + + if (c.func == FSCK && xnid && sanity_check) { + if (fsck_sanity_check_nid(sbi, xnid, F2FS_FT_XATTR, TYPE_XATTR)) + return NULL; + } + + txattr_addr = calloc(inline_size + F2FS_BLKSIZE, 1); + ASSERT(txattr_addr); + + if (inline_size) + memcpy(txattr_addr, inline_xattr_addr(&inode->i), inline_size); + + /* Read from xattr node block. */ + if (xnid) { + struct node_info ni; + int ret; + + get_node_info(sbi, xnid, &ni); + ret = dev_read_block(txattr_addr + inline_size, ni.blk_addr); + ASSERT(ret >= 0); + memset(txattr_addr + inline_size + F2FS_BLKSIZE - + sizeof(struct node_footer), 0, + sizeof(struct node_footer)); + } + + header = XATTR_HDR(txattr_addr); + + /* Never been allocated xattrs */ + if (le32_to_cpu(header->h_magic) != F2FS_XATTR_MAGIC) { + header->h_magic = cpu_to_le32(F2FS_XATTR_MAGIC); + header->h_refcount = cpu_to_le32(1); + } + return txattr_addr; +} + +static struct f2fs_xattr_entry *__find_xattr(void *base_addr, + void *last_base_addr, int index, + size_t len, const char *name) +{ + struct f2fs_xattr_entry *entry; + + list_for_each_xattr(entry, base_addr) { + if ((void *)(entry) + sizeof(__u32) > last_base_addr || + (void *)XATTR_NEXT_ENTRY(entry) > last_base_addr) { + MSG(0, "xattr entry crosses the end of xattr space\n"); + return NULL; + } + + if (entry->e_name_index != index) + continue; + if (entry->e_name_len != len) + continue; + if (!memcmp(entry->e_name, name, len)) + break; + } + return entry; +} + +void write_all_xattrs(struct f2fs_sb_info *sbi, + struct f2fs_node *inode, __u32 hsize, void *txattr_addr) +{ + void *xattr_addr; + struct dnode_of_data dn; + struct node_info ni; + struct f2fs_node *xattr_node; + nid_t new_nid = 0; + block_t blkaddr; + nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid); + u64 inline_size = inline_xattr_size(&inode->i); + int ret; + bool xattrblk_alloced = false; + struct seg_entry *se; + + memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size); + + if (hsize <= inline_size) + return; + + if (!xnid) { + f2fs_alloc_nid(sbi, &new_nid); + + set_new_dnode(&dn, inode, NULL, new_nid); + /* NAT entry would be updated by new_node_page. */ + blkaddr = new_node_block(sbi, &dn, XATTR_NODE_OFFSET); + ASSERT(dn.node_blk); + xattr_node = dn.node_blk; + inode->i.i_xattr_nid = cpu_to_le32(new_nid); + xattrblk_alloced = true; + } else { + set_new_dnode(&dn, inode, NULL, xnid); + get_node_info(sbi, xnid, &ni); + blkaddr = ni.blk_addr; + xattr_node = calloc(F2FS_BLKSIZE, 1); + ASSERT(xattr_node); + ret = dev_read_block(xattr_node, ni.blk_addr); + if (ret < 0) + goto free_xattr_node; + } + + /* write to xattr node block */ + xattr_addr = (void *)xattr_node; + memcpy(xattr_addr, txattr_addr + inline_size, + F2FS_BLKSIZE - sizeof(struct node_footer)); + se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr)); + ret = xattrblk_alloced ? dev_write_block(xattr_node, blkaddr, + f2fs_io_type_to_rw_hint(se->type)) : + update_block(sbi, xattr_node, &blkaddr, NULL); + +free_xattr_node: + free(xattr_node); + ASSERT(ret >= 0); +} + +int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *name, + const void *value, size_t size, int flags) +{ + struct f2fs_node *inode; + void *base_addr; + void *last_base_addr; + struct f2fs_xattr_entry *here, *last; + struct node_info ni; + int error = 0; + int len; + int found, newsize; + __u32 new_hsize; + int ret; + + if (name == NULL) + return -EINVAL; + + if (value == NULL) + return -EINVAL; + + len = strlen(name); + + if (len > F2FS_NAME_LEN || size > MAX_VALUE_LEN) + return -ERANGE; + + if (ino < 3) + return -EINVAL; + + /* Now We just support selinux */ + ASSERT(index == F2FS_XATTR_INDEX_SECURITY); + + get_node_info(sbi, ino, &ni); + inode = calloc(F2FS_BLKSIZE, 1); + ASSERT(inode); + ret = dev_read_block(inode, ni.blk_addr); + ASSERT(ret >= 0); + + base_addr = read_all_xattrs(sbi, inode, true); + ASSERT(base_addr); + + last_base_addr = (void *)base_addr + XATTR_SIZE(&inode->i); + + here = __find_xattr(base_addr, last_base_addr, index, len, name); + if (!here) { + MSG(0, "Need to run fsck due to corrupted xattr.\n"); + error = -EINVAL; + goto exit; + } + + found = IS_XATTR_LAST_ENTRY(here) ? 0 : 1; + + if ((flags & XATTR_REPLACE) && !found) { + error = -ENODATA; + goto exit; + } else if ((flags & XATTR_CREATE) && found) { + error = -EEXIST; + goto exit; + } + + last = here; + while (!IS_XATTR_LAST_ENTRY(last)) + last = XATTR_NEXT_ENTRY(last); + + newsize = XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + len + size); + + /* 1. Check space */ + if (value) { + int free; + /* + * If value is NULL, it is remove operation. + * In case of update operation, we calculate free. + */ + free = MIN_OFFSET - ((char *)last - (char *)base_addr); + if (found) + free = free + ENTRY_SIZE(here); + if (free < newsize) { + error = -ENOSPC; + goto exit; + } + } + + /* 2. Remove old entry */ + if (found) { + /* + * If entry if sound, remove old entry. + * If not found, remove operation is not needed + */ + struct f2fs_xattr_entry *next = XATTR_NEXT_ENTRY(here); + int oldsize = ENTRY_SIZE(here); + + memmove(here, next, (char *)last - (char *)next); + last = (struct f2fs_xattr_entry *)((char *)last - oldsize); + memset(last, 0, oldsize); + + } + + new_hsize = (char *)last - (char *)base_addr; + + /* 3. Write new entry */ + if (value) { + char *pval; + /* + * Before we come here, old entry is removed. + * We just write new entry. + */ + memset(last, 0, newsize); + last->e_name_index = index; + last->e_name_len = len; + memcpy(last->e_name, name, len); + pval = last->e_name + len; + memcpy(pval, value, size); + last->e_value_size = cpu_to_le16(size); + new_hsize += newsize; + } + + write_all_xattrs(sbi, inode, new_hsize, base_addr); + + /* inode need update */ + ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0); +exit: + free(inode); + free(base_addr); + return error; +} + +int inode_set_selinux(struct f2fs_sb_info *sbi, u32 ino, const char *secon) +{ + if (!secon) + return 0; + + return f2fs_setxattr(sbi, ino, F2FS_XATTR_INDEX_SECURITY, + XATTR_SELINUX_SUFFIX, secon, strlen(secon), 1); +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.h new file mode 100644 index 00000000000..867349cb57e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/fsck/xattr.h @@ -0,0 +1,203 @@ +/** + * xattr.h + * + * Many parts of codes are copied from Linux kernel/fs/f2fs. + * + * Copyright (C) 2015 Huawei Ltd. + * Witten by: + * Hou Pengyang + * Liu Shuoran + * Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _XATTR_H_ +#define _XATTR_H_ + +#include "f2fs.h" +#ifdef HAVE_SYS_XATTR_H +#include +#endif + +struct f2fs_xattr_header { + __le32 h_magic; /* magic number for identification */ + __le32 h_refcount; /* reference count */ + __u32 h_sloadd[4]; /* zero right now */ +}; + +struct f2fs_xattr_entry { + __u8 e_name_index; + __u8 e_name_len; + __le16 e_value_size; /* size of attribute value */ + char e_name[0]; /* attribute name */ +}; + +#define FSCRYPT_CONTEXT_V1 1 +#define FSCRYPT_CONTEXT_V2 2 +#ifndef FSCRYPT_KEY_DESCRIPTOR_SIZE +#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 +#endif +#ifndef FSCRYPT_KEY_IDENTIFIER_SIZE +#define FSCRYPT_KEY_IDENTIFIER_SIZE 16 +#endif +#define FSCRYPT_FILE_NONCE_SIZE 16 +#define F2FS_XATTR_NAME_ENCRYPTION_CONTEXT "c" + +struct fscrypt_context_v1 { + u8 version; /* FSCRYPT_CONTEXT_V1 */ + u8 contents_encryption_mode; + u8 filenames_encryption_mode; + u8 flags; + u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; + u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; +}; + +struct fscrypt_context_v2 { + u8 version; /* FSCRYPT_CONTEXT_V2 */ + u8 contents_encryption_mode; + u8 filenames_encryption_mode; + u8 flags; + u8 __reserved[4]; + u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; + u8 nonce[FSCRYPT_FILE_NONCE_SIZE]; +}; + +union fscrypt_context { + u8 version; + struct fscrypt_context_v1 v1; + struct fscrypt_context_v2 v2; +}; + +static_assert(sizeof(struct fscrypt_context_v1) == 28, ""); +static_assert(sizeof(struct fscrypt_context_v2) == 40, ""); + +/* +* Return the size expected for the given fscrypt_context based on its version +* number, or 0 if the context version is unrecognized. +*/ +static inline int fscrypt_context_size(const union fscrypt_context *ctx) +{ + switch (ctx->version) { + case FSCRYPT_CONTEXT_V1: + return sizeof(ctx->v1); + case FSCRYPT_CONTEXT_V2: + return sizeof(ctx->v2); + default: + MSG(0, "Unsupported fscrypt_context format!\n"); + } + return 0; +} + +struct fsverity_descriptor_location { + __le32 version; + __le32 size; + __le64 pos; +}; + +static_assert(sizeof(struct fsverity_descriptor_location) == 16, ""); + +#define F2FS_ACL_VERSION 0x0001 + +struct f2fs_acl_entry { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; +}; + +struct f2fs_acl_entry_short { + __le16 e_tag; + __le16 e_perm; +}; + +struct f2fs_acl_header { + __le32 a_version; +}; + +static inline int f2fs_acl_count(int size) +{ + ssize_t s; + size -= sizeof(struct f2fs_acl_header); + s = size - 4 * sizeof(struct f2fs_acl_entry_short); + if (s < 0) { + if (size % sizeof(struct f2fs_acl_entry_short)) + return -1; + return size / sizeof(struct f2fs_acl_entry_short); + } else { + if (s % sizeof(struct f2fs_acl_entry)) + return -1; + return s / sizeof(struct f2fs_acl_entry) + 4; + } +} + +#ifndef XATTR_USER_PREFIX +#define XATTR_USER_PREFIX "user." +#endif +#ifndef XATTR_SECURITY_PREFIX +#define XATTR_SECURITY_PREFIX "security." +#endif +#ifndef XATTR_TRUSTED_PREFIX +#define XATTR_TRUSTED_PREFIX "trusted." +#endif + +#ifndef XATTR_CREATE +#define XATTR_CREATE 0x1 +#endif +#ifndef XATTR_REPLACE +#define XATTR_REPLACE 0x2 +#endif + +#define XATTR_ROUND (3) + +#define XATTR_SELINUX_SUFFIX "selinux" +#define F2FS_XATTR_INDEX_USER 1 +#define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS 2 +#define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT 3 +#define F2FS_XATTR_INDEX_TRUSTED 4 +#define F2FS_XATTR_INDEX_LUSTRE 5 +#define F2FS_XATTR_INDEX_SECURITY 6 +#define F2FS_XATTR_INDEX_ENCRYPTION 9 +#define F2FS_XATTR_INDEX_VERITY 11 + +#define F2FS_XATTR_NAME_VERITY "v" + +#define IS_XATTR_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) + +#define XATTR_HDR(ptr) ((struct f2fs_xattr_header *)(ptr)) +#define XATTR_ENTRY(ptr) ((struct f2fs_xattr_entry *)(ptr)) +#define F2FS_XATTR_MAGIC 0xF2F52011 + +#define XATTR_NEXT_ENTRY(entry) ((struct f2fs_xattr_entry *) ((char *)(entry) +\ + ENTRY_SIZE(entry))) +#define XATTR_FIRST_ENTRY(ptr) (XATTR_ENTRY(XATTR_HDR(ptr) + 1)) + +#define XATTR_ALIGN(size) ((size + XATTR_ROUND) & ~XATTR_ROUND) + +#define ENTRY_SIZE(entry) (XATTR_ALIGN(sizeof(struct f2fs_xattr_entry) + \ + entry->e_name_len + le16_to_cpu(entry->e_value_size))) + +#define list_for_each_xattr(entry, addr) \ + for (entry = XATTR_FIRST_ENTRY(addr); \ + !IS_XATTR_LAST_ENTRY(entry); \ + entry = XATTR_NEXT_ENTRY(entry)) + +#define VALID_XATTR_BLOCK_SIZE (F2FS_BLKSIZE - sizeof(struct node_footer)) + +#define XATTR_SIZE(i) ((le32_to_cpu((i)->i_xattr_nid) ? \ + VALID_XATTR_BLOCK_SIZE : 0) + \ + (inline_xattr_size(i))) + +#define MIN_OFFSET XATTR_ALIGN(F2FS_BLKSIZE - \ + sizeof(struct node_footer) - sizeof(__u32)) + +#define MAX_VALUE_LEN (MIN_OFFSET - \ + sizeof(struct f2fs_xattr_header) - \ + sizeof(struct f2fs_xattr_entry)) + +#define MAX_INLINE_XATTR_SIZE \ + (DEF_ADDRS_PER_INODE - \ + F2FS_TOTAL_EXTRA_ATTR_SIZE / sizeof(__le32) - \ + DEF_INLINE_RESERVED_SIZE - \ + MIN_INLINE_DENTRY_SIZE / sizeof(__le32)) +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/android_config.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/android_config.h new file mode 100644 index 00000000000..b11e2e459fd --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/android_config.h @@ -0,0 +1,86 @@ +#if defined(__linux__) +#define HAVE_ARCH_STRUCT_FLOCK 1 +#define HAVE_BLK_ZONE_REP_V2 1 +#define HAVE_BYTESWAP_H 1 +#define HAVE_FCNTL_H 1 +#define HAVE_FALLOC_H 1 +#define HAVE_FSYNC 1 +#define HAVE_LINUX_FCNTL_H 1 +#define HAVE_LINUX_HDREG_H 1 +#define HAVE_LINUX_LIMITS_H 1 +#define HAVE_LINUX_LOOP_H 1 +#define HAVE_LINUX_MAJOR_H 1 +#define HAVE_POSIX_ACL_H 1 +#define HAVE_LINUX_TYPES_H 1 +#define HAVE_LINUX_XATTR_H 1 +#define HAVE_LINUX_FS_H 1 +#define HAVE_LINUX_FIEMAP_H 1 +#define HAVE_LINUX_VERITY_H 1 +#define HAVE_MNTENT_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_SYSCALL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_SYSMACROS_H 1 +#define HAVE_SYS_XATTR_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_UUID_UUID_H 1 +#define HAVE_CLOCK_GETTIME 1 +#define HAVE_CLOCK_BOOTTIME 1 + +#define HAVE_FALLOCATE 1 +#define HAVE_FSETXATTR 1 +#define HAVE_FSTAT 1 +#define HAVE_FSTAT64 1 +#define HAVE_GETMNTENT 1 +#define HAVE_MEMSET 1 +#define HAVE_PREAD 1 +#define HAVE_PWRITE 1 +#define HAVE_SELINUX_ANDROID_H 1 +#define HAVE_SETMNTENT 1 +#define HAVE_SPARSE_SPARSE_H 1 +#define HAVE_LIBLZ4 1 +#define HAVE_LIBUUID 1 + +#ifdef WITH_SLOAD +#define HAVE_LIBSELINUX 1 +#endif + +#if defined(__BIONIC__) +#define HAVE_LINUX_BLKZONED_H 1 +#endif + +#endif + +#if defined(__APPLE__) +#define HAVE_FCNTL_H 1 +#define HAVE_FALLOC_H 1 +#define HAVE_POSIX_ACL_H 1 +#define HAVE_STDLIB_H 1 +#define HAVE_STRING_H 1 +#define HAVE_SYS_IOCTL_H 1 +#define HAVE_SYS_SYSCALL_H 1 +#define HAVE_SYS_MOUNT_H 1 +#define HAVE_SYS_UTSNAME_H 1 +#define HAVE_SYS_XATTR_H 1 +#define HAVE_UNISTD_H 1 + +#define HAVE_FALLOCATE 1 +#define HAVE_FSETXATTR 1 +#define HAVE_FSTAT 1 +#define HAVE_FSTAT64 1 +#define HAVE_GETMNTENT 1 +#define HAVE_MEMSET 1 +#define HAVE_SPARSE_SPARSE_H 1 +#define HAVE_LIBLZ4 1 + +#ifdef WITH_SLOAD +#define HAVE_LIBSELINUX 1 +#endif +#endif + +#if defined(_WIN32) +#define HAVE_SPARSE_SPARSE_H 1 +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/f2fs_fs.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/f2fs_fs.h new file mode 100644 index 00000000000..f7268d1e90f --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/f2fs_fs.h @@ -0,0 +1,2205 @@ +/** + * f2fs_fs.h + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * Copyright (c) 2019 Google Inc. + * http://www.google.com/ + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add sload compression support + * + * Dual licensed under the GPL or LGPL version 2 licenses. + * + * The byteswap codes are copied from: + * samba_3_master/lib/ccan/endian/endian.h under LGPL 2.1 + */ +#ifndef __F2FS_FS_H__ +#define __F2FS_FS_H__ + +#ifndef __SANE_USERSPACE_TYPES__ +#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#else +#ifdef __ANDROID__ +#define WITH_ANDROID +#endif +#endif /* HAVE_CONFIG_H */ + +#ifdef WITH_ANDROID +#include +#else +#define WITH_DUMP +#define WITH_DEFRAG +#define WITH_RESIZE +#define WITH_SLOAD +#define WITH_LABEL +#define WITH_INJECT +#endif + +#include +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#include + +#ifdef HAVE_KERNEL_UAPI_LINUX_BLKZONED_H +#include +#elif defined(HAVE_LINUX_BLKZONED_H) +#include +#endif + +#ifdef HAVE_LINUX_RW_HINT_H +#include +#else +enum rw_hint { + WRITE_LIFE_NOT_SET = 0, + WRITE_LIFE_NONE, + WRITE_LIFE_SHORT, + WRITE_LIFE_MEDIUM, + WRITE_LIFE_LONG, + WRITE_LIFE_EXTREME +}; +#endif + +#ifdef HAVE_LIBSELINUX +#include +#include +#endif + +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) x +#elif defined(__cplusplus) +# define UNUSED(x) +#else +# define UNUSED(x) x +#endif + +#ifndef static_assert +#define static_assert _Static_assert +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + +#ifndef fallthrough +#ifdef __clang__ +#define fallthrough do {} while (0) /* fall through */ +#else +#define fallthrough __attribute__((__fallthrough__)) +#endif +#endif + +#ifdef _WIN32 +#undef HAVE_LINUX_TYPES_H +#endif + +/* codes from kernel's f2fs.h, GPL-v2.0 */ +#define MIN_COMPRESS_LOG_SIZE 2 +#define MAX_COMPRESS_LOG_SIZE 8 + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef u32 block_t; +typedef u32 nid_t; +typedef unsigned long pgoff_t; +typedef unsigned short umode_t; + +#ifndef HAVE_LINUX_TYPES_H +typedef u8 __u8; +typedef u16 __u16; +typedef u32 __u32; +typedef u64 __u64; +typedef u16 __le16; +typedef u32 __le32; +typedef u64 __le64; +typedef u16 __be16; +typedef u32 __be32; +typedef u64 __be64; +#endif + +/* + * code borrowed from kernel f2fs dirver: f2fs.h, GPL-2.0 + * : definitions of COMPRESS_DATA_RESERVED_SIZE, + * struct compress_data, COMPRESS_HEADER_SIZE, + * and struct compress_ctx + */ +#define COMPRESS_DATA_RESERVED_SIZE 4 +struct compress_data { + __le32 clen; /* compressed data size */ + __le32 chksum; /* checksum of compressed data */ + __le32 reserved[COMPRESS_DATA_RESERVED_SIZE]; /* reserved */ + u8 cdata[]; /* compressed data */ +}; +#define COMPRESS_HEADER_SIZE (sizeof(struct compress_data)) +/* compress context */ +struct compress_ctx { + unsigned int cluster_size; /* page count in cluster */ + unsigned int log_cluster_size; /* log of cluster size */ + void *rbuf; /* compression input buffer */ + struct compress_data *cbuf; /* comprsssion output header + data */ + size_t rlen; /* valid data length in rbuf */ + size_t clen; /* valid data length in cbuf */ + void *private; /* work buf for compress algorithm */ +}; + +#if HAVE_BYTESWAP_H +#include +#else +/** + * bswap_16 - reverse bytes in a uint16_t value. + * @val: value whose bytes to swap. + * + * Example: + * // Output contains "1024 is 4 as two bytes reversed" + * printf("1024 is %u as two bytes reversed\n", bswap_16(1024)); + */ +static inline uint16_t bswap_16(uint16_t val) +{ + return ((val & (uint16_t)0x00ffU) << 8) + | ((val & (uint16_t)0xff00U) >> 8); +} + +/** + * bswap_32 - reverse bytes in a uint32_t value. + * @val: value whose bytes to swap. + * + * Example: + * // Output contains "1024 is 262144 as four bytes reversed" + * printf("1024 is %u as four bytes reversed\n", bswap_32(1024)); + */ +static inline uint32_t bswap_32(uint32_t val) +{ + return ((val & (uint32_t)0x000000ffUL) << 24) + | ((val & (uint32_t)0x0000ff00UL) << 8) + | ((val & (uint32_t)0x00ff0000UL) >> 8) + | ((val & (uint32_t)0xff000000UL) >> 24); +} +#endif /* !HAVE_BYTESWAP_H */ + +#if defined HAVE_DECL_BSWAP_64 && !HAVE_DECL_BSWAP_64 +/** + * bswap_64 - reverse bytes in a uint64_t value. + * @val: value whose bytes to swap. + * + * Example: + * // Output contains "1024 is 1125899906842624 as eight bytes reversed" + * printf("1024 is %llu as eight bytes reversed\n", + * (unsigned long long)bswap_64(1024)); + */ +static inline uint64_t bswap_64(uint64_t val) +{ + return ((val & (uint64_t)0x00000000000000ffULL) << 56) + | ((val & (uint64_t)0x000000000000ff00ULL) << 40) + | ((val & (uint64_t)0x0000000000ff0000ULL) << 24) + | ((val & (uint64_t)0x00000000ff000000ULL) << 8) + | ((val & (uint64_t)0x000000ff00000000ULL) >> 8) + | ((val & (uint64_t)0x0000ff0000000000ULL) >> 24) + | ((val & (uint64_t)0x00ff000000000000ULL) >> 40) + | ((val & (uint64_t)0xff00000000000000ULL) >> 56); +} +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le16_to_cpu(x) ((uint16_t)(x)) +#define le32_to_cpu(x) ((uint32_t)(x)) +#define le64_to_cpu(x) ((uint64_t)(x)) +#define cpu_to_le16(x) ((uint16_t)(x)) +#define cpu_to_le32(x) ((uint32_t)(x)) +#define cpu_to_le64(x) ((uint64_t)(x)) +#define be32_to_cpu(x) __builtin_bswap64(x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le16_to_cpu(x) bswap_16(x) +#define le32_to_cpu(x) bswap_32(x) +#define le64_to_cpu(x) bswap_64(x) +#define cpu_to_le16(x) bswap_16(x) +#define cpu_to_le32(x) bswap_32(x) +#define cpu_to_le64(x) bswap_64(x) +#define be32_to_cpu(x) ((uint64_t)(x)) +#endif + +#define typecheck(type,x) \ + ({ type __dummy; \ + typeof(x) __dummy2; \ + (void)(&__dummy == &__dummy2); \ + 1; \ + }) + +#define NULL_SEGNO ((unsigned int)~0) + +/* + * Debugging interfaces + */ + +#define INFO_MSG(fmt, ...) \ + do { \ + printf("[INFO] (%s:%4d) ", __func__, __LINE__); \ + printf(" --> "fmt"\n", ##__VA_ARGS__); \ + } while (0) + +#define FIX_MSG(fmt, ...) \ + do { \ + printf("[FIX] (%s:%4d) ", __func__, __LINE__); \ + printf(" --> "fmt"\n", ##__VA_ARGS__); \ + } while (0) + +#define ASSERT_MSG(fmt, ...) \ + do { \ + printf("[ASSERT] (%s:%4d) ", __func__, __LINE__); \ + printf(" --> "fmt"\n", ##__VA_ARGS__); \ + c.bug_on = 1; \ + } while (0) + +#define ASSERT(exp) \ + do { \ + if (!(exp)) { \ + printf("[ASSERT] (%s:%4d) %s\n", \ + __func__, __LINE__, #exp); \ + exit(-1); \ + } \ + } while (0) + +#define ERR_MSG(fmt, ...) \ + do { \ + printf("[%s:%d] " fmt, __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) + +#define MSG(n, fmt, ...) \ + do { \ + if (c.dbg_lv >= n && !c.layout && !c.show_file_map) { \ + printf(fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define DBG(n, fmt, ...) \ + do { \ + if (c.dbg_lv >= n && !c.layout && !c.show_file_map) { \ + printf("[%s:%4d] " fmt, \ + __func__, __LINE__, ##__VA_ARGS__); \ + } \ + } while (0) + +/* Display on console */ +#define DISP(fmt, ptr, member) \ + do { \ + printf("%-30s" fmt, #member, ((ptr)->member)); \ + } while (0) + +#define DISP_raw_str(fmt, member) \ + do { \ + if (c.layout) \ + printf("%-30s " fmt "\n", #member":", member); \ + else \ + printf("%-30s" "\t\t[" fmt "]\n", \ + #member, member); \ + } while (0) + +#define DISP_str(fmt, ptr, member) \ + do { \ + if (c.layout) \ + printf("%-30s " fmt "\n", \ + #member":", ((ptr)->member)); \ + else \ + printf("%-30s" "\t\t[" fmt "]\n", \ + #member, ((ptr)->member)); \ + } while (0) + +#define DISP_u8(ptr, member) \ + do { \ + assert(sizeof((ptr)->member) == 1); \ + if (c.layout) \ + printf("%-30s %u\n", \ + #member":", ((ptr)->member)); \ + else \ + printf("%-30s" "\t\t[0x%8x : %u]\n", \ + #member, ((ptr)->member), ((ptr)->member)); \ + } while (0) + +#define DISP_u16(ptr, member) \ + do { \ + assert(sizeof((ptr)->member) == 2); \ + if (c.layout) \ + printf("%-30s %u\n", \ + #member":", le16_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8x : %u]\n", \ + #member, le16_to_cpu(((ptr)->member)), \ + le16_to_cpu(((ptr)->member))); \ + } while (0) + +#define DISP_u32(ptr, member) \ + do { \ + assert(sizeof((ptr)->member) <= 4); \ + if (c.layout) \ + printf("%-30s %u\n", \ + #member":", le32_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8x : %u]\n", \ + #member, le32_to_cpu(((ptr)->member)), \ + le32_to_cpu(((ptr)->member))); \ + } while (0) + +#define DISP_u64(ptr, member) \ + do { \ + assert(sizeof((ptr)->member) == 8); \ + if (c.layout) \ + printf("%-30s %" PRIu64 "\n", \ + #member":", le64_to_cpu(((ptr)->member))); \ + else \ + printf("%-30s" "\t\t[0x%8" PRIx64 " : %" PRIu64 "]\n", \ + #member, le64_to_cpu(((ptr)->member)), \ + le64_to_cpu(((ptr)->member))); \ + } while (0) + +#define DISP_utf(ptr, member) \ + do { \ + if (c.layout) \ + printf("%-30s %s\n", #member":", \ + ((ptr)->member)); \ + else \ + printf("%-30s" "\t\t[%s]\n", #member, \ + ((ptr)->member)); \ + } while (0) + +/* Display to buffer */ +#define BUF_DISP_u32(buf, data, len, ptr, member) \ + do { \ + assert(sizeof((ptr)->member) <= 4); \ + snprintf(buf, len, #member); \ + snprintf(data, len, "0x%x : %u", ((ptr)->member), \ + ((ptr)->member)); \ + } while (0) + +#define BUF_DISP_u64(buf, data, len, ptr, member) \ + do { \ + assert(sizeof((ptr)->member) == 8); \ + snprintf(buf, len, #member); \ + snprintf(data, len, "0x%llx : %llu", ((ptr)->member), \ + ((ptr)->member)); \ + } while (0) + +#define BUF_DISP_utf(buf, data, len, ptr, member) \ + snprintf(buf, len, #member) + +/* these are defined in kernel */ +#define BITS_PER_BYTE 8 +#ifndef SECTOR_SHIFT +#define SECTOR_SHIFT 9 +#endif +#define F2FS_SUPER_MAGIC 0xF2F52010 /* F2FS Magic Number */ +#define CP_CHKSUM_OFFSET (F2FS_BLKSIZE - sizeof(__le32)) +#define SB_CHKSUM_OFFSET 3068 +#define MAX_PATH_LEN 64 +#define MAX_DEVICES 8 + +#define F2FS_BYTES_TO_BLK(bytes) ((bytes) >> F2FS_BLKSIZE_BITS) +#define F2FS_BLKSIZE_BITS c.blksize_bits + +/* for mkfs */ +#define F2FS_NUMBER_OF_CHECKPOINT_PACK 2 +#define DEFAULT_SECTOR_SIZE 512 +#define DEFAULT_SECTORS_PER_BLOCK (1 << (F2FS_BLKSIZE_BITS - SECTOR_SHIFT)) +#define DEFAULT_BLOCKS_PER_SEGMENT 512 +#define DEFAULT_SEGMENTS_PER_SECTION 1 +#define DEFAULT_BLKSIZE_BITS 12 /* 4096 */ + +#define VERSION_LEN 256 +#define VERSION_TIMESTAMP_LEN 4 +#define VERSION_NAME_LEN (VERSION_LEN - VERSION_TIMESTAMP_LEN) + +#define LPF "lost+found" + +/* one for gc buffer, the other for node */ +#define MIN_RSVD_SECS (NR_CURSEG_TYPE + 2U) +#define CONFIG_RSVD_DEFAULT_OP_RATIO 3.0 + +enum f2fs_config_func { + MKFS, + FSCK, + DUMP, + DEFRAG, + RESIZE, + SLOAD, + LABEL, + INJECT, +}; + +enum default_set { + CONF_NONE = 0, + CONF_ANDROID, +}; + +struct device_info { + char *path; + int32_t fd; + uint32_t sector_size; + uint64_t total_sectors; /* got by get_device_info */ + uint64_t start_blkaddr; + uint64_t end_blkaddr; + uint32_t total_segments; + char *alias_filename; + + /* to handle zone block devices */ + int zoned_model; + uint32_t nr_zones; + uint32_t nr_rnd_zones; + size_t zone_blocks; + uint64_t zone_size; + size_t *zone_cap_blocks; +}; + +typedef struct { + /* Value 0 means no cache, minimum 1024 */ + long num_cache_entry; + + /* Value 0 means always overwrite (no collision allowed). maximum 16 */ + unsigned max_hash_collision; + + bool dbg_en; +} dev_cache_config_t; + +/* f2fs_configration for compression used for sload.f2fs */ +typedef struct { + void (*init)(struct compress_ctx *cc); + int (*compress)(struct compress_ctx *cc); + void (*reset)(struct compress_ctx *cc); +} compress_ops; + +/* Should be aligned to supported_comp_names and support_comp_ops */ +enum compress_algorithms { + COMPR_LZO, + COMPR_LZ4, + MAX_COMPRESS_ALGS, +}; + +enum filter_policy { + COMPR_FILTER_UNASSIGNED = 0, + COMPR_FILTER_ALLOW, + COMPR_FILTER_DENY, +}; + +typedef struct { + void (*add)(const char *); + void (*destroy)(void); + bool (*filter)(const char *); +} filter_ops; + +typedef struct { + bool enabled; /* disabled by default */ + bool required; /* require to enable */ + bool readonly; /* readonly to release blocks */ + struct compress_ctx cc; /* work context */ + enum compress_algorithms alg; /* algorithm to compress */ + compress_ops *ops; /* ops per algorithm */ + unsigned int min_blocks; /* save more blocks than this */ + enum filter_policy filter; /* filter to try compression */ + filter_ops *filter_ops; /* filter ops */ +} compress_config_t; + +#define ALIGN_DOWN(addrs, size) (((addrs) / (size)) * (size)) +#define ALIGN_UP(addrs, size) ALIGN_DOWN(((addrs) + (size) - 1), (size)) + +#ifdef CONFIG_64BIT +#define BITS_PER_LONG 64 +#else +#define BITS_PER_LONG 32 +#endif + +#define BIT_MASK(nr) (1 << (nr % BITS_PER_LONG)) +#define BIT_WORD(nr) (nr / BITS_PER_LONG) + +#define set_sb_le64(member, val) (sb->member = cpu_to_le64(val)) +#define set_sb_le32(member, val) (sb->member = cpu_to_le32(val)) +#define set_sb_le16(member, val) (sb->member = cpu_to_le16(val)) +#define get_sb_le64(member) le64_to_cpu(sb->member) +#define get_sb_le32(member) le32_to_cpu(sb->member) +#define get_sb_le16(member) le16_to_cpu(sb->member) +#define get_newsb_le64(member) le64_to_cpu(new_sb->member) +#define get_newsb_le32(member) le32_to_cpu(new_sb->member) +#define get_newsb_le16(member) le16_to_cpu(new_sb->member) + +#define set_sb(member, val) \ + do { \ + typeof(sb->member) t = (val); \ + switch (sizeof(t)) { \ + case 8: set_sb_le64(member, t); break; \ + case 4: set_sb_le32(member, t); break; \ + case 2: set_sb_le16(member, t); break; \ + } \ + } while(0) + +#define get_sb(member) \ + ({ \ + typeof(sb->member) t; \ + switch (sizeof(t)) { \ + case 8: t = get_sb_le64(member); break; \ + case 4: t = get_sb_le32(member); break; \ + case 2: t = get_sb_le16(member); break; \ + } \ + t; \ + }) +#define get_newsb(member) \ + ({ \ + typeof(new_sb->member) t; \ + switch (sizeof(t)) { \ + case 8: t = get_newsb_le64(member); break; \ + case 4: t = get_newsb_le32(member); break; \ + case 2: t = get_newsb_le16(member); break; \ + } \ + t; \ + }) + +#define set_cp_le64(member, val) (cp->member = cpu_to_le64(val)) +#define set_cp_le32(member, val) (cp->member = cpu_to_le32(val)) +#define set_cp_le16(member, val) (cp->member = cpu_to_le16(val)) +#define get_cp_le64(member) le64_to_cpu(cp->member) +#define get_cp_le32(member) le32_to_cpu(cp->member) +#define get_cp_le16(member) le16_to_cpu(cp->member) + +#define set_cp(member, val) \ + do { \ + typeof(cp->member) t = (val); \ + switch (sizeof(t)) { \ + case 8: set_cp_le64(member, t); break; \ + case 4: set_cp_le32(member, t); break; \ + case 2: set_cp_le16(member, t); break; \ + } \ + } while(0) + +#define get_cp(member) \ + ({ \ + typeof(cp->member) t; \ + switch (sizeof(t)) { \ + case 8: t = get_cp_le64(member); break; \ + case 4: t = get_cp_le32(member); break; \ + case 2: t = get_cp_le16(member); break; \ + } \ + t; \ + }) + +/* + * Copied from include/linux/kernel.h + */ +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_down(x, y) ((x) & ~__round_mask(x, y)) + +#define min(x, y) ({ \ + typeof(x) _min1 = (x); \ + typeof(y) _min2 = (y); \ + (void) (&_min1 == &_min2); \ + _min1 < _min2 ? _min1 : _min2; }) + +#define max(x, y) ({ \ + typeof(x) _max1 = (x); \ + typeof(y) _max2 = (y); \ + (void) (&_max1 == &_max2); \ + _max1 > _max2 ? _max1 : _max2; }) + +#define round_up(x, y) (((x) + (y) - 1) / (y)) +/* + * Copied from fs/f2fs/f2fs.h + */ +#define NR_CURSEG_DATA_TYPE (3) +#define NR_CURSEG_NODE_TYPE (3) +#define NR_CURSEG_TYPE (NR_CURSEG_DATA_TYPE + NR_CURSEG_NODE_TYPE) + +enum { + CURSEG_HOT_DATA = 0, /* directory entry blocks */ + CURSEG_WARM_DATA, /* data blocks */ + CURSEG_COLD_DATA, /* multimedia or GCed data blocks */ + CURSEG_HOT_NODE, /* direct node blocks of directory files */ + CURSEG_WARM_NODE, /* direct node blocks of normal files */ + CURSEG_COLD_NODE, /* indirect node blocks */ + NO_CHECK_TYPE +}; + +enum { + CURSEG_RO_HOT_DATA, + CURSEG_RO_HOT_NODE, + NR_RO_CURSEG_TYPE, +}; + +#define F2FS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ + +/* + * Copied from fs/f2fs/segment.h + */ +#define GET_SUM_TYPE(sum) (F2FS_SUMMARY_BLOCK_FOOTER(sum)->entry_type) +#define SET_SUM_TYPE(sum, type) (F2FS_SUMMARY_BLOCK_FOOTER(sum)->entry_type = type) + +/* + * Copied from include/linux/f2fs_sb.h + */ +#define F2FS_SUPER_OFFSET 1024 /* byte-size offset */ +#define F2FS_MIN_LOG_SECTOR_SIZE 9 /* 9 bits for 512 bytes */ +#define F2FS_MAX_LOG_SECTOR_SIZE F2FS_BLKSIZE_BITS /* max sector size is block size */ +#define F2FS_MIN_BLKSIZE 4096 +#define F2FS_MAX_BLKSIZE 16384 +#define F2FS_BLKSIZE c.blksize /* support configurable block size */ +#define F2FS_MAX_EXTENSION 64 /* # of extension entries */ +#define F2FS_EXTENSION_LEN 8 /* max size of extension */ +#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) / F2FS_BLKSIZE) + +#define NULL_ADDR 0x0U +#define NEW_ADDR -1U +#define COMPRESS_ADDR -2U + +#define F2FS_ROOT_INO(sbi) (sbi->root_ino_num) +#define F2FS_NODE_INO(sbi) (sbi->node_ino_num) +#define F2FS_META_INO(sbi) (sbi->meta_ino_num) + +#define F2FS_MAX_QUOTAS 3 +#define QUOTA_DATA (((1024 * 6 - 1) / F2FS_BLKSIZE) + 1) +#define QUOTA_INO(sb,t) (le32_to_cpu((sb)->qf_ino[t])) + +/* + * On-disk inode flags (f2fs_inode::i_flags) + */ +#define F2FS_COMPR_FL 0x00000004 /* Compress file */ +#define F2FS_NODUMP_FL 0x00000040 /* do not dump file */ +#define F2FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define F2FS_NOATIME_FL 0x00000080 /* do not update atime */ +#define F2FS_CASEFOLD_FL 0x40000000 /* Casefolded file */ +#define F2FS_DEVICE_ALIAS_FL 0x80000000 /* File for aliasing a device */ +#define IS_DEVICE_ALIASING(fi) ((fi)->i_flags & cpu_to_le32(F2FS_DEVICE_ALIAS_FL)) + +#define F2FS_ENC_UTF8_12_1 1 +#define F2FS_ENC_STRICT_MODE_FL (1 << 0) +#define F2FS_ENC_NO_COMPAT_FALLBACK_FL (1 << 1) + +/* This flag is used by node and meta inodes, and by recovery */ +#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) + +/* + * For further optimization on multi-head logs, on-disk layout supports maximum + * 16 logs by default. The number, 16, is expected to cover all the cases + * enoughly. The implementaion currently uses no more than 6 logs. + * Half the logs are used for nodes, and the other half are used for data. + */ +#define MAX_ACTIVE_LOGS 16 +#define MAX_ACTIVE_NODE_LOGS 8 +#define MAX_ACTIVE_DATA_LOGS 8 + +#define F2FS_FEATURE_ENCRYPT 0x0001 +#define F2FS_FEATURE_BLKZONED 0x0002 +#define F2FS_FEATURE_ATOMIC_WRITE 0x0004 +#define F2FS_FEATURE_EXTRA_ATTR 0x0008 +#define F2FS_FEATURE_PRJQUOTA 0x0010 +#define F2FS_FEATURE_INODE_CHKSUM 0x0020 +#define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040 +#define F2FS_FEATURE_QUOTA_INO 0x0080 +#define F2FS_FEATURE_INODE_CRTIME 0x0100 +#define F2FS_FEATURE_LOST_FOUND 0x0200 +#define F2FS_FEATURE_VERITY 0x0400 /* reserved */ +#define F2FS_FEATURE_SB_CHKSUM 0x0800 +#define F2FS_FEATURE_CASEFOLD 0x1000 +#define F2FS_FEATURE_COMPRESSION 0x2000 +#define F2FS_FEATURE_RO 0x4000 +#define F2FS_FEATURE_DEVICE_ALIAS 0x8000 + +#define MAX_NR_FEATURE 32 + +#define MAX_VOLUME_NAME 512 + +/* + * For superblock + */ +struct f2fs_device { + __u8 path[MAX_PATH_LEN]; + __le32 total_segments; +}; + +static_assert(sizeof(struct f2fs_device) == 68, ""); + +/* reason of stop_checkpoint */ +enum stop_cp_reason { + STOP_CP_REASON_SHUTDOWN, + STOP_CP_REASON_FAULT_INJECT, + STOP_CP_REASON_META_PAGE, + STOP_CP_REASON_WRITE_FAIL, + STOP_CP_REASON_CORRUPTED_SUMMARY, + STOP_CP_REASON_UPDATE_INODE, + STOP_CP_REASON_FLUSH_FAIL, + STOP_CP_REASON_NO_SEGMENT, + STOP_CP_REASON_CORRUPTED_FREE_BITMAP, + STOP_CP_REASON_MAX, +}; + +#define MAX_STOP_REASON 32 + +/* detail reason for EFSCORRUPTED */ +enum f2fs_error { + ERROR_CORRUPTED_CLUSTER, + ERROR_FAIL_DECOMPRESSION, + ERROR_INVALID_BLKADDR, + ERROR_CORRUPTED_DIRENT, + ERROR_CORRUPTED_INODE, + ERROR_INCONSISTENT_SUMMARY, + ERROR_INCONSISTENT_FOOTER, + ERROR_INCONSISTENT_SUM_TYPE, + ERROR_CORRUPTED_JOURNAL, + ERROR_INCONSISTENT_NODE_COUNT, + ERROR_INCONSISTENT_BLOCK_COUNT, + ERROR_INVALID_CURSEG, + ERROR_INCONSISTENT_SIT, + ERROR_CORRUPTED_VERITY_XATTR, + ERROR_CORRUPTED_XATTR, + ERROR_INVALID_NODE_REFERENCE, + ERROR_INCONSISTENT_NAT, + ERROR_MAX, +}; + +#define MAX_F2FS_ERRORS 16 + +struct f2fs_super_block { + __le32 magic; /* Magic Number */ + __le16 major_ver; /* Major Version */ + __le16 minor_ver; /* Minor Version */ + __le32 log_sectorsize; /* log2 sector size in bytes */ + __le32 log_sectors_per_block; /* log2 # of sectors per block */ + __le32 log_blocksize; /* log2 block size in bytes */ + __le32 log_blocks_per_seg; /* log2 # of blocks per segment */ + __le32 segs_per_sec; /* # of segments per section */ + __le32 secs_per_zone; /* # of sections per zone */ + __le32 checksum_offset; /* checksum offset inside super block */ + __le64 block_count __attribute__((packed)); + /* total # of user blocks */ + __le32 section_count; /* total # of sections */ + __le32 segment_count; /* total # of segments */ + __le32 segment_count_ckpt; /* # of segments for checkpoint */ + __le32 segment_count_sit; /* # of segments for SIT */ + __le32 segment_count_nat; /* # of segments for NAT */ + __le32 segment_count_ssa; /* # of segments for SSA */ + __le32 segment_count_main; /* # of segments for main area */ + __le32 segment0_blkaddr; /* start block address of segment 0 */ + __le32 cp_blkaddr; /* start block address of checkpoint */ + __le32 sit_blkaddr; /* start block address of SIT */ + __le32 nat_blkaddr; /* start block address of NAT */ + __le32 ssa_blkaddr; /* start block address of SSA */ + __le32 main_blkaddr; /* start block address of main area */ + __le32 root_ino; /* root inode number */ + __le32 node_ino; /* node inode number */ + __le32 meta_ino; /* meta inode number */ + __u8 uuid[16]; /* 128-bit uuid for volume */ + __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ + __le32 extension_count; /* # of extensions below */ + __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ + __le32 cp_payload; + __u8 version[VERSION_LEN]; /* the kernel version */ + __u8 init_version[VERSION_LEN]; /* the initial kernel version */ + __le32 feature; /* defined features */ + __u8 encryption_level; /* versioning level for encryption */ + __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ + struct f2fs_device devs[MAX_DEVICES] __attribute__((packed)); /* device list */ + __le32 qf_ino[F2FS_MAX_QUOTAS] __attribute__((packed)); /* quota inode numbers */ + __u8 hot_ext_count; /* # of hot file extension */ + __le16 s_encoding; /* Filename charset encoding */ + __le16 s_encoding_flags; /* Filename charset encoding flags */ + __u8 s_stop_reason[MAX_STOP_REASON]; /* stop checkpoint reason */ + __u8 s_errors[MAX_F2FS_ERRORS]; /* reason of image corrupts */ + __u8 reserved[258]; /* valid reserved region */ + __le32 crc; /* checksum of superblock */ +} __attribute__((packed)); + +static_assert(sizeof(struct f2fs_super_block) == 3072, ""); + +/* + * For checkpoint + */ +#define CP_RESIZEFS_FLAG 0x00004000 +#define CP_DISABLED_FLAG 0x00001000 +#define CP_QUOTA_NEED_FSCK_FLAG 0x00000800 +#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400 +#define CP_NOCRC_RECOVERY_FLAG 0x00000200 +#define CP_TRIMMED_FLAG 0x00000100 +#define CP_NAT_BITS_FLAG 0x00000080 +#define CP_CRC_RECOVERY_FLAG 0x00000040 +#define CP_FASTBOOT_FLAG 0x00000020 +#define CP_FSCK_FLAG 0x00000010 +#define CP_ERROR_FLAG 0x00000008 +#define CP_COMPACT_SUM_FLAG 0x00000004 +#define CP_ORPHAN_PRESENT_FLAG 0x00000002 +#define CP_UMOUNT_FLAG 0x00000001 + +#define F2FS_CP_PACKS 2 /* # of checkpoint packs */ + +struct f2fs_checkpoint { + __le64 checkpoint_ver; /* checkpoint block version number */ + __le64 user_block_count; /* # of user blocks */ + __le64 valid_block_count; /* # of valid blocks in main area */ + __le32 rsvd_segment_count; /* # of reserved segments for gc */ + __le32 overprov_segment_count; /* # of overprovision segments */ + __le32 free_segment_count; /* # of free segments in main area */ + + /* information of current node segments */ + __le32 cur_node_segno[MAX_ACTIVE_NODE_LOGS]; + __le16 cur_node_blkoff[MAX_ACTIVE_NODE_LOGS]; + /* information of current data segments */ + __le32 cur_data_segno[MAX_ACTIVE_DATA_LOGS]; + __le16 cur_data_blkoff[MAX_ACTIVE_DATA_LOGS]; + __le32 ckpt_flags; /* Flags : umount and journal_present */ + __le32 cp_pack_total_block_count; /* total # of one cp pack */ + __le32 cp_pack_start_sum; /* start block number of data summary */ + __le32 valid_node_count; /* Total number of valid nodes */ + __le32 valid_inode_count; /* Total number of valid inodes */ + __le32 next_free_nid; /* Next free node number */ + __le32 sit_ver_bitmap_bytesize; /* Default value 64 */ + __le32 nat_ver_bitmap_bytesize; /* Default value 256 */ + __le32 checksum_offset; /* checksum offset inside cp block */ + __le64 elapsed_time; /* mounted time */ + /* allocation type of current segment */ + unsigned char alloc_type[MAX_ACTIVE_LOGS]; + + /* SIT and NAT version bitmap */ + unsigned char sit_nat_version_bitmap[]; +}; + +static_assert(sizeof(struct f2fs_checkpoint) == 192, ""); + +#define CP_BITMAP_OFFSET \ + (offsetof(struct f2fs_checkpoint, sit_nat_version_bitmap)) +#define CP_MIN_CHKSUM_OFFSET CP_BITMAP_OFFSET + +#define MIN_NAT_BITMAP_SIZE 64 +#define MAX_SIT_BITMAP_SIZE_IN_CKPT \ + (CP_CHKSUM_OFFSET - CP_BITMAP_OFFSET - MIN_NAT_BITMAP_SIZE) +#define MAX_BITMAP_SIZE_IN_CKPT \ + (CP_CHKSUM_OFFSET - CP_BITMAP_OFFSET) + +/* + * For orphan inode management + */ +#define F2FS_ORPHANS_PER_BLOCK ((F2FS_BLKSIZE - 4 * sizeof(__le32)) / sizeof(__le32)) + +/* + * On disk layout is: + * __le32 ino[F2FS_ORPHANS_PER_BLOCK]; + * struct f2fs_ophan_block_footer + * + * Do NOT use sizeof, use F2FS_BLKSIZE instead + */ +struct f2fs_orphan_block { + __le32 ino[0]; /* F2FS_ORPHANS_PER_BLOCK inode numbers */ +}; +#define F2FS_ORPHAN_BLOCK_FOOTER(blk) ((struct orphan_block_footer *)&(blk)->ino[F2FS_ORPHANS_PER_BLOCK]) + +struct orphan_block_footer { + __le32 reserved; /* reserved */ + __le16 blk_addr; /* block index in current CP */ + __le16 blk_count; /* Number of orphan inode blocks in CP */ + __le32 entry_count; /* Total number of orphan nodes in current CP */ + __le32 check_sum; /* CRC32 for orphan inode block */ +}; + +/* + * For NODE structure + */ +struct f2fs_extent { + __le32 fofs; /* start file offset of the extent */ + __le32 blk_addr; /* start block address of the extent */ + __le32 len; /* lengh of the extent */ +}; + +static_assert(sizeof(struct f2fs_extent) == 12, ""); + +#define F2FS_NAME_LEN 255 + +/* max output length of pretty_print_filename() including null terminator */ +#define F2FS_PRINT_NAMELEN (4 * ((F2FS_NAME_LEN + 2) / 3) + 1) + +/* 200 bytes for inline xattrs by default */ +#define DEFAULT_INLINE_XATTR_ADDRS 50 + +struct node_footer { + __le32 nid; /* node id */ + __le32 ino; /* inode number */ + __le32 flag; /* include cold/fsync/dentry marks and offset */ + __le64 cp_ver __attribute__((packed)); /* checkpoint version */ + __le32 next_blkaddr; /* next node page block address */ +}; + +static_assert(sizeof(struct node_footer) == 24, ""); + +#define OFFSET_OF_END_OF_I_EXT 360 +#define SIZE_OF_I_NID 20 +/* Address Pointers in an Inode */ +#define DEF_ADDRS_PER_INODE ((F2FS_BLKSIZE - OFFSET_OF_END_OF_I_EXT \ + - SIZE_OF_I_NID \ + - sizeof(struct node_footer)) / sizeof(__le32)) +#define CUR_ADDRS_PER_INODE(inode) (DEF_ADDRS_PER_INODE - \ + __get_extra_isize(inode)) +#define ADDRS_PER_INODE(i) addrs_per_page(i, true) +/* Address Pointers in a Direct Block */ +#define DEF_ADDRS_PER_BLOCK ((F2FS_BLKSIZE - sizeof(struct node_footer)) / sizeof(__le32)) +#define ADDRS_PER_BLOCK(i) addrs_per_page(i, false) +/* Node IDs in an Indirect Block */ +#define NIDS_PER_BLOCK ((F2FS_BLKSIZE - sizeof(struct node_footer)) / sizeof(__le32)) + +#define NODE_DIR1_BLOCK (DEF_ADDRS_PER_INODE + 1) +#define NODE_DIR2_BLOCK (DEF_ADDRS_PER_INODE + 2) +#define NODE_IND1_BLOCK (DEF_ADDRS_PER_INODE + 3) +#define NODE_IND2_BLOCK (DEF_ADDRS_PER_INODE + 4) +#define NODE_DIND_BLOCK (DEF_ADDRS_PER_INODE + 5) + +#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */ +#define F2FS_INLINE_DATA 0x02 /* file inline data flag */ +#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */ +#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */ +#define F2FS_INLINE_DOTS 0x10 /* file having implicit dot dentries */ +#define F2FS_EXTRA_ATTR 0x20 /* file having extra attribute */ +#define F2FS_PIN_FILE 0x40 /* file should not be gced */ +#define F2FS_COMPRESS_RELEASED 0x80 /* file released compressed blocks */ + +#define F2FS_EXTRA_ISIZE_OFFSET \ + offsetof(struct f2fs_inode, i_extra_isize) +#define F2FS_TOTAL_EXTRA_ATTR_SIZE \ + (offsetof(struct f2fs_inode, i_extra_end) - F2FS_EXTRA_ISIZE_OFFSET) + +#define F2FS_DEF_PROJID 0 /* default project ID */ + +#define MAX_INLINE_DATA(node) (sizeof(__le32) * \ + (DEF_ADDRS_PER_INODE - \ + get_inline_xattr_addrs(&node->i) - \ + get_extra_isize(node) - \ + DEF_INLINE_RESERVED_SIZE)) +#define DEF_MAX_INLINE_DATA (sizeof(__le32) * \ + (DEF_ADDRS_PER_INODE - \ + DEFAULT_INLINE_XATTR_ADDRS - \ + F2FS_TOTAL_EXTRA_ATTR_SIZE - \ + DEF_INLINE_RESERVED_SIZE)) +#define INLINE_DATA_OFFSET (F2FS_BLKSIZE - \ + sizeof(struct node_footer) - \ + sizeof(__le32) * (DEF_ADDRS_PER_INODE + \ + 5 - DEF_INLINE_RESERVED_SIZE)) + +#define DEF_DIR_LEVEL 0 + +/* + * i_advise uses FADVISE_XXX_BIT. We can add additional hints later. + */ +#define FADVISE_COLD_BIT 0x01 +#define FADVISE_LOST_PINO_BIT 0x02 +#define FADVISE_ENCRYPT_BIT 0x04 +#define FADVISE_ENC_NAME_BIT 0x08 +#define FADVISE_KEEP_SIZE_BIT 0x10 +#define FADVISE_HOT_BIT 0x20 +#define FADVISE_VERITY_BIT 0x40 /* reserved */ + +#define file_is_encrypt(fi) ((fi)->i_advise & FADVISE_ENCRYPT_BIT) +#define file_enc_name(fi) ((fi)->i_advise & FADVISE_ENC_NAME_BIT) +#define IS_CASEFOLDED(dir) ((dir)->i_flags & cpu_to_le32(F2FS_CASEFOLD_FL)) + +/* + * fsck i_compr_blocks counting helper + */ +struct f2fs_compr_blk_cnt { + /* counting i_compr_blocks, init 0 */ + u32 cnt; + + /* + * previous seen compression header (COMPR_ADDR) page offsets, + * use CHEADER_PGOFS_NONE for none + */ + u32 cheader_pgofs; +}; +#define CHEADER_PGOFS_NONE ((u32)-(1 << MAX_COMPRESS_LOG_SIZE)) + +/* + * On disk layout is + * struct f2fs_inode + * struct f2fs_inode_nids + * + * where the size of f2fs_inode depends on block size. + * Do NOT use sizeof + */ +struct f2fs_inode { + __le16 i_mode; /* file mode */ + __u8 i_advise; /* file hints */ + __u8 i_inline; /* file inline flags */ + __le32 i_uid; /* user ID */ + __le32 i_gid; /* group ID */ + __le32 i_links; /* links count */ + __le64 i_size; /* file size in bytes */ + __le64 i_blocks; /* file size in blocks */ + __le64 i_atime; /* access time */ + __le64 i_ctime; /* change time */ + __le64 i_mtime; /* modification time */ + __le32 i_atime_nsec; /* access time in nano scale */ + __le32 i_ctime_nsec; /* change time in nano scale */ + __le32 i_mtime_nsec; /* modification time in nano scale */ + __le32 i_generation; /* file version (for NFS) */ + union { + __le32 i_current_depth; /* only for directory depth */ + __le16 i_gc_failures; /* + * # of gc failures on pinned file. + * only for regular files. + */ + }; + __le32 i_xattr_nid; /* nid to save xattr */ + __le32 i_flags; /* file attributes */ + __le32 i_pino; /* parent inode number */ + __le32 i_namelen; /* file name length */ + __u8 i_name[F2FS_NAME_LEN]; /* file name for SPOR */ + __u8 i_dir_level; /* dentry_level for large dir */ + + struct f2fs_extent i_ext __attribute__((packed)); /* caching a largest extent */ + + union { + struct { + __le16 i_extra_isize; /* extra inode attribute size */ + __le16 i_inline_xattr_size; /* inline xattr size, unit: 4 bytes */ + __le32 i_projid; /* project id */ + __le32 i_inode_checksum;/* inode meta checksum */ + __le64 i_crtime; /* creation time */ + __le32 i_crtime_nsec; /* creation time in nano scale */ + __le64 i_compr_blocks; /* # of compressed blocks */ + __u8 i_compress_algorithm; /* compress algorithm */ + __u8 i_log_cluster_size; /* log of cluster size */ + __le16 i_compress_flag; /* compress flag */ + /* 0 bit: chksum flag + * [8,15] bits: compress level + */ + __le32 i_extra_end[0]; /* for attribute size calculation */ + } __attribute__((packed)); + __le32 i_addr[0]; /* Pointers to DEF_ADDRS_PER_INODE data blocks */ + }; +}; +struct f2fs_inode_nids { + __le32 i_nid[5]; /* direct(2), indirect(2), + double_indirect(1) node id */ +}; + +#define F2FS_INODE_NIDS(inode) ((struct f2fs_inode_nids *)(&(inode)->i_addr[DEF_ADDRS_PER_INODE])) +#define F2FS_INODE_I_NID(inode, i) (F2FS_INODE_NIDS((inode))->i_nid[(i)]) + +static_assert(offsetof(struct f2fs_inode, i_extra_end) - + offsetof(struct f2fs_inode, i_extra_isize) == 36, ""); + +struct direct_node { + __le32 addr[0]; /* array of DEF_ADDRS_PER_BLOCK data block address */ +}; + +struct indirect_node { + __le32 nid[0]; /* array of NIDS_PER_BLOCK data block address */ +}; + +enum { + COLD_BIT_SHIFT = 0, + FSYNC_BIT_SHIFT, + DENT_BIT_SHIFT, + OFFSET_BIT_SHIFT +}; + +#define XATTR_NODE_OFFSET ((((unsigned int)-1) << OFFSET_BIT_SHIFT) \ + >> OFFSET_BIT_SHIFT) +/* + * On disk format is: + * struct f2fs_node + * struct node_footer + * + * where the size of f2fs_node depends on Block Size. + * Do NOT use sizeof. Use F2FS_BLKSIZE instead. + */ +struct f2fs_node { + /* can be one of three types: inode, direct, and indirect types */ + union { + struct f2fs_inode i; + struct direct_node dn; + struct indirect_node in; + }; +}; +#define F2FS_NODE_FOOTER(blk) ((struct node_footer *)\ + &(((char *)(&(blk)->i))[F2FS_BLKSIZE - sizeof(struct node_footer)])) + +/* + * For NAT entries + */ +#define NAT_ENTRY_PER_BLOCK (F2FS_BLKSIZE / sizeof(struct f2fs_nat_entry)) +#define NAT_BLOCK_OFFSET(start_nid) (start_nid / NAT_ENTRY_PER_BLOCK) + +#define DEFAULT_NAT_ENTRY_RATIO 20 + +struct f2fs_nat_entry { + __u8 version; /* latest version of cached nat entry */ + __le32 ino; /* inode number */ + __le32 block_addr; /* block address */ +} __attribute__((packed)); + +static_assert(sizeof(struct f2fs_nat_entry) == 9, ""); + +struct f2fs_nat_block { + struct f2fs_nat_entry entries[0]; /* NAT_ENTRY_PER_BLOCK */ +}; + +/* + * For SIT entries + * + * Each segment is 2MB in size by default so that a bitmap for validity of + * there-in blocks should occupy 64 bytes, 512 bits. + * Not allow to change this. + */ +#define SIT_VBLOCK_MAP_SIZE 64 +#define SIT_ENTRY_PER_BLOCK (F2FS_BLKSIZE / sizeof(struct f2fs_sit_entry)) + +/* + * F2FS uses 4 bytes to represent block address. As a result, supported size of + * disk is 16 TB and it equals to 16 * 1024 * 1024 / 2 segments. + */ +#define F2FS_MIN_SEGMENT 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ +#define F2FS_MAX_SEGMENT ((16 * 1024 * 1024) / 2) +#define MAX_SIT_BITMAP_SIZE (SEG_ALIGN(SIZE_ALIGN(F2FS_MAX_SEGMENT, \ + SIT_ENTRY_PER_BLOCK)) * \ + c.blks_per_seg / 8) +#define MAX_CP_PAYLOAD (SEG_ALIGN(SIZE_ALIGN(UINT32_MAX, NAT_ENTRY_PER_BLOCK)) * \ + DEFAULT_NAT_ENTRY_RATIO / 100 * \ + c.blks_per_seg / 8 + \ + MAX_SIT_BITMAP_SIZE - MAX_BITMAP_SIZE_IN_CKPT) + +/* + * Note that f2fs_sit_entry->vblocks has the following bit-field information. + * [15:10] : allocation type such as CURSEG_XXXX_TYPE + * [9:0] : valid block count + */ +#define SIT_VBLOCKS_SHIFT 10 +#define SIT_VBLOCKS_MASK ((1 << SIT_VBLOCKS_SHIFT) - 1) +#define GET_SIT_VBLOCKS(raw_sit) \ + (le16_to_cpu((raw_sit)->vblocks) & SIT_VBLOCKS_MASK) +#define GET_SIT_TYPE(raw_sit) \ + ((le16_to_cpu((raw_sit)->vblocks) & ~SIT_VBLOCKS_MASK) \ + >> SIT_VBLOCKS_SHIFT) + +struct f2fs_sit_entry { + __le16 vblocks; /* reference above */ + __u8 valid_map[SIT_VBLOCK_MAP_SIZE]; /* bitmap for valid blocks */ + __le64 mtime; /* segment age for cleaning */ +} __attribute__((packed)); + +static_assert(sizeof(struct f2fs_sit_entry) == 74, ""); + +/* + * On disk layout is: + * struct f2fs_sit_entry entries[SIT_ENTRY_PER_BLOCK]; + */ +struct f2fs_sit_block { + struct f2fs_sit_entry entries[0]; +}; + +/* + * For segment summary + * + * One summary block contains exactly 2048 summary entries, which represents + * exactly 32MB segment by default. Not allow to change the basic units. + * + * NOTE: For initializing fields, you must use set_summary + * + * - If data page, nid represents dnode's nid + * - If node page, nid represents the node page's nid. + * + * The ofs_in_node is used by only data page. It represents offset + * from node's page's beginning to get a data block address. + * ex) data_blkaddr = (block_t)(nodepage_start_address + ofs_in_node) + */ +#define ENTRIES_IN_SUM (F2FS_BLKSIZE / 8) +#define SUMMARY_SIZE (7) /* sizeof(struct summary) */ +#define SUM_FOOTER_SIZE (5) /* sizeof(struct summary_footer) */ +#define SUM_ENTRIES_SIZE (SUMMARY_SIZE * ENTRIES_IN_SUM) + +/* a summary entry for a 4KB-sized block in a segment */ +struct f2fs_summary { + __le32 nid; /* parent node id */ + union { + __u8 reserved[3]; + struct { + __u8 version; /* node version number */ + __le16 ofs_in_node; /* block index in parent node */ + } __attribute__((packed)); + }; +} __attribute__((packed)); + +static_assert(sizeof(struct f2fs_summary) == 7, ""); + +/* summary block type, node or data, is stored to the summary_footer */ +#define SUM_TYPE_NODE (1) +#define SUM_TYPE_DATA (0) + +struct summary_footer { + unsigned char entry_type; /* SUM_TYPE_XXX */ + __le32 check_sum __attribute__((packed)); /* summary checksum */ +}; + +static_assert(sizeof(struct summary_footer) == 5, ""); + +#define SUM_JOURNAL_SIZE (F2FS_BLKSIZE - SUM_FOOTER_SIZE -\ + SUM_ENTRIES_SIZE) +#define NAT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ + sizeof(struct nat_journal_entry)) +#define NAT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ + sizeof(struct nat_journal_entry)) +#define SIT_JOURNAL_ENTRIES ((SUM_JOURNAL_SIZE - 2) /\ + sizeof(struct sit_journal_entry)) +#define SIT_JOURNAL_RESERVED ((SUM_JOURNAL_SIZE - 2) %\ + sizeof(struct sit_journal_entry)) + +/* + * Reserved area should make size of f2fs_extra_info equals to + * that of nat_journal and sit_journal. + */ +#define EXTRA_INFO_RESERVED (SUM_JOURNAL_SIZE - 2 - 8) + +/* + * frequently updated NAT/SIT entries can be stored in the spare area in + * summary blocks + */ +enum { + NAT_JOURNAL = 0, + SIT_JOURNAL +}; + +struct nat_journal_entry { + __le32 nid; + struct f2fs_nat_entry ne; +} __attribute__((packed)); + +static_assert(sizeof(struct nat_journal_entry) == 13, ""); + +/* + * Layout is as follows: + * struct nat_journal_entry entries[NAT_JOURNAL_ENTRIES]; + * __u8 reserved[NAT_JOURNAL_RESERVED]; + */ +struct nat_journal { + struct nat_journal_entry entries[0]; +}; + +struct sit_journal_entry { + __le32 segno; + struct f2fs_sit_entry se; +} __attribute__((packed)); + +static_assert(sizeof(struct sit_journal_entry) == 78, ""); + +/* + * Layout is as follows: + * struct sit_journal_entry entries[SIT_JOURNAL_ENTRIES]; + * __u8 reserved[SIT_JOURNAL_RESERVED]; + */ +struct sit_journal { + struct sit_journal_entry entries[0]; +}; + +/* + * Layout is as follows: + * __le64 kbytes_written; + * __u8 reserved[EXTRA_INFO_RESERVED]; + */ +struct f2fs_extra_info { + __le64 kbytes_written; + __u8 reserved[0]; +} __attribute__((packed)); + +/* + * This struct's used size depends on F2FS_BLKSIZE. DO NOT use sizeof + */ +struct f2fs_journal { + union { + __le16 n_nats; + __le16 n_sits; + }; + /* spare area is used by NAT or SIT journals or extra info */ + union { + struct nat_journal nat_j; + struct sit_journal sit_j; + struct f2fs_extra_info info; + }; +} __attribute__((packed)); + +/* + * Block-sized summary block structure + * Layout of f2fs_summary block is + * struct f2fs_summary entries[ENTRIES_IN_SUM]; + * struct f2fs_journal journal; + * struct summary_footer footer; + * + * Do NOT use sizeof, use F2FS_BLKSIZE + * + */ +struct f2fs_summary_block { + struct f2fs_summary entries[0]; +}; +#define F2FS_SUMMARY_BLOCK_JOURNAL(blk) ((struct f2fs_journal *)(&(blk)->entries[ENTRIES_IN_SUM])) +#define F2FS_SUMMARY_BLOCK_FOOTER(blk) ((struct summary_footer *)&((char *)\ + (&(blk)->entries[0]))[F2FS_BLKSIZE - SUM_FOOTER_SIZE]) + +/* + * For directory operations + */ +#define F2FS_DOT_HASH 0 +#define F2FS_DDOT_HASH F2FS_DOT_HASH +#define F2FS_MAX_HASH (~((0x3ULL) << 62)) +#define F2FS_HASH_COL_BIT ((0x1ULL) << 63) + +typedef __le32 f2fs_hash_t; + +/* One directory entry slot covers 8bytes-long file name */ +#define F2FS_SLOT_LEN 8 +#define F2FS_SLOT_LEN_BITS 3 + +#define GET_DENTRY_SLOTS(x) ((x + F2FS_SLOT_LEN - 1) >> F2FS_SLOT_LEN_BITS) + +/* the number of dentry in a block */ +#define NR_DENTRY_IN_BLOCK ((BITS_PER_BYTE * F2FS_BLKSIZE) / \ + ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * BITS_PER_BYTE + 1)) +/* MAX level for dir lookup */ +#define MAX_DIR_HASH_DEPTH 63 + +/* MAX buckets in one level of dir */ +#define MAX_DIR_BUCKETS (1 << ((MAX_DIR_HASH_DEPTH / 2) - 1)) + +#define SIZE_OF_DIR_ENTRY 11 /* by byte */ +#define SIZE_OF_DENTRY_BITMAP ((NR_DENTRY_IN_BLOCK + BITS_PER_BYTE - 1) / \ + BITS_PER_BYTE) +#define SIZE_OF_RESERVED (F2FS_BLKSIZE - ((SIZE_OF_DIR_ENTRY + \ + F2FS_SLOT_LEN) * \ + NR_DENTRY_IN_BLOCK + SIZE_OF_DENTRY_BITMAP)) +#define MIN_INLINE_DENTRY_SIZE 40 /* just include '.' and '..' entries */ + +/* One directory entry slot representing F2FS_SLOT_LEN-sized file name */ +struct f2fs_dir_entry { + __le32 hash_code; /* hash code of file name */ + __le32 ino; /* inode number */ + __le16 name_len; /* lengh of file name */ + __u8 file_type; /* file type */ +} __attribute__((packed)); + +static_assert(sizeof(struct f2fs_dir_entry) == 11, ""); + +/* + * Block-sized directory entry block + * On disk structure: + * struct f2fs_dentry_block; + * __u8 reserved[SIZE_OF_RESERVED]; + * struct f2fs_dir_entry dentry[NR_DENTRY_IN_BLOCK]; + * __u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN]; + * + * Do NOT use sizeof. Use F2FS_BLKSIZE instead + */ +struct f2fs_dentry_block { + /* validity bitmap for directory entries in each block */ + __u8 dentry_bitmap[0]; /* size is SIZE_OF_DENTRY_BITMAP, based on block size */ +}; + +#define F2FS_DENTRY_BLOCK_DENTRIES(blk) ((struct f2fs_dir_entry *)\ + &((blk)->dentry_bitmap[SIZE_OF_DENTRY_BITMAP + SIZE_OF_RESERVED])) +#define F2FS_DENTRY_BLOCK_DENTRY(blk, i) (F2FS_DENTRY_BLOCK_DENTRIES((blk))[(i)]) + +#define F2FS_DENTRY_BLOCK_FILENAMES(blk) ((__u8(*)[F2FS_SLOT_LEN])&F2FS_DENTRY_BLOCK_DENTRY(blk,\ + NR_DENTRY_IN_BLOCK)) +#define F2FS_DENTRY_BLOCK_FILENAME(blk, i) (&((__u8 *)&F2FS_DENTRY_BLOCK_DENTRY(blk,\ + NR_DENTRY_IN_BLOCK))[(i) * F2FS_SLOT_LEN]) + +/* for inline stuff */ +#define DEF_INLINE_RESERVED_SIZE 1 + +/* for inline dir */ +#define NR_INLINE_DENTRY(node) (MAX_INLINE_DATA(node) * BITS_PER_BYTE / \ + ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \ + BITS_PER_BYTE + 1)) +#define INLINE_DENTRY_BITMAP_SIZE(node) ((NR_INLINE_DENTRY(node) + \ + BITS_PER_BYTE - 1) / BITS_PER_BYTE) +#define INLINE_RESERVED_SIZE(node) (MAX_INLINE_DATA(node) - \ + ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \ + NR_INLINE_DENTRY(node) + \ + INLINE_DENTRY_BITMAP_SIZE(node))) + +/* file types used in inode_info->flags */ +enum FILE_TYPE { + F2FS_FT_UNKNOWN, + F2FS_FT_REG_FILE, + F2FS_FT_DIR, + F2FS_FT_CHRDEV, + F2FS_FT_BLKDEV, + F2FS_FT_FIFO, + F2FS_FT_SOCK, + F2FS_FT_SYMLINK, + F2FS_FT_MAX, + /* added for fsck */ + F2FS_FT_ORPHAN, + F2FS_FT_XATTR, + F2FS_FT_LAST_FILE_TYPE = F2FS_FT_XATTR, +}; + +enum dot_type { + NON_DOT, + TYPE_DOT, + TYPE_DOTDOT +}; + +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_IFDIR 0040000 +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) +#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) + +/* from f2fs/segment.h */ +enum { + LFS = 0, + SSR +}; + +/* invalid sb types */ +#define SB_FORCE_STOP 0x1 /* s_stop_reason is set */ +#define SB_ABNORMAL_STOP 0x2 /* s_stop_reason is set except shutdown */ +#define SB_FS_ERRORS 0x4 /* s_erros is set */ +#define SB_INVALID 0x8 /* sb is invalid */ +#define SB_ENCODE_FLAG 0x16 /* encode_flag */ +#define SB_NEED_FIX (SB_ABNORMAL_STOP | SB_FS_ERRORS | \ + SB_INVALID | SB_ENCODE_FLAG) + +#define MAX_CACHE_SUMS 8 + +/* feature list in Android */ +enum { + F2FS_FEATURE_NAT_BITS = 0x0001, +}; + +/* nolinear lookup tune */ +enum { + LINEAR_LOOKUP_DEFAULT = 0, + LINEAR_LOOKUP_ENABLE, + LINEAR_LOOKUP_DISABLE, +}; + +/* Fault inject control */ +enum { + FAULT_SEG_TYPE, + FAULT_SUM_TYPE, + FAULT_SUM_ENT, + FAULT_NAT, + FAULT_NODE, + FAULT_XATTR_ENT, + FAULT_COMPR, + FAULT_INODE, + FAULT_DENTRY, + FAULT_DATA, + FAULT_QUOTA, + FAULT_MAX +}; + +#define F2FS_ALL_FAULT_TYPE ((1UL << (FAULT_MAX)) - 1) + +struct f2fs_fault_info { + int inject_ops; + int inject_rate; + unsigned int inject_type; + unsigned int fault_cnt[FAULT_MAX]; +}; + +extern const char *f2fs_fault_name[FAULT_MAX]; +#define IS_FAULT_SET(fi, type) ((fi)->inject_type & (1UL << (type))) + +struct f2fs_configuration { + uint32_t conf_reserved_sections; + uint32_t reserved_segments; + uint32_t new_reserved_segments; + int sparse_mode; + int zoned_mode; + int zoned_model; + size_t zone_blocks; + double overprovision; + double new_overprovision; + uint32_t cur_seg[NR_CURSEG_TYPE]; + uint32_t segs_per_sec; + uint32_t secs_per_zone; + uint32_t segs_per_zone; + uint32_t start_sector; + uint32_t total_segments; + uint32_t sector_size; + uint64_t device_size; + uint64_t total_sectors; + uint64_t wanted_total_sectors; + uint64_t wanted_sector_size; + uint64_t target_sectors; + uint32_t sectors_per_blk; + uint32_t blks_per_seg; + __u8 init_version[VERSION_LEN + 1]; + __u8 sb_version[VERSION_LEN + 1]; + __u8 version[VERSION_LEN + 1]; + char *vol_label; + char *vol_uuid; + uint16_t s_encoding; + uint16_t s_encoding_flags; + int32_t kd; + int32_t dump_fd; + char *dump_symlink; + int dump_sym_target_len; + struct device_info devices[MAX_DEVICES]; + int ndevs; + char *extension_list[2]; + const char *rootdev_name; + int dbg_lv; + int show_dentry; + int trim; + int trimmed; + int func; + void *private; + int dry_run; + int no_kernel_check; + int fix_on; + int force; + int ignore_error; + int defset; + int bug_on; + unsigned int invalid_sb; + int bug_nat_bits; + bool quota_fixed; + int alloc_failed; + int auto_fix; + int layout; + int show_file_map; + u64 show_file_map_max_offset; + int quota_fix; + int preen_mode; + int ro; + int preserve_limits; /* preserve quota limits */ + int large_nat_bitmap; + int fix_chksum; /* fix old cp.chksum position */ + int nolinear_lookup; /* disable linear lookup */ + unsigned int feature; /* defined features */ + unsigned int disabled_feature; /* disabled feature, used for Android only */ + unsigned int quota_bits; /* quota bits */ + time_t fixed_time; + int roll_forward; + bool need_fsync; + bool need_whint; + int whint; + int aliased_devices; + uint32_t aliased_segments; + + /* mkfs parameters */ + int fake_seed; + uint32_t next_free_nid; + uint32_t lpf_ino; + uint32_t first_alias_ino; + uint32_t root_uid; + uint32_t root_gid; + uint32_t blksize; + uint32_t blksize_bits; + + /* defragmentation parameters */ + int defrag_shrink; + uint64_t defrag_start; + uint64_t defrag_len; + uint64_t defrag_target; + + /* sload parameters */ + char *from_dir; + char *mount_point; + char *target_out_dir; + char *fs_config_file; +#ifdef HAVE_LIBSELINUX + struct selinux_opt seopt_file[8]; + int nr_opt; +#endif + + /* dump parameters */ + int preserve_perms; + int preserve_symlinks; + + /* resize parameters */ + int safe_resize; + + /* precomputed fs UUID checksum for seeding other checksums */ + uint32_t chksum_seed; + + /* cache parameters */ + dev_cache_config_t cache_config; + + /* compression support for sload.f2fs */ + compress_config_t compress; + + block_t curseg_offset[NR_CURSEG_TYPE]; + struct f2fs_summary sum[NR_CURSEG_TYPE][MAX_CACHE_SUMS]; + union { + struct f2fs_journal sit_jnl; + char sit_bytes[F2FS_MAX_BLKSIZE]; + }; + union { + struct f2fs_journal nat_jnl; + char nat_bytes[F2FS_MAX_BLKSIZE]; + }; + + /* Fault injection control */ + struct f2fs_fault_info fault_info; +}; + +extern int utf8_to_utf16(char *, const char *, size_t, size_t); +extern int utf16_to_utf8(char *, const char *, size_t, size_t); +extern int log_base_2(uint32_t); +extern unsigned int addrs_per_page(struct f2fs_inode *, bool); +extern u64 f2fs_max_file_offset(struct f2fs_inode *); +extern __u32 f2fs_inode_chksum(struct f2fs_node *); +extern __u32 f2fs_checkpoint_chksum(struct f2fs_checkpoint *); +extern int write_inode(struct f2fs_node *, u64, enum rw_hint); + +extern int get_bits_in_byte(unsigned char n); +extern int test_and_set_bit_le(u32, u8 *); +extern int test_and_clear_bit_le(u32, u8 *); +extern int test_bit_le(u32, const u8 *); +extern int f2fs_test_bit(unsigned int, const char *); +extern int f2fs_set_bit(unsigned int, char *); +extern int f2fs_clear_bit(unsigned int, char *); +extern u64 find_next_bit_le(const u8 *, u64, u64); +extern u64 find_next_zero_bit_le(const u8 *, u64, u64); + +extern uint32_t f2fs_cal_crc32(uint32_t, void *, int); +extern int f2fs_crc_valid(uint32_t blk_crc, void *buf, int len); + +extern void f2fs_init_configuration(void); +extern int f2fs_devs_are_umounted(void); +extern int f2fs_dev_is_writable(void); +extern int f2fs_dev_is_umounted(char *); +extern int f2fs_get_device_info(void); +extern int f2fs_get_f2fs_info(void); +extern unsigned int calc_extra_isize(void); +extern int get_device_info(int); +extern int f2fs_init_sparse_file(void); +extern void f2fs_release_sparse_resource(void); +extern int f2fs_finalize_device(void); +extern int f2fs_fsync_device(void); + +extern void dcache_init(void); +extern void dcache_release(void); + +extern int dev_read(void *, __u64, size_t); +#ifdef POSIX_FADV_WILLNEED +extern int dev_readahead(__u64, size_t); +#else +extern int dev_readahead(__u64, size_t UNUSED(len)); +#endif +extern enum rw_hint f2fs_io_type_to_rw_hint(int); +extern int dev_write(void *, __u64, size_t, enum rw_hint); +extern int dev_write_block(void *, __u64, enum rw_hint); +extern int dev_write_dump(void *, __u64, size_t); +#if !defined(__MINGW32__) +extern int dev_write_symlink(char *, size_t); +#endif +/* All bytes in the buffer must be 0 use dev_fill(). */ +extern int dev_fill(void *, __u64, size_t, enum rw_hint); +extern int dev_fill_block(void *, __u64, enum rw_hint); + +extern int dev_read_block(void *, __u64); +extern int dev_reada_block(__u64); + +extern int dev_read_version(void *, __u64, size_t); +extern void get_kernel_version(__u8 *); +extern void get_kernel_uname_version(__u8 *); +f2fs_hash_t f2fs_dentry_hash(int, int, const unsigned char *, int); + +static inline bool f2fs_has_extra_isize(struct f2fs_inode *inode) +{ + return (inode->i_inline & F2FS_EXTRA_ATTR); +} + +static inline int __get_extra_isize(struct f2fs_inode *inode) +{ + if (f2fs_has_extra_isize(inode)) + return le16_to_cpu(inode->i_extra_isize) / sizeof(__le32); + return 0; +} + +extern struct f2fs_configuration c; +static inline int get_inline_xattr_addrs(struct f2fs_inode *inode) +{ + if (c.feature & F2FS_FEATURE_FLEXIBLE_INLINE_XATTR) + return le16_to_cpu(inode->i_inline_xattr_size); + else if (inode->i_inline & F2FS_INLINE_XATTR || + inode->i_inline & F2FS_INLINE_DENTRY) + return DEFAULT_INLINE_XATTR_ADDRS; + else + return 0; +} + +#define get_extra_isize(node) __get_extra_isize(&node->i) + +#define F2FS_ZONED_NONE 0 +#define F2FS_ZONED_HA 1 +#define F2FS_ZONED_HM 2 + +#ifdef HAVE_LINUX_BLKZONED_H + +/* Let's just use v2, since v1 should be compatible with v2 */ +#define BLK_ZONE_REP_CAPACITY (1 << 0) +struct blk_zone_v2 { + __u64 start; /* Zone start sector */ + __u64 len; /* Zone length in number of sectors */ + __u64 wp; /* Zone write pointer position */ + __u8 type; /* Zone type */ + __u8 cond; /* Zone condition */ + __u8 non_seq; /* Non-sequential write resources active */ + __u8 reset; /* Reset write pointer recommended */ + __u8 resv[4]; + __u64 capacity; /* Zone capacity in number of sectors */ + __u8 reserved[24]; +}; +#define blk_zone blk_zone_v2 + +struct blk_zone_report_v2 { + __u64 sector; + __u32 nr_zones; + __u32 flags; + struct blk_zone zones[0]; +}; +#define blk_zone_report blk_zone_report_v2 + +#define blk_zone_type(z) (z)->type +#define blk_zone_conv(z) ((z)->type == BLK_ZONE_TYPE_CONVENTIONAL) +#define blk_zone_seq_req(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_REQ) +#define blk_zone_seq_pref(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_PREF) +#define blk_zone_seq(z) (blk_zone_seq_req(z) || blk_zone_seq_pref(z)) + +static inline const char * +blk_zone_type_str(struct blk_zone *blkz) +{ + switch (blk_zone_type(blkz)) { + case BLK_ZONE_TYPE_CONVENTIONAL: + return( "Conventional" ); + case BLK_ZONE_TYPE_SEQWRITE_REQ: + return( "Sequential-write-required" ); + case BLK_ZONE_TYPE_SEQWRITE_PREF: + return( "Sequential-write-preferred" ); + } + return( "Unknown-type" ); +} + +#define blk_zone_cond(z) (z)->cond + +static inline const char * +blk_zone_cond_str(struct blk_zone *blkz) +{ + switch (blk_zone_cond(blkz)) { + case BLK_ZONE_COND_NOT_WP: + return "Not-write-pointer"; + case BLK_ZONE_COND_EMPTY: + return "Empty"; + case BLK_ZONE_COND_IMP_OPEN: + return "Implicit-open"; + case BLK_ZONE_COND_EXP_OPEN: + return "Explicit-open"; + case BLK_ZONE_COND_CLOSED: + return "Closed"; + case BLK_ZONE_COND_READONLY: + return "Read-only"; + case BLK_ZONE_COND_FULL: + return "Full"; + case BLK_ZONE_COND_OFFLINE: + return "Offline"; + } + return "Unknown-cond"; +} + +/* + * Handle kernel zone capacity support + */ +#define blk_zone_empty(z) (blk_zone_cond(z) == BLK_ZONE_COND_EMPTY) +#define blk_zone_open(z) (blk_zone_cond(z) == BLK_ZONE_COND_IMP_OPEN || \ + blk_zone_cond(z) == BLK_ZONE_COND_EXP_OPEN) +#define blk_zone_sector(z) (z)->start +#define blk_zone_length(z) (z)->len +#define blk_zone_wp_sector(z) (z)->wp +#define blk_zone_need_reset(z) (int)(z)->reset +#define blk_zone_non_seq(z) (int)(z)->non_seq +#define blk_zone_capacity(z, f) ((f & BLK_ZONE_REP_CAPACITY) ? \ + (z)->capacity : (z)->len) + +#endif + +struct blk_zone; + +extern int f2fs_get_zoned_model(int); +extern int f2fs_get_zone_blocks(int); +extern int f2fs_report_zone(int, uint64_t, struct blk_zone *); +typedef int (report_zones_cb_t)(int i, void *, void *); +extern int f2fs_report_zones(int, report_zones_cb_t *, void *); +extern int f2fs_check_zones(int); +int f2fs_reset_zone(int, void *); +extern int f2fs_reset_zones(int); +int f2fs_finish_zone(int i, void *blkzone); +extern uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb); + +#define SIZE_ALIGN(val, size) (((val) + (size) - 1) / (size)) +#define SEG_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg) +#define ZONE_ALIGN(blks) SIZE_ALIGN(blks, c.blks_per_seg * \ + c.segs_per_zone) + +static inline uint32_t get_reserved(struct f2fs_super_block *sb, double ovp) +{ + uint32_t usable_main_segs = f2fs_get_usable_segments(sb); + uint32_t segs_per_sec = round_up(usable_main_segs, get_sb(section_count)); + uint32_t reserved; + + if (c.conf_reserved_sections) + reserved = c.conf_reserved_sections * segs_per_sec; + else + reserved = (100 / ovp + 1 + NR_CURSEG_TYPE) * segs_per_sec; + + /* Let's keep the section alignment */ + return round_up(reserved, segs_per_sec) * segs_per_sec; +} + +static inline uint32_t overprovision_segment_buffer(struct f2fs_super_block *sb) +{ + /* Give 6 current sections to avoid huge GC overheads. */ + return 6 * get_sb(segs_per_sec); +} + +static inline double get_best_overprovision(struct f2fs_super_block *sb) +{ + double ovp, candidate, end, diff, space; + double max_ovp = 0, max_space = 0; + uint32_t usable_main_segs = f2fs_get_usable_segments(sb); + uint32_t reserved; + + if (get_sb(segment_count_main) < 256) { + candidate = 10; + end = 95; + diff = 5; + } else { + candidate = 0.01; + end = 10; + diff = 0.01; + } + + for (; candidate <= end; candidate += diff) { + reserved = get_reserved(sb, candidate); + ovp = (usable_main_segs - reserved) * candidate / 100; + if (ovp < 0) + continue; + space = usable_main_segs - max((double)reserved, ovp) - + overprovision_segment_buffer(sb); + if (max_space < space) { + max_space = space; + max_ovp = candidate; + } + } + return max_ovp; +} + +static inline __le64 get_cp_crc(struct f2fs_checkpoint *cp) +{ + uint64_t cp_ver = get_cp(checkpoint_ver); + size_t crc_offset = get_cp(checksum_offset); + uint32_t crc = le32_to_cpu(*(__le32 *)((unsigned char *)cp + + crc_offset)); + + cp_ver |= ((uint64_t)crc << 32); + return cpu_to_le64(cp_ver); +} + +static inline int exist_qf_ino(struct f2fs_super_block *sb) +{ + int i; + + for (i = 0; i < F2FS_MAX_QUOTAS; i++) + if (sb->qf_ino[i]) + return 1; + return 0; +} + +static inline int is_qf_ino(struct f2fs_super_block *sb, nid_t ino) +{ + int i; + + for (i = 0; i < F2FS_MAX_QUOTAS; i++) + if (sb->qf_ino[i] == ino) + return 1; + return 0; +} + +static inline void show_version(const char *prog) +{ +#if defined(F2FS_TOOLS_VERSION) && defined(F2FS_TOOLS_DATE) + MSG(0, "%s %s (%s)\n", prog, F2FS_TOOLS_VERSION, F2FS_TOOLS_DATE); +#else + MSG(0, "%s -- version not supported\n", prog); +#endif +} + +static inline void f2fs_init_inode(struct f2fs_super_block *sb, + struct f2fs_node *raw_node, nid_t ino, time_t mtime, mode_t mode) +{ + F2FS_NODE_FOOTER(raw_node)->nid = cpu_to_le32(ino); + F2FS_NODE_FOOTER(raw_node)->ino = cpu_to_le32(ino); + F2FS_NODE_FOOTER(raw_node)->cp_ver = cpu_to_le64(1); + + raw_node->i.i_uid = cpu_to_le32(c.root_uid); + raw_node->i.i_gid = cpu_to_le32(c.root_gid); + + raw_node->i.i_atime = cpu_to_le32(mtime); + raw_node->i.i_atime_nsec = 0; + raw_node->i.i_ctime = cpu_to_le32(mtime); + raw_node->i.i_ctime_nsec = 0; + raw_node->i.i_mtime = cpu_to_le32(mtime); + raw_node->i.i_mtime_nsec = 0; + raw_node->i.i_generation = 0; + raw_node->i.i_xattr_nid = 0; + raw_node->i.i_flags = 0; + raw_node->i.i_current_depth = cpu_to_le32(LINUX_S_ISDIR(mode) ? 1 : 0); + raw_node->i.i_dir_level = DEF_DIR_LEVEL; + raw_node->i.i_mode = cpu_to_le16(mode); + raw_node->i.i_links = cpu_to_le32(LINUX_S_ISDIR(mode) ? 2 : 1); + + /* for dentry block in directory */ + raw_node->i.i_size = cpu_to_le64(1 << get_sb(log_blocksize)); + raw_node->i.i_blocks = cpu_to_le64(2); + + if (c.feature & F2FS_FEATURE_EXTRA_ATTR) { + raw_node->i.i_inline = F2FS_EXTRA_ATTR; + raw_node->i.i_extra_isize = cpu_to_le16(calc_extra_isize()); + } + + if (c.feature & F2FS_FEATURE_PRJQUOTA) + raw_node->i.i_projid = cpu_to_le32(F2FS_DEF_PROJID); + + if (c.feature & F2FS_FEATURE_INODE_CRTIME) { + raw_node->i.i_crtime = cpu_to_le32(mtime); + raw_node->i.i_crtime_nsec = 0; + } + + if (c.feature & F2FS_FEATURE_COMPRESSION) { + raw_node->i.i_compr_blocks = 0; + raw_node->i.i_compress_algorithm = 0; + raw_node->i.i_log_cluster_size = 0; + raw_node->i.i_compress_flag = 0; + } + + raw_node->i.i_ext.fofs = 0; + raw_node->i.i_ext.blk_addr = 0; + raw_node->i.i_ext.len = 0; +} + +struct feature { + char *name; + u32 mask; + u32 settable; +}; + +#define INIT_FEATURE_TABLE \ +struct feature feature_table[] = { \ + { "encrypt", F2FS_FEATURE_ENCRYPT, 1}, \ + { "blkzoned", F2FS_FEATURE_BLKZONED, 0}, \ + { "extra_attr", F2FS_FEATURE_EXTRA_ATTR, 1}, \ + { "project_quota", F2FS_FEATURE_PRJQUOTA, 1}, \ + { "inode_checksum", F2FS_FEATURE_INODE_CHKSUM, 1}, \ + { "flexible_inline_xattr", F2FS_FEATURE_FLEXIBLE_INLINE_XATTR,1}, \ + { "quota", F2FS_FEATURE_QUOTA_INO, 1}, \ + { "inode_crtime", F2FS_FEATURE_INODE_CRTIME, 1}, \ + { "lost_found", F2FS_FEATURE_LOST_FOUND, 1}, \ + { "verity", F2FS_FEATURE_VERITY, 1}, \ + { "sb_checksum", F2FS_FEATURE_SB_CHKSUM, 1}, \ + { "casefold", F2FS_FEATURE_CASEFOLD, 1}, \ + { "compression", F2FS_FEATURE_COMPRESSION, 1}, \ + { "ro", F2FS_FEATURE_RO, 1}, \ + { NULL, 0x0, 0}, \ +}; + +static inline u32 feature_map(struct feature *table, char *feature) +{ + struct feature *p; + for (p = table; p->name; p++) { + if (!p->settable) + continue; + if (strcmp(p->name, feature)) + continue; + break; + } + return p->mask; +} + +static inline char *feature_name(struct feature *table, u32 mask) +{ + struct feature *p; + for (p = table; p->name; p++) { + if (p->mask != mask) + continue; + break; + } + return p->name; +} + +static inline int set_feature_bits(struct feature *table, char *features) +{ + u32 mask = feature_map(table, features); + if (mask) { + c.feature |= mask; + } else { + MSG(0, "Error: Wrong features %s\n", features); + return -1; + } + return 0; +} + +static inline int parse_feature(struct feature *table, const char *features) +{ + char *buf, *sub, *next; + + buf = strdup(features); + if (!buf) + return -1; + + for (sub = buf; sub && *sub; sub = next ? next + 1 : NULL) { + /* Skip the beginning blanks */ + while (*sub && *sub == ' ') + sub++; + next = sub; + /* Skip a feature word */ + while (*next && *next != ' ' && *next != ',') + next++; + + if (*next == 0) + next = NULL; + else + *next = 0; + + if (set_feature_bits(table, sub)) { + free(buf); + return -1; + } + } + free(buf); + return 0; +} + +static inline int parse_root_owner(char *ids, + uint32_t *root_uid, uint32_t *root_gid) +{ + char *uid = ids; + char *gid = NULL; + int i; + + /* uid:gid */ + for (i = 0; i < strlen(ids) - 1; i++) + if (*(ids + i) == ':') + gid = ids + i + 1; + if (!gid) + return -1; + + *root_uid = atoi(uid); + *root_gid = atoi(gid); + return 0; +} + +/* + * NLS definitions + */ +struct f2fs_nls_table { + int version; + const struct f2fs_nls_ops *ops; +}; + +struct f2fs_nls_ops { + int (*casefold)(const struct f2fs_nls_table *charset, + const unsigned char *str, size_t len, + unsigned char *dest, size_t dlen); +}; + +extern const struct f2fs_nls_table *f2fs_load_nls_table(int encoding); +#define F2FS_ENC_UTF8_12_0 1 + +extern int f2fs_str2encoding(const char *string); +extern char *f2fs_encoding2str(const int encoding); +extern int f2fs_get_encoding_flags(int encoding); +extern int f2fs_str2encoding_flags(char **param, __u16 *flags); + +static inline void check_block_struct_sizes(void) +{ + /* Check Orphan Block Size */ + assert(F2FS_ORPHANS_PER_BLOCK * sizeof(__le32) + + sizeof(struct orphan_block_footer) == F2FS_BLKSIZE); + + /* Check Inode Block Size */ + assert(offsetof(struct f2fs_inode, i_extra_isize) + DEF_ADDRS_PER_INODE * sizeof(__le32) + + sizeof(struct f2fs_inode_nids) + sizeof(struct node_footer) == F2FS_BLKSIZE); + + /* Check Direct Block Size */ + assert(DEF_ADDRS_PER_BLOCK * sizeof(__le32) + sizeof(struct node_footer) == F2FS_BLKSIZE); + + /* Check Indirect Block Size */ + assert(NIDS_PER_BLOCK * sizeof(__le32) + sizeof(struct node_footer) == F2FS_BLKSIZE); + + /* Check NAT Block Size */ + assert((NAT_ENTRY_PER_BLOCK + 1) * sizeof(struct f2fs_nat_entry) > F2FS_BLKSIZE); + assert(NAT_ENTRY_PER_BLOCK * sizeof(struct f2fs_nat_entry) <= F2FS_BLKSIZE); + + /* Check SIT Block Size */ + assert((SIT_ENTRY_PER_BLOCK + 1) * sizeof(struct f2fs_sit_entry) > F2FS_BLKSIZE); + assert(SIT_ENTRY_PER_BLOCK * sizeof(struct f2fs_sit_entry) <= F2FS_BLKSIZE); + + /* Check NAT Journal Block Size */ + assert(sizeof(struct f2fs_summary) * ENTRIES_IN_SUM + + offsetof(struct f2fs_journal, nat_j) + + NAT_JOURNAL_ENTRIES * sizeof(struct nat_journal_entry) + + NAT_JOURNAL_RESERVED + sizeof(struct summary_footer) == F2FS_BLKSIZE); + + /* Check SIT Journal Block Size */ + assert(sizeof(struct f2fs_summary) * ENTRIES_IN_SUM + + offsetof(struct f2fs_journal, sit_j) + + SIT_JOURNAL_ENTRIES * sizeof(struct sit_journal_entry) + + SIT_JOURNAL_RESERVED + sizeof(struct summary_footer) == F2FS_BLKSIZE); + + /* Check Info Journal Block Size */ + assert(sizeof(struct f2fs_summary) * ENTRIES_IN_SUM + sizeof(__le64) + + offsetof(struct f2fs_journal, info) + + EXTRA_INFO_RESERVED + sizeof(struct summary_footer) == F2FS_BLKSIZE); + + /* Check Dentry Block Size */ + assert(sizeof(__u8) * (SIZE_OF_DENTRY_BITMAP + SIZE_OF_RESERVED) + + NR_DENTRY_IN_BLOCK * sizeof(struct f2fs_dir_entry) + + NR_DENTRY_IN_BLOCK * F2FS_SLOT_LEN * sizeof(u8) == F2FS_BLKSIZE); +} + +/* Fault inject control */ +#define time_to_inject(type) __time_to_inject(type, __func__, \ + __builtin_return_address(0)) +static inline bool __time_to_inject(int type, const char *func, + const char *parent_func) +{ + struct f2fs_fault_info *ffi = &c.fault_info; + + if (!ffi->inject_rate) + return false; + + if (!IS_FAULT_SET(ffi, type)) + return false; + + ffi->inject_ops++; + if (ffi->inject_ops >= ffi->inject_rate) { + ffi->inject_ops = 0; + if (ffi->fault_cnt[type] != UINT_MAX) + ffi->fault_cnt[type]++; + MSG(0, "inject %s in %s of %p\n", + f2fs_fault_name[type], func, parent_func); + return true; + } + return false; +} + +#endif /*__F2FS_FS_H */ diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/quota.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/quota.h new file mode 100644 index 00000000000..f0eff71a9a2 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/include/quota.h @@ -0,0 +1,83 @@ +/* + * + * Header file for disk format of new quotafile format + * + * Copied essential definitions and structures for mkfs.f2fs from quotaio.h + * + * Aditya Kali + * Jan Kara + * Hyojun Kim - Ported to f2fs-tools + * + */ +#ifndef F2FS_QUOTA_H +#define F2FS_QUOTA_H + +enum quota_type { + USRQUOTA = 0, + GRPQUOTA = 1, + PRJQUOTA = 2, + MAXQUOTAS = 3, +}; + +#if MAXQUOTAS > 32 +#error "cannot have more than 32 quota types to fit in qtype_bits" +#endif + +#define QUOTA_USR_BIT (1 << USRQUOTA) +#define QUOTA_GRP_BIT (1 << GRPQUOTA) +#define QUOTA_PRJ_BIT (1 << PRJQUOTA) +#define QUOTA_ALL_BIT (QUOTA_USR_BIT | QUOTA_GRP_BIT | QUOTA_PRJ_BIT) + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927, /* GRPQUOTA */\ + 0xd9c03f14 /* PRJQUOTA */\ +} + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ + +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#define QT_TREEOFF 1 /* Offset of tree in file in blocks */ + +struct v2_disk_dqheader { + uint32_t dqh_magic; /* Magic number identifying file */ + uint32_t dqh_version; /* File version */ +}; + +static_assert(sizeof(struct v2_disk_dqheader) == 8, ""); + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + uint32_t dqi_bgrace; /* Time before block soft limit becomes hard limit */ + uint32_t dqi_igrace; /* Time before inode soft limit becomes hard limit */ + uint32_t dqi_flags; /* Flags for quotafile (DQF_*) */ + uint32_t dqi_blocks; /* Number of blocks in file */ + uint32_t dqi_free_blk; /* Number of first free block in the list */ + uint32_t dqi_free_entry; /* Number of block with at least one free entry */ +}; + +static_assert(sizeof(struct v2_disk_dqinfo) == 24, ""); + +struct v2r1_disk_dqblk { + __le32 dqb_id; /* id this quota applies to */ + __le32 dqb_pad; + __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */ + __le64 dqb_isoftlimit; /* preferred inode limit */ + __le64 dqb_curinodes; /* current # allocated inodes */ + __le64 dqb_bhardlimit; /* absolute limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_bsoftlimit; /* preferred limit on disk space + * (in QUOTABLOCK_SIZE) */ + __le64 dqb_curspace; /* current space occupied (in bytes) */ + __le64 dqb_btime; /* time limit for excessive disk use */ + __le64 dqb_itime; /* time limit for excessive inode use */ +}; + +static_assert(sizeof(struct v2r1_disk_dqblk) == 72, ""); + +#endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/Makefile.am new file mode 100644 index 00000000000..69d46f833c3 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/Makefile.am @@ -0,0 +1,25 @@ +## Makefile.am + +lib_LTLIBRARIES = libf2fs.la + +libf2fs_la_SOURCES = libf2fs.c libf2fs_io.c libf2fs_zoned.c nls_utf8.c +libf2fs_la_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 +libf2fs_la_CPPFLAGS = -I$(top_srcdir)/include +libf2fs_la_LDFLAGS = -version-info $(LIBF2FS_CURRENT):$(LIBF2FS_REVISION):$(LIBF2FS_AGE) + +root_libdir=@root_libdir@ + +install-exec-hook: + if test -n "$(root_libdir)" -a "$(libdir)" != "$(root_libdir)" -a \ + -f "$(DESTDIR)$(libdir)/libf2fs.so"; then \ + $(MKDIR_P) $(DESTDIR)$(root_libdir); \ + mv $(DESTDIR)$(libdir)/libf2fs.so.* $(DESTDIR)$(root_libdir); \ + so_img_name=$$(readlink $(DESTDIR)$(libdir)/libf2fs.so); \ + so_img_rel_target=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ + (cd $(DESTDIR)$(libdir) && \ + rm -f libf2fs.so && \ + $(LN_S) $$so_img_rel_target$(root_libdir)/$$so_img_name libf2fs.so); \ + fi + +uninstall-hook: + rm -f $(DESTDIR)$(root_libdir)/libf2fs.so* diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs.c new file mode 100644 index 00000000000..d2579d76a5c --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs.c @@ -0,0 +1,1490 @@ +/** + * libf2fs.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include +#ifdef HAVE_LINUX_LOOP_H +#include +#ifdef HAVE_LINUX_MAJOR_H +#include +#endif +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#ifdef HAVE_SCSI_SG_H +#include +#endif +#ifdef HAVE_LINUX_HDREG_H +#include +#endif +#ifdef HAVE_LINUX_LIMITS_H +#include +#endif + +/* SCSI command for standard inquiry*/ +#define MODELINQUIRY 0x12,0x00,0x00,0x00,0x4A,0x00 + +#ifndef _WIN32 /* O_BINARY is windows-specific flag */ +#define O_BINARY 0 +#else +/* On Windows, wchar_t is 8 bit sized and it causes compilation errors. */ +#define wchar_t int +#endif + +/* + * UTF conversion codes are Copied from exfat tools. + */ +static const char *utf8_to_wchar(const char *input, wchar_t *wc, + size_t insize) +{ + if ((input[0] & 0x80) == 0 && insize >= 1) { + *wc = (wchar_t) input[0]; + return input + 1; + } + if ((input[0] & 0xe0) == 0xc0 && insize >= 2) { + *wc = (((wchar_t) input[0] & 0x1f) << 6) | + ((wchar_t) input[1] & 0x3f); + return input + 2; + } + if ((input[0] & 0xf0) == 0xe0 && insize >= 3) { + *wc = (((wchar_t) input[0] & 0x0f) << 12) | + (((wchar_t) input[1] & 0x3f) << 6) | + ((wchar_t) input[2] & 0x3f); + return input + 3; + } + if ((input[0] & 0xf8) == 0xf0 && insize >= 4) { + *wc = (((wchar_t) input[0] & 0x07) << 18) | + (((wchar_t) input[1] & 0x3f) << 12) | + (((wchar_t) input[2] & 0x3f) << 6) | + ((wchar_t) input[3] & 0x3f); + return input + 4; + } + if ((input[0] & 0xfc) == 0xf8 && insize >= 5) { + *wc = (((wchar_t) input[0] & 0x03) << 24) | + (((wchar_t) input[1] & 0x3f) << 18) | + (((wchar_t) input[2] & 0x3f) << 12) | + (((wchar_t) input[3] & 0x3f) << 6) | + ((wchar_t) input[4] & 0x3f); + return input + 5; + } + if ((input[0] & 0xfe) == 0xfc && insize >= 6) { + *wc = (((wchar_t) input[0] & 0x01) << 30) | + (((wchar_t) input[1] & 0x3f) << 24) | + (((wchar_t) input[2] & 0x3f) << 18) | + (((wchar_t) input[3] & 0x3f) << 12) | + (((wchar_t) input[4] & 0x3f) << 6) | + ((wchar_t) input[5] & 0x3f); + return input + 6; + } + return NULL; +} + +static uint16_t *wchar_to_utf16(uint16_t *output, wchar_t wc, size_t outsize) +{ + if (wc <= 0xffff) { + if (outsize == 0) + return NULL; + output[0] = cpu_to_le16(wc); + return output + 1; + } + if (outsize < 2) + return NULL; + wc -= 0x10000; + output[0] = cpu_to_le16(0xd800 | ((wc >> 10) & 0x3ff)); + output[1] = cpu_to_le16(0xdc00 | (wc & 0x3ff)); + return output + 2; +} + +int utf8_to_utf16(char *output, const char *input, size_t outsize, + size_t insize) +{ + const char *inp = input; + uint16_t *outp; + wchar_t wc; + uint16_t *volume_name = calloc(sizeof(uint16_t), MAX_VOLUME_NAME); + + if (!volume_name) + return -ENOMEM; + + outp = volume_name; + + while ((size_t)(inp - input) < insize && *inp) { + inp = utf8_to_wchar(inp, &wc, insize - (inp - input)); + if (inp == NULL) { + DBG(0, "illegal UTF-8 sequence\n"); + free(volume_name); + return -EILSEQ; + } + outp = wchar_to_utf16(outp, wc, outsize - (outp - volume_name)); + if (outp == NULL) { + DBG(0, "name is too long\n"); + free(volume_name); + return -ENAMETOOLONG; + } + } + *outp = cpu_to_le16(0); + memcpy(output, volume_name, sizeof(uint16_t) * MAX_VOLUME_NAME); + free(volume_name); + return 0; +} + +static uint16_t *utf16_to_wchar(uint16_t *input, wchar_t *wc, size_t insize) +{ + if ((le16_to_cpu(input[0]) & 0xfc00) == 0xd800) { + if (insize < 2 || (le16_to_cpu(input[1]) & 0xfc00) != 0xdc00) + return NULL; + *wc = ((wchar_t) (le16_to_cpu(input[0]) & 0x3ff) << 10); + *wc |= (le16_to_cpu(input[1]) & 0x3ff); + *wc += 0x10000; + return input + 2; + } else { + *wc = le16_to_cpu(*input); + return input + 1; + } +} + +static char *wchar_to_utf8(char *output, wchar_t wc, size_t outsize) +{ + if (wc <= 0x7f) { + if (outsize < 1) + return NULL; + *output++ = (char) wc; + } else if (wc <= 0x7ff) { + if (outsize < 2) + return NULL; + *output++ = 0xc0 | (wc >> 6); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0xffff) { + if (outsize < 3) + return NULL; + *output++ = 0xe0 | (wc >> 12); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x1fffff) { + if (outsize < 4) + return NULL; + *output++ = 0xf0 | (wc >> 18); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x3ffffff) { + if (outsize < 5) + return NULL; + *output++ = 0xf8 | (wc >> 24); + *output++ = 0x80 | ((wc >> 18) & 0x3f); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else if (wc <= 0x7fffffff) { + if (outsize < 6) + return NULL; + *output++ = 0xfc | (wc >> 30); + *output++ = 0x80 | ((wc >> 24) & 0x3f); + *output++ = 0x80 | ((wc >> 18) & 0x3f); + *output++ = 0x80 | ((wc >> 12) & 0x3f); + *output++ = 0x80 | ((wc >> 6) & 0x3f); + *output++ = 0x80 | (wc & 0x3f); + } else + return NULL; + + return output; +} + +int utf16_to_utf8(char *output, const char *input, size_t outsize, + size_t insize) +{ + char *outp = output; + wchar_t wc; + uint16_t *inp; + uint16_t *volume_name = calloc(sizeof(uint16_t), MAX_VOLUME_NAME); + + if (!volume_name) + return -ENOMEM; + + memcpy(volume_name, input, sizeof(uint16_t) * MAX_VOLUME_NAME); + inp = volume_name; + + while ((size_t)(inp - volume_name) < insize && le16_to_cpu(*inp)) { + inp = utf16_to_wchar(inp, &wc, insize - (inp - volume_name)); + if (inp == NULL) { + DBG(0, "illegal UTF-16 sequence\n"); + free(volume_name); + return -EILSEQ; + } + outp = wchar_to_utf8(outp, wc, outsize - (outp - output)); + if (outp == NULL) { + DBG(0, "name is too long\n"); + free(volume_name); + return -ENAMETOOLONG; + } + } + *outp = '\0'; + free(volume_name); + return 0; +} + +int log_base_2(uint32_t num) +{ + int ret = 0; + if (num <= 0 || (num & (num - 1)) != 0) + return -1; + + while (num >>= 1) + ret++; + return ret; +} + +/* + * f2fs bit operations + */ +static const int bits_in_byte[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, +}; + +int get_bits_in_byte(unsigned char n) +{ + return bits_in_byte[n]; +} + +int test_and_set_bit_le(u32 nr, u8 *addr) +{ + int mask, retval; + + addr += nr >> 3; + mask = 1 << ((nr & 0x07)); + retval = mask & *addr; + *addr |= mask; + return retval; +} + +int test_and_clear_bit_le(u32 nr, u8 *addr) +{ + int mask, retval; + + addr += nr >> 3; + mask = 1 << ((nr & 0x07)); + retval = mask & *addr; + *addr &= ~mask; + return retval; +} + +int test_bit_le(u32 nr, const u8 *addr) +{ + return ((1 << (nr & 7)) & (addr[nr >> 3])); +} + +int f2fs_test_bit(unsigned int nr, const char *p) +{ + int mask; + char *addr = (char *)p; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + return (mask & *addr) != 0; +} + +int f2fs_set_bit(unsigned int nr, char *addr) +{ + int mask; + int ret; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + ret = mask & *addr; + *addr |= mask; + return ret; +} + +int f2fs_clear_bit(unsigned int nr, char *addr) +{ + int mask; + int ret; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + ret = mask & *addr; + *addr &= ~mask; + return ret; +} + +static inline u64 __ffs(u8 word) +{ + int num = 0; + + if ((word & 0xf) == 0) { + num += 4; + word >>= 4; + } + if ((word & 0x3) == 0) { + num += 2; + word >>= 2; + } + if ((word & 0x1) == 0) + num += 1; + return num; +} + +/* Copied from linux/lib/find_bit.c */ +#define BITMAP_FIRST_BYTE_MASK(start) (0xff << ((start) & (BITS_PER_BYTE - 1))) + +static u64 _find_next_bit_le(const u8 *addr, u64 nbits, u64 start, char invert) +{ + u8 tmp; + + if (!nbits || start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_BYTE] ^ invert; + + /* Handle 1st word. */ + tmp &= BITMAP_FIRST_BYTE_MASK(start); + start = round_down(start, BITS_PER_BYTE); + + while (!tmp) { + start += BITS_PER_BYTE; + if (start >= nbits) + return nbits; + + tmp = addr[start / BITS_PER_BYTE] ^ invert; + } + + return min(start + __ffs(tmp), nbits); +} + +u64 find_next_bit_le(const u8 *addr, u64 size, u64 offset) +{ + return _find_next_bit_le(addr, size, offset, 0); +} + + +u64 find_next_zero_bit_le(const u8 *addr, u64 size, u64 offset) +{ + return _find_next_bit_le(addr, size, offset, 0xff); +} + +/* + * Hashing code adapted from ext3 + */ +#define DELTA 0x9E3779B9 + +static void TEA_transform(unsigned int buf[4], unsigned int const in[]) +{ + __u32 sum = 0; + __u32 b0 = buf[0], b1 = buf[1]; + __u32 a = in[0], b = in[1], c = in[2], d = in[3]; + int n = 16; + + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + } while (--n); + + buf[0] += b0; + buf[1] += b1; + +} + +static void str2hashbuf(const unsigned char *msg, int len, + unsigned int *buf, int num) +{ + unsigned pad, val; + int i; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; + + val = pad; + if (len > num * 4) + len = num * 4; + for (i = 0; i < len; i++) { + if ((i % 4) == 0) + val = pad; + val = msg[i] + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) + *buf++ = val; + while (--num >= 0) + *buf++ = pad; + +} + +/** + * Return hash value of directory entry + * @param name dentry name + * @param len name lenth + * @return return on success hash value, errno on failure + */ +static f2fs_hash_t __f2fs_dentry_hash(const unsigned char *name, int len)/* Need update */ +{ + __u32 hash; + f2fs_hash_t f2fs_hash; + const unsigned char *p; + __u32 in[8], buf[4]; + + /* special hash codes for special dentries */ + if ((len <= 2) && (name[0] == '.') && + (name[1] == '.' || name[1] == '\0')) + return 0; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + p = name; + while (1) { + str2hashbuf(p, len, in, 4); + TEA_transform(buf, in); + p += 16; + if (len <= 16) + break; + len -= 16; + } + hash = buf[0]; + + f2fs_hash = cpu_to_le32(hash & ~F2FS_HASH_COL_BIT); + return f2fs_hash; +} + +f2fs_hash_t f2fs_dentry_hash(int encoding, int casefolded, + const unsigned char *name, int len) +{ + const struct f2fs_nls_table *table = f2fs_load_nls_table(encoding); + int r, dlen; + unsigned char *buff; + + if (len && casefolded) { + buff = malloc(sizeof(char) * PATH_MAX); + ASSERT(buff); + + dlen = table->ops->casefold(table, name, len, buff, PATH_MAX); + if (dlen < 0) { + free(buff); + goto opaque_seq; + } + r = __f2fs_dentry_hash(buff, dlen); + + free(buff); + return r; + } +opaque_seq: + return __f2fs_dentry_hash(name, len); +} + +unsigned int addrs_per_page(struct f2fs_inode *i, bool is_inode) +{ + unsigned int addrs = is_inode ? CUR_ADDRS_PER_INODE(i) - + get_inline_xattr_addrs(i) : DEF_ADDRS_PER_BLOCK; + + if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) || + !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL)) + return addrs; + return ALIGN_DOWN(addrs, 1 << i->i_log_cluster_size); +} + +u64 f2fs_max_file_offset(struct f2fs_inode *i) +{ + if (!LINUX_S_ISREG(le16_to_cpu(i->i_mode)) || + !(le32_to_cpu(i->i_flags) & F2FS_COMPR_FL)) + return le64_to_cpu(i->i_size); + return ALIGN_UP(le64_to_cpu(i->i_size), 1 << i->i_log_cluster_size); +} + +/* + * CRC32 + */ +#define CRCPOLY_LE 0xedb88320 + +uint32_t f2fs_cal_crc32(uint32_t crc, void *buf, int len) +{ + int i; + unsigned char *p = (unsigned char *)buf; + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? CRCPOLY_LE : 0); + } + return crc; +} + +int f2fs_crc_valid(uint32_t blk_crc, void *buf, int len) +{ + uint32_t cal_crc = 0; + + cal_crc = f2fs_cal_crc32(F2FS_SUPER_MAGIC, buf, len); + + if (cal_crc != blk_crc) { + DBG(0,"CRC validation failed: cal_crc = %u, " + "blk_crc = %u buff_size = 0x%x\n", + cal_crc, blk_crc, len); + return -1; + } + return 0; +} + +__u32 f2fs_inode_chksum(struct f2fs_node *node) +{ + struct f2fs_inode *ri = &node->i; + __le32 ino = F2FS_NODE_FOOTER(node)->ino; + __le32 gen = ri->i_generation; + __u32 chksum, chksum_seed; + __u32 dummy_cs = 0; + unsigned int offset = offsetof(struct f2fs_inode, i_inode_checksum); + unsigned int cs_size = sizeof(dummy_cs); + + chksum = f2fs_cal_crc32(c.chksum_seed, (__u8 *)&ino, + sizeof(ino)); + chksum_seed = f2fs_cal_crc32(chksum, (__u8 *)&gen, sizeof(gen)); + + chksum = f2fs_cal_crc32(chksum_seed, (__u8 *)ri, offset); + chksum = f2fs_cal_crc32(chksum, (__u8 *)&dummy_cs, cs_size); + offset += cs_size; + chksum = f2fs_cal_crc32(chksum, (__u8 *)ri + offset, + F2FS_BLKSIZE - offset); + return chksum; +} + +__u32 f2fs_checkpoint_chksum(struct f2fs_checkpoint *cp) +{ + unsigned int chksum_ofs = le32_to_cpu(cp->checksum_offset); + __u32 chksum; + + chksum = f2fs_cal_crc32(F2FS_SUPER_MAGIC, cp, chksum_ofs); + if (chksum_ofs < CP_CHKSUM_OFFSET) { + chksum_ofs += sizeof(chksum); + chksum = f2fs_cal_crc32(chksum, (__u8 *)cp + chksum_ofs, + F2FS_BLKSIZE - chksum_ofs); + } + return chksum; +} + +int write_inode(struct f2fs_node *inode, u64 blkaddr, enum rw_hint whint) +{ + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + inode->i.i_inode_checksum = + cpu_to_le32(f2fs_inode_chksum(inode)); + return dev_write_block(inode, blkaddr, whint); +} + +/* + * try to identify the root device + */ +char *get_rootdev() +{ +#if defined(_WIN32) || defined(WITH_ANDROID) + return NULL; +#else + struct stat sb; + int fd, ret; + char buf[PATH_MAX + 1]; + char *uevent, *ptr; + char *rootdev; + + if (stat("/", &sb) == -1) + return NULL; + + snprintf(buf, PATH_MAX, "/sys/dev/block/%u:%u/uevent", + major(sb.st_dev), minor(sb.st_dev)); + + fd = open(buf, O_RDONLY); + + if (fd < 0) + return NULL; + + ret = lseek(fd, (off_t)0, SEEK_END); + (void)lseek(fd, (off_t)0, SEEK_SET); + + if (ret == -1) { + close(fd); + return NULL; + } + + uevent = malloc(ret + 1); + ASSERT(uevent); + + uevent[ret] = '\0'; + + ret = read(fd, uevent, ret); + close(fd); + + ptr = strstr(uevent, "DEVNAME"); + if (!ptr) + goto out_free; + + ret = sscanf(ptr, "DEVNAME=%s\n", buf); + if (strlen(buf) == 0) + goto out_free; + + ret = strlen(buf) + 5; + rootdev = malloc(ret + 1); + if (!rootdev) + goto out_free; + rootdev[ret] = '\0'; + + snprintf(rootdev, ret + 1, "/dev/%s", buf); + free(uevent); + return rootdev; + +out_free: + free(uevent); + return NULL; +#endif +} + +/* + * device information + */ +void f2fs_init_configuration(void) +{ + int i; + + memset(&c, 0, sizeof(struct f2fs_configuration)); + c.ndevs = 1; + c.blksize = 1 << DEFAULT_BLKSIZE_BITS; + c.blksize_bits = DEFAULT_BLKSIZE_BITS; + c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK; + c.blks_per_seg = DEFAULT_BLOCKS_PER_SEGMENT; + c.wanted_total_sectors = -1; + c.wanted_sector_size = -1; +#ifndef WITH_ANDROID + c.preserve_limits = 1; + c.no_kernel_check = 1; +#else + c.no_kernel_check = 0; +#endif + + for (i = 0; i < MAX_DEVICES; i++) { + c.devices[i].fd = -1; + c.devices[i].sector_size = DEFAULT_SECTOR_SIZE; + c.devices[i].end_blkaddr = -1; + c.devices[i].zoned_model = F2FS_ZONED_NONE; + } + + /* calculated by overprovision ratio */ + c.segs_per_sec = 1; + c.secs_per_zone = 1; + c.segs_per_zone = 1; + c.vol_label = ""; + c.trim = 1; + c.kd = -1; + c.fixed_time = -1; + c.s_encoding = 0; + c.s_encoding_flags = 0; + + /* default root owner */ + c.root_uid = getuid(); + c.root_gid = getgid(); +} + +int f2fs_dev_is_writable(void) +{ + return !c.ro || c.force; +} + +#ifdef HAVE_SETMNTENT +static int is_mounted(const char *mpt, const char *device) +{ + FILE *file = NULL; + struct mntent *mnt = NULL; + + file = setmntent(mpt, "r"); + if (file == NULL) + return 0; + + while ((mnt = getmntent(file)) != NULL) { + if (!strcmp(device, mnt->mnt_fsname)) { +#ifdef MNTOPT_RO + if (hasmntopt(mnt, MNTOPT_RO)) + c.ro = 1; +#endif + break; + } + } + endmntent(file); + return mnt ? 1 : 0; +} +#endif + +int f2fs_dev_is_umounted(char *path) +{ +#ifdef _WIN32 + return 0; +#else + struct stat st_buf; + int is_rootdev = 0; + int ret = 0; + char *rootdev_name = get_rootdev(); + + if (rootdev_name) { + if (!strcmp(path, rootdev_name)) + is_rootdev = 1; + free(rootdev_name); + } + + /* + * try with /proc/mounts fist to detect RDONLY. + * f2fs_stop_checkpoint makes RO in /proc/mounts while RW in /etc/mtab. + */ +#ifdef __linux__ + ret = is_mounted("/proc/mounts", path); + if (ret) { + MSG(0, "Info: Mounted device!\n"); + return -1; + } +#endif +#if defined(MOUNTED) || defined(_PATH_MOUNTED) +#ifndef MOUNTED +#define MOUNTED _PATH_MOUNTED +#endif + ret = is_mounted(MOUNTED, path); + if (ret) { + MSG(0, "Info: Mounted device!\n"); + return -1; + } +#endif + /* + * If we are supposed to operate on the root device, then + * also check the mounts for '/dev/root', which sometimes + * functions as an alias for the root device. + */ + if (is_rootdev) { +#ifdef __linux__ + ret = is_mounted("/proc/mounts", "/dev/root"); + if (ret) { + MSG(0, "Info: Mounted device!\n"); + return -1; + } +#endif + } + + /* + * If f2fs is umounted with -l, the process can still use + * the file system. In this case, we should not format. + */ + if (stat(path, &st_buf)) { + /* sparse file will be created after this. */ + if (c.sparse_mode) + return 0; + MSG(0, "Info: stat failed errno:%d\n", errno); + return -1; + } + + if (S_ISBLK(st_buf.st_mode)) { + int fd = open(path, O_RDONLY | O_EXCL); + + if (fd >= 0) { + close(fd); + } else if (errno == EBUSY) { + MSG(0, "\tError: In use by the system!\n"); + return -EBUSY; + } + } else if (S_ISREG(st_buf.st_mode)) { + /* check whether regular is backfile of loop device */ +#if defined(HAVE_LINUX_LOOP_H) && defined(HAVE_LINUX_MAJOR_H) + struct mntent *mnt; + struct stat st_loop; + FILE *f; + + f = setmntent("/proc/mounts", "r"); + + while ((mnt = getmntent(f)) != NULL) { + struct loop_info64 loopinfo = {0, }; + int loop_fd, err; + + if (mnt->mnt_fsname[0] != '/') + continue; + if (stat(mnt->mnt_fsname, &st_loop) != 0) + continue; + if (!S_ISBLK(st_loop.st_mode)) + continue; + if (major(st_loop.st_rdev) != LOOP_MAJOR) + continue; + + loop_fd = open(mnt->mnt_fsname, O_RDONLY); + if (loop_fd < 0) { + /* non-root users have no permission */ + if (errno == EPERM || errno == EACCES) { + MSG(0, "Info: open %s failed errno:%d - be careful to overwrite a mounted loopback file.\n", + mnt->mnt_fsname, errno); + return 0; + } + MSG(0, "Info: open %s failed errno:%d\n", + mnt->mnt_fsname, errno); + return -errno; + } + + err = ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo); + close(loop_fd); + if (err < 0) { + MSG(0, "\tError: ioctl LOOP_GET_STATUS64 failed errno:%d!\n", + errno); + return -errno; + } + + if (st_buf.st_dev == loopinfo.lo_device && + st_buf.st_ino == loopinfo.lo_inode) { + MSG(0, "\tError: In use by loop device!\n"); + return -EBUSY; + } + } +#endif + } + return ret; +#endif +} + +int f2fs_devs_are_umounted(void) +{ + int ret, i; + + for (i = 0; i < c.ndevs; i++) { + ret = f2fs_dev_is_umounted((char *)c.devices[i].path); + if (ret) + return ret; + } + return 0; +} + +void get_kernel_version(__u8 *version) +{ + int i; + for (i = 0; i < VERSION_NAME_LEN; i++) { + if (version[i] == '\n') + break; + } + memset(version + i, 0, VERSION_LEN + 1 - i); +} + +void get_kernel_uname_version(__u8 *version) +{ +#ifdef HAVE_SYS_UTSNAME_H + struct utsname buf; + + memset(version, 0, VERSION_LEN); + if (uname(&buf)) + return; + +#if defined(WITH_KERNEL_VERSION) + snprintf((char *)version, + VERSION_NAME_LEN, "%s %s", buf.release, buf.version); +#else + snprintf((char *)version, + VERSION_NAME_LEN, "%s", buf.release); +#endif +#else + memset(version, 0, VERSION_LEN); +#endif +} + +#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE) +#define BLKGETSIZE _IO(0x12,96) +#endif + +#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64) +#define BLKGETSIZE64 _IOR(0x12,114, size_t) +#endif + +#if defined(__linux__) && defined(_IO) && !defined(BLKSSZGET) +#define BLKSSZGET _IO(0x12,104) +#endif + +#if defined(__APPLE__) +#include +#define BLKGETSIZE DKIOCGETBLOCKCOUNT +#define BLKSSZGET DKIOCGETBLOCKCOUNT +#endif /* APPLE_DARWIN */ + +#ifndef _WIN32 +static int open_check_fs(char *path, int flag) +{ + if (c.func != DUMP && (c.func != FSCK || c.fix_on || c.auto_fix)) + return -1; + + /* allow to open ro */ + return open(path, O_RDONLY | flag); +} + +#ifdef __linux__ +static int is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} +#endif + +int get_device_info(int i) +{ + int32_t fd = 0; + uint32_t sector_size; +#ifndef BLKGETSIZE64 + uint32_t total_sectors; +#endif + struct stat *stat_buf; +#ifdef HDIO_GETGIO + struct hd_geometry geom; +#endif +#if !defined(WITH_ANDROID) && defined(__linux__) + sg_io_hdr_t io_hdr; + unsigned char reply_buffer[96] = {0}; + unsigned char model_inq[6] = {MODELINQUIRY}; +#endif + struct device_info *dev = c.devices + i; + int flags = O_RDWR; + + if (c.sparse_mode) { + fd = open(dev->path, O_RDWR | O_CREAT | O_BINARY, 0644); + if (fd < 0) { + fd = open_check_fs(dev->path, O_BINARY); + if (fd < 0) { + MSG(0, "\tError: Failed to open a sparse file!\n"); + return -1; + } + } + } + + stat_buf = calloc(1, sizeof(struct stat)); + ASSERT(stat_buf); + + if (stat(dev->path, stat_buf) < 0) { + MSG(0, "\tError: Failed to get the device stat!\n"); + free(stat_buf); + return -1; + } + +#ifdef __linux__ + if (S_ISBLK(stat_buf->st_mode)) { + if (f2fs_get_zoned_model(i) < 0) { + free(stat_buf); + return -1; + } + } +#endif + + if (!c.sparse_mode) { + if (dev->zoned_model == F2FS_ZONED_HM) + flags |= O_DSYNC; + + if (S_ISBLK(stat_buf->st_mode) && + !c.force && c.func != DUMP && !c.dry_run) { + flags |= O_EXCL; + fd = open(dev->path, flags); + if (fd < 0) + fd = open_check_fs(dev->path, O_EXCL); + } else { + fd = open(dev->path, flags); + if (fd < 0) + fd = open_check_fs(dev->path, 0); + } + } + if (fd < 0) { + MSG(0, "\tError: Failed to open the device!\n"); + free(stat_buf); + return -1; + } + + dev->fd = fd; + + if (c.sparse_mode && i == 0) { + if (f2fs_init_sparse_file()) { + free(stat_buf); + return -1; + } + } + + if (c.kd == -1) { +#if !defined(WITH_ANDROID) && defined(__linux__) + c.kd = open("/proc/version", O_RDONLY); +#endif + if (c.kd < 0) { + MSG(0, "Info: not exist /proc/version!\n"); + c.kd = -2; + } + } + + if (c.sparse_mode) { + dev->total_sectors = c.device_size / dev->sector_size; + } else if (S_ISREG(stat_buf->st_mode)) { + dev->total_sectors = stat_buf->st_size / dev->sector_size; + } else if (S_ISBLK(stat_buf->st_mode)) { +#ifdef BLKSSZGET + if (ioctl(fd, BLKSSZGET, §or_size) < 0) + MSG(0, "\tError: Using the default sector size\n"); + else if (dev->sector_size < sector_size) + dev->sector_size = sector_size; +#endif +#ifdef BLKGETSIZE64 + if (ioctl(fd, BLKGETSIZE64, &dev->total_sectors) < 0) { + MSG(0, "\tError: Cannot get the device size\n"); + free(stat_buf); + return -1; + } +#else + if (ioctl(fd, BLKGETSIZE, &total_sectors) < 0) { + MSG(0, "\tError: Cannot get the device size\n"); + free(stat_buf); + return -1; + } + dev->total_sectors = total_sectors; +#endif + dev->total_sectors /= dev->sector_size; + + if (i == 0) { +#ifdef HDIO_GETGIO + if (ioctl(fd, HDIO_GETGEO, &geom) < 0) + c.start_sector = 0; + else + c.start_sector = geom.start; +#else + c.start_sector = 0; +#endif + } + +#if !defined(WITH_ANDROID) && defined(__linux__) + /* Send INQUIRY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = sizeof(reply_buffer); + io_hdr.dxferp = reply_buffer; + io_hdr.cmd_len = sizeof(model_inq); + io_hdr.cmdp = model_inq; + io_hdr.timeout = 1000; + + if (!ioctl(fd, SG_IO, &io_hdr)) { + MSG(0, "Info: [%s] Disk Model: %.16s\n", + dev->path, reply_buffer+16); + } +#endif + } else { + MSG(0, "\tError: Volume type is not supported!!!\n"); + free(stat_buf); + return -1; + } + + if (!c.sector_size) { + c.sector_size = dev->sector_size; + c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size; + } else if (c.sector_size != c.devices[i].sector_size) { + MSG(0, "\tError: Different sector sizes!!!\n"); + free(stat_buf); + return -1; + } + +#ifdef __linux__ + if (dev->zoned_model != F2FS_ZONED_NONE) { + + /* Get the number of blocks per zones */ + if (f2fs_get_zone_blocks(i)) { + MSG(0, "\tError: Failed to get number of blocks per zone\n"); + free(stat_buf); + return -1; + } + + if (!is_power_of_2(dev->zone_size)) + MSG(0, "Info: zoned: zone size %" PRIu64 "u (not a power of 2)\n", + dev->zone_size); + + /* + * Check zone configuration: for the first disk of a + * multi-device volume, conventional zones are needed. + */ + if (f2fs_check_zones(i)) { + MSG(0, "\tError: Failed to check zone configuration\n"); + free(stat_buf); + return -1; + } + MSG(0, "Info: Host-%s zoned block device:\n", + (dev->zoned_model == F2FS_ZONED_HA) ? + "aware" : "managed"); + MSG(0, " %u zones, %" PRIu64 "u zone size(bytes), %u randomly writeable zones\n", + dev->nr_zones, dev->zone_size, + dev->nr_rnd_zones); + MSG(0, " %zu blocks per zone\n", + dev->zone_blocks); + + if (c.conf_reserved_sections) { + if (c.conf_reserved_sections < MIN_RSVD_SECS) { + MSG(0, " Too small sections are reserved(%u secs)\n", + c.conf_reserved_sections); + c.conf_reserved_sections = MIN_RSVD_SECS; + MSG(0, " It is operated as a minimum reserved sections(%u secs)\n", + c.conf_reserved_sections); + } else { + MSG(0, " %u sections are reserved\n", + c.conf_reserved_sections); + } + if (!c.overprovision) { + c.overprovision = CONFIG_RSVD_DEFAULT_OP_RATIO; + MSG(0, " Overprovision ratio is set to default(%.1lf%%)\n", + c.overprovision); + } + } + } +#endif + + /* adjust wanted_total_sectors */ + if (c.wanted_total_sectors != -1) { + MSG(0, "Info: wanted sectors = %"PRIu64" (in %"PRIu64" bytes)\n", + c.wanted_total_sectors, c.wanted_sector_size); + if (c.wanted_sector_size == -1) { + c.wanted_sector_size = dev->sector_size; + } else if (dev->sector_size != c.wanted_sector_size) { + c.wanted_total_sectors *= c.wanted_sector_size; + c.wanted_total_sectors /= dev->sector_size; + } + } + + c.total_sectors += dev->total_sectors; + free(stat_buf); + return 0; +} + +#else + +#include "windows.h" +#include "winioctl.h" + +#if (_WIN32_WINNT >= 0x0500) +#define HAVE_GET_FILE_SIZE_EX 1 +#endif + +static int win_get_device_size(const char *file, uint64_t *device_size) +{ + HANDLE dev; + PARTITION_INFORMATION pi; + DISK_GEOMETRY gi; + DWORD retbytes; +#ifdef HAVE_GET_FILE_SIZE_EX + LARGE_INTEGER filesize; +#else + DWORD filesize; +#endif /* HAVE_GET_FILE_SIZE_EX */ + + dev = CreateFile(file, GENERIC_READ, + FILE_SHARE_READ | FILE_SHARE_WRITE , + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (dev == INVALID_HANDLE_VALUE) + return EBADF; + if (DeviceIoControl(dev, IOCTL_DISK_GET_PARTITION_INFO, + &pi, sizeof(PARTITION_INFORMATION), + &pi, sizeof(PARTITION_INFORMATION), + &retbytes, NULL)) { + + *device_size = pi.PartitionLength.QuadPart; + + } else if (DeviceIoControl(dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, + &gi, sizeof(DISK_GEOMETRY), + &gi, sizeof(DISK_GEOMETRY), + &retbytes, NULL)) { + + *device_size = gi.BytesPerSector * + gi.SectorsPerTrack * + gi.TracksPerCylinder * + gi.Cylinders.QuadPart; + +#ifdef HAVE_GET_FILE_SIZE_EX + } else if (GetFileSizeEx(dev, &filesize)) { + *device_size = filesize.QuadPart; + } +#else + } else { + filesize = GetFileSize(dev, NULL); + if (INVALID_FILE_SIZE != filesize) + return -1; + *device_size = filesize; + } +#endif /* HAVE_GET_FILE_SIZE_EX */ + + CloseHandle(dev); + return 0; +} + +int get_device_info(int i) +{ + struct device_info *dev = c.devices + i; + uint64_t device_size = 0; + int32_t fd = 0; + + /* Block device target is not supported on Windows. */ + if (!c.sparse_mode) { + if (win_get_device_size(dev->path, &device_size)) { + MSG(0, "\tError: Failed to get device size!\n"); + return -1; + } + } else { + device_size = c.device_size; + } + if (c.sparse_mode) { + fd = open((char *)dev->path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644); + } else { + fd = open((char *)dev->path, O_RDWR | O_BINARY); + } + if (fd < 0) { + MSG(0, "\tError: Failed to open the device!\n"); + return -1; + } + dev->fd = fd; + dev->total_sectors = device_size / dev->sector_size; + c.start_sector = 0; + c.sector_size = dev->sector_size; + c.sectors_per_blk = F2FS_BLKSIZE / c.sector_size; + c.total_sectors += dev->total_sectors; + + if (c.sparse_mode && i==0 && f2fs_init_sparse_file()) + return -1; + return 0; +} +#endif + +int f2fs_get_device_info(void) +{ + int i; + + for (i = 0; i < c.ndevs; i++) + if (get_device_info(i)) + return -1; + return 0; +} + +int f2fs_get_f2fs_info(void) +{ + int i; + + if (c.wanted_total_sectors < c.total_sectors) { + MSG(0, "Info: total device sectors = %"PRIu64" (in %u bytes)\n", + c.total_sectors, c.sector_size); + c.total_sectors = c.wanted_total_sectors; + c.devices[0].total_sectors = c.total_sectors; + } + if (c.total_sectors * c.sector_size > + (uint64_t)F2FS_MAX_SEGMENT * 2 * 1024 * 1024) { + MSG(0, "\tError: F2FS can support 16TB at most!!!\n"); + return -1; + } + + /* + * Check device types and determine the final volume operation mode: + * - If all devices are regular block devices, default operation. + * - If at least one HM device is found, operate in HM mode (BLKZONED + * feature will be enabled by mkfs). + * - If an HA device is found, let mkfs decide based on the -m option + * setting by the user. + */ + c.zoned_model = F2FS_ZONED_NONE; + for (i = 0; i < c.ndevs; i++) { + switch (c.devices[i].zoned_model) { + case F2FS_ZONED_NONE: + continue; + case F2FS_ZONED_HM: + c.zoned_model = F2FS_ZONED_HM; + break; + case F2FS_ZONED_HA: + if (c.zoned_model != F2FS_ZONED_HM) + c.zoned_model = F2FS_ZONED_HA; + break; + } + } + + if (c.zoned_model != F2FS_ZONED_NONE) { + + /* + * For zoned model, the zones sizes of all zoned devices must + * be equal. + */ + for (i = 0; i < c.ndevs; i++) { + if (c.devices[i].zoned_model == F2FS_ZONED_NONE) + continue; + if (c.zone_blocks && + c.zone_blocks != c.devices[i].zone_blocks) { + MSG(0, "\tError: zones of different size are " + "not supported\n"); + return -1; + } + c.zone_blocks = c.devices[i].zone_blocks; + } + + /* + * Align sections to the device zone size and align F2FS zones + * to the device zones. For F2FS_ZONED_HA model without the + * BLKZONED feature set at format time, this is only an + * optimization as sequential writes will not be enforced. + */ + c.segs_per_sec = c.zone_blocks / DEFAULT_BLOCKS_PER_SEGMENT; + c.secs_per_zone = 1; + } else { + if(c.zoned_mode != 0) { + MSG(0, "\n Error: %s may not be a zoned block device \n", + c.devices[0].path); + return -1; + } + } + + c.segs_per_zone = c.segs_per_sec * c.secs_per_zone; + + if (c.func != MKFS) + return 0; + + MSG(0, "Info: Segments per section = %d\n", c.segs_per_sec); + MSG(0, "Info: Sections per zone = %d\n", c.secs_per_zone); + MSG(0, "Info: sector size = %u\n", c.sector_size); + MSG(0, "Info: total sectors = %"PRIu64" (%"PRIu64" MB)\n", + c.total_sectors, (c.total_sectors * + (c.sector_size >> 9)) >> 11); + return 0; +} + +unsigned int calc_extra_isize(void) +{ + unsigned int size = offsetof(struct f2fs_inode, i_projid); + + if (c.feature & F2FS_FEATURE_FLEXIBLE_INLINE_XATTR) + size = offsetof(struct f2fs_inode, i_projid); + if (c.feature & F2FS_FEATURE_PRJQUOTA) + size = offsetof(struct f2fs_inode, i_inode_checksum); + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + size = offsetof(struct f2fs_inode, i_crtime); + if (c.feature & F2FS_FEATURE_INODE_CRTIME) + size = offsetof(struct f2fs_inode, i_compr_blocks); + if (c.feature & F2FS_FEATURE_COMPRESSION) + size = offsetof(struct f2fs_inode, i_extra_end); + + return size - F2FS_EXTRA_ISIZE_OFFSET; +} + +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof(array[0])) + +static const struct { + char *name; + __u16 encoding_magic; + __u16 default_flags; + +} f2fs_encoding_map[] = { + { + .encoding_magic = F2FS_ENC_UTF8_12_1, + .name = "utf8", + .default_flags = 0, + }, +}; + +static const struct enc_flags { + __u16 flag; + char *param; +} encoding_flags[] = { + { F2FS_ENC_STRICT_MODE_FL, "strict" }, +}; + +/* Return a positive number < 0xff indicating the encoding magic number + * or a negative value indicating error. */ +int f2fs_str2encoding(const char *string) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++) + if (!strcmp(string, f2fs_encoding_map[i].name)) + return f2fs_encoding_map[i].encoding_magic; + + return -EINVAL; +} + +char *f2fs_encoding2str(const int encoding) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++) + if (f2fs_encoding_map[i].encoding_magic == encoding) + return f2fs_encoding_map[i].name; + + return NULL; +} + +int f2fs_get_encoding_flags(int encoding) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(f2fs_encoding_map); i++) + if (f2fs_encoding_map[i].encoding_magic == encoding) + return f2fs_encoding_map[encoding].default_flags; + + return 0; +} + +int f2fs_str2encoding_flags(char **param, __u16 *flags) +{ + char *f = strtok(*param, ","); + const struct enc_flags *fl; + int i, neg = 0; + + while (f) { + neg = 0; + if (!strncmp("no", f, 2)) { + neg = 1; + f += 2; + } + + for (i = 0; i < ARRAY_SIZE(encoding_flags); i++) { + fl = &encoding_flags[i]; + if (!strcmp(fl->param, f)) { + if (neg) { + MSG(0, "Sub %s\n", fl->param); + *flags &= ~fl->flag; + } else { + MSG(0, "Add %s\n", fl->param); + *flags |= fl->flag; + } + + goto next_flag; + } + } + *param = f; + return -EINVAL; + next_flag: + f = strtok(NULL, ":"); + } + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_io.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_io.c new file mode 100644 index 00000000000..2030440457d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_io.c @@ -0,0 +1,914 @@ +/** + * libf2fs.c + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * Copyright (c) 2019 Google Inc. + * http://www.google.com/ + * Copyright (c) 2020 Google Inc. + * Robin Hsu + * : add quick-buffer for sload compression support + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_LINUX_HDREG_H +#include +#endif + +#ifndef F_SET_RW_HINT +#define F_LINUX_SPECIFIC_BASE 1024 +#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) +#endif + +#include +#include +#include +#include "f2fs_fs.h" + +struct f2fs_configuration c; + +#ifdef HAVE_SPARSE_SPARSE_H +#include +struct sparse_file *f2fs_sparse_file; +static char **blocks; +uint64_t blocks_count; +static char *zeroed_block; +#endif + +static int __get_device_fd(__u64 *offset) +{ + __u64 blk_addr = *offset >> F2FS_BLKSIZE_BITS; + int i; + + for (i = 0; i < c.ndevs; i++) { + if (c.devices[i].start_blkaddr <= blk_addr && + c.devices[i].end_blkaddr >= blk_addr) { + *offset -= + c.devices[i].start_blkaddr << F2FS_BLKSIZE_BITS; + return c.devices[i].fd; + } + } + return -1; +} + +/* ---------- dev_cache, Least Used First (LUF) policy ------------------- */ +/* + * Least used block will be the first victim to be replaced when max hash + * collision exceeds + */ +static bool *dcache_valid; /* is the cached block valid? */ +static off_t *dcache_blk; /* which block it cached */ +static uint64_t *dcache_lastused; /* last used ticks for cache entries */ +static char *dcache_buf; /* cached block data */ +static uint64_t dcache_usetick; /* current use tick */ + +static uint64_t dcache_raccess; +static uint64_t dcache_rhit; +static uint64_t dcache_rmiss; +static uint64_t dcache_rreplace; + +static bool dcache_exit_registered = false; + +/* + * Shadow config: + * + * Active set of the configurations. + * Global configuration 'dcache_config' will be transferred here when + * when dcache_init() is called + */ +static dev_cache_config_t dcache_config = {0, 16, 1}; +static bool dcache_initialized = false; + +#define MIN_NUM_CACHE_ENTRY 1024L +#define MAX_MAX_HASH_COLLISION 16 + +static long dcache_relocate_offset0[] = { + 20, -20, 40, -40, 80, -80, 160, -160, + 320, -320, 640, -640, 1280, -1280, 2560, -2560, +}; +static int dcache_relocate_offset[16]; + +static void dcache_print_statistics(void) +{ + long i; + long useCnt; + + /* Number of used cache entries */ + useCnt = 0; + for (i = 0; i < dcache_config.num_cache_entry; i++) + if (dcache_valid[i]) + ++useCnt; + + /* + * c: number of cache entries + * u: used entries + * RA: number of read access blocks + * CH: cache hit + * CM: cache miss + * Repl: read cache replaced + */ + printf ("\nc, u, RA, CH, CM, Repl=\n"); + printf ("%ld %ld %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", + dcache_config.num_cache_entry, + useCnt, + dcache_raccess, + dcache_rhit, + dcache_rmiss, + dcache_rreplace); +} + +void dcache_release(void) +{ + if (!dcache_initialized) + return; + + dcache_initialized = false; + + if (c.cache_config.dbg_en) + dcache_print_statistics(); + + if (dcache_blk != NULL) + free(dcache_blk); + if (dcache_lastused != NULL) + free(dcache_lastused); + if (dcache_buf != NULL) + free(dcache_buf); + if (dcache_valid != NULL) + free(dcache_valid); + dcache_config.num_cache_entry = 0; + dcache_blk = NULL; + dcache_lastused = NULL; + dcache_buf = NULL; + dcache_valid = NULL; +} + +// return 0 for success, error code for failure. +static int dcache_alloc_all(long n) +{ + if (n <= 0) + return -1; + if ((dcache_blk = (off_t *) malloc(sizeof(off_t) * n)) == NULL + || (dcache_lastused = (uint64_t *) + malloc(sizeof(uint64_t) * n)) == NULL + || (dcache_buf = (char *) malloc (F2FS_BLKSIZE * n)) == NULL + || (dcache_valid = (bool *) calloc(sizeof(bool) * n, 1)) == NULL) + { + dcache_release(); + return -1; + } + dcache_config.num_cache_entry = n; + return 0; +} + +static void dcache_relocate_init(void) +{ + int i; + int n0 = (sizeof(dcache_relocate_offset0) + / sizeof(dcache_relocate_offset0[0])); + int n = (sizeof(dcache_relocate_offset) + / sizeof(dcache_relocate_offset[0])); + + ASSERT(n == n0); + for (i = 0; i < n && i < dcache_config.max_hash_collision; i++) { + if (labs(dcache_relocate_offset0[i]) + > dcache_config.num_cache_entry / 2) { + dcache_config.max_hash_collision = i; + break; + } + dcache_relocate_offset[i] = + dcache_config.num_cache_entry + + dcache_relocate_offset0[i]; + } +} + +void dcache_init(void) +{ + long n; + + if (c.cache_config.num_cache_entry <= 0) + return; + + /* release previous cache init, if any */ + dcache_release(); + + dcache_blk = NULL; + dcache_lastused = NULL; + dcache_buf = NULL; + dcache_valid = NULL; + + dcache_config = c.cache_config; + + n = max(MIN_NUM_CACHE_ENTRY, dcache_config.num_cache_entry); + + /* halve alloc size until alloc succeed, or min cache reached */ + while (dcache_alloc_all(n) != 0 && n != MIN_NUM_CACHE_ENTRY) + n = max(MIN_NUM_CACHE_ENTRY, n/2); + + /* must be the last: data dependent on num_cache_entry */ + dcache_relocate_init(); + dcache_initialized = true; + + if (!dcache_exit_registered) { + dcache_exit_registered = true; + atexit(dcache_release); /* auto release */ + } + + dcache_raccess = 0; + dcache_rhit = 0; + dcache_rmiss = 0; + dcache_rreplace = 0; +} + +static inline char *dcache_addr(long entry) +{ + return dcache_buf + F2FS_BLKSIZE * entry; +} + +/* relocate on (n+1)-th collision */ +static inline long dcache_relocate(long entry, int n) +{ + assert(dcache_config.num_cache_entry != 0); + return (entry + dcache_relocate_offset[n]) % + dcache_config.num_cache_entry; +} + +static long dcache_find(__u64 blk) +{ + register long n = dcache_config.num_cache_entry; + register unsigned m = dcache_config.max_hash_collision; + long entry, least_used, target; + unsigned try; + + assert(n > 0); + target = least_used = entry = blk % n; /* simple modulo hash */ + + for (try = 0; try < m; try++) { + if (!dcache_valid[target] || dcache_blk[target] == blk) + return target; /* found target or empty cache slot */ + if (dcache_lastused[target] < dcache_lastused[least_used]) + least_used = target; + target = dcache_relocate(entry, try); /* next target */ + } + return least_used; /* max search reached, return least used slot */ +} + +/* Physical read into cache */ +static int dcache_io_read(long entry, __u64 offset, off_t blk) +{ + int fd = __get_device_fd(&offset); + + if (fd < 0) + return fd; + +#ifdef HAVE_PREAD + if (pread(fd, dcache_buf + entry * F2FS_BLKSIZE, F2FS_BLKSIZE, offset) < 0) { + MSG(0, "\n pread() fail.\n"); + return -1; + } +#else + if (lseek(fd, offset, SEEK_SET) < 0) { + MSG(0, "\n lseek fail.\n"); + return -1; + } + if (read(fd, dcache_buf + entry * F2FS_BLKSIZE, F2FS_BLKSIZE) < 0) { + MSG(0, "\n read() fail.\n"); + return -1; + } +#endif + dcache_lastused[entry] = ++dcache_usetick; + dcache_valid[entry] = true; + dcache_blk[entry] = blk; + return 0; +} + +/* + * - Note: Read/Write are not symmetric: + * For read, we need to do it block by block, due to the cache nature: + * some blocks may be cached, and others don't. + * For write, since we always do a write-thru, we can join all writes into one, + * and write it once at the caller. This function updates the cache for write, but + * not the do a physical write. The caller is responsible for the physical write. + * - Note: We concentrate read/write together, due to the fact of similar structure to find + * the relavant cache entries + * - Return values: + * 0: success + * 1: cache not available (uninitialized) + * -1: error + */ +static int dcache_update_rw(void *buf, __u64 offset, + size_t byte_count, bool is_write) +{ + __u64 blk, start; + int addr_in_blk; + + if (!dcache_initialized) + dcache_init(); /* auto initialize */ + + if (!dcache_initialized) + return 1; /* not available */ + + blk = offset / F2FS_BLKSIZE; + addr_in_blk = offset % F2FS_BLKSIZE; + start = blk * F2FS_BLKSIZE; + + while (byte_count != 0) { + size_t cur_size = min(byte_count, + (size_t)(F2FS_BLKSIZE - addr_in_blk)); + long entry = dcache_find(blk); + + if (!is_write) + ++dcache_raccess; + + if (dcache_valid[entry] && dcache_blk[entry] == blk) { + /* cache hit */ + if (is_write) /* write: update cache */ + memcpy(dcache_addr(entry) + addr_in_blk, + buf, cur_size); + else + ++dcache_rhit; + } else { + /* cache miss */ + if (!is_write) { + int err; + ++dcache_rmiss; + if (dcache_valid[entry]) + ++dcache_rreplace; + /* read: physical I/O read into cache */ + err = dcache_io_read(entry, start, blk); + if (err) + return err; + } + } + + /* read: copy data from cache */ + /* write: nothing to do, since we don't do physical write. */ + if (!is_write) + memcpy(buf, dcache_addr(entry) + addr_in_blk, + cur_size); + + /* next block */ + ++blk; + buf += cur_size; + start += F2FS_BLKSIZE; + byte_count -= cur_size; + addr_in_blk = 0; + } + return 0; +} + +/* + * dcache_update_cache() just update cache, won't do physical I/O. + * Thus even no error, we need normal non-cache I/O for actual write + * + * return value: 1: cache not available + * 0: success, -1: I/O error + */ +int dcache_update_cache(void *buf, __u64 offset, size_t count) +{ + return dcache_update_rw(buf, offset, count, true); +} + +/* handles read into cache + read into buffer */ +int dcache_read(void *buf, __u64 offset, size_t count) +{ + return dcache_update_rw(buf, offset, count, false); +} + +/* + * IO interfaces + */ +int dev_read_version(void *buf, __u64 offset, size_t len) +{ + if (c.sparse_mode) + return 0; +#ifdef HAVE_RPEAD + if (pread(c.kd, buf, len, (off_t)offset) < 0) + return -1; +#else + if (lseek(c.kd, (off_t)offset, SEEK_SET) < 0) + return -1; + if (read(c.kd, buf, len) < 0) + return -1; +#endif + return 0; +} + +#ifdef HAVE_SPARSE_SPARSE_H +static int sparse_read_blk(__u64 block, int count, void *buf) +{ + int i; + char *out = buf; + __u64 cur_block; + + for (i = 0; i < count; ++i) { + cur_block = block + i; + if (blocks[cur_block]) + memcpy(out + (i * F2FS_BLKSIZE), + blocks[cur_block], F2FS_BLKSIZE); + else if (blocks) + memset(out + (i * F2FS_BLKSIZE), 0, F2FS_BLKSIZE); + } + return 0; +} + +static int sparse_write_blk(__u64 block, int count, const void *buf) +{ + int i; + __u64 cur_block; + const char *in = buf; + + for (i = 0; i < count; ++i) { + cur_block = block + i; + if (blocks[cur_block] == zeroed_block) + blocks[cur_block] = NULL; + if (!blocks[cur_block]) { + blocks[cur_block] = calloc(1, F2FS_BLKSIZE); + if (!blocks[cur_block]) + return -ENOMEM; + } + memcpy(blocks[cur_block], in + (i * F2FS_BLKSIZE), + F2FS_BLKSIZE); + } + return 0; +} + +static int sparse_write_zeroed_blk(__u64 block, int count) +{ + int i; + __u64 cur_block; + + for (i = 0; i < count; ++i) { + cur_block = block + i; + if (blocks[cur_block]) + continue; + blocks[cur_block] = zeroed_block; + } + return 0; +} + +#ifdef SPARSE_CALLBACK_USES_SIZE_T +static int sparse_import_segment(void *UNUSED(priv), const void *data, + size_t len, unsigned int block, unsigned int nr_blocks) +#else +static int sparse_import_segment(void *UNUSED(priv), const void *data, int len, + unsigned int block, unsigned int nr_blocks) +#endif +{ + /* Ignore chunk headers, only write the data */ + if (!nr_blocks || len % F2FS_BLKSIZE) + return 0; + + return sparse_write_blk(block, nr_blocks, data); +} + +static int sparse_merge_blocks(uint64_t start, uint64_t num, int zero) +{ + char *buf; + uint64_t i; + + if (zero) { + blocks[start] = NULL; + return sparse_file_add_fill(f2fs_sparse_file, 0x0, + F2FS_BLKSIZE * num, start); + } + + buf = calloc(num, F2FS_BLKSIZE); + if (!buf) { + fprintf(stderr, "failed to alloc %llu\n", + (unsigned long long)num * F2FS_BLKSIZE); + return -ENOMEM; + } + + for (i = 0; i < num; i++) { + memcpy(buf + i * F2FS_BLKSIZE, blocks[start + i], F2FS_BLKSIZE); + free(blocks[start + i]); + blocks[start + i] = NULL; + } + + /* free_sparse_blocks will release this buf. */ + blocks[start] = buf; + + return sparse_file_add_data(f2fs_sparse_file, blocks[start], + F2FS_BLKSIZE * num, start); +} +#else +static int sparse_read_blk(__u64 UNUSED(block), + int UNUSED(count), void *UNUSED(buf)) +{ + return 0; +} + +static int sparse_write_blk(__u64 UNUSED(block), + int UNUSED(count), const void *UNUSED(buf)) +{ + return 0; +} + +static int sparse_write_zeroed_blk(__u64 UNUSED(block), int UNUSED(count)) +{ + return 0; +} +#endif + +int dev_read(void *buf, __u64 offset, size_t len) +{ + int fd; + int err; + + if (c.sparse_mode) + return sparse_read_blk(offset / F2FS_BLKSIZE, + len / F2FS_BLKSIZE, buf); + + /* err = 1: cache not available, fall back to non-cache R/W */ + /* err = 0: success, err=-1: I/O error */ + err = dcache_read(buf, offset, len); + if (err <= 0) + return err; + + fd = __get_device_fd(&offset); + if (fd < 0) + return fd; +#ifdef HAVE_PREAD + if (pread(fd, buf, len, (off_t)offset) < 0) + return -1; +#else + if (lseek(fd, (off_t)offset, SEEK_SET) < 0) + return -1; + if (read(fd, buf, len) < 0) + return -1; +#endif + return 0; +} + +#ifdef POSIX_FADV_WILLNEED +int dev_readahead(__u64 offset, size_t len) +#else +int dev_readahead(__u64 offset, size_t UNUSED(len)) +#endif +{ + int fd = __get_device_fd(&offset); + + if (fd < 0) + return fd; +#ifdef POSIX_FADV_WILLNEED + return posix_fadvise(fd, offset, len, POSIX_FADV_WILLNEED); +#else + return 0; +#endif +} +/* + * Copied from fs/f2fs/segment.c + */ +/* + * This returns write hints for each segment type. This hints will be + * passed down to block layer as below by default. + * + * User F2FS Block + * ---- ---- ----- + * META WRITE_LIFE_NONE|REQ_META + * HOT_NODE WRITE_LIFE_NONE + * WARM_NODE WRITE_LIFE_MEDIUM + * COLD_NODE WRITE_LIFE_LONG + * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME + * extension list " " + * + * -- buffered io + * COLD_DATA WRITE_LIFE_EXTREME + * HOT_DATA WRITE_LIFE_SHORT + * WARM_DATA WRITE_LIFE_NOT_SET + * + * -- direct io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG " WRITE_LIFE_LONG + */ +enum rw_hint f2fs_io_type_to_rw_hint(int seg_type) +{ + switch (seg_type) { + case CURSEG_WARM_DATA: + return WRITE_LIFE_NOT_SET; + case CURSEG_HOT_DATA: + return WRITE_LIFE_SHORT; + case CURSEG_COLD_DATA: + return WRITE_LIFE_EXTREME; + case CURSEG_WARM_NODE: + return WRITE_LIFE_MEDIUM; + case CURSEG_HOT_NODE: + return WRITE_LIFE_NONE; + case CURSEG_COLD_NODE: + return WRITE_LIFE_LONG; + default: + return WRITE_LIFE_NONE; + } +} + +static int __dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint) +{ + int fd; + + fd = __get_device_fd(&offset); + if (fd < 0) + return fd; + +#if ! defined(__MINGW32__) + if (c.need_whint && (c.whint != whint)) { + u64 hint = whint; + int ret; + + ret = fcntl(fd, F_SET_RW_HINT, &hint); + if (ret != -1) + c.whint = whint; + } +#endif + +#ifdef HAVE_PWRITE + if (pwrite(fd, buf, len, (off_t)offset) < 0) + return -1; +#else + if (lseek(fd, (off_t)offset, SEEK_SET) < 0) + return -1; + if (write(fd, buf, len) < 0) + return -1; +#endif + + c.need_fsync = true; + + return 0; +} + +int dev_write(void *buf, __u64 offset, size_t len, enum rw_hint whint) +{ + if (c.dry_run) + return 0; + + if (c.sparse_mode) + return sparse_write_blk(offset / F2FS_BLKSIZE, + len / F2FS_BLKSIZE, buf); + + /* + * dcache_update_cache() just update cache, won't do I/O. + * Thus even no error, we need normal non-cache I/O for actual write + */ + if (dcache_update_cache(buf, offset, len) < 0) + return -1; + + return __dev_write(buf, offset, len, whint); +} + +int dev_write_block(void *buf, __u64 blk_addr, enum rw_hint whint) +{ + return dev_write(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint); +} + +int dev_write_dump(void *buf, __u64 offset, size_t len) +{ +#ifdef HAVE_PWRITE + if (pwrite(c.dump_fd, buf, len, (off_t)offset) < 0) + return -1; +#else + if (lseek(c.dump_fd, (off_t)offset, SEEK_SET) < 0) + return -1; + if (write(c.dump_fd, buf, len) < 0) + return -1; +#endif + return 0; +} + +#if !defined(__MINGW32__) +int dev_write_symlink(char *buf, size_t len) +{ + buf[len] = 0; + if (symlink(buf, c.dump_symlink)) + return -1; + return 0; +} +#endif + +int dev_fill(void *buf, __u64 offset, size_t len, enum rw_hint whint) +{ + if (c.sparse_mode) + return sparse_write_zeroed_blk(offset / F2FS_BLKSIZE, + len / F2FS_BLKSIZE); + + /* Only allow fill to zero */ + if (*((__u8*)buf)) + return -1; + + return __dev_write(buf, offset, len, whint); +} + +int dev_fill_block(void *buf, __u64 blk_addr, enum rw_hint whint) +{ + return dev_fill(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE, whint); +} + +int dev_read_block(void *buf, __u64 blk_addr) +{ + return dev_read(buf, blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); +} + +int dev_reada_block(__u64 blk_addr) +{ + return dev_readahead(blk_addr << F2FS_BLKSIZE_BITS, F2FS_BLKSIZE); +} + +int f2fs_fsync_device(void) +{ +#ifdef HAVE_FSYNC + int i; + + if (!c.need_fsync) + return 0; + + for (i = 0; i < c.ndevs; i++) { + if (fsync(c.devices[i].fd) < 0) { + MSG(0, "\tError: Could not conduct fsync!!!\n"); + return -1; + } + } +#endif + return 0; +} + +int f2fs_init_sparse_file(void) +{ +#ifdef HAVE_SPARSE_SPARSE_H + if (c.func == MKFS) { + f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, c.device_size); + if (!f2fs_sparse_file) + return -1; + } else { + f2fs_sparse_file = sparse_file_import(c.devices[0].fd, + true, false); + if (!f2fs_sparse_file) + return -1; + + c.blksize = sparse_file_block_size(f2fs_sparse_file); + c.blksize_bits = log_base_2(c.blksize); + if (c.blksize_bits == -1) { + MSG(0, "\tError: Sparse file blocksize not a power of 2.\n"); + return -1; + } + + c.device_size = sparse_file_len(f2fs_sparse_file, 0, 0); + c.device_size &= (~((uint64_t)(F2FS_BLKSIZE - 1))); + } + + blocks_count = c.device_size / F2FS_BLKSIZE; + blocks = calloc(blocks_count, sizeof(char *)); + if (!blocks) { + MSG(0, "\tError: Calloc Failed for blocks!!!\n"); + return -1; + } + + zeroed_block = calloc(1, F2FS_BLKSIZE); + if (!zeroed_block) { + MSG(0, "\tError: Calloc Failed for zeroed block!!!\n"); + return -1; + } + + return sparse_file_foreach_chunk(f2fs_sparse_file, true, false, + sparse_import_segment, NULL); +#else + MSG(0, "\tError: Sparse mode is only supported for android\n"); + return -1; +#endif +} + +void f2fs_release_sparse_resource(void) +{ +#ifdef HAVE_SPARSE_SPARSE_H + int j; + + if (c.sparse_mode) { + if (f2fs_sparse_file != NULL) { + sparse_file_destroy(f2fs_sparse_file); + f2fs_sparse_file = NULL; + } + for (j = 0; j < blocks_count; j++) + free(blocks[j]); + free(blocks); + blocks = NULL; + free(zeroed_block); + zeroed_block = NULL; + } +#endif +} + +#define MAX_CHUNK_SIZE (1 * 1024 * 1024 * 1024ULL) +#define MAX_CHUNK_COUNT (MAX_CHUNK_SIZE / F2FS_BLKSIZE) +int f2fs_finalize_device(void) +{ + int i; + int ret = 0; + +#ifdef HAVE_SPARSE_SPARSE_H + if (c.sparse_mode) { + int64_t chunk_start = (blocks[0] == NULL) ? -1 : 0; + uint64_t j; + + if (c.func != MKFS) { + sparse_file_destroy(f2fs_sparse_file); + ret = ftruncate(c.devices[0].fd, 0); + ASSERT(!ret); + lseek(c.devices[0].fd, 0, SEEK_SET); + f2fs_sparse_file = sparse_file_new(F2FS_BLKSIZE, + c.device_size); + } + + for (j = 0; j < blocks_count; ++j) { + if (chunk_start != -1) { + if (j - chunk_start >= MAX_CHUNK_COUNT) { + ret = sparse_merge_blocks(chunk_start, + j - chunk_start, 0); + ASSERT(!ret); + chunk_start = -1; + } + } + + if (chunk_start == -1) { + if (!blocks[j]) + continue; + + if (blocks[j] == zeroed_block) { + ret = sparse_merge_blocks(j, 1, 1); + ASSERT(!ret); + } else { + chunk_start = j; + } + } else { + if (blocks[j] && blocks[j] != zeroed_block) + continue; + + ret = sparse_merge_blocks(chunk_start, + j - chunk_start, 0); + ASSERT(!ret); + + if (blocks[j] == zeroed_block) { + ret = sparse_merge_blocks(j, 1, 1); + ASSERT(!ret); + } + + chunk_start = -1; + } + } + if (chunk_start != -1) { + ret = sparse_merge_blocks(chunk_start, + blocks_count - chunk_start, 0); + ASSERT(!ret); + } + + sparse_file_write(f2fs_sparse_file, c.devices[0].fd, + /*gzip*/0, /*sparse*/1, /*crc*/0); + + f2fs_release_sparse_resource(); + } +#endif + /* + * We should call fsync() to flush out all the dirty pages + * in the block device page cache. + */ + for (i = 0; i < c.ndevs; i++) { +#ifdef HAVE_FSYNC + if (c.need_fsync) { + ret = fsync(c.devices[i].fd); + if (ret < 0) { + MSG(0, "\tError: Could not conduct fsync!!!\n"); + break; + } + } +#endif + ret = close(c.devices[i].fd); + if (ret < 0) { + MSG(0, "\tError: Failed to close device file!!!\n"); + break; + } + free(c.devices[i].path); + free(c.devices[i].zone_cap_blocks); + } + close(c.kd); + + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_zoned.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_zoned.c new file mode 100644 index 00000000000..6730bba0da8 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/libf2fs_zoned.c @@ -0,0 +1,637 @@ +/** + * libf2fs_zoned.c + * + * Copyright (c) 2016 Western Digital Corporation. + * Written by: Damien Le Moal + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#ifdef HAVE_LINUX_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include + +#ifdef HAVE_LINUX_BLKZONED_H +#ifndef BLKFINISHZONE +#define BLKFINISHZONE _IOW(0x12, 136, struct blk_zone_range) +#endif + +int get_sysfs_path(struct device_info *dev, const char *attr, + char *buf, size_t buflen) +{ + struct stat statbuf; + char str[PATH_MAX]; + char sysfs_path[PATH_MAX]; + ssize_t len; + char *delim; + int ret; + + if (stat(dev->path, &statbuf) < 0) + return -1; + + snprintf(str, sizeof(str), "/sys/dev/block/%d:%d", + major(statbuf.st_rdev), minor(statbuf.st_rdev)); + len = readlink(str, buf, buflen - 1); + if (len < 0) + return -1; + buf[len] = '\0'; + + ret = snprintf(sysfs_path, sizeof(sysfs_path), + "/sys/dev/block/%s", buf); + if (ret >= sizeof(sysfs_path)) + return -1; + + /* Test if the device is a partition */ + ret = snprintf(str, sizeof(str), "%s/partition", sysfs_path); + if (ret >= sizeof(str)) + return -1; + ret = stat(str, &statbuf); + if (ret) { + if (errno == ENOENT) { + /* Not a partition */ + goto out; + } + return -1; + } + + /* + * The device is a partition: remove the device name from the + * attribute file path to obtain the sysfs path of the holder device. + * e.g.: /sys/dev/block/.../sda/sda1 -> /sys/dev/block/.../sda + */ + delim = strrchr(sysfs_path, '/'); + if (!delim) + return -1; + *delim = '\0'; + +out: + ret = snprintf(buf, buflen, "%s/%s", sysfs_path, attr); + if (ret >= buflen) + return -1; + + return 0; +} + +int f2fs_get_zoned_model(int i) +{ + struct device_info *dev = c.devices + i; + char str[PATH_MAX]; + FILE *file; + int res; + + /* Check that this is a zoned block device */ + res = get_sysfs_path(dev, "queue/zoned", str, sizeof(str)); + if (res != 0) { + MSG(0, "\tInfo: can't find /sys, assuming normal block device\n"); + dev->zoned_model = F2FS_ZONED_NONE; + return 0; + } + + file = fopen(str, "r"); + if (!file) { + /* + * The kernel does not support zoned block devices, but we have + * a block device file. This means that if the zoned file is + * not found, then the device is not zoned or is zoned but can + * be randomly written (i.e. host-aware zoned model). + * Treat the device as a regular block device. Otherwise, signal + * the failure to verify the disk zone model. + */ + if (errno == ENOENT) { + dev->zoned_model = F2FS_ZONED_NONE; + return 0; + } + MSG(0, "\tError: Failed to check the device zoned model\n"); + return -1; + } + + memset(str, 0, sizeof(str)); + res = fscanf(file, "%s", str); + fclose(file); + + if (res != 1) { + MSG(0, "\tError: Failed to parse the device zoned model\n"); + return -1; + } + + if (strcmp(str, "none") == 0) { + /* Regular block device */ + dev->zoned_model = F2FS_ZONED_NONE; + } else if (strcmp(str, "host-aware") == 0) { + /* Host-aware zoned block device: can be randomly written */ + dev->zoned_model = F2FS_ZONED_HA; + } else if (strcmp(str, "host-managed") == 0) { + /* Host-managed zoned block device: sequential writes needed */ + dev->zoned_model = F2FS_ZONED_HM; + } else { + MSG(0, "\tError: Unsupported device zoned model\n"); + return -1; + } + + return 0; +} + +uint32_t f2fs_get_zone_chunk_sectors(struct device_info *dev) +{ + uint32_t sectors; + char str[PATH_MAX]; + FILE *file; + int res; + + res = get_sysfs_path(dev, "queue/chunk_sectors", str, sizeof(str)); + if (res != 0) { + MSG(0, "\tError: Failed to get device sysfs attribute path\n"); + return 0; + } + + file = fopen(str, "r"); + if (!file) + return 0; + + memset(str, 0, sizeof(str)); + res = fscanf(file, "%s", str); + fclose(file); + + if (res != 1) + return 0; + + sectors = atoi(str); + + return sectors; +} + +int f2fs_get_zone_blocks(int i) +{ + struct device_info *dev = c.devices + i; + uint64_t sectors; + + /* Get zone size */ + dev->zone_blocks = 0; + + sectors = f2fs_get_zone_chunk_sectors(dev); + if (!sectors) + return -1; + + dev->zone_size = sectors << SECTOR_SHIFT; + dev->zone_blocks = sectors >> (F2FS_BLKSIZE_BITS - SECTOR_SHIFT); + sectors = dev->zone_size / c.sector_size; + + /* + * Total number of zones: there may + * be a last smaller runt zone. + */ + dev->nr_zones = dev->total_sectors / sectors; + if (dev->total_sectors % sectors) + dev->nr_zones++; + + return 0; +} + +int f2fs_report_zone(int i, uint64_t sector, struct blk_zone *blkzone) +{ + struct one_zone_report { + struct blk_zone_report rep; + struct blk_zone zone; + } *rep; + int ret = -1; + + static_assert(sizeof(*rep) == sizeof(rep->rep) + sizeof(rep->zone), ""); + + rep = calloc(1, sizeof(*rep)); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -ENOMEM; + } + + rep->rep = (struct blk_zone_report){ + .sector = sector, + .nr_zones = 1, + }; + ret = ioctl(c.devices[i].fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONE failed: errno=%d\n", errno); + goto out; + } + + *blkzone = rep->zone; +out: + free(rep); + return ret; +} + +#define F2FS_REPORT_ZONES_BUFSZ 524288 + +int f2fs_report_zones(int j, report_zones_cb_t *report_zones_cb, void *opaque) +{ + struct device_info *dev = c.devices + j; + struct blk_zone_report *rep; + struct blk_zone *blkz; + unsigned int i, n = 0; + uint64_t total_sectors = (dev->total_sectors * c.sector_size) + >> SECTOR_SHIFT; + uint64_t sector = 0; + int ret = -1; + + rep = malloc(F2FS_REPORT_ZONES_BUFSZ); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -ENOMEM; + } + + while (sector < total_sectors) { + + /* Get zone info */ + rep->sector = sector; + rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report)) + / sizeof(struct blk_zone); + + ret = ioctl(dev->fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONE failed: errno=%d\n", + errno); + goto out; + } + + if (!rep->nr_zones) { + ret = -EIO; + ERR_MSG("Unexpected ioctl BLKREPORTZONE result\n"); + goto out; + } + + blkz = (struct blk_zone *)(rep + 1); + for (i = 0; i < rep->nr_zones; i++) { + ret = report_zones_cb(n, blkz, opaque); + if (ret) + goto out; + sector = blk_zone_sector(blkz) + blk_zone_length(blkz); + n++; + blkz++; + } + } +out: + free(rep); + return ret; +} + +int f2fs_check_zones(int j) +{ + struct device_info *dev = c.devices + j; + struct blk_zone_report *rep; + struct blk_zone *blkz; + unsigned int i, n = 0; + uint64_t total_sectors; + uint64_t sector; + int last_is_conv = 1; + int ret = -1; + + rep = malloc(F2FS_REPORT_ZONES_BUFSZ); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -ENOMEM; + } + + dev->zone_cap_blocks = malloc(dev->nr_zones * sizeof(size_t)); + if (!dev->zone_cap_blocks) { + free(rep); + ERR_MSG("No memory for zone capacity list.\n"); + return -ENOMEM; + } + memset(dev->zone_cap_blocks, 0, (dev->nr_zones * sizeof(size_t))); + + dev->nr_rnd_zones = 0; + sector = 0; + total_sectors = (dev->total_sectors * c.sector_size) >> 9; + + while (sector < total_sectors) { + + /* Get zone info */ + memset(rep, 0, F2FS_REPORT_ZONES_BUFSZ); + rep->sector = sector; + rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report)) + / sizeof(struct blk_zone); + + ret = ioctl(dev->fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONE failed\n"); + goto out; + } + + if (!rep->nr_zones) + break; + + blkz = (struct blk_zone *)(rep + 1); + for (i = 0; i < rep->nr_zones && sector < total_sectors; i++) { + + if (blk_zone_cond(blkz) == BLK_ZONE_COND_READONLY || + blk_zone_cond(blkz) == BLK_ZONE_COND_OFFLINE) + last_is_conv = 0; + if (blk_zone_conv(blkz) || + blk_zone_seq_pref(blkz)) { + if (last_is_conv) + dev->nr_rnd_zones++; + } else { + last_is_conv = 0; + } + + if (blk_zone_conv(blkz)) { + DBG(2, + "Zone %05u: Conventional, cond 0x%x (%s), sector %llu, %llu sectors\n", + n, + blk_zone_cond(blkz), + blk_zone_cond_str(blkz), + blk_zone_sector(blkz), + blk_zone_length(blkz)); + dev->zone_cap_blocks[n] = + blk_zone_length(blkz) >> + (F2FS_BLKSIZE_BITS - SECTOR_SHIFT); + } else { + DBG(2, + "Zone %05u: type 0x%x (%s), cond 0x%x (%s)," + " need_reset %d, non_seq %d, sector %llu," + " %llu sectors, capacity %llu," + " wp sector %llu\n", + n, + blk_zone_type(blkz), + blk_zone_type_str(blkz), + blk_zone_cond(blkz), + blk_zone_cond_str(blkz), + blk_zone_need_reset(blkz), + blk_zone_non_seq(blkz), + blk_zone_sector(blkz), + blk_zone_length(blkz), + blk_zone_capacity(blkz, rep->flags), + blk_zone_wp_sector(blkz)); + dev->zone_cap_blocks[n] = + blk_zone_capacity(blkz, rep->flags) >> + (F2FS_BLKSIZE_BITS - SECTOR_SHIFT); + } + + sector = blk_zone_sector(blkz) + blk_zone_length(blkz); + n++; + blkz++; + } + } + + if (sector != total_sectors) { + ERR_MSG("Invalid zones: last sector reported is %llu, expected %llu\n", + (unsigned long long)(sector << 9) / c.sector_size, + (unsigned long long)dev->total_sectors); + ret = -1; + goto out; + } + + if (n != dev->nr_zones) { + ERR_MSG("Inconsistent number of zones: expected %u zones, got %u\n", + dev->nr_zones, n); + ret = -1; + goto out; + } + + /* + * For a multi-device volume, fixed position metadata blocks are + * stored * only on the first device of the volume. Checking for the + * presence of * conventional zones (randomly writeabl zones) for + * storing these blocks * on a host-managed device is thus needed only + * for the device index 0. + */ + if (j == 0 && dev->zoned_model == F2FS_ZONED_HM && + !dev->nr_rnd_zones) { + ERR_MSG("No conventional zone for super block\n"); + ret = -1; + } +out: + free(rep); + return ret; +} + +int f2fs_reset_zone(int i, void *blkzone) +{ + struct blk_zone *blkz = (struct blk_zone *)blkzone; + struct device_info *dev = c.devices + i; + struct blk_zone_range range; + int ret; + + if (!blk_zone_seq(blkz) || blk_zone_empty(blkz)) + return 0; + + /* Non empty sequential zone: reset */ + range.sector = blk_zone_sector(blkz); + range.nr_sectors = blk_zone_length(blkz); + ret = ioctl(dev->fd, BLKRESETZONE, &range); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKRESETZONE failed: errno=%d\n", errno); + } + + return ret; +} + +int f2fs_reset_zones(int j) +{ + struct device_info *dev = c.devices + j; + struct blk_zone_report *rep; + struct blk_zone *blkz; + struct blk_zone_range range; + uint64_t total_sectors; + uint64_t sector; + unsigned int i; + int ret = -1; + + rep = malloc(F2FS_REPORT_ZONES_BUFSZ); + if (!rep) { + ERR_MSG("No memory for report zones\n"); + return -1; + } + + sector = 0; + total_sectors = (dev->total_sectors * c.sector_size) >> 9; + while (sector < total_sectors) { + + /* Get zone info */ + memset(rep, 0, F2FS_REPORT_ZONES_BUFSZ); + rep->sector = sector; + rep->nr_zones = (F2FS_REPORT_ZONES_BUFSZ - sizeof(struct blk_zone_report)) + / sizeof(struct blk_zone); + + ret = ioctl(dev->fd, BLKREPORTZONE, rep); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKREPORTZONES failed\n"); + goto out; + } + + if (!rep->nr_zones) + break; + + blkz = (struct blk_zone *)(rep + 1); + for (i = 0; i < rep->nr_zones && sector < total_sectors; i++) { + if (blk_zone_seq(blkz) && + !blk_zone_empty(blkz)) { + /* Non empty sequential zone: reset */ + range.sector = blk_zone_sector(blkz); + range.nr_sectors = blk_zone_length(blkz); + ret = ioctl(dev->fd, BLKRESETZONE, &range); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKRESETZONE failed\n"); + goto out; + } + } + sector = blk_zone_sector(blkz) + blk_zone_length(blkz); + blkz++; + } + } +out: + free(rep); + if (!ret) + MSG(0, "Info: Discarded %"PRIu64" MB\n", (sector << 9) >> 20); + return ret; +} + +int f2fs_finish_zone(int i, void *blkzone) +{ + struct blk_zone *blkz = (struct blk_zone *)blkzone; + struct device_info *dev = c.devices + i; + struct blk_zone_range range; + int ret; + + if (!blk_zone_seq(blkz) || !blk_zone_open(blkz)) + return 0; + + /* Non empty sequential zone: finish */ + range.sector = blk_zone_sector(blkz); + range.nr_sectors = blk_zone_length(blkz); + ret = ioctl(dev->fd, BLKFINISHZONE, &range); + if (ret != 0) { + ret = -errno; + ERR_MSG("ioctl BLKFINISHZONE failed: errno=%d, status=%s\n", + errno, blk_zone_cond_str(blkz)); + } + + return ret; +} + +uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb) +{ +#ifdef HAVE_BLK_ZONE_REP_V2 + int i, j; + uint32_t usable_segs = 0, zone_segs; + + if (c.func == RESIZE) + return get_sb(segment_count_main); + + for (i = 0; i < c.ndevs; i++) { + /* + * for the case: there is only one host managed device, and + * the device has both convential zones and sequential zones. + */ + if (c.ndevs == 1) { + usable_segs += c.devices[i].total_segments; + break; + } + if (c.devices[i].zoned_model != F2FS_ZONED_HM) { + usable_segs += c.devices[i].total_segments; + continue; + } + for (j = 0; j < c.devices[i].nr_zones; j++) { + zone_segs = c.devices[i].zone_cap_blocks[j] >> + get_sb(log_blocks_per_seg); + if (c.devices[i].zone_cap_blocks[j] % + DEFAULT_BLOCKS_PER_SEGMENT) + usable_segs += zone_segs + 1; + else + usable_segs += zone_segs; + } + } + usable_segs -= (get_sb(main_blkaddr) - get_sb(segment0_blkaddr)) >> + get_sb(log_blocks_per_seg); + return usable_segs; +#endif + return get_sb(segment_count_main); +} + +#else + +int f2fs_report_zone(int i, uint64_t UNUSED(sector), + struct blk_zone *UNUSED(blkzone)) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +int f2fs_report_zones(int i, report_zones_cb_t *UNUSED(report_zones_cb), + void *UNUSED(opaque)) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +int f2fs_get_zoned_model(int i) +{ + struct device_info *dev = c.devices + i; + + c.zoned_mode = 0; + dev->zoned_model = F2FS_ZONED_NONE; + return 0; +} + +int f2fs_get_zone_blocks(int i) +{ + struct device_info *dev = c.devices + i; + + c.zoned_mode = 0; + dev->nr_zones = 0; + dev->zone_blocks = 0; + dev->zoned_model = F2FS_ZONED_NONE; + + return 0; +} + +int f2fs_check_zones(int i) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +int f2fs_reset_zone(int i, void *UNUSED(blkzone)) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +int f2fs_reset_zones(int i) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +int f2fs_finish_zone(int i, void *UNUSED(blkzone)) +{ + ERR_MSG("%d: Unsupported zoned block device\n", i); + return -1; +} + +uint32_t f2fs_get_usable_segments(struct f2fs_super_block *sb) +{ + return get_sb(segment_count_main); +} +#endif + diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/nls_utf8.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/nls_utf8.c new file mode 100644 index 00000000000..e6f34ba60b1 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/nls_utf8.c @@ -0,0 +1,935 @@ +/* + * Copyright (c) 2014 SGI. + * Copyright (c) 2018 Collabora Ltd. + * All rights reserved. + * + * 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. + * + * 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. See the + * GNU General Public License for more details. + * + */ + +/* + * This code is adapted from the Linux Kernel. We have a + * userspace version here such that the hashes will match that + * implementation. + */ + +#include +#include +#include +#include +#include + +#include + +/* Encoding a unicode version number as a single unsigned int. */ +#define UNICODE_MAJ_SHIFT (16) +#define UNICODE_MIN_SHIFT (8) + +#define UNICODE_AGE(MAJ, MIN, REV) \ + (((unsigned int)(MAJ) << UNICODE_MAJ_SHIFT) | \ + ((unsigned int)(MIN) << UNICODE_MIN_SHIFT) | \ + ((unsigned int)(REV))) + +/* Needed in struct utf8cursor below. */ +#define UTF8HANGULLEAF (12) + +/* + * Cursor structure used by the normalizer. + */ +struct utf8cursor { + const struct utf8data *data; + const char *s; + const char *p; + const char *ss; + const char *sp; + unsigned int len; + unsigned int slen; + short int ccc; + short int nccc; + unsigned char hangul[UTF8HANGULLEAF]; +}; + +/* + * Initialize a utf8cursor to normalize a string. + * Returns 0 on success. + * Returns -1 on failure. + */ +// extern int utf8cursor(struct utf8cursor *u8c, const struct utf8data *data, +// const char *s); +// extern int utf8ncursor(struct utf8cursor *u8c, const struct utf8data *data, +// const char *s, size_t len); + +/* + * Get the next byte in the normalization. + * Returns a value > 0 && < 256 on success. + * Returns 0 when the end of the normalization is reached. + * Returns -1 if the string being normalized is not valid UTF-8. + */ +// extern int utf8byte(struct utf8cursor *u8c); + + +struct utf8data { + unsigned int maxage; + unsigned int offset; +}; + +#define __INCLUDED_FROM_UTF8NORM_C__ +#include "utf8data.h" +#undef __INCLUDED_FROM_UTF8NORM_C__ + +#define ARRAY_SIZE(array) \ + (sizeof(array) / sizeof(array[0])) + +#if 0 +/* Highest unicode version supported by the data tables. */ +static int utf8version_is_supported(uint8_t maj, uint8_t min, uint8_t rev) +{ + int i = ARRAY_SIZE(utf8agetab) - 1; + unsigned int sb_utf8version = UNICODE_AGE(maj, min, rev); + + while (i >= 0 && utf8agetab[i] != 0) { + if (sb_utf8version == utf8agetab[i]) + return 1; + i--; + } + return 0; +} +#endif + +#if 0 +static int utf8version_latest(void) +{ + return utf8vers; +} +#endif + +/* + * UTF-8 valid ranges. + * + * The UTF-8 encoding spreads the bits of a 32bit word over several + * bytes. This table gives the ranges that can be held and how they'd + * be represented. + * + * 0x00000000 0x0000007F: 0xxxxxxx + * 0x00000000 0x000007FF: 110xxxxx 10xxxxxx + * 0x00000000 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx + * 0x00000000 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0x00000000 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0x00000000 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * There is an additional requirement on UTF-8, in that only the + * shortest representation of a 32bit value is to be used. A decoder + * must not decode sequences that do not satisfy this requirement. + * Thus the allowed ranges have a lower bound. + * + * 0x00000000 0x0000007F: 0xxxxxxx + * 0x00000080 0x000007FF: 110xxxxx 10xxxxxx + * 0x00000800 0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx + * 0x00010000 0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0x00200000 0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 0x04000000 0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * + * Actual unicode characters are limited to the range 0x0 - 0x10FFFF, + * 17 planes of 65536 values. This limits the sequences actually seen + * even more, to just the following. + * + * 0 - 0x7F: 0 - 0x7F + * 0x80 - 0x7FF: 0xC2 0x80 - 0xDF 0xBF + * 0x800 - 0xFFFF: 0xE0 0xA0 0x80 - 0xEF 0xBF 0xBF + * 0x10000 - 0x10FFFF: 0xF0 0x90 0x80 0x80 - 0xF4 0x8F 0xBF 0xBF + * + * Within those ranges the surrogates 0xD800 - 0xDFFF are not allowed. + * + * Note that the longest sequence seen with valid usage is 4 bytes, + * the same a single UTF-32 character. This makes the UTF-8 + * representation of Unicode strictly smaller than UTF-32. + * + * The shortest sequence requirement was introduced by: + * Corrigendum #1: UTF-8 Shortest Form + * It can be found here: + * http://www.unicode.org/versions/corrigendum1.html + * + */ + +/* + * Return the number of bytes used by the current UTF-8 sequence. + * Assumes the input points to the first byte of a valid UTF-8 + * sequence. + */ +static inline int utf8clen(const char *s) +{ + unsigned char c = *s; + + return 1 + (c >= 0xC0) + (c >= 0xE0) + (c >= 0xF0); +} + +/* + * Decode a 3-byte UTF-8 sequence. + */ +static unsigned int +utf8decode3(const char *str) +{ + unsigned int uc; + + uc = *str++ & 0x0F; + uc <<= 6; + uc |= *str++ & 0x3F; + uc <<= 6; + uc |= *str++ & 0x3F; + + return uc; +} + +/* + * Encode a 3-byte UTF-8 sequence. + */ +static int +utf8encode3(char *str, unsigned int val) +{ + str[2] = (val & 0x3F) | 0x80; + val >>= 6; + str[1] = (val & 0x3F) | 0x80; + val >>= 6; + str[0] = val | 0xE0; + + return 3; +} + +/* + * utf8trie_t + * + * A compact binary tree, used to decode UTF-8 characters. + * + * Internal nodes are one byte for the node itself, and up to three + * bytes for an offset into the tree. The first byte contains the + * following information: + * NEXTBYTE - flag - advance to next byte if set + * BITNUM - 3 bit field - the bit number to tested + * OFFLEN - 2 bit field - number of bytes in the offset + * if offlen == 0 (non-branching node) + * RIGHTPATH - 1 bit field - set if the following node is for the + * right-hand path (tested bit is set) + * TRIENODE - 1 bit field - set if the following node is an internal + * node, otherwise it is a leaf node + * if offlen != 0 (branching node) + * LEFTNODE - 1 bit field - set if the left-hand node is internal + * RIGHTNODE - 1 bit field - set if the right-hand node is internal + * + * Due to the way utf8 works, there cannot be branching nodes with + * NEXTBYTE set, and moreover those nodes always have a righthand + * descendant. + */ +typedef const unsigned char utf8trie_t; +#define BITNUM 0x07 +#define NEXTBYTE 0x08 +#define OFFLEN 0x30 +#define OFFLEN_SHIFT 4 +#define RIGHTPATH 0x40 +#define TRIENODE 0x80 +#define RIGHTNODE 0x40 +#define LEFTNODE 0x80 + +/* + * utf8leaf_t + * + * The leaves of the trie are embedded in the trie, and so the same + * underlying datatype: unsigned char. + * + * leaf[0]: The unicode version, stored as a generation number that is + * an index into utf8agetab[]. With this we can filter code + * points based on the unicode version in which they were + * defined. The CCC of a non-defined code point is 0. + * leaf[1]: Canonical Combining Class. During normalization, we need + * to do a stable sort into ascending order of all characters + * with a non-zero CCC that occur between two characters with + * a CCC of 0, or at the begin or end of a string. + * The unicode standard guarantees that all CCC values are + * between 0 and 254 inclusive, which leaves 255 available as + * a special value. + * Code points with CCC 0 are known as stoppers. + * leaf[2]: Decomposition. If leaf[1] == 255, then leaf[2] is the + * start of a NUL-terminated string that is the decomposition + * of the character. + * The CCC of a decomposable character is the same as the CCC + * of the first character of its decomposition. + * Some characters decompose as the empty string: these are + * characters with the Default_Ignorable_Code_Point property. + * These do affect normalization, as they all have CCC 0. + * + * The decompositions in the trie have been fully expanded, with the + * exception of Hangul syllables, which are decomposed algorithmically. + * + * Casefolding, if applicable, is also done using decompositions. + * + * The trie is constructed in such a way that leaves exist for all + * UTF-8 sequences that match the criteria from the "UTF-8 valid + * ranges" comment above, and only for those sequences. Therefore a + * lookup in the trie can be used to validate the UTF-8 input. + */ +typedef const unsigned char utf8leaf_t; + +#define LEAF_GEN(LEAF) ((LEAF)[0]) +#define LEAF_CCC(LEAF) ((LEAF)[1]) +#define LEAF_STR(LEAF) ((const char *)((LEAF) + 2)) + +#define MINCCC (0) +#define MAXCCC (254) +#define STOPPER (0) +#define DECOMPOSE (255) + +/* Marker for hangul syllable decomposition. */ +#define HANGUL ((char)(255)) +/* Size of the synthesized leaf used for Hangul syllable decomposition. */ +#define UTF8HANGULLEAF (12) + +/* + * Hangul decomposition (algorithm from Section 3.12 of Unicode 6.3.0) + * + * AC00;;Lo;0;L;;;;;N;;;;; + * D7A3;;Lo;0;L;;;;;N;;;;; + * + * SBase = 0xAC00 + * LBase = 0x1100 + * VBase = 0x1161 + * TBase = 0x11A7 + * LCount = 19 + * VCount = 21 + * TCount = 28 + * NCount = 588 (VCount * TCount) + * SCount = 11172 (LCount * NCount) + * + * Decomposition: + * SIndex = s - SBase + * + * LV (Canonical/Full) + * LIndex = SIndex / NCount + * VIndex = (Sindex % NCount) / TCount + * LPart = LBase + LIndex + * VPart = VBase + VIndex + * + * LVT (Canonical) + * LVIndex = (SIndex / TCount) * TCount + * TIndex = (Sindex % TCount) + * LVPart = SBase + LVIndex + * TPart = TBase + TIndex + * + * LVT (Full) + * LIndex = SIndex / NCount + * VIndex = (Sindex % NCount) / TCount + * TIndex = (Sindex % TCount) + * LPart = LBase + LIndex + * VPart = VBase + VIndex + * if (TIndex == 0) { + * d = + * } else { + * TPart = TBase + TIndex + * d = + * } + */ + +/* Constants */ +#define SB (0xAC00) +#define LB (0x1100) +#define VB (0x1161) +#define TB (0x11A7) +#define LC (19) +#define VC (21) +#define TC (28) +#define NC (VC * TC) +#define SC (LC * NC) + +/* Algorithmic decomposition of hangul syllable. */ +static utf8leaf_t * +utf8hangul(const char *str, unsigned char *hangul) +{ + unsigned int si; + unsigned int li; + unsigned int vi; + unsigned int ti; + unsigned char *h; + + /* Calculate the SI, LI, VI, and TI values. */ + si = utf8decode3(str) - SB; + li = si / NC; + vi = (si % NC) / TC; + ti = si % TC; + + /* Fill in base of leaf. */ + h = hangul; + LEAF_GEN(h) = 2; + LEAF_CCC(h) = DECOMPOSE; + h += 2; + + /* Add LPart, a 3-byte UTF-8 sequence. */ + h += utf8encode3((char *)h, li + LB); + + /* Add VPart, a 3-byte UTF-8 sequence. */ + h += utf8encode3((char *)h, vi + VB); + + /* Add TPart if required, also a 3-byte UTF-8 sequence. */ + if (ti) + h += utf8encode3((char *)h, ti + TB); + + /* Terminate string. */ + h[0] = '\0'; + + return hangul; +} + +/* + * Use trie to scan s, touching at most len bytes. + * Returns the leaf if one exists, NULL otherwise. + * + * A non-NULL return guarantees that the UTF-8 sequence starting at s + * is well-formed and corresponds to a known unicode code point. The + * shorthand for this will be "is valid UTF-8 unicode". + */ +static utf8leaf_t *utf8nlookup(const struct utf8data *data, + unsigned char *hangul, const char *s, size_t len) +{ + utf8trie_t *trie; + int offlen; + int offset; + int mask; + int node; + + if (!data) + return NULL; + if (len == 0) + return NULL; + + trie = utf8data + data->offset; + node = 1; + while (node) { + offlen = (*trie & OFFLEN) >> OFFLEN_SHIFT; + if (*trie & NEXTBYTE) { + if (--len == 0) + return NULL; + s++; + } + mask = 1 << (*trie & BITNUM); + if (*s & mask) { + /* Right leg */ + if (offlen) { + /* Right node at offset of trie */ + node = (*trie & RIGHTNODE); + offset = trie[offlen]; + while (--offlen) { + offset <<= 8; + offset |= trie[offlen]; + } + trie += offset; + } else if (*trie & RIGHTPATH) { + /* Right node after this node */ + node = (*trie & TRIENODE); + trie++; + } else { + /* No right node. */ + return NULL; + } + } else { + /* Left leg */ + if (offlen) { + /* Left node after this node. */ + node = (*trie & LEFTNODE); + trie += offlen + 1; + } else if (*trie & RIGHTPATH) { + /* No left node. */ + return NULL; + } else { + /* Left node after this node */ + node = (*trie & TRIENODE); + trie++; + } + } + } + /* + * Hangul decomposition is done algorithmically. These are the + * codepoints >= 0xAC00 and <= 0xD7A3. Their UTF-8 encoding is + * always 3 bytes long, so s has been advanced twice, and the + * start of the sequence is at s-2. + */ + if (LEAF_CCC(trie) == DECOMPOSE && LEAF_STR(trie)[0] == HANGUL) + trie = utf8hangul(s - 2, hangul); + return trie; +} + +/* + * Use trie to scan s. + * Returns the leaf if one exists, NULL otherwise. + * + * Forwards to utf8nlookup(). + */ +static utf8leaf_t *utf8lookup(const struct utf8data *data, + unsigned char *hangul, const char *s) +{ + return utf8nlookup(data, hangul, s, (size_t)-1); +} + +#if 0 +/* + * Maximum age of any character in s. + * Return -1 if s is not valid UTF-8 unicode. + * Return 0 if only non-assigned code points are used. + */ +static int utf8agemax(const struct utf8data *data, const char *s) +{ + utf8leaf_t *leaf; + int age = 0; + int leaf_age; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + + while (*s) { + leaf = utf8lookup(data, hangul, s); + if (!leaf) + return -1; + + leaf_age = utf8agetab[LEAF_GEN(leaf)]; + if (leaf_age <= data->maxage && leaf_age > age) + age = leaf_age; + s += utf8clen(s); + } + return age; +} +#endif + +#if 0 +/* + * Minimum age of any character in s. + * Return -1 if s is not valid UTF-8 unicode. + * Return 0 if non-assigned code points are used. + */ +static int utf8agemin(const struct utf8data *data, const char *s) +{ + utf8leaf_t *leaf; + int age; + int leaf_age; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + age = data->maxage; + while (*s) { + leaf = utf8lookup(data, hangul, s); + if (!leaf) + return -1; + leaf_age = utf8agetab[LEAF_GEN(leaf)]; + if (leaf_age <= data->maxage && leaf_age < age) + age = leaf_age; + s += utf8clen(s); + } + return age; +} +#endif + +#if 0 +/* + * Maximum age of any character in s, touch at most len bytes. + * Return -1 if s is not valid UTF-8 unicode. + */ +static int utf8nagemax(const struct utf8data *data, const char *s, size_t len) +{ + utf8leaf_t *leaf; + int age = 0; + int leaf_age; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + + while (len && *s) { + leaf = utf8nlookup(data, hangul, s, len); + if (!leaf) + return -1; + leaf_age = utf8agetab[LEAF_GEN(leaf)]; + if (leaf_age <= data->maxage && leaf_age > age) + age = leaf_age; + len -= utf8clen(s); + s += utf8clen(s); + } + return age; +} +#endif + +#if 0 +/* + * Maximum age of any character in s, touch at most len bytes. + * Return -1 if s is not valid UTF-8 unicode. + */ +static int utf8nagemin(const struct utf8data *data, const char *s, size_t len) +{ + utf8leaf_t *leaf; + int leaf_age; + int age; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + age = data->maxage; + while (len && *s) { + leaf = utf8nlookup(data, hangul, s, len); + if (!leaf) + return -1; + leaf_age = utf8agetab[LEAF_GEN(leaf)]; + if (leaf_age <= data->maxage && leaf_age < age) + age = leaf_age; + len -= utf8clen(s); + s += utf8clen(s); + } + return age; +} +#endif + +#if 0 +/* + * Length of the normalization of s. + * Return -1 if s is not valid UTF-8 unicode. + * + * A string of Default_Ignorable_Code_Point has length 0. + */ +static ssize_t utf8len(const struct utf8data *data, const char *s) +{ + utf8leaf_t *leaf; + size_t ret = 0; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + while (*s) { + leaf = utf8lookup(data, hangul, s); + if (!leaf) + return -1; + if (utf8agetab[LEAF_GEN(leaf)] > data->maxage) + ret += utf8clen(s); + else if (LEAF_CCC(leaf) == DECOMPOSE) + ret += strlen(LEAF_STR(leaf)); + else + ret += utf8clen(s); + s += utf8clen(s); + } + return ret; +} +#endif + +#if 0 +/* + * Length of the normalization of s, touch at most len bytes. + * Return -1 if s is not valid UTF-8 unicode. + */ +static ssize_t utf8nlen(const struct utf8data *data, const char *s, size_t len) +{ + utf8leaf_t *leaf; + size_t ret = 0; + unsigned char hangul[UTF8HANGULLEAF]; + + if (!data) + return -1; + while (len && *s) { + leaf = utf8nlookup(data, hangul, s, len); + if (!leaf) + return -1; + if (utf8agetab[LEAF_GEN(leaf)] > data->maxage) + ret += utf8clen(s); + else if (LEAF_CCC(leaf) == DECOMPOSE) + ret += strlen(LEAF_STR(leaf)); + else + ret += utf8clen(s); + len -= utf8clen(s); + s += utf8clen(s); + } + return ret; +} +#endif + +/* + * Set up an utf8cursor for use by utf8byte(). + * + * u8c : pointer to cursor. + * data : const struct utf8data to use for normalization. + * s : string. + * len : length of s. + * + * Returns -1 on error, 0 on success. + */ +static int utf8ncursor(struct utf8cursor *u8c, const struct utf8data *data, + const char *s, size_t len) +{ + if (!data) + return -1; + if (!s) + return -1; + u8c->data = data; + u8c->s = s; + u8c->p = NULL; + u8c->ss = NULL; + u8c->sp = NULL; + u8c->len = len; + u8c->slen = 0; + u8c->ccc = STOPPER; + u8c->nccc = STOPPER; + /* Check we didn't clobber the maximum length. */ + if (u8c->len != len) + return -1; + /* The first byte of s may not be an utf8 continuation. */ + if (len > 0 && (*s & 0xC0) == 0x80) + return -1; + return 0; +} + +#if 0 +/* + * Set up an utf8cursor for use by utf8byte(). + * + * u8c : pointer to cursor. + * data : const struct utf8data to use for normalization. + * s : NUL-terminated string. + * + * Returns -1 on error, 0 on success. + */ +static int utf8cursor(struct utf8cursor *u8c, const struct utf8data *data, + const char *s) +{ + return utf8ncursor(u8c, data, s, (unsigned int)-1); +} +#endif + +/* + * Get one byte from the normalized form of the string described by u8c. + * + * Returns the byte cast to an unsigned char on succes, and -1 on failure. + * + * The cursor keeps track of the location in the string in u8c->s. + * When a character is decomposed, the current location is stored in + * u8c->p, and u8c->s is set to the start of the decomposition. Note + * that bytes from a decomposition do not count against u8c->len. + * + * Characters are emitted if they match the current CCC in u8c->ccc. + * Hitting end-of-string while u8c->ccc == STOPPER means we're done, + * and the function returns 0 in that case. + * + * Sorting by CCC is done by repeatedly scanning the string. The + * values of u8c->s and u8c->p are stored in u8c->ss and u8c->sp at + * the start of the scan. The first pass finds the lowest CCC to be + * emitted and stores it in u8c->nccc, the second pass emits the + * characters with this CCC and finds the next lowest CCC. This limits + * the number of passes to 1 + the number of different CCCs in the + * sequence being scanned. + * + * Therefore: + * u8c->p != NULL -> a decomposition is being scanned. + * u8c->ss != NULL -> this is a repeating scan. + * u8c->ccc == -1 -> this is the first scan of a repeating scan. + */ +static int utf8byte(struct utf8cursor *u8c) +{ + utf8leaf_t *leaf; + int ccc; + + for (;;) { + /* Check for the end of a decomposed character. */ + if (u8c->p && *u8c->s == '\0') { + u8c->s = u8c->p; + u8c->p = NULL; + } + + /* Check for end-of-string. */ + if (!u8c->p && (u8c->len == 0 || *u8c->s == '\0')) { + /* There is no next byte. */ + if (u8c->ccc == STOPPER) + return 0; + /* End-of-string during a scan counts as a stopper. */ + ccc = STOPPER; + goto ccc_mismatch; + } else if ((*u8c->s & 0xC0) == 0x80) { + /* This is a continuation of the current character. */ + if (!u8c->p) + u8c->len--; + return (unsigned char)*u8c->s++; + } + + /* Look up the data for the current character. */ + if (u8c->p) { + leaf = utf8lookup(u8c->data, u8c->hangul, u8c->s); + } else { + leaf = utf8nlookup(u8c->data, u8c->hangul, + u8c->s, u8c->len); + } + + /* No leaf found implies that the input is a binary blob. */ + if (!leaf) + return -1; + + ccc = LEAF_CCC(leaf); + /* Characters that are too new have CCC 0. */ + if (utf8agetab[LEAF_GEN(leaf)] > u8c->data->maxage) { + ccc = STOPPER; + } else if (ccc == DECOMPOSE) { + u8c->len -= utf8clen(u8c->s); + u8c->p = u8c->s + utf8clen(u8c->s); + u8c->s = LEAF_STR(leaf); + /* Empty decomposition implies CCC 0. */ + if (*u8c->s == '\0') { + if (u8c->ccc == STOPPER) + continue; + ccc = STOPPER; + goto ccc_mismatch; + } + + leaf = utf8lookup(u8c->data, u8c->hangul, u8c->s); + if (!leaf) + return -1; + ccc = LEAF_CCC(leaf); + } + + /* + * If this is not a stopper, then see if it updates + * the next canonical class to be emitted. + */ + if (ccc != STOPPER && u8c->ccc < ccc && ccc < u8c->nccc) + u8c->nccc = ccc; + + /* + * Return the current byte if this is the current + * combining class. + */ + if (ccc == u8c->ccc) { + if (!u8c->p) + u8c->len--; + return (unsigned char)*u8c->s++; + } + + /* Current combining class mismatch. */ +ccc_mismatch: + if (u8c->nccc == STOPPER) { + /* + * Scan forward for the first canonical class + * to be emitted. Save the position from + * which to restart. + */ + u8c->ccc = MINCCC - 1; + u8c->nccc = ccc; + u8c->sp = u8c->p; + u8c->ss = u8c->s; + u8c->slen = u8c->len; + if (!u8c->p) + u8c->len -= utf8clen(u8c->s); + u8c->s += utf8clen(u8c->s); + } else if (ccc != STOPPER) { + /* Not a stopper, and not the ccc we're emitting. */ + if (!u8c->p) + u8c->len -= utf8clen(u8c->s); + u8c->s += utf8clen(u8c->s); + } else if (u8c->nccc != MAXCCC + 1) { + /* At a stopper, restart for next ccc. */ + u8c->ccc = u8c->nccc; + u8c->nccc = MAXCCC + 1; + u8c->s = u8c->ss; + u8c->p = u8c->sp; + u8c->len = u8c->slen; + } else { + /* All done, proceed from here. */ + u8c->ccc = STOPPER; + u8c->nccc = STOPPER; + u8c->sp = NULL; + u8c->ss = NULL; + u8c->slen = 0; + } + } +} + +#if 0 +/* + * Look for the correct const struct utf8data for a unicode version. + * Returns NULL if the version requested is too new. + * + * Two normalization forms are supported: nfdi and nfdicf. + * + * nfdi: + * - Apply unicode normalization form NFD. + * - Remove any Default_Ignorable_Code_Point. + * + * nfdicf: + * - Apply unicode normalization form NFD. + * - Remove any Default_Ignorable_Code_Point. + * - Apply a full casefold (C + F). + */ +static const struct utf8data *utf8nfdi(unsigned int maxage) +{ + int i = ARRAY_SIZE(utf8nfdidata) - 1; + + while (maxage < utf8nfdidata[i].maxage) + i--; + if (maxage > utf8nfdidata[i].maxage) + return NULL; + return &utf8nfdidata[i]; +} +#endif + +static const struct utf8data *utf8nfdicf(unsigned int maxage) +{ + int i = ARRAY_SIZE(utf8nfdicfdata) - 1; + + while (maxage < utf8nfdicfdata[i].maxage) + i--; + if (maxage > utf8nfdicfdata[i].maxage) + return NULL; + return &utf8nfdicfdata[i]; +} + +static int utf8_casefold(const struct f2fs_nls_table *table, + const unsigned char *str, size_t len, + unsigned char *dest, size_t dlen) +{ + const struct utf8data *data = utf8nfdicf(table->version); + struct utf8cursor cur; + size_t nlen = 0; + + if (utf8ncursor(&cur, data, (const char *) str, len) < 0) + goto invalid_seq; + + for (nlen = 0; nlen < dlen; nlen++) { + int c = utf8byte(&cur); + + dest[nlen] = c; + if (!c) + return nlen; + if (c == -1) + break; + } + + return -ENAMETOOLONG; + +invalid_seq: + if (dlen < len) + return -ENAMETOOLONG; + + /* Signal invalid sequence */ + return -EINVAL; +} + +static const struct f2fs_nls_ops utf8_ops = { + .casefold = utf8_casefold, +}; + +static const struct f2fs_nls_table nls_utf8 = { + .ops = &utf8_ops, + .version = UNICODE_AGE(12, 1, 0), +}; + +const struct f2fs_nls_table *f2fs_load_nls_table(int encoding) +{ + if (encoding == F2FS_ENC_UTF8_12_1) + return &nls_utf8; + + return NULL; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/utf8data.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/utf8data.h new file mode 100644 index 00000000000..76e4f0e1b08 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/lib/utf8data.h @@ -0,0 +1,4109 @@ +/* This file is generated code, do not edit. */ +#ifndef __INCLUDED_FROM_UTF8NORM_C__ +#error Only nls_utf8-norm.c should include this file. +#endif + +static const unsigned int utf8vers = 0xc0100; + +static const unsigned int utf8agetab[] = { + 0, + 0x10100, + 0x20000, + 0x20100, + 0x30000, + 0x30100, + 0x30200, + 0x40000, + 0x40100, + 0x50000, + 0x50100, + 0x50200, + 0x60000, + 0x60100, + 0x60200, + 0x60300, + 0x70000, + 0x80000, + 0x90000, + 0xa0000, + 0xb0000, + 0xc0000, + 0xc0100 +}; + +static const struct utf8data utf8nfdicfdata[] = { + { 0, 0 }, + { 0x10100, 0 }, + { 0x20000, 0 }, + { 0x20100, 0 }, + { 0x30000, 0 }, + { 0x30100, 0 }, + { 0x30200, 1792 }, + { 0x40000, 3200 }, + { 0x40100, 3200 }, + { 0x50000, 3200 }, + { 0x50100, 3200 }, + { 0x50200, 3200 }, + { 0x60000, 3200 }, + { 0x60100, 3200 }, + { 0x60200, 3200 }, + { 0x60300, 3200 }, + { 0x70000, 3200 }, + { 0x80000, 3200 }, + { 0x90000, 3200 }, + { 0xa0000, 3200 }, + { 0xb0000, 3200 }, + { 0xc0000, 3200 }, + { 0xc0100, 3200 } +}; + +static const struct utf8data utf8nfdidata[] = { + { 0, 896 }, + { 0x10100, 896 }, + { 0x20000, 896 }, + { 0x20100, 896 }, + { 0x30000, 896 }, + { 0x30100, 896 }, + { 0x30200, 2496 }, + { 0x40000, 20736 }, + { 0x40100, 20736 }, + { 0x50000, 20736 }, + { 0x50100, 20736 }, + { 0x50200, 20736 }, + { 0x60000, 20736 }, + { 0x60100, 20736 }, + { 0x60200, 20736 }, + { 0x60300, 20736 }, + { 0x70000, 20736 }, + { 0x80000, 20736 }, + { 0x90000, 20736 }, + { 0xa0000, 20736 }, + { 0xb0000, 20736 }, + { 0xc0000, 20736 }, + { 0xc0100, 20736 } +}; + +static const unsigned char utf8data[64256] = { + /* nfdicf_30100 */ + 0xd7,0x07,0x66,0x84,0x0c,0x01,0x00,0xc6,0xd5,0x16,0xe4,0x99,0x1a,0xe3,0x63,0x15, + 0xe2,0x4c,0x0e,0xc1,0xe0,0x4e,0x0d,0xcf,0x86,0x65,0x2d,0x0d,0x01,0x00,0xd4,0xb8, + 0xd3,0x27,0xe2,0x89,0xa3,0xe1,0xce,0x35,0xe0,0x2c,0x22,0xcf,0x86,0xc5,0xe4,0x15, + 0x6d,0xe3,0x60,0x68,0xe2,0xf6,0x65,0xe1,0x29,0x65,0xe0,0xee,0x64,0xcf,0x86,0xe5, + 0xb3,0x64,0x64,0x96,0x64,0x0b,0x00,0xd2,0x0e,0xe1,0xb5,0x3c,0xe0,0xba,0xa3,0xcf, + 0x86,0xcf,0x06,0x01,0x00,0xd1,0x0c,0xe0,0x1e,0xa9,0xcf,0x86,0xcf,0x06,0x02,0xff, + 0xff,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x01, + 0x00,0xe4,0xe1,0x45,0xe3,0x3b,0x45,0xd2,0x06,0xcf,0x06,0x01,0x00,0xe1,0x87,0xad, + 0xd0,0x21,0xcf,0x86,0xe5,0x81,0xaa,0xe4,0x00,0xaa,0xe3,0xbf,0xa9,0xe2,0x9e,0xa9, + 0xe1,0x8d,0xa9,0x10,0x08,0x01,0xff,0xe8,0xb1,0x88,0x00,0x01,0xff,0xe6,0x9b,0xb4, + 0x00,0xcf,0x86,0xe5,0x63,0xac,0xd4,0x19,0xe3,0xa2,0xab,0xe2,0x81,0xab,0xe1,0x70, + 0xab,0x10,0x08,0x01,0xff,0xe9,0xb9,0xbf,0x00,0x01,0xff,0xe8,0xab,0x96,0x00,0xe3, + 0x09,0xac,0xe2,0xe8,0xab,0xe1,0xd7,0xab,0x10,0x08,0x01,0xff,0xe7,0xb8,0xb7,0x00, + 0x01,0xff,0xe9,0x9b,0xbb,0x00,0x83,0xe2,0x19,0xfa,0xe1,0xf2,0xf6,0xe0,0x6f,0xf5, + 0xcf,0x86,0xd5,0x31,0xc4,0xe3,0x54,0x4e,0xe2,0xf5,0x4c,0xe1,0xa4,0xcc,0xe0,0x9c, + 0x4b,0xcf,0x86,0xe5,0x8e,0x49,0xe4,0xaf,0x46,0xe3,0x11,0xbd,0xe2,0x68,0xbc,0xe1, + 0x43,0xbc,0xe0,0x1c,0xbc,0xcf,0x86,0xe5,0xe9,0xbb,0x94,0x07,0x63,0xd4,0xbb,0x07, + 0x00,0x07,0x00,0xe4,0xdb,0xf4,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd2,0x0b, + 0xe1,0xea,0xe1,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd1,0x0e,0xe0,0xd9,0xe2,0xcf,0x86, + 0xe5,0x9e,0xe2,0xcf,0x06,0x11,0x00,0xd0,0x0b,0xcf,0x86,0xe5,0xd9,0xe2,0xcf,0x06, + 0x13,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xe4,0x74,0xf4,0xe3,0x5d,0xf3, + 0xd2,0xa0,0xe1,0x13,0xe7,0xd0,0x21,0xcf,0x86,0xe5,0x14,0xe4,0xe4,0x90,0xe3,0xe3, + 0x4e,0xe3,0xe2,0x2d,0xe3,0xe1,0x1b,0xe3,0x10,0x08,0x05,0xff,0xe4,0xb8,0xbd,0x00, + 0x05,0xff,0xe4,0xb8,0xb8,0x00,0xcf,0x86,0xd5,0x1c,0xe4,0x70,0xe5,0xe3,0x2f,0xe5, + 0xe2,0x0e,0xe5,0xe1,0xfd,0xe4,0x10,0x08,0x05,0xff,0xe5,0x92,0xa2,0x00,0x05,0xff, + 0xe5,0x93,0xb6,0x00,0xd4,0x34,0xd3,0x18,0xe2,0xf7,0xe5,0xe1,0xe6,0xe5,0x10,0x09, + 0x05,0xff,0xf0,0xa1,0x9a,0xa8,0x00,0x05,0xff,0xf0,0xa1,0x9b,0xaa,0x00,0xe2,0x17, + 0xe6,0x91,0x11,0x10,0x09,0x05,0xff,0xf0,0xa1,0x8d,0xaa,0x00,0x05,0xff,0xe5,0xac, + 0x88,0x00,0x05,0xff,0xe5,0xac,0xbe,0x00,0xe3,0x5d,0xe6,0xd2,0x14,0xe1,0x2c,0xe6, + 0x10,0x08,0x05,0xff,0xe5,0xaf,0xb3,0x00,0x05,0xff,0xf0,0xa1,0xac,0x98,0x00,0xe1, + 0x38,0xe6,0x10,0x08,0x05,0xff,0xe5,0xbc,0xb3,0x00,0x05,0xff,0xe5,0xb0,0xa2,0x00, + 0xd1,0xd5,0xd0,0x6a,0xcf,0x86,0xe5,0x8d,0xeb,0xd4,0x19,0xe3,0xc6,0xea,0xe2,0xa4, + 0xea,0xe1,0x93,0xea,0x10,0x08,0x05,0xff,0xe6,0xb4,0xbe,0x00,0x05,0xff,0xe6,0xb5, + 0xb7,0x00,0xd3,0x18,0xe2,0x10,0xeb,0xe1,0xff,0xea,0x10,0x09,0x05,0xff,0xf0,0xa3, + 0xbd,0x9e,0x00,0x05,0xff,0xf0,0xa3,0xbe,0x8e,0x00,0xd2,0x13,0xe1,0x28,0xeb,0x10, + 0x08,0x05,0xff,0xe7,0x81,0xbd,0x00,0x05,0xff,0xe7,0x81,0xb7,0x00,0xd1,0x11,0x10, + 0x08,0x05,0xff,0xe7,0x85,0x85,0x00,0x05,0xff,0xf0,0xa4,0x89,0xa3,0x00,0x10,0x08, + 0x05,0xff,0xe7,0x86,0x9c,0x00,0x05,0xff,0xe4,0x8e,0xab,0x00,0xcf,0x86,0xe5,0x2a, + 0xed,0xd4,0x1a,0xe3,0x62,0xec,0xe2,0x48,0xec,0xe1,0x35,0xec,0x10,0x08,0x05,0xff, + 0xe7,0x9b,0xb4,0x00,0x05,0xff,0xf0,0xa5,0x83,0xb3,0x00,0xd3,0x16,0xe2,0xaa,0xec, + 0xe1,0x98,0xec,0x10,0x08,0x05,0xff,0xe7,0xa3,0x8c,0x00,0x05,0xff,0xe4,0x83,0xa3, + 0x00,0xd2,0x13,0xe1,0xc6,0xec,0x10,0x08,0x05,0xff,0xe4,0x84,0xaf,0x00,0x05,0xff, + 0xe7,0xa9,0x80,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0xa5,0xbc,0x00,0x05, + 0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x05, + 0xff,0xe7,0xaa,0xae,0x00,0xe0,0xdc,0xef,0xcf,0x86,0xd5,0x1d,0xe4,0x51,0xee,0xe3, + 0x0d,0xee,0xe2,0xeb,0xed,0xe1,0xda,0xed,0x10,0x09,0x05,0xff,0xf0,0xa3,0x8d,0x9f, + 0x00,0x05,0xff,0xe4,0x8f,0x95,0x00,0xd4,0x19,0xe3,0xf8,0xee,0xe2,0xd4,0xee,0xe1, + 0xc3,0xee,0x10,0x08,0x05,0xff,0xe8,0x8d,0x93,0x00,0x05,0xff,0xe8,0x8f,0x8a,0x00, + 0xd3,0x18,0xe2,0x43,0xef,0xe1,0x32,0xef,0x10,0x09,0x05,0xff,0xf0,0xa6,0xbe,0xb1, + 0x00,0x05,0xff,0xf0,0xa7,0x83,0x92,0x00,0xd2,0x13,0xe1,0x5b,0xef,0x10,0x08,0x05, + 0xff,0xe8,0x9a,0x88,0x00,0x05,0xff,0xe8,0x9c,0x8e,0x00,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe8,0x9c,0xa8,0x00,0x05,0xff,0xe8,0x9d,0xab,0x00,0x10,0x08,0x05,0xff,0xe8, + 0x9e,0x86,0x00,0x05,0xff,0xe4,0xb5,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* nfdi_30100 */ + 0x57,0x04,0x01,0x00,0xc6,0xd5,0x16,0xe4,0xc2,0x59,0xe3,0xfb,0x54,0xe2,0x74,0x4f, + 0xc1,0xe0,0xa0,0x4d,0xcf,0x86,0x65,0x84,0x4d,0x01,0x00,0xd4,0xb8,0xd3,0x27,0xe2, + 0x0c,0xa0,0xe1,0xdf,0x8d,0xe0,0x39,0x71,0xcf,0x86,0xc5,0xe4,0x98,0x69,0xe3,0xe3, + 0x64,0xe2,0x79,0x62,0xe1,0xac,0x61,0xe0,0x71,0x61,0xcf,0x86,0xe5,0x36,0x61,0x64, + 0x19,0x61,0x0b,0x00,0xd2,0x0e,0xe1,0xc2,0xa0,0xe0,0x3d,0xa0,0xcf,0x86,0xcf,0x06, + 0x01,0x00,0xd1,0x0c,0xe0,0xa1,0xa5,0xcf,0x86,0xcf,0x06,0x02,0xff,0xff,0xd0,0x08, + 0xcf,0x86,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x01,0x00,0xe4,0x9e, + 0xb6,0xe3,0x18,0xae,0xd2,0x06,0xcf,0x06,0x01,0x00,0xe1,0x0a,0xaa,0xd0,0x21,0xcf, + 0x86,0xe5,0x04,0xa7,0xe4,0x83,0xa6,0xe3,0x42,0xa6,0xe2,0x21,0xa6,0xe1,0x10,0xa6, + 0x10,0x08,0x01,0xff,0xe8,0xb1,0x88,0x00,0x01,0xff,0xe6,0x9b,0xb4,0x00,0xcf,0x86, + 0xe5,0xe6,0xa8,0xd4,0x19,0xe3,0x25,0xa8,0xe2,0x04,0xa8,0xe1,0xf3,0xa7,0x10,0x08, + 0x01,0xff,0xe9,0xb9,0xbf,0x00,0x01,0xff,0xe8,0xab,0x96,0x00,0xe3,0x8c,0xa8,0xe2, + 0x6b,0xa8,0xe1,0x5a,0xa8,0x10,0x08,0x01,0xff,0xe7,0xb8,0xb7,0x00,0x01,0xff,0xe9, + 0x9b,0xbb,0x00,0x83,0xe2,0x9c,0xf6,0xe1,0x75,0xf3,0xe0,0xf2,0xf1,0xcf,0x86,0xd5, + 0x31,0xc4,0xe3,0x6d,0xcc,0xe2,0x46,0xca,0xe1,0x27,0xc9,0xe0,0xb7,0xbf,0xcf,0x86, + 0xe5,0xaa,0xbb,0xe4,0xa3,0xba,0xe3,0x94,0xb9,0xe2,0xeb,0xb8,0xe1,0xc6,0xb8,0xe0, + 0x9f,0xb8,0xcf,0x86,0xe5,0x6c,0xb8,0x94,0x07,0x63,0x57,0xb8,0x07,0x00,0x07,0x00, + 0xe4,0x5e,0xf1,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd2,0x0b,0xe1,0x6d,0xde, + 0xcf,0x86,0xcf,0x06,0x05,0x00,0xd1,0x0e,0xe0,0x5c,0xdf,0xcf,0x86,0xe5,0x21,0xdf, + 0xcf,0x06,0x11,0x00,0xd0,0x0b,0xcf,0x86,0xe5,0x5c,0xdf,0xcf,0x06,0x13,0x00,0xcf, + 0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xe4,0xf7,0xf0,0xe3,0xe0,0xef,0xd2,0xa0,0xe1, + 0x96,0xe3,0xd0,0x21,0xcf,0x86,0xe5,0x97,0xe0,0xe4,0x13,0xe0,0xe3,0xd1,0xdf,0xe2, + 0xb0,0xdf,0xe1,0x9e,0xdf,0x10,0x08,0x05,0xff,0xe4,0xb8,0xbd,0x00,0x05,0xff,0xe4, + 0xb8,0xb8,0x00,0xcf,0x86,0xd5,0x1c,0xe4,0xf3,0xe1,0xe3,0xb2,0xe1,0xe2,0x91,0xe1, + 0xe1,0x80,0xe1,0x10,0x08,0x05,0xff,0xe5,0x92,0xa2,0x00,0x05,0xff,0xe5,0x93,0xb6, + 0x00,0xd4,0x34,0xd3,0x18,0xe2,0x7a,0xe2,0xe1,0x69,0xe2,0x10,0x09,0x05,0xff,0xf0, + 0xa1,0x9a,0xa8,0x00,0x05,0xff,0xf0,0xa1,0x9b,0xaa,0x00,0xe2,0x9a,0xe2,0x91,0x11, + 0x10,0x09,0x05,0xff,0xf0,0xa1,0x8d,0xaa,0x00,0x05,0xff,0xe5,0xac,0x88,0x00,0x05, + 0xff,0xe5,0xac,0xbe,0x00,0xe3,0xe0,0xe2,0xd2,0x14,0xe1,0xaf,0xe2,0x10,0x08,0x05, + 0xff,0xe5,0xaf,0xb3,0x00,0x05,0xff,0xf0,0xa1,0xac,0x98,0x00,0xe1,0xbb,0xe2,0x10, + 0x08,0x05,0xff,0xe5,0xbc,0xb3,0x00,0x05,0xff,0xe5,0xb0,0xa2,0x00,0xd1,0xd5,0xd0, + 0x6a,0xcf,0x86,0xe5,0x10,0xe8,0xd4,0x19,0xe3,0x49,0xe7,0xe2,0x27,0xe7,0xe1,0x16, + 0xe7,0x10,0x08,0x05,0xff,0xe6,0xb4,0xbe,0x00,0x05,0xff,0xe6,0xb5,0xb7,0x00,0xd3, + 0x18,0xe2,0x93,0xe7,0xe1,0x82,0xe7,0x10,0x09,0x05,0xff,0xf0,0xa3,0xbd,0x9e,0x00, + 0x05,0xff,0xf0,0xa3,0xbe,0x8e,0x00,0xd2,0x13,0xe1,0xab,0xe7,0x10,0x08,0x05,0xff, + 0xe7,0x81,0xbd,0x00,0x05,0xff,0xe7,0x81,0xb7,0x00,0xd1,0x11,0x10,0x08,0x05,0xff, + 0xe7,0x85,0x85,0x00,0x05,0xff,0xf0,0xa4,0x89,0xa3,0x00,0x10,0x08,0x05,0xff,0xe7, + 0x86,0x9c,0x00,0x05,0xff,0xe4,0x8e,0xab,0x00,0xcf,0x86,0xe5,0xad,0xe9,0xd4,0x1a, + 0xe3,0xe5,0xe8,0xe2,0xcb,0xe8,0xe1,0xb8,0xe8,0x10,0x08,0x05,0xff,0xe7,0x9b,0xb4, + 0x00,0x05,0xff,0xf0,0xa5,0x83,0xb3,0x00,0xd3,0x16,0xe2,0x2d,0xe9,0xe1,0x1b,0xe9, + 0x10,0x08,0x05,0xff,0xe7,0xa3,0x8c,0x00,0x05,0xff,0xe4,0x83,0xa3,0x00,0xd2,0x13, + 0xe1,0x49,0xe9,0x10,0x08,0x05,0xff,0xe4,0x84,0xaf,0x00,0x05,0xff,0xe7,0xa9,0x80, + 0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0xa5,0xbc,0x00,0x05,0xff,0xf0,0xa5, + 0xaa,0xa7,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x05,0xff,0xe7,0xaa, + 0xae,0x00,0xe0,0x5f,0xec,0xcf,0x86,0xd5,0x1d,0xe4,0xd4,0xea,0xe3,0x90,0xea,0xe2, + 0x6e,0xea,0xe1,0x5d,0xea,0x10,0x09,0x05,0xff,0xf0,0xa3,0x8d,0x9f,0x00,0x05,0xff, + 0xe4,0x8f,0x95,0x00,0xd4,0x19,0xe3,0x7b,0xeb,0xe2,0x57,0xeb,0xe1,0x46,0xeb,0x10, + 0x08,0x05,0xff,0xe8,0x8d,0x93,0x00,0x05,0xff,0xe8,0x8f,0x8a,0x00,0xd3,0x18,0xe2, + 0xc6,0xeb,0xe1,0xb5,0xeb,0x10,0x09,0x05,0xff,0xf0,0xa6,0xbe,0xb1,0x00,0x05,0xff, + 0xf0,0xa7,0x83,0x92,0x00,0xd2,0x13,0xe1,0xde,0xeb,0x10,0x08,0x05,0xff,0xe8,0x9a, + 0x88,0x00,0x05,0xff,0xe8,0x9c,0x8e,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x9c, + 0xa8,0x00,0x05,0xff,0xe8,0x9d,0xab,0x00,0x10,0x08,0x05,0xff,0xe8,0x9e,0x86,0x00, + 0x05,0xff,0xe4,0xb5,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* nfdicf_30200 */ + 0xd7,0x07,0x66,0x84,0x05,0x01,0x00,0xc6,0xd5,0x16,0xe4,0x99,0x13,0xe3,0x63,0x0e, + 0xe2,0x4c,0x07,0xc1,0xe0,0x4e,0x06,0xcf,0x86,0x65,0x2d,0x06,0x01,0x00,0xd4,0x2a, + 0xe3,0xd0,0x35,0xe2,0x88,0x9c,0xe1,0xcd,0x2e,0xe0,0x2b,0x1b,0xcf,0x86,0xc5,0xe4, + 0x14,0x66,0xe3,0x5f,0x61,0xe2,0xf5,0x5e,0xe1,0x28,0x5e,0xe0,0xed,0x5d,0xcf,0x86, + 0xe5,0xb2,0x5d,0x64,0x95,0x5d,0x0b,0x00,0x83,0xe2,0xa7,0xf3,0xe1,0x80,0xf0,0xe0, + 0xfd,0xee,0xcf,0x86,0xd5,0x31,0xc4,0xe3,0xe2,0x47,0xe2,0x83,0x46,0xe1,0x32,0xc6, + 0xe0,0x2a,0x45,0xcf,0x86,0xe5,0x1c,0x43,0xe4,0x3d,0x40,0xe3,0x9f,0xb6,0xe2,0xf6, + 0xb5,0xe1,0xd1,0xb5,0xe0,0xaa,0xb5,0xcf,0x86,0xe5,0x77,0xb5,0x94,0x07,0x63,0x62, + 0xb5,0x07,0x00,0x07,0x00,0xe4,0x69,0xee,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00, + 0xd2,0x0b,0xe1,0x78,0xdb,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd1,0x0e,0xe0,0x67,0xdc, + 0xcf,0x86,0xe5,0x2c,0xdc,0xcf,0x06,0x11,0x00,0xd0,0x0b,0xcf,0x86,0xe5,0x67,0xdc, + 0xcf,0x06,0x13,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xe4,0x02,0xee,0xe3, + 0xeb,0xec,0xd2,0xa0,0xe1,0xa1,0xe0,0xd0,0x21,0xcf,0x86,0xe5,0xa2,0xdd,0xe4,0x1e, + 0xdd,0xe3,0xdc,0xdc,0xe2,0xbb,0xdc,0xe1,0xa9,0xdc,0x10,0x08,0x05,0xff,0xe4,0xb8, + 0xbd,0x00,0x05,0xff,0xe4,0xb8,0xb8,0x00,0xcf,0x86,0xd5,0x1c,0xe4,0xfe,0xde,0xe3, + 0xbd,0xde,0xe2,0x9c,0xde,0xe1,0x8b,0xde,0x10,0x08,0x05,0xff,0xe5,0x92,0xa2,0x00, + 0x05,0xff,0xe5,0x93,0xb6,0x00,0xd4,0x34,0xd3,0x18,0xe2,0x85,0xdf,0xe1,0x74,0xdf, + 0x10,0x09,0x05,0xff,0xf0,0xa1,0x9a,0xa8,0x00,0x05,0xff,0xf0,0xa1,0x9b,0xaa,0x00, + 0xe2,0xa5,0xdf,0x91,0x11,0x10,0x09,0x05,0xff,0xf0,0xa1,0x8d,0xaa,0x00,0x05,0xff, + 0xe5,0xac,0x88,0x00,0x05,0xff,0xe5,0xac,0xbe,0x00,0xe3,0xeb,0xdf,0xd2,0x14,0xe1, + 0xba,0xdf,0x10,0x08,0x05,0xff,0xe5,0xaf,0xb3,0x00,0x05,0xff,0xf0,0xa1,0xac,0x98, + 0x00,0xe1,0xc6,0xdf,0x10,0x08,0x05,0xff,0xe5,0xbc,0xb3,0x00,0x05,0xff,0xe5,0xb0, + 0xa2,0x00,0xd1,0xd5,0xd0,0x6a,0xcf,0x86,0xe5,0x1b,0xe5,0xd4,0x19,0xe3,0x54,0xe4, + 0xe2,0x32,0xe4,0xe1,0x21,0xe4,0x10,0x08,0x05,0xff,0xe6,0xb4,0xbe,0x00,0x05,0xff, + 0xe6,0xb5,0xb7,0x00,0xd3,0x18,0xe2,0x9e,0xe4,0xe1,0x8d,0xe4,0x10,0x09,0x05,0xff, + 0xf0,0xa3,0xbd,0x9e,0x00,0x05,0xff,0xf0,0xa3,0xbe,0x8e,0x00,0xd2,0x13,0xe1,0xb6, + 0xe4,0x10,0x08,0x05,0xff,0xe7,0x81,0xbd,0x00,0x05,0xff,0xe7,0x81,0xb7,0x00,0xd1, + 0x11,0x10,0x08,0x05,0xff,0xe7,0x85,0x85,0x00,0x05,0xff,0xf0,0xa4,0x89,0xa3,0x00, + 0x10,0x08,0x05,0xff,0xe7,0x86,0x9c,0x00,0x05,0xff,0xe4,0x8e,0xab,0x00,0xcf,0x86, + 0xe5,0xb8,0xe6,0xd4,0x1a,0xe3,0xf0,0xe5,0xe2,0xd6,0xe5,0xe1,0xc3,0xe5,0x10,0x08, + 0x05,0xff,0xe7,0x9b,0xb4,0x00,0x05,0xff,0xf0,0xa5,0x83,0xb3,0x00,0xd3,0x16,0xe2, + 0x38,0xe6,0xe1,0x26,0xe6,0x10,0x08,0x05,0xff,0xe7,0xa3,0x8c,0x00,0x05,0xff,0xe4, + 0x83,0xa3,0x00,0xd2,0x13,0xe1,0x54,0xe6,0x10,0x08,0x05,0xff,0xe4,0x84,0xaf,0x00, + 0x05,0xff,0xe7,0xa9,0x80,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0xa5,0xbc, + 0x00,0x05,0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0xaa,0xa7, + 0x00,0x05,0xff,0xe7,0xaa,0xae,0x00,0xe0,0x6a,0xe9,0xcf,0x86,0xd5,0x1d,0xe4,0xdf, + 0xe7,0xe3,0x9b,0xe7,0xe2,0x79,0xe7,0xe1,0x68,0xe7,0x10,0x09,0x05,0xff,0xf0,0xa3, + 0x8d,0x9f,0x00,0x05,0xff,0xe4,0x8f,0x95,0x00,0xd4,0x19,0xe3,0x86,0xe8,0xe2,0x62, + 0xe8,0xe1,0x51,0xe8,0x10,0x08,0x05,0xff,0xe8,0x8d,0x93,0x00,0x05,0xff,0xe8,0x8f, + 0x8a,0x00,0xd3,0x18,0xe2,0xd1,0xe8,0xe1,0xc0,0xe8,0x10,0x09,0x05,0xff,0xf0,0xa6, + 0xbe,0xb1,0x00,0x05,0xff,0xf0,0xa7,0x83,0x92,0x00,0xd2,0x13,0xe1,0xe9,0xe8,0x10, + 0x08,0x05,0xff,0xe8,0x9a,0x88,0x00,0x05,0xff,0xe8,0x9c,0x8e,0x00,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe8,0x9c,0xa8,0x00,0x05,0xff,0xe8,0x9d,0xab,0x00,0x10,0x08,0x05, + 0xff,0xe8,0x9e,0x86,0x00,0x05,0xff,0xe4,0xb5,0x97,0x00,0x00,0x00,0x00,0x00,0x00, + /* nfdi_30200 */ + 0x57,0x04,0x01,0x00,0xc6,0xd5,0x16,0xe4,0x82,0x53,0xe3,0xbb,0x4e,0xe2,0x34,0x49, + 0xc1,0xe0,0x60,0x47,0xcf,0x86,0x65,0x44,0x47,0x01,0x00,0xd4,0x2a,0xe3,0x1c,0x9a, + 0xe2,0xcb,0x99,0xe1,0x9e,0x87,0xe0,0xf8,0x6a,0xcf,0x86,0xc5,0xe4,0x57,0x63,0xe3, + 0xa2,0x5e,0xe2,0x38,0x5c,0xe1,0x6b,0x5b,0xe0,0x30,0x5b,0xcf,0x86,0xe5,0xf5,0x5a, + 0x64,0xd8,0x5a,0x0b,0x00,0x83,0xe2,0xea,0xf0,0xe1,0xc3,0xed,0xe0,0x40,0xec,0xcf, + 0x86,0xd5,0x31,0xc4,0xe3,0xbb,0xc6,0xe2,0x94,0xc4,0xe1,0x75,0xc3,0xe0,0x05,0xba, + 0xcf,0x86,0xe5,0xf8,0xb5,0xe4,0xf1,0xb4,0xe3,0xe2,0xb3,0xe2,0x39,0xb3,0xe1,0x14, + 0xb3,0xe0,0xed,0xb2,0xcf,0x86,0xe5,0xba,0xb2,0x94,0x07,0x63,0xa5,0xb2,0x07,0x00, + 0x07,0x00,0xe4,0xac,0xeb,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd2,0x0b,0xe1, + 0xbb,0xd8,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd1,0x0e,0xe0,0xaa,0xd9,0xcf,0x86,0xe5, + 0x6f,0xd9,0xcf,0x06,0x11,0x00,0xd0,0x0b,0xcf,0x86,0xe5,0xaa,0xd9,0xcf,0x06,0x13, + 0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xe4,0x45,0xeb,0xe3,0x2e,0xea,0xd2, + 0xa0,0xe1,0xe4,0xdd,0xd0,0x21,0xcf,0x86,0xe5,0xe5,0xda,0xe4,0x61,0xda,0xe3,0x1f, + 0xda,0xe2,0xfe,0xd9,0xe1,0xec,0xd9,0x10,0x08,0x05,0xff,0xe4,0xb8,0xbd,0x00,0x05, + 0xff,0xe4,0xb8,0xb8,0x00,0xcf,0x86,0xd5,0x1c,0xe4,0x41,0xdc,0xe3,0x00,0xdc,0xe2, + 0xdf,0xdb,0xe1,0xce,0xdb,0x10,0x08,0x05,0xff,0xe5,0x92,0xa2,0x00,0x05,0xff,0xe5, + 0x93,0xb6,0x00,0xd4,0x34,0xd3,0x18,0xe2,0xc8,0xdc,0xe1,0xb7,0xdc,0x10,0x09,0x05, + 0xff,0xf0,0xa1,0x9a,0xa8,0x00,0x05,0xff,0xf0,0xa1,0x9b,0xaa,0x00,0xe2,0xe8,0xdc, + 0x91,0x11,0x10,0x09,0x05,0xff,0xf0,0xa1,0x8d,0xaa,0x00,0x05,0xff,0xe5,0xac,0x88, + 0x00,0x05,0xff,0xe5,0xac,0xbe,0x00,0xe3,0x2e,0xdd,0xd2,0x14,0xe1,0xfd,0xdc,0x10, + 0x08,0x05,0xff,0xe5,0xaf,0xb3,0x00,0x05,0xff,0xf0,0xa1,0xac,0x98,0x00,0xe1,0x09, + 0xdd,0x10,0x08,0x05,0xff,0xe5,0xbc,0xb3,0x00,0x05,0xff,0xe5,0xb0,0xa2,0x00,0xd1, + 0xd5,0xd0,0x6a,0xcf,0x86,0xe5,0x5e,0xe2,0xd4,0x19,0xe3,0x97,0xe1,0xe2,0x75,0xe1, + 0xe1,0x64,0xe1,0x10,0x08,0x05,0xff,0xe6,0xb4,0xbe,0x00,0x05,0xff,0xe6,0xb5,0xb7, + 0x00,0xd3,0x18,0xe2,0xe1,0xe1,0xe1,0xd0,0xe1,0x10,0x09,0x05,0xff,0xf0,0xa3,0xbd, + 0x9e,0x00,0x05,0xff,0xf0,0xa3,0xbe,0x8e,0x00,0xd2,0x13,0xe1,0xf9,0xe1,0x10,0x08, + 0x05,0xff,0xe7,0x81,0xbd,0x00,0x05,0xff,0xe7,0x81,0xb7,0x00,0xd1,0x11,0x10,0x08, + 0x05,0xff,0xe7,0x85,0x85,0x00,0x05,0xff,0xf0,0xa4,0x89,0xa3,0x00,0x10,0x08,0x05, + 0xff,0xe7,0x86,0x9c,0x00,0x05,0xff,0xe4,0x8e,0xab,0x00,0xcf,0x86,0xe5,0xfb,0xe3, + 0xd4,0x1a,0xe3,0x33,0xe3,0xe2,0x19,0xe3,0xe1,0x06,0xe3,0x10,0x08,0x05,0xff,0xe7, + 0x9b,0xb4,0x00,0x05,0xff,0xf0,0xa5,0x83,0xb3,0x00,0xd3,0x16,0xe2,0x7b,0xe3,0xe1, + 0x69,0xe3,0x10,0x08,0x05,0xff,0xe7,0xa3,0x8c,0x00,0x05,0xff,0xe4,0x83,0xa3,0x00, + 0xd2,0x13,0xe1,0x97,0xe3,0x10,0x08,0x05,0xff,0xe4,0x84,0xaf,0x00,0x05,0xff,0xe7, + 0xa9,0x80,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0xa5,0xbc,0x00,0x05,0xff, + 0xf0,0xa5,0xaa,0xa7,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x05,0xff, + 0xe7,0xaa,0xae,0x00,0xe0,0xad,0xe6,0xcf,0x86,0xd5,0x1d,0xe4,0x22,0xe5,0xe3,0xde, + 0xe4,0xe2,0xbc,0xe4,0xe1,0xab,0xe4,0x10,0x09,0x05,0xff,0xf0,0xa3,0x8d,0x9f,0x00, + 0x05,0xff,0xe4,0x8f,0x95,0x00,0xd4,0x19,0xe3,0xc9,0xe5,0xe2,0xa5,0xe5,0xe1,0x94, + 0xe5,0x10,0x08,0x05,0xff,0xe8,0x8d,0x93,0x00,0x05,0xff,0xe8,0x8f,0x8a,0x00,0xd3, + 0x18,0xe2,0x14,0xe6,0xe1,0x03,0xe6,0x10,0x09,0x05,0xff,0xf0,0xa6,0xbe,0xb1,0x00, + 0x05,0xff,0xf0,0xa7,0x83,0x92,0x00,0xd2,0x13,0xe1,0x2c,0xe6,0x10,0x08,0x05,0xff, + 0xe8,0x9a,0x88,0x00,0x05,0xff,0xe8,0x9c,0x8e,0x00,0xd1,0x10,0x10,0x08,0x05,0xff, + 0xe8,0x9c,0xa8,0x00,0x05,0xff,0xe8,0x9d,0xab,0x00,0x10,0x08,0x05,0xff,0xe8,0x9e, + 0x86,0x00,0x05,0xff,0xe4,0xb5,0x97,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* nfdicf_c0100 */ + 0xd7,0xb0,0x56,0x04,0x01,0x00,0x95,0xa8,0xd4,0x5e,0xd3,0x2e,0xd2,0x16,0xd1,0x0a, + 0x10,0x04,0x01,0x00,0x01,0xff,0x61,0x00,0x10,0x06,0x01,0xff,0x62,0x00,0x01,0xff, + 0x63,0x00,0xd1,0x0c,0x10,0x06,0x01,0xff,0x64,0x00,0x01,0xff,0x65,0x00,0x10,0x06, + 0x01,0xff,0x66,0x00,0x01,0xff,0x67,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x06,0x01,0xff, + 0x68,0x00,0x01,0xff,0x69,0x00,0x10,0x06,0x01,0xff,0x6a,0x00,0x01,0xff,0x6b,0x00, + 0xd1,0x0c,0x10,0x06,0x01,0xff,0x6c,0x00,0x01,0xff,0x6d,0x00,0x10,0x06,0x01,0xff, + 0x6e,0x00,0x01,0xff,0x6f,0x00,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x06,0x01,0xff, + 0x70,0x00,0x01,0xff,0x71,0x00,0x10,0x06,0x01,0xff,0x72,0x00,0x01,0xff,0x73,0x00, + 0xd1,0x0c,0x10,0x06,0x01,0xff,0x74,0x00,0x01,0xff,0x75,0x00,0x10,0x06,0x01,0xff, + 0x76,0x00,0x01,0xff,0x77,0x00,0x92,0x16,0xd1,0x0c,0x10,0x06,0x01,0xff,0x78,0x00, + 0x01,0xff,0x79,0x00,0x10,0x06,0x01,0xff,0x7a,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0xc6,0xe5,0xf9,0x14,0xe4,0x6f,0x0d,0xe3,0x39,0x08,0xe2,0x22,0x01,0xc1,0xd0,0x24, + 0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x07,0x63,0xd8,0x43,0x01,0x00,0x93,0x13,0x52, + 0x04,0x01,0x00,0x91,0x0b,0x10,0x04,0x01,0x00,0x01,0xff,0xce,0xbc,0x00,0x01,0x00, + 0x01,0x00,0xcf,0x86,0xe5,0xb3,0x44,0xd4,0x7f,0xd3,0x3f,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x61,0xcc,0x80,0x00,0x01,0xff,0x61,0xcc,0x81,0x00,0x10,0x08,0x01, + 0xff,0x61,0xcc,0x82,0x00,0x01,0xff,0x61,0xcc,0x83,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x61,0xcc,0x88,0x00,0x01,0xff,0x61,0xcc,0x8a,0x00,0x10,0x07,0x01,0xff,0xc3, + 0xa6,0x00,0x01,0xff,0x63,0xcc,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x65,0xcc,0x80,0x00,0x01,0xff,0x65,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x65,0xcc, + 0x82,0x00,0x01,0xff,0x65,0xcc,0x88,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc, + 0x80,0x00,0x01,0xff,0x69,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x69,0xcc,0x82,0x00, + 0x01,0xff,0x69,0xcc,0x88,0x00,0xd3,0x3b,0xd2,0x1f,0xd1,0x0f,0x10,0x07,0x01,0xff, + 0xc3,0xb0,0x00,0x01,0xff,0x6e,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x80, + 0x00,0x01,0xff,0x6f,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x82, + 0x00,0x01,0xff,0x6f,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x88,0x00,0x01, + 0x00,0xd2,0x1f,0xd1,0x0f,0x10,0x07,0x01,0xff,0xc3,0xb8,0x00,0x01,0xff,0x75,0xcc, + 0x80,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0x81,0x00,0x01,0xff,0x75,0xcc,0x82,0x00, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc,0x88,0x00,0x01,0xff,0x79,0xcc,0x81,0x00, + 0x10,0x07,0x01,0xff,0xc3,0xbe,0x00,0x01,0xff,0x73,0x73,0x00,0xe1,0xd4,0x03,0xe0, + 0xeb,0x01,0xcf,0x86,0xd5,0xfb,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0x61,0xcc,0x84,0x00,0x01,0xff,0x61,0xcc,0x84,0x00,0x10,0x08,0x01,0xff, + 0x61,0xcc,0x86,0x00,0x01,0xff,0x61,0xcc,0x86,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x61,0xcc,0xa8,0x00,0x01,0xff,0x61,0xcc,0xa8,0x00,0x10,0x08,0x01,0xff,0x63,0xcc, + 0x81,0x00,0x01,0xff,0x63,0xcc,0x81,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x63,0xcc,0x82,0x00,0x01,0xff,0x63,0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x63,0xcc, + 0x87,0x00,0x01,0xff,0x63,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x63,0xcc, + 0x8c,0x00,0x01,0xff,0x63,0xcc,0x8c,0x00,0x10,0x08,0x01,0xff,0x64,0xcc,0x8c,0x00, + 0x01,0xff,0x64,0xcc,0x8c,0x00,0xd3,0x3b,0xd2,0x1b,0xd1,0x0b,0x10,0x07,0x01,0xff, + 0xc4,0x91,0x00,0x01,0x00,0x10,0x08,0x01,0xff,0x65,0xcc,0x84,0x00,0x01,0xff,0x65, + 0xcc,0x84,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x65,0xcc,0x86,0x00,0x01,0xff,0x65, + 0xcc,0x86,0x00,0x10,0x08,0x01,0xff,0x65,0xcc,0x87,0x00,0x01,0xff,0x65,0xcc,0x87, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x65,0xcc,0xa8,0x00,0x01,0xff,0x65, + 0xcc,0xa8,0x00,0x10,0x08,0x01,0xff,0x65,0xcc,0x8c,0x00,0x01,0xff,0x65,0xcc,0x8c, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x67,0xcc,0x82,0x00,0x01,0xff,0x67,0xcc,0x82, + 0x00,0x10,0x08,0x01,0xff,0x67,0xcc,0x86,0x00,0x01,0xff,0x67,0xcc,0x86,0x00,0xd4, + 0x7b,0xd3,0x3b,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x67,0xcc,0x87,0x00,0x01, + 0xff,0x67,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x67,0xcc,0xa7,0x00,0x01,0xff,0x67, + 0xcc,0xa7,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x68,0xcc,0x82,0x00,0x01,0xff,0x68, + 0xcc,0x82,0x00,0x10,0x07,0x01,0xff,0xc4,0xa7,0x00,0x01,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0x69,0xcc,0x83,0x00,0x01,0xff,0x69,0xcc,0x83,0x00,0x10,0x08, + 0x01,0xff,0x69,0xcc,0x84,0x00,0x01,0xff,0x69,0xcc,0x84,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0x69,0xcc,0x86,0x00,0x01,0xff,0x69,0xcc,0x86,0x00,0x10,0x08,0x01,0xff, + 0x69,0xcc,0xa8,0x00,0x01,0xff,0x69,0xcc,0xa8,0x00,0xd3,0x37,0xd2,0x17,0xd1,0x0c, + 0x10,0x08,0x01,0xff,0x69,0xcc,0x87,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xc4,0xb3, + 0x00,0x01,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6a,0xcc,0x82,0x00,0x01,0xff,0x6a, + 0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x6b,0xcc,0xa7,0x00,0x01,0xff,0x6b,0xcc,0xa7, + 0x00,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x6c,0xcc,0x81,0x00,0x10, + 0x08,0x01,0xff,0x6c,0xcc,0x81,0x00,0x01,0xff,0x6c,0xcc,0xa7,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x6c,0xcc,0xa7,0x00,0x01,0xff,0x6c,0xcc,0x8c,0x00,0x10,0x08,0x01, + 0xff,0x6c,0xcc,0x8c,0x00,0x01,0xff,0xc5,0x80,0x00,0xcf,0x86,0xd5,0xed,0xd4,0x72, + 0xd3,0x37,0xd2,0x17,0xd1,0x0b,0x10,0x04,0x01,0x00,0x01,0xff,0xc5,0x82,0x00,0x10, + 0x04,0x01,0x00,0x01,0xff,0x6e,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6e, + 0xcc,0x81,0x00,0x01,0xff,0x6e,0xcc,0xa7,0x00,0x10,0x08,0x01,0xff,0x6e,0xcc,0xa7, + 0x00,0x01,0xff,0x6e,0xcc,0x8c,0x00,0xd2,0x1b,0xd1,0x10,0x10,0x08,0x01,0xff,0x6e, + 0xcc,0x8c,0x00,0x01,0xff,0xca,0xbc,0x6e,0x00,0x10,0x07,0x01,0xff,0xc5,0x8b,0x00, + 0x01,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x84,0x00,0x01,0xff,0x6f,0xcc, + 0x84,0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x86,0x00,0x01,0xff,0x6f,0xcc,0x86,0x00, + 0xd3,0x3b,0xd2,0x1b,0xd1,0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x8b,0x00,0x01,0xff, + 0x6f,0xcc,0x8b,0x00,0x10,0x07,0x01,0xff,0xc5,0x93,0x00,0x01,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x72,0xcc,0x81,0x00,0x01,0xff,0x72,0xcc,0x81,0x00,0x10,0x08,0x01, + 0xff,0x72,0xcc,0xa7,0x00,0x01,0xff,0x72,0xcc,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x72,0xcc,0x8c,0x00,0x01,0xff,0x72,0xcc,0x8c,0x00,0x10,0x08,0x01, + 0xff,0x73,0xcc,0x81,0x00,0x01,0xff,0x73,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x73,0xcc,0x82,0x00,0x01,0xff,0x73,0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x73, + 0xcc,0xa7,0x00,0x01,0xff,0x73,0xcc,0xa7,0x00,0xd4,0x7b,0xd3,0x3b,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x73,0xcc,0x8c,0x00,0x01,0xff,0x73,0xcc,0x8c,0x00,0x10, + 0x08,0x01,0xff,0x74,0xcc,0xa7,0x00,0x01,0xff,0x74,0xcc,0xa7,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x74,0xcc,0x8c,0x00,0x01,0xff,0x74,0xcc,0x8c,0x00,0x10,0x07,0x01, + 0xff,0xc5,0xa7,0x00,0x01,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc, + 0x83,0x00,0x01,0xff,0x75,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0x84,0x00, + 0x01,0xff,0x75,0xcc,0x84,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc,0x86,0x00, + 0x01,0xff,0x75,0xcc,0x86,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0x8a,0x00,0x01,0xff, + 0x75,0xcc,0x8a,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc, + 0x8b,0x00,0x01,0xff,0x75,0xcc,0x8b,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0xa8,0x00, + 0x01,0xff,0x75,0xcc,0xa8,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0x82,0x00, + 0x01,0xff,0x77,0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x79,0xcc,0x82,0x00,0x01,0xff, + 0x79,0xcc,0x82,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x79,0xcc,0x88,0x00, + 0x01,0xff,0x7a,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x7a,0xcc,0x81,0x00,0x01,0xff, + 0x7a,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x7a,0xcc,0x87,0x00,0x01,0xff, + 0x7a,0xcc,0x8c,0x00,0x10,0x08,0x01,0xff,0x7a,0xcc,0x8c,0x00,0x01,0xff,0x73,0x00, + 0xe0,0x65,0x01,0xcf,0x86,0xd5,0xb4,0xd4,0x5a,0xd3,0x2f,0xd2,0x16,0xd1,0x0b,0x10, + 0x04,0x01,0x00,0x01,0xff,0xc9,0x93,0x00,0x10,0x07,0x01,0xff,0xc6,0x83,0x00,0x01, + 0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xc6,0x85,0x00,0x01,0x00,0x10,0x07,0x01,0xff, + 0xc9,0x94,0x00,0x01,0xff,0xc6,0x88,0x00,0xd2,0x19,0xd1,0x0b,0x10,0x04,0x01,0x00, + 0x01,0xff,0xc9,0x96,0x00,0x10,0x07,0x01,0xff,0xc9,0x97,0x00,0x01,0xff,0xc6,0x8c, + 0x00,0x51,0x04,0x01,0x00,0x10,0x07,0x01,0xff,0xc7,0x9d,0x00,0x01,0xff,0xc9,0x99, + 0x00,0xd3,0x32,0xd2,0x19,0xd1,0x0e,0x10,0x07,0x01,0xff,0xc9,0x9b,0x00,0x01,0xff, + 0xc6,0x92,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xc9,0xa0,0x00,0xd1,0x0b,0x10,0x07, + 0x01,0xff,0xc9,0xa3,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xc9,0xa9,0x00,0x01,0xff, + 0xc9,0xa8,0x00,0xd2,0x0f,0x91,0x0b,0x10,0x07,0x01,0xff,0xc6,0x99,0x00,0x01,0x00, + 0x01,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xc9,0xaf,0x00,0x01,0xff,0xc9,0xb2,0x00, + 0x10,0x04,0x01,0x00,0x01,0xff,0xc9,0xb5,0x00,0xd4,0x5d,0xd3,0x34,0xd2,0x1b,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x9b,0x00,0x01,0xff,0x6f,0xcc,0x9b,0x00,0x10, + 0x07,0x01,0xff,0xc6,0xa3,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xc6,0xa5, + 0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xca,0x80,0x00,0x01,0xff,0xc6,0xa8,0x00,0xd2, + 0x0f,0x91,0x0b,0x10,0x04,0x01,0x00,0x01,0xff,0xca,0x83,0x00,0x01,0x00,0xd1,0x0b, + 0x10,0x07,0x01,0xff,0xc6,0xad,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xca,0x88,0x00, + 0x01,0xff,0x75,0xcc,0x9b,0x00,0xd3,0x33,0xd2,0x1d,0xd1,0x0f,0x10,0x08,0x01,0xff, + 0x75,0xcc,0x9b,0x00,0x01,0xff,0xca,0x8a,0x00,0x10,0x07,0x01,0xff,0xca,0x8b,0x00, + 0x01,0xff,0xc6,0xb4,0x00,0xd1,0x0b,0x10,0x04,0x01,0x00,0x01,0xff,0xc6,0xb6,0x00, + 0x10,0x04,0x01,0x00,0x01,0xff,0xca,0x92,0x00,0xd2,0x0f,0x91,0x0b,0x10,0x07,0x01, + 0xff,0xc6,0xb9,0x00,0x01,0x00,0x01,0x00,0x91,0x0b,0x10,0x07,0x01,0xff,0xc6,0xbd, + 0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0xd4,0xd4,0x44,0xd3,0x16,0x52,0x04,0x01, + 0x00,0x51,0x07,0x01,0xff,0xc7,0x86,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xc7,0x89, + 0x00,0xd2,0x12,0x91,0x0b,0x10,0x07,0x01,0xff,0xc7,0x89,0x00,0x01,0x00,0x01,0xff, + 0xc7,0x8c,0x00,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x61,0xcc,0x8c,0x00,0x10, + 0x08,0x01,0xff,0x61,0xcc,0x8c,0x00,0x01,0xff,0x69,0xcc,0x8c,0x00,0xd3,0x46,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc,0x8c,0x00,0x01,0xff,0x6f,0xcc,0x8c, + 0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x8c,0x00,0x01,0xff,0x75,0xcc,0x8c,0x00,0xd1, + 0x12,0x10,0x08,0x01,0xff,0x75,0xcc,0x8c,0x00,0x01,0xff,0x75,0xcc,0x88,0xcc,0x84, + 0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88,0xcc,0x84,0x00,0x01,0xff,0x75,0xcc,0x88, + 0xcc,0x81,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88,0xcc,0x81, + 0x00,0x01,0xff,0x75,0xcc,0x88,0xcc,0x8c,0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88, + 0xcc,0x8c,0x00,0x01,0xff,0x75,0xcc,0x88,0xcc,0x80,0x00,0xd1,0x0e,0x10,0x0a,0x01, + 0xff,0x75,0xcc,0x88,0xcc,0x80,0x00,0x01,0x00,0x10,0x0a,0x01,0xff,0x61,0xcc,0x88, + 0xcc,0x84,0x00,0x01,0xff,0x61,0xcc,0x88,0xcc,0x84,0x00,0xd4,0x87,0xd3,0x41,0xd2, + 0x26,0xd1,0x14,0x10,0x0a,0x01,0xff,0x61,0xcc,0x87,0xcc,0x84,0x00,0x01,0xff,0x61, + 0xcc,0x87,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xc3,0xa6,0xcc,0x84,0x00,0x01,0xff, + 0xc3,0xa6,0xcc,0x84,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xc7,0xa5,0x00,0x01,0x00, + 0x10,0x08,0x01,0xff,0x67,0xcc,0x8c,0x00,0x01,0xff,0x67,0xcc,0x8c,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x6b,0xcc,0x8c,0x00,0x01,0xff,0x6b,0xcc,0x8c,0x00, + 0x10,0x08,0x01,0xff,0x6f,0xcc,0xa8,0x00,0x01,0xff,0x6f,0xcc,0xa8,0x00,0xd1,0x14, + 0x10,0x0a,0x01,0xff,0x6f,0xcc,0xa8,0xcc,0x84,0x00,0x01,0xff,0x6f,0xcc,0xa8,0xcc, + 0x84,0x00,0x10,0x09,0x01,0xff,0xca,0x92,0xcc,0x8c,0x00,0x01,0xff,0xca,0x92,0xcc, + 0x8c,0x00,0xd3,0x38,0xd2,0x1a,0xd1,0x0f,0x10,0x08,0x01,0xff,0x6a,0xcc,0x8c,0x00, + 0x01,0xff,0xc7,0xb3,0x00,0x10,0x07,0x01,0xff,0xc7,0xb3,0x00,0x01,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0x67,0xcc,0x81,0x00,0x01,0xff,0x67,0xcc,0x81,0x00,0x10,0x07, + 0x04,0xff,0xc6,0x95,0x00,0x04,0xff,0xc6,0xbf,0x00,0xd2,0x24,0xd1,0x10,0x10,0x08, + 0x04,0xff,0x6e,0xcc,0x80,0x00,0x04,0xff,0x6e,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff, + 0x61,0xcc,0x8a,0xcc,0x81,0x00,0x01,0xff,0x61,0xcc,0x8a,0xcc,0x81,0x00,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xc3,0xa6,0xcc,0x81,0x00,0x01,0xff,0xc3,0xa6,0xcc,0x81,0x00, + 0x10,0x09,0x01,0xff,0xc3,0xb8,0xcc,0x81,0x00,0x01,0xff,0xc3,0xb8,0xcc,0x81,0x00, + 0xe2,0x31,0x02,0xe1,0xc3,0x44,0xe0,0xc8,0x01,0xcf,0x86,0xd5,0xfb,0xd4,0x80,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x61,0xcc,0x8f,0x00,0x01,0xff,0x61, + 0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x61,0xcc,0x91,0x00,0x01,0xff,0x61,0xcc,0x91, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x65,0xcc,0x8f,0x00,0x01,0xff,0x65,0xcc,0x8f, + 0x00,0x10,0x08,0x01,0xff,0x65,0xcc,0x91,0x00,0x01,0xff,0x65,0xcc,0x91,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc,0x8f,0x00,0x01,0xff,0x69,0xcc,0x8f, + 0x00,0x10,0x08,0x01,0xff,0x69,0xcc,0x91,0x00,0x01,0xff,0x69,0xcc,0x91,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x8f,0x00,0x01,0xff,0x6f,0xcc,0x8f,0x00,0x10, + 0x08,0x01,0xff,0x6f,0xcc,0x91,0x00,0x01,0xff,0x6f,0xcc,0x91,0x00,0xd3,0x40,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x72,0xcc,0x8f,0x00,0x01,0xff,0x72,0xcc,0x8f, + 0x00,0x10,0x08,0x01,0xff,0x72,0xcc,0x91,0x00,0x01,0xff,0x72,0xcc,0x91,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x75,0xcc,0x8f,0x00,0x01,0xff,0x75,0xcc,0x8f,0x00,0x10, + 0x08,0x01,0xff,0x75,0xcc,0x91,0x00,0x01,0xff,0x75,0xcc,0x91,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x04,0xff,0x73,0xcc,0xa6,0x00,0x04,0xff,0x73,0xcc,0xa6,0x00,0x10, + 0x08,0x04,0xff,0x74,0xcc,0xa6,0x00,0x04,0xff,0x74,0xcc,0xa6,0x00,0xd1,0x0b,0x10, + 0x07,0x04,0xff,0xc8,0x9d,0x00,0x04,0x00,0x10,0x08,0x04,0xff,0x68,0xcc,0x8c,0x00, + 0x04,0xff,0x68,0xcc,0x8c,0x00,0xd4,0x79,0xd3,0x31,0xd2,0x16,0xd1,0x0b,0x10,0x07, + 0x06,0xff,0xc6,0x9e,0x00,0x07,0x00,0x10,0x07,0x04,0xff,0xc8,0xa3,0x00,0x04,0x00, + 0xd1,0x0b,0x10,0x07,0x04,0xff,0xc8,0xa5,0x00,0x04,0x00,0x10,0x08,0x04,0xff,0x61, + 0xcc,0x87,0x00,0x04,0xff,0x61,0xcc,0x87,0x00,0xd2,0x24,0xd1,0x10,0x10,0x08,0x04, + 0xff,0x65,0xcc,0xa7,0x00,0x04,0xff,0x65,0xcc,0xa7,0x00,0x10,0x0a,0x04,0xff,0x6f, + 0xcc,0x88,0xcc,0x84,0x00,0x04,0xff,0x6f,0xcc,0x88,0xcc,0x84,0x00,0xd1,0x14,0x10, + 0x0a,0x04,0xff,0x6f,0xcc,0x83,0xcc,0x84,0x00,0x04,0xff,0x6f,0xcc,0x83,0xcc,0x84, + 0x00,0x10,0x08,0x04,0xff,0x6f,0xcc,0x87,0x00,0x04,0xff,0x6f,0xcc,0x87,0x00,0xd3, + 0x27,0xe2,0x21,0x43,0xd1,0x14,0x10,0x0a,0x04,0xff,0x6f,0xcc,0x87,0xcc,0x84,0x00, + 0x04,0xff,0x6f,0xcc,0x87,0xcc,0x84,0x00,0x10,0x08,0x04,0xff,0x79,0xcc,0x84,0x00, + 0x04,0xff,0x79,0xcc,0x84,0x00,0xd2,0x13,0x51,0x04,0x08,0x00,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0xa5,0x00,0x08,0xff,0xc8,0xbc,0x00,0xd1,0x0b,0x10,0x04,0x08,0x00,0x08, + 0xff,0xc6,0x9a,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1,0xa6,0x00,0x08,0x00,0xcf,0x86, + 0x95,0x5f,0x94,0x5b,0xd3,0x2f,0xd2,0x16,0xd1,0x0b,0x10,0x04,0x08,0x00,0x08,0xff, + 0xc9,0x82,0x00,0x10,0x04,0x09,0x00,0x09,0xff,0xc6,0x80,0x00,0xd1,0x0e,0x10,0x07, + 0x09,0xff,0xca,0x89,0x00,0x09,0xff,0xca,0x8c,0x00,0x10,0x07,0x09,0xff,0xc9,0x87, + 0x00,0x09,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x09,0xff,0xc9,0x89,0x00,0x09,0x00, + 0x10,0x07,0x09,0xff,0xc9,0x8b,0x00,0x09,0x00,0xd1,0x0b,0x10,0x07,0x09,0xff,0xc9, + 0x8d,0x00,0x09,0x00,0x10,0x07,0x09,0xff,0xc9,0x8f,0x00,0x09,0x00,0x01,0x00,0x01, + 0x00,0xd1,0x8b,0xd0,0x0c,0xcf,0x86,0xe5,0x10,0x43,0x64,0xef,0x42,0x01,0xe6,0xcf, + 0x86,0xd5,0x2a,0xe4,0x99,0x43,0xe3,0x7f,0x43,0xd2,0x11,0xe1,0x5e,0x43,0x10,0x07, + 0x01,0xff,0xcc,0x80,0x00,0x01,0xff,0xcc,0x81,0x00,0xe1,0x65,0x43,0x10,0x09,0x01, + 0xff,0xcc,0x88,0xcc,0x81,0x00,0x01,0xff,0xce,0xb9,0x00,0xd4,0x0f,0x93,0x0b,0x92, + 0x07,0x61,0xab,0x43,0x01,0xea,0x06,0xe6,0x06,0xe6,0xd3,0x2c,0xd2,0x16,0xd1,0x0b, + 0x10,0x07,0x0a,0xff,0xcd,0xb1,0x00,0x0a,0x00,0x10,0x07,0x0a,0xff,0xcd,0xb3,0x00, + 0x0a,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xca,0xb9,0x00,0x01,0x00,0x10,0x07,0x0a, + 0xff,0xcd,0xb7,0x00,0x0a,0x00,0xd2,0x07,0x61,0x97,0x43,0x00,0x00,0x51,0x04,0x09, + 0x00,0x10,0x06,0x01,0xff,0x3b,0x00,0x10,0xff,0xcf,0xb3,0x00,0xe0,0x31,0x01,0xcf, + 0x86,0xd5,0xd3,0xd4,0x5f,0xd3,0x21,0x52,0x04,0x00,0x00,0xd1,0x0d,0x10,0x04,0x01, + 0x00,0x01,0xff,0xc2,0xa8,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x81, + 0x00,0x01,0xff,0xc2,0xb7,0x00,0xd2,0x1f,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb5, + 0xcc,0x81,0x00,0x01,0xff,0xce,0xb7,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce,0xb9, + 0xcc,0x81,0x00,0x00,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xce,0xbf,0xcc,0x81,0x00, + 0x00,0x00,0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x81,0x00,0x01,0xff,0xcf,0x89,0xcc, + 0x81,0x00,0xd3,0x3c,0xd2,0x20,0xd1,0x12,0x10,0x0b,0x01,0xff,0xce,0xb9,0xcc,0x88, + 0xcc,0x81,0x00,0x01,0xff,0xce,0xb1,0x00,0x10,0x07,0x01,0xff,0xce,0xb2,0x00,0x01, + 0xff,0xce,0xb3,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xce,0xb4,0x00,0x01,0xff,0xce, + 0xb5,0x00,0x10,0x07,0x01,0xff,0xce,0xb6,0x00,0x01,0xff,0xce,0xb7,0x00,0xd2,0x1c, + 0xd1,0x0e,0x10,0x07,0x01,0xff,0xce,0xb8,0x00,0x01,0xff,0xce,0xb9,0x00,0x10,0x07, + 0x01,0xff,0xce,0xba,0x00,0x01,0xff,0xce,0xbb,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff, + 0xce,0xbc,0x00,0x01,0xff,0xce,0xbd,0x00,0x10,0x07,0x01,0xff,0xce,0xbe,0x00,0x01, + 0xff,0xce,0xbf,0x00,0xe4,0x85,0x43,0xd3,0x35,0xd2,0x19,0xd1,0x0e,0x10,0x07,0x01, + 0xff,0xcf,0x80,0x00,0x01,0xff,0xcf,0x81,0x00,0x10,0x04,0x00,0x00,0x01,0xff,0xcf, + 0x83,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xcf,0x84,0x00,0x01,0xff,0xcf,0x85,0x00, + 0x10,0x07,0x01,0xff,0xcf,0x86,0x00,0x01,0xff,0xcf,0x87,0x00,0xe2,0x2b,0x43,0xd1, + 0x0e,0x10,0x07,0x01,0xff,0xcf,0x88,0x00,0x01,0xff,0xcf,0x89,0x00,0x10,0x09,0x01, + 0xff,0xce,0xb9,0xcc,0x88,0x00,0x01,0xff,0xcf,0x85,0xcc,0x88,0x00,0xcf,0x86,0xd5, + 0x94,0xd4,0x3c,0xd3,0x13,0x92,0x0f,0x51,0x04,0x01,0x00,0x10,0x07,0x01,0xff,0xcf, + 0x83,0x00,0x01,0x00,0x01,0x00,0xd2,0x07,0x61,0x3a,0x43,0x01,0x00,0xd1,0x12,0x10, + 0x09,0x01,0xff,0xce,0xbf,0xcc,0x81,0x00,0x01,0xff,0xcf,0x85,0xcc,0x81,0x00,0x10, + 0x09,0x01,0xff,0xcf,0x89,0xcc,0x81,0x00,0x0a,0xff,0xcf,0x97,0x00,0xd3,0x2c,0xd2, + 0x11,0xe1,0x46,0x43,0x10,0x07,0x01,0xff,0xce,0xb2,0x00,0x01,0xff,0xce,0xb8,0x00, + 0xd1,0x10,0x10,0x09,0x01,0xff,0xcf,0x92,0xcc,0x88,0x00,0x01,0xff,0xcf,0x86,0x00, + 0x10,0x07,0x01,0xff,0xcf,0x80,0x00,0x04,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x06, + 0xff,0xcf,0x99,0x00,0x06,0x00,0x10,0x07,0x01,0xff,0xcf,0x9b,0x00,0x04,0x00,0xd1, + 0x0b,0x10,0x07,0x01,0xff,0xcf,0x9d,0x00,0x04,0x00,0x10,0x07,0x01,0xff,0xcf,0x9f, + 0x00,0x04,0x00,0xd4,0x58,0xd3,0x2c,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xcf, + 0xa1,0x00,0x04,0x00,0x10,0x07,0x01,0xff,0xcf,0xa3,0x00,0x01,0x00,0xd1,0x0b,0x10, + 0x07,0x01,0xff,0xcf,0xa5,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xcf,0xa7,0x00,0x01, + 0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xcf,0xa9,0x00,0x01,0x00,0x10,0x07, + 0x01,0xff,0xcf,0xab,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xcf,0xad,0x00, + 0x01,0x00,0x10,0x07,0x01,0xff,0xcf,0xaf,0x00,0x01,0x00,0xd3,0x2b,0xd2,0x12,0x91, + 0x0e,0x10,0x07,0x01,0xff,0xce,0xba,0x00,0x01,0xff,0xcf,0x81,0x00,0x01,0x00,0xd1, + 0x0e,0x10,0x07,0x05,0xff,0xce,0xb8,0x00,0x05,0xff,0xce,0xb5,0x00,0x10,0x04,0x06, + 0x00,0x07,0xff,0xcf,0xb8,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x04,0x07,0x00,0x07,0xff, + 0xcf,0xb2,0x00,0x10,0x07,0x07,0xff,0xcf,0xbb,0x00,0x07,0x00,0xd1,0x0b,0x10,0x04, + 0x08,0x00,0x08,0xff,0xcd,0xbb,0x00,0x10,0x07,0x08,0xff,0xcd,0xbc,0x00,0x08,0xff, + 0xcd,0xbd,0x00,0xe3,0xed,0x46,0xe2,0x3d,0x05,0xe1,0x27,0x02,0xe0,0x66,0x01,0xcf, + 0x86,0xd5,0xf0,0xd4,0x7e,0xd3,0x40,0xd2,0x22,0xd1,0x12,0x10,0x09,0x04,0xff,0xd0, + 0xb5,0xcc,0x80,0x00,0x01,0xff,0xd0,0xb5,0xcc,0x88,0x00,0x10,0x07,0x01,0xff,0xd1, + 0x92,0x00,0x01,0xff,0xd0,0xb3,0xcc,0x81,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd1, + 0x94,0x00,0x01,0xff,0xd1,0x95,0x00,0x10,0x07,0x01,0xff,0xd1,0x96,0x00,0x01,0xff, + 0xd1,0x96,0xcc,0x88,0x00,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd1,0x98,0x00, + 0x01,0xff,0xd1,0x99,0x00,0x10,0x07,0x01,0xff,0xd1,0x9a,0x00,0x01,0xff,0xd1,0x9b, + 0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd0,0xba,0xcc,0x81,0x00,0x04,0xff,0xd0,0xb8, + 0xcc,0x80,0x00,0x10,0x09,0x01,0xff,0xd1,0x83,0xcc,0x86,0x00,0x01,0xff,0xd1,0x9f, + 0x00,0xd3,0x38,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd0,0xb0,0x00,0x01,0xff, + 0xd0,0xb1,0x00,0x10,0x07,0x01,0xff,0xd0,0xb2,0x00,0x01,0xff,0xd0,0xb3,0x00,0xd1, + 0x0e,0x10,0x07,0x01,0xff,0xd0,0xb4,0x00,0x01,0xff,0xd0,0xb5,0x00,0x10,0x07,0x01, + 0xff,0xd0,0xb6,0x00,0x01,0xff,0xd0,0xb7,0x00,0xd2,0x1e,0xd1,0x10,0x10,0x07,0x01, + 0xff,0xd0,0xb8,0x00,0x01,0xff,0xd0,0xb8,0xcc,0x86,0x00,0x10,0x07,0x01,0xff,0xd0, + 0xba,0x00,0x01,0xff,0xd0,0xbb,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd0,0xbc,0x00, + 0x01,0xff,0xd0,0xbd,0x00,0x10,0x07,0x01,0xff,0xd0,0xbe,0x00,0x01,0xff,0xd0,0xbf, + 0x00,0xe4,0x25,0x42,0xd3,0x38,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd1,0x80, + 0x00,0x01,0xff,0xd1,0x81,0x00,0x10,0x07,0x01,0xff,0xd1,0x82,0x00,0x01,0xff,0xd1, + 0x83,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd1,0x84,0x00,0x01,0xff,0xd1,0x85,0x00, + 0x10,0x07,0x01,0xff,0xd1,0x86,0x00,0x01,0xff,0xd1,0x87,0x00,0xd2,0x1c,0xd1,0x0e, + 0x10,0x07,0x01,0xff,0xd1,0x88,0x00,0x01,0xff,0xd1,0x89,0x00,0x10,0x07,0x01,0xff, + 0xd1,0x8a,0x00,0x01,0xff,0xd1,0x8b,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd1,0x8c, + 0x00,0x01,0xff,0xd1,0x8d,0x00,0x10,0x07,0x01,0xff,0xd1,0x8e,0x00,0x01,0xff,0xd1, + 0x8f,0x00,0xcf,0x86,0xd5,0x07,0x64,0xcf,0x41,0x01,0x00,0xd4,0x58,0xd3,0x2c,0xd2, + 0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd1,0xa1,0x00,0x01,0x00,0x10,0x07,0x01,0xff, + 0xd1,0xa3,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd1,0xa5,0x00,0x01,0x00, + 0x10,0x07,0x01,0xff,0xd1,0xa7,0x00,0x01,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01, + 0xff,0xd1,0xa9,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd1,0xab,0x00,0x01,0x00,0xd1, + 0x0b,0x10,0x07,0x01,0xff,0xd1,0xad,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd1,0xaf, + 0x00,0x01,0x00,0xd3,0x33,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd1,0xb1,0x00, + 0x01,0x00,0x10,0x07,0x01,0xff,0xd1,0xb3,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01, + 0xff,0xd1,0xb5,0x00,0x01,0x00,0x10,0x09,0x01,0xff,0xd1,0xb5,0xcc,0x8f,0x00,0x01, + 0xff,0xd1,0xb5,0xcc,0x8f,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd1,0xb9, + 0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd1,0xbb,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07, + 0x01,0xff,0xd1,0xbd,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd1,0xbf,0x00,0x01,0x00, + 0xe0,0x41,0x01,0xcf,0x86,0xd5,0x8e,0xd4,0x36,0xd3,0x11,0xe2,0x91,0x41,0xe1,0x88, + 0x41,0x10,0x07,0x01,0xff,0xd2,0x81,0x00,0x01,0x00,0xd2,0x0f,0x51,0x04,0x04,0x00, + 0x10,0x07,0x06,0xff,0xd2,0x8b,0x00,0x06,0x00,0xd1,0x0b,0x10,0x07,0x04,0xff,0xd2, + 0x8d,0x00,0x04,0x00,0x10,0x07,0x04,0xff,0xd2,0x8f,0x00,0x04,0x00,0xd3,0x2c,0xd2, + 0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2,0x91,0x00,0x01,0x00,0x10,0x07,0x01,0xff, + 0xd2,0x93,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2,0x95,0x00,0x01,0x00, + 0x10,0x07,0x01,0xff,0xd2,0x97,0x00,0x01,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01, + 0xff,0xd2,0x99,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0x9b,0x00,0x01,0x00,0xd1, + 0x0b,0x10,0x07,0x01,0xff,0xd2,0x9d,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0x9f, + 0x00,0x01,0x00,0xd4,0x58,0xd3,0x2c,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2, + 0xa1,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xa3,0x00,0x01,0x00,0xd1,0x0b,0x10, + 0x07,0x01,0xff,0xd2,0xa5,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xa7,0x00,0x01, + 0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2,0xa9,0x00,0x01,0x00,0x10,0x07, + 0x01,0xff,0xd2,0xab,0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2,0xad,0x00, + 0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xaf,0x00,0x01,0x00,0xd3,0x2c,0xd2,0x16,0xd1, + 0x0b,0x10,0x07,0x01,0xff,0xd2,0xb1,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xb3, + 0x00,0x01,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2,0xb5,0x00,0x01,0x00,0x10,0x07, + 0x01,0xff,0xd2,0xb7,0x00,0x01,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd2, + 0xb9,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xbb,0x00,0x01,0x00,0xd1,0x0b,0x10, + 0x07,0x01,0xff,0xd2,0xbd,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xd2,0xbf,0x00,0x01, + 0x00,0xcf,0x86,0xd5,0xdc,0xd4,0x5a,0xd3,0x36,0xd2,0x20,0xd1,0x10,0x10,0x07,0x01, + 0xff,0xd3,0x8f,0x00,0x01,0xff,0xd0,0xb6,0xcc,0x86,0x00,0x10,0x09,0x01,0xff,0xd0, + 0xb6,0xcc,0x86,0x00,0x01,0xff,0xd3,0x84,0x00,0xd1,0x0b,0x10,0x04,0x01,0x00,0x06, + 0xff,0xd3,0x86,0x00,0x10,0x04,0x06,0x00,0x01,0xff,0xd3,0x88,0x00,0xd2,0x16,0xd1, + 0x0b,0x10,0x04,0x01,0x00,0x06,0xff,0xd3,0x8a,0x00,0x10,0x04,0x06,0x00,0x01,0xff, + 0xd3,0x8c,0x00,0xe1,0x69,0x40,0x10,0x04,0x01,0x00,0x06,0xff,0xd3,0x8e,0x00,0xd3, + 0x41,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd0,0xb0,0xcc,0x86,0x00,0x01,0xff, + 0xd0,0xb0,0xcc,0x86,0x00,0x10,0x09,0x01,0xff,0xd0,0xb0,0xcc,0x88,0x00,0x01,0xff, + 0xd0,0xb0,0xcc,0x88,0x00,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd3,0x95,0x00,0x01,0x00, + 0x10,0x09,0x01,0xff,0xd0,0xb5,0xcc,0x86,0x00,0x01,0xff,0xd0,0xb5,0xcc,0x86,0x00, + 0xd2,0x1d,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd3,0x99,0x00,0x01,0x00,0x10,0x09,0x01, + 0xff,0xd3,0x99,0xcc,0x88,0x00,0x01,0xff,0xd3,0x99,0xcc,0x88,0x00,0xd1,0x12,0x10, + 0x09,0x01,0xff,0xd0,0xb6,0xcc,0x88,0x00,0x01,0xff,0xd0,0xb6,0xcc,0x88,0x00,0x10, + 0x09,0x01,0xff,0xd0,0xb7,0xcc,0x88,0x00,0x01,0xff,0xd0,0xb7,0xcc,0x88,0x00,0xd4, + 0x82,0xd3,0x41,0xd2,0x1d,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd3,0xa1,0x00,0x01,0x00, + 0x10,0x09,0x01,0xff,0xd0,0xb8,0xcc,0x84,0x00,0x01,0xff,0xd0,0xb8,0xcc,0x84,0x00, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xd0,0xb8,0xcc,0x88,0x00,0x01,0xff,0xd0,0xb8,0xcc, + 0x88,0x00,0x10,0x09,0x01,0xff,0xd0,0xbe,0xcc,0x88,0x00,0x01,0xff,0xd0,0xbe,0xcc, + 0x88,0x00,0xd2,0x1d,0xd1,0x0b,0x10,0x07,0x01,0xff,0xd3,0xa9,0x00,0x01,0x00,0x10, + 0x09,0x01,0xff,0xd3,0xa9,0xcc,0x88,0x00,0x01,0xff,0xd3,0xa9,0xcc,0x88,0x00,0xd1, + 0x12,0x10,0x09,0x04,0xff,0xd1,0x8d,0xcc,0x88,0x00,0x04,0xff,0xd1,0x8d,0xcc,0x88, + 0x00,0x10,0x09,0x01,0xff,0xd1,0x83,0xcc,0x84,0x00,0x01,0xff,0xd1,0x83,0xcc,0x84, + 0x00,0xd3,0x41,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd1,0x83,0xcc,0x88,0x00, + 0x01,0xff,0xd1,0x83,0xcc,0x88,0x00,0x10,0x09,0x01,0xff,0xd1,0x83,0xcc,0x8b,0x00, + 0x01,0xff,0xd1,0x83,0xcc,0x8b,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd1,0x87,0xcc, + 0x88,0x00,0x01,0xff,0xd1,0x87,0xcc,0x88,0x00,0x10,0x07,0x08,0xff,0xd3,0xb7,0x00, + 0x08,0x00,0xd2,0x1d,0xd1,0x12,0x10,0x09,0x01,0xff,0xd1,0x8b,0xcc,0x88,0x00,0x01, + 0xff,0xd1,0x8b,0xcc,0x88,0x00,0x10,0x07,0x09,0xff,0xd3,0xbb,0x00,0x09,0x00,0xd1, + 0x0b,0x10,0x07,0x09,0xff,0xd3,0xbd,0x00,0x09,0x00,0x10,0x07,0x09,0xff,0xd3,0xbf, + 0x00,0x09,0x00,0xe1,0x26,0x02,0xe0,0x78,0x01,0xcf,0x86,0xd5,0xb0,0xd4,0x58,0xd3, + 0x2c,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x06,0xff,0xd4,0x81,0x00,0x06,0x00,0x10,0x07, + 0x06,0xff,0xd4,0x83,0x00,0x06,0x00,0xd1,0x0b,0x10,0x07,0x06,0xff,0xd4,0x85,0x00, + 0x06,0x00,0x10,0x07,0x06,0xff,0xd4,0x87,0x00,0x06,0x00,0xd2,0x16,0xd1,0x0b,0x10, + 0x07,0x06,0xff,0xd4,0x89,0x00,0x06,0x00,0x10,0x07,0x06,0xff,0xd4,0x8b,0x00,0x06, + 0x00,0xd1,0x0b,0x10,0x07,0x06,0xff,0xd4,0x8d,0x00,0x06,0x00,0x10,0x07,0x06,0xff, + 0xd4,0x8f,0x00,0x06,0x00,0xd3,0x2c,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x09,0xff,0xd4, + 0x91,0x00,0x09,0x00,0x10,0x07,0x09,0xff,0xd4,0x93,0x00,0x09,0x00,0xd1,0x0b,0x10, + 0x07,0x0a,0xff,0xd4,0x95,0x00,0x0a,0x00,0x10,0x07,0x0a,0xff,0xd4,0x97,0x00,0x0a, + 0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x0a,0xff,0xd4,0x99,0x00,0x0a,0x00,0x10,0x07, + 0x0a,0xff,0xd4,0x9b,0x00,0x0a,0x00,0xd1,0x0b,0x10,0x07,0x0a,0xff,0xd4,0x9d,0x00, + 0x0a,0x00,0x10,0x07,0x0a,0xff,0xd4,0x9f,0x00,0x0a,0x00,0xd4,0x58,0xd3,0x2c,0xd2, + 0x16,0xd1,0x0b,0x10,0x07,0x0a,0xff,0xd4,0xa1,0x00,0x0a,0x00,0x10,0x07,0x0a,0xff, + 0xd4,0xa3,0x00,0x0a,0x00,0xd1,0x0b,0x10,0x07,0x0b,0xff,0xd4,0xa5,0x00,0x0b,0x00, + 0x10,0x07,0x0c,0xff,0xd4,0xa7,0x00,0x0c,0x00,0xd2,0x16,0xd1,0x0b,0x10,0x07,0x10, + 0xff,0xd4,0xa9,0x00,0x10,0x00,0x10,0x07,0x10,0xff,0xd4,0xab,0x00,0x10,0x00,0xd1, + 0x0b,0x10,0x07,0x10,0xff,0xd4,0xad,0x00,0x10,0x00,0x10,0x07,0x10,0xff,0xd4,0xaf, + 0x00,0x10,0x00,0xd3,0x35,0xd2,0x19,0xd1,0x0b,0x10,0x04,0x00,0x00,0x01,0xff,0xd5, + 0xa1,0x00,0x10,0x07,0x01,0xff,0xd5,0xa2,0x00,0x01,0xff,0xd5,0xa3,0x00,0xd1,0x0e, + 0x10,0x07,0x01,0xff,0xd5,0xa4,0x00,0x01,0xff,0xd5,0xa5,0x00,0x10,0x07,0x01,0xff, + 0xd5,0xa6,0x00,0x01,0xff,0xd5,0xa7,0x00,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff, + 0xd5,0xa8,0x00,0x01,0xff,0xd5,0xa9,0x00,0x10,0x07,0x01,0xff,0xd5,0xaa,0x00,0x01, + 0xff,0xd5,0xab,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd5,0xac,0x00,0x01,0xff,0xd5, + 0xad,0x00,0x10,0x07,0x01,0xff,0xd5,0xae,0x00,0x01,0xff,0xd5,0xaf,0x00,0xcf,0x86, + 0xe5,0x08,0x3f,0xd4,0x70,0xd3,0x38,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd5, + 0xb0,0x00,0x01,0xff,0xd5,0xb1,0x00,0x10,0x07,0x01,0xff,0xd5,0xb2,0x00,0x01,0xff, + 0xd5,0xb3,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd5,0xb4,0x00,0x01,0xff,0xd5,0xb5, + 0x00,0x10,0x07,0x01,0xff,0xd5,0xb6,0x00,0x01,0xff,0xd5,0xb7,0x00,0xd2,0x1c,0xd1, + 0x0e,0x10,0x07,0x01,0xff,0xd5,0xb8,0x00,0x01,0xff,0xd5,0xb9,0x00,0x10,0x07,0x01, + 0xff,0xd5,0xba,0x00,0x01,0xff,0xd5,0xbb,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd5, + 0xbc,0x00,0x01,0xff,0xd5,0xbd,0x00,0x10,0x07,0x01,0xff,0xd5,0xbe,0x00,0x01,0xff, + 0xd5,0xbf,0x00,0xe3,0x87,0x3e,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd6,0x80, + 0x00,0x01,0xff,0xd6,0x81,0x00,0x10,0x07,0x01,0xff,0xd6,0x82,0x00,0x01,0xff,0xd6, + 0x83,0x00,0xd1,0x0e,0x10,0x07,0x01,0xff,0xd6,0x84,0x00,0x01,0xff,0xd6,0x85,0x00, + 0x10,0x07,0x01,0xff,0xd6,0x86,0x00,0x00,0x00,0xe0,0x2f,0x3f,0xcf,0x86,0xe5,0xc0, + 0x3e,0xe4,0x97,0x3e,0xe3,0x76,0x3e,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x01,0xff,0xd5,0xa5,0xd6,0x82,0x00,0xe4,0x3e,0x25,0xe3,0xc3,0x1a, + 0xe2,0x7b,0x81,0xe1,0xc0,0x13,0xd0,0x1e,0xcf,0x86,0xc5,0xe4,0x08,0x4b,0xe3,0x53, + 0x46,0xe2,0xe9,0x43,0xe1,0x1c,0x43,0xe0,0xe1,0x42,0xcf,0x86,0xe5,0xa6,0x42,0x64, + 0x89,0x42,0x0b,0x00,0xcf,0x86,0xe5,0xfa,0x01,0xe4,0x03,0x56,0xe3,0x76,0x01,0xe2, + 0x8e,0x53,0xd1,0x0c,0xe0,0xef,0x52,0xcf,0x86,0x65,0x8d,0x52,0x04,0x00,0xe0,0x0d, + 0x01,0xcf,0x86,0xd5,0x0a,0xe4,0x10,0x53,0x63,0xff,0x52,0x0a,0x00,0xd4,0x80,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x80,0x00,0x01,0xff,0xe2, + 0xb4,0x81,0x00,0x10,0x08,0x01,0xff,0xe2,0xb4,0x82,0x00,0x01,0xff,0xe2,0xb4,0x83, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x84,0x00,0x01,0xff,0xe2,0xb4,0x85, + 0x00,0x10,0x08,0x01,0xff,0xe2,0xb4,0x86,0x00,0x01,0xff,0xe2,0xb4,0x87,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x88,0x00,0x01,0xff,0xe2,0xb4,0x89, + 0x00,0x10,0x08,0x01,0xff,0xe2,0xb4,0x8a,0x00,0x01,0xff,0xe2,0xb4,0x8b,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x8c,0x00,0x01,0xff,0xe2,0xb4,0x8d,0x00,0x10, + 0x08,0x01,0xff,0xe2,0xb4,0x8e,0x00,0x01,0xff,0xe2,0xb4,0x8f,0x00,0xd3,0x40,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x90,0x00,0x01,0xff,0xe2,0xb4,0x91, + 0x00,0x10,0x08,0x01,0xff,0xe2,0xb4,0x92,0x00,0x01,0xff,0xe2,0xb4,0x93,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x94,0x00,0x01,0xff,0xe2,0xb4,0x95,0x00,0x10, + 0x08,0x01,0xff,0xe2,0xb4,0x96,0x00,0x01,0xff,0xe2,0xb4,0x97,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0x98,0x00,0x01,0xff,0xe2,0xb4,0x99,0x00,0x10, + 0x08,0x01,0xff,0xe2,0xb4,0x9a,0x00,0x01,0xff,0xe2,0xb4,0x9b,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe2,0xb4,0x9c,0x00,0x01,0xff,0xe2,0xb4,0x9d,0x00,0x10,0x08,0x01, + 0xff,0xe2,0xb4,0x9e,0x00,0x01,0xff,0xe2,0xb4,0x9f,0x00,0xcf,0x86,0xe5,0x42,0x52, + 0x94,0x50,0xd3,0x3c,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0xa0,0x00, + 0x01,0xff,0xe2,0xb4,0xa1,0x00,0x10,0x08,0x01,0xff,0xe2,0xb4,0xa2,0x00,0x01,0xff, + 0xe2,0xb4,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0xb4,0xa4,0x00,0x01,0xff, + 0xe2,0xb4,0xa5,0x00,0x10,0x04,0x00,0x00,0x0d,0xff,0xe2,0xb4,0xa7,0x00,0x52,0x04, + 0x00,0x00,0x91,0x0c,0x10,0x04,0x00,0x00,0x0d,0xff,0xe2,0xb4,0xad,0x00,0x00,0x00, + 0x01,0x00,0xd2,0x1b,0xe1,0xfc,0x52,0xe0,0xad,0x52,0xcf,0x86,0x95,0x0f,0x94,0x0b, + 0x93,0x07,0x62,0x92,0x52,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xd1,0x13,0xe0, + 0xd3,0x53,0xcf,0x86,0x95,0x0a,0xe4,0xa8,0x53,0x63,0x97,0x53,0x04,0x00,0x04,0x00, + 0xd0,0x0d,0xcf,0x86,0x95,0x07,0x64,0x22,0x54,0x08,0x00,0x04,0x00,0xcf,0x86,0x55, + 0x04,0x04,0x00,0x54,0x04,0x04,0x00,0xd3,0x07,0x62,0x2f,0x54,0x04,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8f,0xb0,0x00,0x11,0xff,0xe1,0x8f,0xb1,0x00, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0xb2,0x00,0x11,0xff,0xe1,0x8f,0xb3,0x00,0x91,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0xb4,0x00,0x11,0xff,0xe1,0x8f,0xb5,0x00,0x00,0x00, + 0xd4,0x1c,0xe3,0xe0,0x56,0xe2,0x17,0x56,0xe1,0xda,0x55,0xe0,0xbb,0x55,0xcf,0x86, + 0x95,0x0a,0xe4,0xa4,0x55,0x63,0x88,0x55,0x04,0x00,0x04,0x00,0xe3,0xd2,0x01,0xe2, + 0x2b,0x5a,0xd1,0x0c,0xe0,0x4c,0x59,0xcf,0x86,0x65,0x25,0x59,0x0a,0x00,0xe0,0x9c, + 0x59,0xcf,0x86,0xd5,0xc5,0xd4,0x45,0xd3,0x31,0xd2,0x1c,0xd1,0x0e,0x10,0x07,0x12, + 0xff,0xd0,0xb2,0x00,0x12,0xff,0xd0,0xb4,0x00,0x10,0x07,0x12,0xff,0xd0,0xbe,0x00, + 0x12,0xff,0xd1,0x81,0x00,0x51,0x07,0x12,0xff,0xd1,0x82,0x00,0x10,0x07,0x12,0xff, + 0xd1,0x8a,0x00,0x12,0xff,0xd1,0xa3,0x00,0x92,0x10,0x91,0x0c,0x10,0x08,0x12,0xff, + 0xea,0x99,0x8b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x14,0xff,0xe1,0x83,0x90,0x00,0x14,0xff,0xe1,0x83,0x91,0x00,0x10,0x08, + 0x14,0xff,0xe1,0x83,0x92,0x00,0x14,0xff,0xe1,0x83,0x93,0x00,0xd1,0x10,0x10,0x08, + 0x14,0xff,0xe1,0x83,0x94,0x00,0x14,0xff,0xe1,0x83,0x95,0x00,0x10,0x08,0x14,0xff, + 0xe1,0x83,0x96,0x00,0x14,0xff,0xe1,0x83,0x97,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x14,0xff,0xe1,0x83,0x98,0x00,0x14,0xff,0xe1,0x83,0x99,0x00,0x10,0x08,0x14,0xff, + 0xe1,0x83,0x9a,0x00,0x14,0xff,0xe1,0x83,0x9b,0x00,0xd1,0x10,0x10,0x08,0x14,0xff, + 0xe1,0x83,0x9c,0x00,0x14,0xff,0xe1,0x83,0x9d,0x00,0x10,0x08,0x14,0xff,0xe1,0x83, + 0x9e,0x00,0x14,0xff,0xe1,0x83,0x9f,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x14,0xff,0xe1,0x83,0xa0,0x00,0x14,0xff,0xe1,0x83,0xa1,0x00,0x10,0x08, + 0x14,0xff,0xe1,0x83,0xa2,0x00,0x14,0xff,0xe1,0x83,0xa3,0x00,0xd1,0x10,0x10,0x08, + 0x14,0xff,0xe1,0x83,0xa4,0x00,0x14,0xff,0xe1,0x83,0xa5,0x00,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xa6,0x00,0x14,0xff,0xe1,0x83,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x14,0xff,0xe1,0x83,0xa8,0x00,0x14,0xff,0xe1,0x83,0xa9,0x00,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xaa,0x00,0x14,0xff,0xe1,0x83,0xab,0x00,0xd1,0x10,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xac,0x00,0x14,0xff,0xe1,0x83,0xad,0x00,0x10,0x08,0x14,0xff,0xe1,0x83, + 0xae,0x00,0x14,0xff,0xe1,0x83,0xaf,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x14,0xff,0xe1,0x83,0xb0,0x00,0x14,0xff,0xe1,0x83,0xb1,0x00,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xb2,0x00,0x14,0xff,0xe1,0x83,0xb3,0x00,0xd1,0x10,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xb4,0x00,0x14,0xff,0xe1,0x83,0xb5,0x00,0x10,0x08,0x14,0xff,0xe1,0x83, + 0xb6,0x00,0x14,0xff,0xe1,0x83,0xb7,0x00,0xd2,0x1c,0xd1,0x10,0x10,0x08,0x14,0xff, + 0xe1,0x83,0xb8,0x00,0x14,0xff,0xe1,0x83,0xb9,0x00,0x10,0x08,0x14,0xff,0xe1,0x83, + 0xba,0x00,0x00,0x00,0xd1,0x0c,0x10,0x04,0x00,0x00,0x14,0xff,0xe1,0x83,0xbd,0x00, + 0x10,0x08,0x14,0xff,0xe1,0x83,0xbe,0x00,0x14,0xff,0xe1,0x83,0xbf,0x00,0xe2,0x9d, + 0x08,0xe1,0x48,0x04,0xe0,0x1c,0x02,0xcf,0x86,0xe5,0x11,0x01,0xd4,0x84,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x61,0xcc,0xa5,0x00,0x01,0xff,0x61,0xcc, + 0xa5,0x00,0x10,0x08,0x01,0xff,0x62,0xcc,0x87,0x00,0x01,0xff,0x62,0xcc,0x87,0x00, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x62,0xcc,0xa3,0x00,0x01,0xff,0x62,0xcc,0xa3,0x00, + 0x10,0x08,0x01,0xff,0x62,0xcc,0xb1,0x00,0x01,0xff,0x62,0xcc,0xb1,0x00,0xd2,0x24, + 0xd1,0x14,0x10,0x0a,0x01,0xff,0x63,0xcc,0xa7,0xcc,0x81,0x00,0x01,0xff,0x63,0xcc, + 0xa7,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x64,0xcc,0x87,0x00,0x01,0xff,0x64,0xcc, + 0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x64,0xcc,0xa3,0x00,0x01,0xff,0x64,0xcc, + 0xa3,0x00,0x10,0x08,0x01,0xff,0x64,0xcc,0xb1,0x00,0x01,0xff,0x64,0xcc,0xb1,0x00, + 0xd3,0x48,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x64,0xcc,0xa7,0x00,0x01,0xff, + 0x64,0xcc,0xa7,0x00,0x10,0x08,0x01,0xff,0x64,0xcc,0xad,0x00,0x01,0xff,0x64,0xcc, + 0xad,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x65,0xcc,0x84,0xcc,0x80,0x00,0x01,0xff, + 0x65,0xcc,0x84,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x65,0xcc,0x84,0xcc,0x81,0x00, + 0x01,0xff,0x65,0xcc,0x84,0xcc,0x81,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x65,0xcc,0xad,0x00,0x01,0xff,0x65,0xcc,0xad,0x00,0x10,0x08,0x01,0xff,0x65,0xcc, + 0xb0,0x00,0x01,0xff,0x65,0xcc,0xb0,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x65,0xcc, + 0xa7,0xcc,0x86,0x00,0x01,0xff,0x65,0xcc,0xa7,0xcc,0x86,0x00,0x10,0x08,0x01,0xff, + 0x66,0xcc,0x87,0x00,0x01,0xff,0x66,0xcc,0x87,0x00,0xd4,0x84,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x67,0xcc,0x84,0x00,0x01,0xff,0x67,0xcc,0x84,0x00, + 0x10,0x08,0x01,0xff,0x68,0xcc,0x87,0x00,0x01,0xff,0x68,0xcc,0x87,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0x68,0xcc,0xa3,0x00,0x01,0xff,0x68,0xcc,0xa3,0x00,0x10,0x08, + 0x01,0xff,0x68,0xcc,0x88,0x00,0x01,0xff,0x68,0xcc,0x88,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0x68,0xcc,0xa7,0x00,0x01,0xff,0x68,0xcc,0xa7,0x00,0x10,0x08, + 0x01,0xff,0x68,0xcc,0xae,0x00,0x01,0xff,0x68,0xcc,0xae,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0x69,0xcc,0xb0,0x00,0x01,0xff,0x69,0xcc,0xb0,0x00,0x10,0x0a,0x01,0xff, + 0x69,0xcc,0x88,0xcc,0x81,0x00,0x01,0xff,0x69,0xcc,0x88,0xcc,0x81,0x00,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x6b,0xcc,0x81,0x00,0x01,0xff,0x6b,0xcc, + 0x81,0x00,0x10,0x08,0x01,0xff,0x6b,0xcc,0xa3,0x00,0x01,0xff,0x6b,0xcc,0xa3,0x00, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x6b,0xcc,0xb1,0x00,0x01,0xff,0x6b,0xcc,0xb1,0x00, + 0x10,0x08,0x01,0xff,0x6c,0xcc,0xa3,0x00,0x01,0xff,0x6c,0xcc,0xa3,0x00,0xd2,0x24, + 0xd1,0x14,0x10,0x0a,0x01,0xff,0x6c,0xcc,0xa3,0xcc,0x84,0x00,0x01,0xff,0x6c,0xcc, + 0xa3,0xcc,0x84,0x00,0x10,0x08,0x01,0xff,0x6c,0xcc,0xb1,0x00,0x01,0xff,0x6c,0xcc, + 0xb1,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6c,0xcc,0xad,0x00,0x01,0xff,0x6c,0xcc, + 0xad,0x00,0x10,0x08,0x01,0xff,0x6d,0xcc,0x81,0x00,0x01,0xff,0x6d,0xcc,0x81,0x00, + 0xcf,0x86,0xe5,0x15,0x01,0xd4,0x88,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x6d,0xcc,0x87,0x00,0x01,0xff,0x6d,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x6d, + 0xcc,0xa3,0x00,0x01,0xff,0x6d,0xcc,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6e, + 0xcc,0x87,0x00,0x01,0xff,0x6e,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x6e,0xcc,0xa3, + 0x00,0x01,0xff,0x6e,0xcc,0xa3,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x6e, + 0xcc,0xb1,0x00,0x01,0xff,0x6e,0xcc,0xb1,0x00,0x10,0x08,0x01,0xff,0x6e,0xcc,0xad, + 0x00,0x01,0xff,0x6e,0xcc,0xad,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x83, + 0xcc,0x81,0x00,0x01,0xff,0x6f,0xcc,0x83,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x6f, + 0xcc,0x83,0xcc,0x88,0x00,0x01,0xff,0x6f,0xcc,0x83,0xcc,0x88,0x00,0xd3,0x48,0xd2, + 0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x84,0xcc,0x80,0x00,0x01,0xff,0x6f, + 0xcc,0x84,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x84,0xcc,0x81,0x00,0x01, + 0xff,0x6f,0xcc,0x84,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x70,0xcc,0x81, + 0x00,0x01,0xff,0x70,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x70,0xcc,0x87,0x00,0x01, + 0xff,0x70,0xcc,0x87,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x72,0xcc,0x87, + 0x00,0x01,0xff,0x72,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x72,0xcc,0xa3,0x00,0x01, + 0xff,0x72,0xcc,0xa3,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x72,0xcc,0xa3,0xcc,0x84, + 0x00,0x01,0xff,0x72,0xcc,0xa3,0xcc,0x84,0x00,0x10,0x08,0x01,0xff,0x72,0xcc,0xb1, + 0x00,0x01,0xff,0x72,0xcc,0xb1,0x00,0xd4,0x8c,0xd3,0x48,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x73,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x87,0x00,0x10,0x08,0x01, + 0xff,0x73,0xcc,0xa3,0x00,0x01,0xff,0x73,0xcc,0xa3,0x00,0xd1,0x14,0x10,0x0a,0x01, + 0xff,0x73,0xcc,0x81,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x81,0xcc,0x87,0x00,0x10, + 0x0a,0x01,0xff,0x73,0xcc,0x8c,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x8c,0xcc,0x87, + 0x00,0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff,0x73,0xcc,0xa3,0xcc,0x87,0x00,0x01, + 0xff,0x73,0xcc,0xa3,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x74,0xcc,0x87,0x00,0x01, + 0xff,0x74,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x74,0xcc,0xa3,0x00,0x01, + 0xff,0x74,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x74,0xcc,0xb1,0x00,0x01,0xff,0x74, + 0xcc,0xb1,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x74,0xcc,0xad, + 0x00,0x01,0xff,0x74,0xcc,0xad,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0xa4,0x00,0x01, + 0xff,0x75,0xcc,0xa4,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc,0xb0,0x00,0x01, + 0xff,0x75,0xcc,0xb0,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0xad,0x00,0x01,0xff,0x75, + 0xcc,0xad,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x75,0xcc,0x83,0xcc,0x81, + 0x00,0x01,0xff,0x75,0xcc,0x83,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x84, + 0xcc,0x88,0x00,0x01,0xff,0x75,0xcc,0x84,0xcc,0x88,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x76,0xcc,0x83,0x00,0x01,0xff,0x76,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x76, + 0xcc,0xa3,0x00,0x01,0xff,0x76,0xcc,0xa3,0x00,0xe0,0x11,0x02,0xcf,0x86,0xd5,0xe2, + 0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0x80,0x00, + 0x01,0xff,0x77,0xcc,0x80,0x00,0x10,0x08,0x01,0xff,0x77,0xcc,0x81,0x00,0x01,0xff, + 0x77,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0x88,0x00,0x01,0xff, + 0x77,0xcc,0x88,0x00,0x10,0x08,0x01,0xff,0x77,0xcc,0x87,0x00,0x01,0xff,0x77,0xcc, + 0x87,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0xa3,0x00,0x01,0xff, + 0x77,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x78,0xcc,0x87,0x00,0x01,0xff,0x78,0xcc, + 0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x78,0xcc,0x88,0x00,0x01,0xff,0x78,0xcc, + 0x88,0x00,0x10,0x08,0x01,0xff,0x79,0xcc,0x87,0x00,0x01,0xff,0x79,0xcc,0x87,0x00, + 0xd3,0x33,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x7a,0xcc,0x82,0x00,0x01,0xff, + 0x7a,0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x7a,0xcc,0xa3,0x00,0x01,0xff,0x7a,0xcc, + 0xa3,0x00,0xe1,0x12,0x59,0x10,0x08,0x01,0xff,0x7a,0xcc,0xb1,0x00,0x01,0xff,0x7a, + 0xcc,0xb1,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0x8a,0x00,0x01, + 0xff,0x79,0xcc,0x8a,0x00,0x10,0x08,0x01,0xff,0x61,0xca,0xbe,0x00,0x02,0xff,0x73, + 0xcc,0x87,0x00,0x51,0x04,0x0a,0x00,0x10,0x07,0x0a,0xff,0x73,0x73,0x00,0x0a,0x00, + 0xd4,0x98,0xd3,0x48,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x61,0xcc,0xa3,0x00, + 0x01,0xff,0x61,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x61,0xcc,0x89,0x00,0x01,0xff, + 0x61,0xcc,0x89,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x61,0xcc,0x82,0xcc,0x81,0x00, + 0x01,0xff,0x61,0xcc,0x82,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x61,0xcc,0x82,0xcc, + 0x80,0x00,0x01,0xff,0x61,0xcc,0x82,0xcc,0x80,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a, + 0x01,0xff,0x61,0xcc,0x82,0xcc,0x89,0x00,0x01,0xff,0x61,0xcc,0x82,0xcc,0x89,0x00, + 0x10,0x0a,0x01,0xff,0x61,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x61,0xcc,0x82,0xcc, + 0x83,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x61,0xcc,0xa3,0xcc,0x82,0x00,0x01,0xff, + 0x61,0xcc,0xa3,0xcc,0x82,0x00,0x10,0x0a,0x01,0xff,0x61,0xcc,0x86,0xcc,0x81,0x00, + 0x01,0xff,0x61,0xcc,0x86,0xcc,0x81,0x00,0xd3,0x50,0xd2,0x28,0xd1,0x14,0x10,0x0a, + 0x01,0xff,0x61,0xcc,0x86,0xcc,0x80,0x00,0x01,0xff,0x61,0xcc,0x86,0xcc,0x80,0x00, + 0x10,0x0a,0x01,0xff,0x61,0xcc,0x86,0xcc,0x89,0x00,0x01,0xff,0x61,0xcc,0x86,0xcc, + 0x89,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x61,0xcc,0x86,0xcc,0x83,0x00,0x01,0xff, + 0x61,0xcc,0x86,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x61,0xcc,0xa3,0xcc,0x86,0x00, + 0x01,0xff,0x61,0xcc,0xa3,0xcc,0x86,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x65,0xcc,0xa3,0x00,0x01,0xff,0x65,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x65,0xcc, + 0x89,0x00,0x01,0xff,0x65,0xcc,0x89,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x65,0xcc, + 0x83,0x00,0x01,0xff,0x65,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x65,0xcc,0x82,0xcc, + 0x81,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x81,0x00,0xcf,0x86,0xe5,0x31,0x01,0xd4, + 0x90,0xd3,0x50,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x65,0xcc,0x82,0xcc,0x80, + 0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x65,0xcc,0x82, + 0xcc,0x89,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x89,0x00,0xd1,0x14,0x10,0x0a,0x01, + 0xff,0x65,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x83,0x00,0x10, + 0x0a,0x01,0xff,0x65,0xcc,0xa3,0xcc,0x82,0x00,0x01,0xff,0x65,0xcc,0xa3,0xcc,0x82, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc,0x89,0x00,0x01,0xff,0x69, + 0xcc,0x89,0x00,0x10,0x08,0x01,0xff,0x69,0xcc,0xa3,0x00,0x01,0xff,0x69,0xcc,0xa3, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0xa3,0x00,0x01,0xff,0x6f,0xcc,0xa3, + 0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x89,0x00,0xd3, + 0x50,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x81,0x00,0x01, + 0xff,0x6f,0xcc,0x82,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x80, + 0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x80,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f, + 0xcc,0x82,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x89,0x00,0x10,0x0a,0x01, + 0xff,0x6f,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x83,0x00,0xd2, + 0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0xa3,0xcc,0x82,0x00,0x01,0xff,0x6f, + 0xcc,0xa3,0xcc,0x82,0x00,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x81,0x00,0x01, + 0xff,0x6f,0xcc,0x9b,0xcc,0x81,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x9b, + 0xcc,0x80,0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x6f, + 0xcc,0x9b,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x89,0x00,0xd4,0x98,0xd3, + 0x48,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x83,0x00,0x01, + 0xff,0x6f,0xcc,0x9b,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0xa3, + 0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x75, + 0xcc,0xa3,0x00,0x01,0xff,0x75,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0x89, + 0x00,0x01,0xff,0x75,0xcc,0x89,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x75, + 0xcc,0x9b,0xcc,0x81,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x81,0x00,0x10,0x0a,0x01, + 0xff,0x75,0xcc,0x9b,0xcc,0x80,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x80,0x00,0xd1, + 0x14,0x10,0x0a,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x89,0x00,0x01,0xff,0x75,0xcc,0x9b, + 0xcc,0x89,0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x83,0x00,0x01,0xff,0x75, + 0xcc,0x9b,0xcc,0x83,0x00,0xd3,0x44,0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff,0x75, + 0xcc,0x9b,0xcc,0xa3,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0xa3,0x00,0x10,0x08,0x01, + 0xff,0x79,0xcc,0x80,0x00,0x01,0xff,0x79,0xcc,0x80,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x79,0xcc,0xa3,0x00,0x01,0xff,0x79,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x79, + 0xcc,0x89,0x00,0x01,0xff,0x79,0xcc,0x89,0x00,0xd2,0x1c,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x79,0xcc,0x83,0x00,0x01,0xff,0x79,0xcc,0x83,0x00,0x10,0x08,0x0a,0xff,0xe1, + 0xbb,0xbb,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xe1,0xbb,0xbd,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xe1,0xbb,0xbf,0x00,0x0a,0x00,0xe1,0xbf,0x02,0xe0,0xa1, + 0x01,0xcf,0x86,0xd5,0xc6,0xd4,0x6c,0xd3,0x18,0xe2,0x0e,0x59,0xe1,0xf7,0x58,0x10, + 0x09,0x01,0xff,0xce,0xb1,0xcc,0x93,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0x00,0xd2, + 0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x93,0x00,0x01,0xff,0xce,0xb1, + 0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff, + 0xce,0xb1,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc, + 0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01, + 0xff,0xce,0xb1,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcd,0x82, + 0x00,0xd3,0x18,0xe2,0x4a,0x59,0xe1,0x33,0x59,0x10,0x09,0x01,0xff,0xce,0xb5,0xcc, + 0x93,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94,0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01, + 0xff,0xce,0xb5,0xcc,0x93,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94,0x00,0x10,0x0b,0x01, + 0xff,0xce,0xb5,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94,0xcc,0x80, + 0x00,0x91,0x16,0x10,0x0b,0x01,0xff,0xce,0xb5,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff, + 0xce,0xb5,0xcc,0x94,0xcc,0x81,0x00,0x00,0x00,0xd4,0x6c,0xd3,0x18,0xe2,0x74,0x59, + 0xe1,0x5d,0x59,0x10,0x09,0x01,0xff,0xce,0xb7,0xcc,0x93,0x00,0x01,0xff,0xce,0xb7, + 0xcc,0x94,0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb7,0xcc,0x93,0x00, + 0x01,0xff,0xce,0xb7,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc, + 0x80,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01, + 0xff,0xce,0xb7,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x81, + 0x00,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xb7, + 0xcc,0x94,0xcd,0x82,0x00,0xd3,0x18,0xe2,0xb0,0x59,0xe1,0x99,0x59,0x10,0x09,0x01, + 0xff,0xce,0xb9,0xcc,0x93,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94,0x00,0xd2,0x28,0xd1, + 0x12,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x93,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94, + 0x00,0x10,0x0b,0x01,0xff,0xce,0xb9,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xb9, + 0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb9,0xcc,0x93,0xcc, + 0x81,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff,0xce, + 0xb9,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94,0xcd,0x82,0x00,0xcf, + 0x86,0xd5,0xac,0xd4,0x5a,0xd3,0x18,0xe2,0xed,0x59,0xe1,0xd6,0x59,0x10,0x09,0x01, + 0xff,0xce,0xbf,0xcc,0x93,0x00,0x01,0xff,0xce,0xbf,0xcc,0x94,0x00,0xd2,0x28,0xd1, + 0x12,0x10,0x09,0x01,0xff,0xce,0xbf,0xcc,0x93,0x00,0x01,0xff,0xce,0xbf,0xcc,0x94, + 0x00,0x10,0x0b,0x01,0xff,0xce,0xbf,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xbf, + 0xcc,0x94,0xcc,0x80,0x00,0x91,0x16,0x10,0x0b,0x01,0xff,0xce,0xbf,0xcc,0x93,0xcc, + 0x81,0x00,0x01,0xff,0xce,0xbf,0xcc,0x94,0xcc,0x81,0x00,0x00,0x00,0xd3,0x18,0xe2, + 0x17,0x5a,0xe1,0x00,0x5a,0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x93,0x00,0x01,0xff, + 0xcf,0x85,0xcc,0x94,0x00,0xd2,0x1c,0xd1,0x0d,0x10,0x04,0x00,0x00,0x01,0xff,0xcf, + 0x85,0xcc,0x94,0x00,0x10,0x04,0x00,0x00,0x01,0xff,0xcf,0x85,0xcc,0x94,0xcc,0x80, + 0x00,0xd1,0x0f,0x10,0x04,0x00,0x00,0x01,0xff,0xcf,0x85,0xcc,0x94,0xcc,0x81,0x00, + 0x10,0x04,0x00,0x00,0x01,0xff,0xcf,0x85,0xcc,0x94,0xcd,0x82,0x00,0xe4,0xd3,0x5a, + 0xd3,0x18,0xe2,0x52,0x5a,0xe1,0x3b,0x5a,0x10,0x09,0x01,0xff,0xcf,0x89,0xcc,0x93, + 0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff, + 0xcf,0x89,0xcc,0x93,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff, + 0xcf,0x89,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc,0x80,0x00, + 0xd1,0x16,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xcf, + 0x89,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcd,0x82, + 0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcd,0x82,0x00,0xe0,0xd9,0x02,0xcf,0x86,0xe5, + 0x91,0x01,0xd4,0xc8,0xd3,0x64,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb1, + 0xcc,0x93,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xce,0xb9,0x00,0x10,0x0d, + 0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xcc, + 0x94,0xcc,0x80,0xce,0xb9,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93, + 0xcc,0x81,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcc,0x81,0xce,0xb9,0x00, + 0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcd,0x82,0xce,0xb9,0x00,0x01,0xff,0xce, + 0xb1,0xcc,0x94,0xcd,0x82,0xce,0xb9,0x00,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff, + 0xce,0xb1,0xcc,0x93,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xce,0xb9,0x00, + 0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xce, + 0xb1,0xcc,0x94,0xcc,0x80,0xce,0xb9,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xce,0xb1, + 0xcc,0x93,0xcc,0x81,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcc,0x81,0xce, + 0xb9,0x00,0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcd,0x82,0xce,0xb9,0x00,0x01, + 0xff,0xce,0xb1,0xcc,0x94,0xcd,0x82,0xce,0xb9,0x00,0xd3,0x64,0xd2,0x30,0xd1,0x16, + 0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xcc, + 0x94,0xce,0xb9,0x00,0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x80,0xce,0xb9, + 0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x80,0xce,0xb9,0x00,0xd1,0x1a,0x10,0x0d, + 0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x81,0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xcc, + 0x94,0xcc,0x81,0xce,0xb9,0x00,0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcd,0x82, + 0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcd,0x82,0xce,0xb9,0x00,0xd2,0x30, + 0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xce,0xb9,0x00,0x01,0xff,0xce, + 0xb7,0xcc,0x94,0xce,0xb9,0x00,0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x80, + 0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x80,0xce,0xb9,0x00,0xd1,0x1a, + 0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x81,0xce,0xb9,0x00,0x01,0xff,0xce, + 0xb7,0xcc,0x94,0xcc,0x81,0xce,0xb9,0x00,0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93, + 0xcd,0x82,0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcd,0x82,0xce,0xb9,0x00, + 0xd4,0xc8,0xd3,0x64,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x93, + 0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xce,0xb9,0x00,0x10,0x0d,0x01,0xff, + 0xcf,0x89,0xcc,0x93,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc, + 0x80,0xce,0xb9,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x81, + 0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc,0x81,0xce,0xb9,0x00,0x10,0x0d, + 0x01,0xff,0xcf,0x89,0xcc,0x93,0xcd,0x82,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc, + 0x94,0xcd,0x82,0xce,0xb9,0x00,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff,0xcf,0x89, + 0xcc,0x93,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xce,0xb9,0x00,0x10,0x0d, + 0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc, + 0x94,0xcc,0x80,0xce,0xb9,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xcf,0x89,0xcc,0x93, + 0xcc,0x81,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc,0x81,0xce,0xb9,0x00, + 0x10,0x0d,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcd,0x82,0xce,0xb9,0x00,0x01,0xff,0xcf, + 0x89,0xcc,0x94,0xcd,0x82,0xce,0xb9,0x00,0xd3,0x49,0xd2,0x26,0xd1,0x12,0x10,0x09, + 0x01,0xff,0xce,0xb1,0xcc,0x86,0x00,0x01,0xff,0xce,0xb1,0xcc,0x84,0x00,0x10,0x0b, + 0x01,0xff,0xce,0xb1,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xce,0xb1,0xce,0xb9,0x00, + 0xd1,0x0f,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x81,0xce,0xb9,0x00,0x00,0x00,0x10, + 0x09,0x01,0xff,0xce,0xb1,0xcd,0x82,0x00,0x01,0xff,0xce,0xb1,0xcd,0x82,0xce,0xb9, + 0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x86,0x00,0x01,0xff, + 0xce,0xb1,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x80,0x00,0x01,0xff, + 0xce,0xb1,0xcc,0x81,0x00,0xe1,0xf3,0x5a,0x10,0x09,0x01,0xff,0xce,0xb1,0xce,0xb9, + 0x00,0x01,0x00,0xcf,0x86,0xd5,0xbd,0xd4,0x7e,0xd3,0x44,0xd2,0x21,0xd1,0x0d,0x10, + 0x04,0x01,0x00,0x01,0xff,0xc2,0xa8,0xcd,0x82,0x00,0x10,0x0b,0x01,0xff,0xce,0xb7, + 0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xce,0xb7,0xce,0xb9,0x00,0xd1,0x0f,0x10,0x0b, + 0x01,0xff,0xce,0xb7,0xcc,0x81,0xce,0xb9,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xce, + 0xb7,0xcd,0x82,0x00,0x01,0xff,0xce,0xb7,0xcd,0x82,0xce,0xb9,0x00,0xd2,0x24,0xd1, + 0x12,0x10,0x09,0x01,0xff,0xce,0xb5,0xcc,0x80,0x00,0x01,0xff,0xce,0xb5,0xcc,0x81, + 0x00,0x10,0x09,0x01,0xff,0xce,0xb7,0xcc,0x80,0x00,0x01,0xff,0xce,0xb7,0xcc,0x81, + 0x00,0xe1,0x02,0x5b,0x10,0x09,0x01,0xff,0xce,0xb7,0xce,0xb9,0x00,0x01,0xff,0xe1, + 0xbe,0xbf,0xcc,0x80,0x00,0xd3,0x18,0xe2,0x28,0x5b,0xe1,0x11,0x5b,0x10,0x09,0x01, + 0xff,0xce,0xb9,0xcc,0x86,0x00,0x01,0xff,0xce,0xb9,0xcc,0x84,0x00,0xe2,0x4c,0x5b, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x86,0x00,0x01,0xff,0xce,0xb9,0xcc, + 0x84,0x00,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x80,0x00,0x01,0xff,0xce,0xb9,0xcc, + 0x81,0x00,0xd4,0x51,0xd3,0x18,0xe2,0x6f,0x5b,0xe1,0x58,0x5b,0x10,0x09,0x01,0xff, + 0xcf,0x85,0xcc,0x86,0x00,0x01,0xff,0xcf,0x85,0xcc,0x84,0x00,0xd2,0x24,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x86,0x00,0x01,0xff,0xcf,0x85,0xcc,0x84,0x00, + 0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x80,0x00,0x01,0xff,0xcf,0x85,0xcc,0x81,0x00, + 0xe1,0x8f,0x5b,0x10,0x09,0x01,0xff,0xcf,0x81,0xcc,0x94,0x00,0x01,0xff,0xc2,0xa8, + 0xcc,0x80,0x00,0xd3,0x3b,0xd2,0x18,0x51,0x04,0x00,0x00,0x10,0x0b,0x01,0xff,0xcf, + 0x89,0xcc,0x80,0xce,0xb9,0x00,0x01,0xff,0xcf,0x89,0xce,0xb9,0x00,0xd1,0x0f,0x10, + 0x0b,0x01,0xff,0xcf,0x89,0xcc,0x81,0xce,0xb9,0x00,0x00,0x00,0x10,0x09,0x01,0xff, + 0xcf,0x89,0xcd,0x82,0x00,0x01,0xff,0xcf,0x89,0xcd,0x82,0xce,0xb9,0x00,0xd2,0x24, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xbf,0xcc,0x80,0x00,0x01,0xff,0xce,0xbf,0xcc, + 0x81,0x00,0x10,0x09,0x01,0xff,0xcf,0x89,0xcc,0x80,0x00,0x01,0xff,0xcf,0x89,0xcc, + 0x81,0x00,0xe1,0x99,0x5b,0x10,0x09,0x01,0xff,0xcf,0x89,0xce,0xb9,0x00,0x01,0xff, + 0xc2,0xb4,0x00,0xe0,0x0c,0x68,0xcf,0x86,0xe5,0x23,0x02,0xe4,0x25,0x01,0xe3,0x85, + 0x5e,0xd2,0x2a,0xe1,0x5f,0x5c,0xe0,0xdd,0x5b,0xcf,0x86,0xe5,0xbb,0x5b,0x94,0x1b, + 0xe3,0xa4,0x5b,0x92,0x14,0x91,0x10,0x10,0x08,0x01,0xff,0xe2,0x80,0x82,0x00,0x01, + 0xff,0xe2,0x80,0x83,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd1,0xd6,0xd0,0x46,0xcf, + 0x86,0x55,0x04,0x01,0x00,0xd4,0x29,0xd3,0x13,0x52,0x04,0x01,0x00,0x51,0x04,0x01, + 0x00,0x10,0x07,0x01,0xff,0xcf,0x89,0x00,0x01,0x00,0x92,0x12,0x51,0x04,0x01,0x00, + 0x10,0x06,0x01,0xff,0x6b,0x00,0x01,0xff,0x61,0xcc,0x8a,0x00,0x01,0x00,0xe3,0x25, + 0x5d,0x92,0x10,0x51,0x04,0x01,0x00,0x10,0x08,0x01,0xff,0xe2,0x85,0x8e,0x00,0x01, + 0x00,0x01,0x00,0xcf,0x86,0xd5,0x0a,0xe4,0x42,0x5d,0x63,0x2d,0x5d,0x06,0x00,0x94, + 0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x85,0xb0,0x00,0x01, + 0xff,0xe2,0x85,0xb1,0x00,0x10,0x08,0x01,0xff,0xe2,0x85,0xb2,0x00,0x01,0xff,0xe2, + 0x85,0xb3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x85,0xb4,0x00,0x01,0xff,0xe2, + 0x85,0xb5,0x00,0x10,0x08,0x01,0xff,0xe2,0x85,0xb6,0x00,0x01,0xff,0xe2,0x85,0xb7, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x85,0xb8,0x00,0x01,0xff,0xe2, + 0x85,0xb9,0x00,0x10,0x08,0x01,0xff,0xe2,0x85,0xba,0x00,0x01,0xff,0xe2,0x85,0xbb, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x85,0xbc,0x00,0x01,0xff,0xe2,0x85,0xbd, + 0x00,0x10,0x08,0x01,0xff,0xe2,0x85,0xbe,0x00,0x01,0xff,0xe2,0x85,0xbf,0x00,0x01, + 0x00,0xe0,0x34,0x5d,0xcf,0x86,0xe5,0x13,0x5d,0xe4,0xf2,0x5c,0xe3,0xe1,0x5c,0xe2, + 0xd4,0x5c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x04,0xff,0xe2,0x86,0x84,0x00, + 0xe3,0x23,0x61,0xe2,0xf0,0x60,0xd1,0x0c,0xe0,0x9d,0x60,0xcf,0x86,0x65,0x7e,0x60, + 0x01,0x00,0xd0,0x62,0xcf,0x86,0x55,0x04,0x01,0x00,0x54,0x04,0x01,0x00,0xd3,0x18, + 0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x08,0x01,0xff,0xe2,0x93,0x90,0x00, + 0x01,0xff,0xe2,0x93,0x91,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x93, + 0x92,0x00,0x01,0xff,0xe2,0x93,0x93,0x00,0x10,0x08,0x01,0xff,0xe2,0x93,0x94,0x00, + 0x01,0xff,0xe2,0x93,0x95,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe2,0x93,0x96,0x00, + 0x01,0xff,0xe2,0x93,0x97,0x00,0x10,0x08,0x01,0xff,0xe2,0x93,0x98,0x00,0x01,0xff, + 0xe2,0x93,0x99,0x00,0xcf,0x86,0xe5,0x57,0x60,0x94,0x80,0xd3,0x40,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe2,0x93,0x9a,0x00,0x01,0xff,0xe2,0x93,0x9b,0x00,0x10, + 0x08,0x01,0xff,0xe2,0x93,0x9c,0x00,0x01,0xff,0xe2,0x93,0x9d,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe2,0x93,0x9e,0x00,0x01,0xff,0xe2,0x93,0x9f,0x00,0x10,0x08,0x01, + 0xff,0xe2,0x93,0xa0,0x00,0x01,0xff,0xe2,0x93,0xa1,0x00,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe2,0x93,0xa2,0x00,0x01,0xff,0xe2,0x93,0xa3,0x00,0x10,0x08,0x01, + 0xff,0xe2,0x93,0xa4,0x00,0x01,0xff,0xe2,0x93,0xa5,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe2,0x93,0xa6,0x00,0x01,0xff,0xe2,0x93,0xa7,0x00,0x10,0x08,0x01,0xff,0xe2, + 0x93,0xa8,0x00,0x01,0xff,0xe2,0x93,0xa9,0x00,0x01,0x00,0xd4,0x0c,0xe3,0x33,0x62, + 0xe2,0x2c,0x62,0xcf,0x06,0x04,0x00,0xe3,0x0c,0x65,0xe2,0xff,0x63,0xe1,0x2e,0x02, + 0xe0,0x84,0x01,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x08,0xff,0xe2,0xb0,0xb0,0x00,0x08,0xff,0xe2,0xb0,0xb1,0x00,0x10,0x08, + 0x08,0xff,0xe2,0xb0,0xb2,0x00,0x08,0xff,0xe2,0xb0,0xb3,0x00,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe2,0xb0,0xb4,0x00,0x08,0xff,0xe2,0xb0,0xb5,0x00,0x10,0x08,0x08,0xff, + 0xe2,0xb0,0xb6,0x00,0x08,0xff,0xe2,0xb0,0xb7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe2,0xb0,0xb8,0x00,0x08,0xff,0xe2,0xb0,0xb9,0x00,0x10,0x08,0x08,0xff, + 0xe2,0xb0,0xba,0x00,0x08,0xff,0xe2,0xb0,0xbb,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe2,0xb0,0xbc,0x00,0x08,0xff,0xe2,0xb0,0xbd,0x00,0x10,0x08,0x08,0xff,0xe2,0xb0, + 0xbe,0x00,0x08,0xff,0xe2,0xb0,0xbf,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe2,0xb1,0x80,0x00,0x08,0xff,0xe2,0xb1,0x81,0x00,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x82,0x00,0x08,0xff,0xe2,0xb1,0x83,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x84,0x00,0x08,0xff,0xe2,0xb1,0x85,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x86,0x00,0x08,0xff,0xe2,0xb1,0x87,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x88,0x00,0x08,0xff,0xe2,0xb1,0x89,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x8a,0x00,0x08,0xff,0xe2,0xb1,0x8b,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x8c,0x00,0x08,0xff,0xe2,0xb1,0x8d,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1,0x8e,0x00, + 0x08,0xff,0xe2,0xb1,0x8f,0x00,0x94,0x7c,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe2,0xb1,0x90,0x00,0x08,0xff,0xe2,0xb1,0x91,0x00,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x92,0x00,0x08,0xff,0xe2,0xb1,0x93,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x94,0x00,0x08,0xff,0xe2,0xb1,0x95,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x96,0x00,0x08,0xff,0xe2,0xb1,0x97,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe2,0xb1,0x98,0x00,0x08,0xff,0xe2,0xb1,0x99,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x9a,0x00,0x08,0xff,0xe2,0xb1,0x9b,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe2,0xb1, + 0x9c,0x00,0x08,0xff,0xe2,0xb1,0x9d,0x00,0x10,0x08,0x08,0xff,0xe2,0xb1,0x9e,0x00, + 0x00,0x00,0x08,0x00,0xcf,0x86,0xd5,0x07,0x64,0xef,0x61,0x08,0x00,0xd4,0x63,0xd3, + 0x32,0xd2,0x1b,0xd1,0x0c,0x10,0x08,0x09,0xff,0xe2,0xb1,0xa1,0x00,0x09,0x00,0x10, + 0x07,0x09,0xff,0xc9,0xab,0x00,0x09,0xff,0xe1,0xb5,0xbd,0x00,0xd1,0x0b,0x10,0x07, + 0x09,0xff,0xc9,0xbd,0x00,0x09,0x00,0x10,0x04,0x09,0x00,0x09,0xff,0xe2,0xb1,0xa8, + 0x00,0xd2,0x18,0xd1,0x0c,0x10,0x04,0x09,0x00,0x09,0xff,0xe2,0xb1,0xaa,0x00,0x10, + 0x04,0x09,0x00,0x09,0xff,0xe2,0xb1,0xac,0x00,0xd1,0x0b,0x10,0x04,0x09,0x00,0x0a, + 0xff,0xc9,0x91,0x00,0x10,0x07,0x0a,0xff,0xc9,0xb1,0x00,0x0a,0xff,0xc9,0x90,0x00, + 0xd3,0x27,0xd2,0x17,0xd1,0x0b,0x10,0x07,0x0b,0xff,0xc9,0x92,0x00,0x0a,0x00,0x10, + 0x08,0x0a,0xff,0xe2,0xb1,0xb3,0x00,0x0a,0x00,0x91,0x0c,0x10,0x04,0x09,0x00,0x09, + 0xff,0xe2,0xb1,0xb6,0x00,0x09,0x00,0x52,0x04,0x0a,0x00,0x51,0x04,0x0a,0x00,0x10, + 0x07,0x0b,0xff,0xc8,0xbf,0x00,0x0b,0xff,0xc9,0x80,0x00,0xe0,0x83,0x01,0xcf,0x86, + 0xd5,0xc0,0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2, + 0x81,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x83,0x00,0x08,0x00,0xd1,0x0c, + 0x10,0x08,0x08,0xff,0xe2,0xb2,0x85,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2, + 0x87,0x00,0x08,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0x89,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x8b,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08, + 0x08,0xff,0xe2,0xb2,0x8d,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x8f,0x00, + 0x08,0x00,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0x91,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x93,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08, + 0x08,0xff,0xe2,0xb2,0x95,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x97,0x00, + 0x08,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0x99,0x00,0x08,0x00, + 0x10,0x08,0x08,0xff,0xe2,0xb2,0x9b,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08,0x08,0xff, + 0xe2,0xb2,0x9d,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0x9f,0x00,0x08,0x00, + 0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0xa1,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0xa3,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08, + 0x08,0xff,0xe2,0xb2,0xa5,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0xa7,0x00, + 0x08,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0xa9,0x00,0x08,0x00, + 0x10,0x08,0x08,0xff,0xe2,0xb2,0xab,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08,0x08,0xff, + 0xe2,0xb2,0xad,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0xaf,0x00,0x08,0x00, + 0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0xb1,0x00,0x08,0x00, + 0x10,0x08,0x08,0xff,0xe2,0xb2,0xb3,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08,0x08,0xff, + 0xe2,0xb2,0xb5,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0xb7,0x00,0x08,0x00, + 0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2,0xb9,0x00,0x08,0x00,0x10,0x08, + 0x08,0xff,0xe2,0xb2,0xbb,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb2, + 0xbd,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb2,0xbf,0x00,0x08,0x00,0xcf,0x86, + 0xd5,0xc0,0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb3, + 0x81,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x83,0x00,0x08,0x00,0xd1,0x0c, + 0x10,0x08,0x08,0xff,0xe2,0xb3,0x85,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3, + 0x87,0x00,0x08,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb3,0x89,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x8b,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08, + 0x08,0xff,0xe2,0xb3,0x8d,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x8f,0x00, + 0x08,0x00,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb3,0x91,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x93,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08, + 0x08,0xff,0xe2,0xb3,0x95,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x97,0x00, + 0x08,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb3,0x99,0x00,0x08,0x00, + 0x10,0x08,0x08,0xff,0xe2,0xb3,0x9b,0x00,0x08,0x00,0xd1,0x0c,0x10,0x08,0x08,0xff, + 0xe2,0xb3,0x9d,0x00,0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0x9f,0x00,0x08,0x00, + 0xd4,0x3b,0xd3,0x1c,0x92,0x18,0xd1,0x0c,0x10,0x08,0x08,0xff,0xe2,0xb3,0xa1,0x00, + 0x08,0x00,0x10,0x08,0x08,0xff,0xe2,0xb3,0xa3,0x00,0x08,0x00,0x08,0x00,0xd2,0x10, + 0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x0b,0xff,0xe2,0xb3,0xac,0x00,0xe1,0x3b, + 0x5f,0x10,0x04,0x0b,0x00,0x0b,0xff,0xe2,0xb3,0xae,0x00,0xe3,0x40,0x5f,0x92,0x10, + 0x51,0x04,0x0b,0xe6,0x10,0x08,0x0d,0xff,0xe2,0xb3,0xb3,0x00,0x0d,0x00,0x00,0x00, + 0xe2,0x98,0x08,0xd1,0x0b,0xe0,0x11,0x67,0xcf,0x86,0xcf,0x06,0x01,0x00,0xe0,0x65, + 0x6c,0xcf,0x86,0xe5,0xa7,0x05,0xd4,0x06,0xcf,0x06,0x04,0x00,0xd3,0x0c,0xe2,0xf8, + 0x67,0xe1,0x8f,0x67,0xcf,0x06,0x04,0x00,0xe2,0xdb,0x01,0xe1,0x26,0x01,0xd0,0x09, + 0xcf,0x86,0x65,0xf4,0x67,0x0a,0x00,0xcf,0x86,0xd5,0xc0,0xd4,0x60,0xd3,0x30,0xd2, + 0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x81,0x00,0x0a,0x00,0x10,0x08,0x0a, + 0xff,0xea,0x99,0x83,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x85, + 0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x99,0x87,0x00,0x0a,0x00,0xd2,0x18,0xd1, + 0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x89,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea, + 0x99,0x8b,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x8d,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x99,0x8f,0x00,0x0a,0x00,0xd3,0x30,0xd2,0x18,0xd1, + 0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x91,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea, + 0x99,0x93,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x95,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x99,0x97,0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10, + 0x08,0x0a,0xff,0xea,0x99,0x99,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x99,0x9b, + 0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0x9d,0x00,0x0a,0x00,0x10, + 0x08,0x0a,0xff,0xea,0x99,0x9f,0x00,0x0a,0x00,0xe4,0x5d,0x67,0xd3,0x30,0xd2,0x18, + 0xd1,0x0c,0x10,0x08,0x0c,0xff,0xea,0x99,0xa1,0x00,0x0c,0x00,0x10,0x08,0x0a,0xff, + 0xea,0x99,0xa3,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x99,0xa5,0x00, + 0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x99,0xa7,0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c, + 0x10,0x08,0x0a,0xff,0xea,0x99,0xa9,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x99, + 0xab,0x00,0x0a,0x00,0xe1,0x0c,0x67,0x10,0x08,0x0a,0xff,0xea,0x99,0xad,0x00,0x0a, + 0x00,0xe0,0x35,0x67,0xcf,0x86,0x95,0xab,0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c, + 0x10,0x08,0x0a,0xff,0xea,0x9a,0x81,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9a, + 0x83,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9a,0x85,0x00,0x0a,0x00, + 0x10,0x08,0x0a,0xff,0xea,0x9a,0x87,0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08, + 0x0a,0xff,0xea,0x9a,0x89,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9a,0x8b,0x00, + 0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9a,0x8d,0x00,0x0a,0x00,0x10,0x08, + 0x0a,0xff,0xea,0x9a,0x8f,0x00,0x0a,0x00,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08, + 0x0a,0xff,0xea,0x9a,0x91,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9a,0x93,0x00, + 0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9a,0x95,0x00,0x0a,0x00,0x10,0x08, + 0x0a,0xff,0xea,0x9a,0x97,0x00,0x0a,0x00,0xe2,0x92,0x66,0xd1,0x0c,0x10,0x08,0x10, + 0xff,0xea,0x9a,0x99,0x00,0x10,0x00,0x10,0x08,0x10,0xff,0xea,0x9a,0x9b,0x00,0x10, + 0x00,0x0b,0x00,0xe1,0x10,0x02,0xd0,0xb9,0xcf,0x86,0xd5,0x07,0x64,0x9e,0x66,0x08, + 0x00,0xd4,0x58,0xd3,0x28,0xd2,0x10,0x51,0x04,0x09,0x00,0x10,0x08,0x0a,0xff,0xea, + 0x9c,0xa3,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9c,0xa5,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x9c,0xa7,0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10, + 0x08,0x0a,0xff,0xea,0x9c,0xa9,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9c,0xab, + 0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9c,0xad,0x00,0x0a,0x00,0x10, + 0x08,0x0a,0xff,0xea,0x9c,0xaf,0x00,0x0a,0x00,0xd3,0x28,0xd2,0x10,0x51,0x04,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x9c,0xb3,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a, + 0xff,0xea,0x9c,0xb5,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9c,0xb7,0x00,0x0a, + 0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9c,0xb9,0x00,0x0a,0x00,0x10, + 0x08,0x0a,0xff,0xea,0x9c,0xbb,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea, + 0x9c,0xbd,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9c,0xbf,0x00,0x0a,0x00,0xcf, + 0x86,0xd5,0xc0,0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea, + 0x9d,0x81,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x83,0x00,0x0a,0x00,0xd1, + 0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0x85,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea, + 0x9d,0x87,0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0x89, + 0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x8b,0x00,0x0a,0x00,0xd1,0x0c,0x10, + 0x08,0x0a,0xff,0xea,0x9d,0x8d,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x8f, + 0x00,0x0a,0x00,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0x91, + 0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x93,0x00,0x0a,0x00,0xd1,0x0c,0x10, + 0x08,0x0a,0xff,0xea,0x9d,0x95,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x97, + 0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0x99,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x9b,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a, + 0xff,0xea,0x9d,0x9d,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0x9f,0x00,0x0a, + 0x00,0xd4,0x60,0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0xa1, + 0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0xa3,0x00,0x0a,0x00,0xd1,0x0c,0x10, + 0x08,0x0a,0xff,0xea,0x9d,0xa5,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0xa7, + 0x00,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9d,0xa9,0x00,0x0a, + 0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0xab,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a, + 0xff,0xea,0x9d,0xad,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0xaf,0x00,0x0a, + 0x00,0x53,0x04,0x0a,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x04,0x0a,0x00,0x0a,0xff,0xea, + 0x9d,0xba,0x00,0x10,0x04,0x0a,0x00,0x0a,0xff,0xea,0x9d,0xbc,0x00,0xd1,0x0c,0x10, + 0x04,0x0a,0x00,0x0a,0xff,0xe1,0xb5,0xb9,0x00,0x10,0x08,0x0a,0xff,0xea,0x9d,0xbf, + 0x00,0x0a,0x00,0xe0,0x71,0x01,0xcf,0x86,0xd5,0xa6,0xd4,0x4e,0xd3,0x30,0xd2,0x18, + 0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9e,0x81,0x00,0x0a,0x00,0x10,0x08,0x0a,0xff, + 0xea,0x9e,0x83,0x00,0x0a,0x00,0xd1,0x0c,0x10,0x08,0x0a,0xff,0xea,0x9e,0x85,0x00, + 0x0a,0x00,0x10,0x08,0x0a,0xff,0xea,0x9e,0x87,0x00,0x0a,0x00,0xd2,0x10,0x51,0x04, + 0x0a,0x00,0x10,0x04,0x0a,0x00,0x0a,0xff,0xea,0x9e,0x8c,0x00,0xe1,0x9a,0x64,0x10, + 0x04,0x0a,0x00,0x0c,0xff,0xc9,0xa5,0x00,0xd3,0x28,0xd2,0x18,0xd1,0x0c,0x10,0x08, + 0x0c,0xff,0xea,0x9e,0x91,0x00,0x0c,0x00,0x10,0x08,0x0d,0xff,0xea,0x9e,0x93,0x00, + 0x0d,0x00,0x51,0x04,0x10,0x00,0x10,0x08,0x10,0xff,0xea,0x9e,0x97,0x00,0x10,0x00, + 0xd2,0x18,0xd1,0x0c,0x10,0x08,0x10,0xff,0xea,0x9e,0x99,0x00,0x10,0x00,0x10,0x08, + 0x10,0xff,0xea,0x9e,0x9b,0x00,0x10,0x00,0xd1,0x0c,0x10,0x08,0x10,0xff,0xea,0x9e, + 0x9d,0x00,0x10,0x00,0x10,0x08,0x10,0xff,0xea,0x9e,0x9f,0x00,0x10,0x00,0xd4,0x63, + 0xd3,0x30,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x0c,0xff,0xea,0x9e,0xa1,0x00,0x0c,0x00, + 0x10,0x08,0x0c,0xff,0xea,0x9e,0xa3,0x00,0x0c,0x00,0xd1,0x0c,0x10,0x08,0x0c,0xff, + 0xea,0x9e,0xa5,0x00,0x0c,0x00,0x10,0x08,0x0c,0xff,0xea,0x9e,0xa7,0x00,0x0c,0x00, + 0xd2,0x1a,0xd1,0x0c,0x10,0x08,0x0c,0xff,0xea,0x9e,0xa9,0x00,0x0c,0x00,0x10,0x07, + 0x0d,0xff,0xc9,0xa6,0x00,0x10,0xff,0xc9,0x9c,0x00,0xd1,0x0e,0x10,0x07,0x10,0xff, + 0xc9,0xa1,0x00,0x10,0xff,0xc9,0xac,0x00,0x10,0x07,0x12,0xff,0xc9,0xaa,0x00,0x14, + 0x00,0xd3,0x35,0xd2,0x1d,0xd1,0x0e,0x10,0x07,0x10,0xff,0xca,0x9e,0x00,0x10,0xff, + 0xca,0x87,0x00,0x10,0x07,0x11,0xff,0xca,0x9d,0x00,0x11,0xff,0xea,0xad,0x93,0x00, + 0xd1,0x0c,0x10,0x08,0x11,0xff,0xea,0x9e,0xb5,0x00,0x11,0x00,0x10,0x08,0x11,0xff, + 0xea,0x9e,0xb7,0x00,0x11,0x00,0xd2,0x18,0xd1,0x0c,0x10,0x08,0x14,0xff,0xea,0x9e, + 0xb9,0x00,0x14,0x00,0x10,0x08,0x15,0xff,0xea,0x9e,0xbb,0x00,0x15,0x00,0xd1,0x0c, + 0x10,0x08,0x15,0xff,0xea,0x9e,0xbd,0x00,0x15,0x00,0x10,0x08,0x15,0xff,0xea,0x9e, + 0xbf,0x00,0x15,0x00,0xcf,0x86,0xe5,0xd4,0x63,0x94,0x2f,0x93,0x2b,0xd2,0x10,0x51, + 0x04,0x00,0x00,0x10,0x08,0x15,0xff,0xea,0x9f,0x83,0x00,0x15,0x00,0xd1,0x0f,0x10, + 0x08,0x15,0xff,0xea,0x9e,0x94,0x00,0x15,0xff,0xca,0x82,0x00,0x10,0x08,0x15,0xff, + 0xe1,0xb6,0x8e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe4,0xb4,0x66,0xd3,0x1d,0xe2, + 0x5b,0x64,0xe1,0x0a,0x64,0xe0,0xf7,0x63,0xcf,0x86,0xe5,0xd8,0x63,0x94,0x0b,0x93, + 0x07,0x62,0xc3,0x63,0x08,0x00,0x08,0x00,0x08,0x00,0xd2,0x0f,0xe1,0x5a,0x65,0xe0, + 0x27,0x65,0xcf,0x86,0x65,0x0c,0x65,0x0a,0x00,0xd1,0xab,0xd0,0x1a,0xcf,0x86,0xe5, + 0x17,0x66,0xe4,0xfa,0x65,0xe3,0xe1,0x65,0xe2,0xd4,0x65,0x91,0x08,0x10,0x04,0x00, + 0x00,0x0c,0x00,0x0c,0x00,0xcf,0x86,0x55,0x04,0x10,0x00,0xd4,0x0b,0x93,0x07,0x62, + 0x27,0x66,0x11,0x00,0x00,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x11,0xff, + 0xe1,0x8e,0xa0,0x00,0x11,0xff,0xe1,0x8e,0xa1,0x00,0x10,0x08,0x11,0xff,0xe1,0x8e, + 0xa2,0x00,0x11,0xff,0xe1,0x8e,0xa3,0x00,0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e, + 0xa4,0x00,0x11,0xff,0xe1,0x8e,0xa5,0x00,0x10,0x08,0x11,0xff,0xe1,0x8e,0xa6,0x00, + 0x11,0xff,0xe1,0x8e,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e, + 0xa8,0x00,0x11,0xff,0xe1,0x8e,0xa9,0x00,0x10,0x08,0x11,0xff,0xe1,0x8e,0xaa,0x00, + 0x11,0xff,0xe1,0x8e,0xab,0x00,0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e,0xac,0x00, + 0x11,0xff,0xe1,0x8e,0xad,0x00,0x10,0x08,0x11,0xff,0xe1,0x8e,0xae,0x00,0x11,0xff, + 0xe1,0x8e,0xaf,0x00,0xe0,0xb2,0x65,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e,0xb0,0x00,0x11,0xff,0xe1,0x8e, + 0xb1,0x00,0x10,0x08,0x11,0xff,0xe1,0x8e,0xb2,0x00,0x11,0xff,0xe1,0x8e,0xb3,0x00, + 0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e,0xb4,0x00,0x11,0xff,0xe1,0x8e,0xb5,0x00, + 0x10,0x08,0x11,0xff,0xe1,0x8e,0xb6,0x00,0x11,0xff,0xe1,0x8e,0xb7,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8e,0xb8,0x00,0x11,0xff,0xe1,0x8e,0xb9,0x00, + 0x10,0x08,0x11,0xff,0xe1,0x8e,0xba,0x00,0x11,0xff,0xe1,0x8e,0xbb,0x00,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8e,0xbc,0x00,0x11,0xff,0xe1,0x8e,0xbd,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8e,0xbe,0x00,0x11,0xff,0xe1,0x8e,0xbf,0x00,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8f,0x80,0x00,0x11,0xff,0xe1,0x8f,0x81,0x00, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x82,0x00,0x11,0xff,0xe1,0x8f,0x83,0x00,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x84,0x00,0x11,0xff,0xe1,0x8f,0x85,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x86,0x00,0x11,0xff,0xe1,0x8f,0x87,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x88,0x00,0x11,0xff,0xe1,0x8f,0x89,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x8a,0x00,0x11,0xff,0xe1,0x8f,0x8b,0x00,0xd1,0x10,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x8c,0x00,0x11,0xff,0xe1,0x8f,0x8d,0x00,0x10,0x08,0x11,0xff, + 0xe1,0x8f,0x8e,0x00,0x11,0xff,0xe1,0x8f,0x8f,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x11,0xff,0xe1,0x8f,0x90,0x00,0x11,0xff,0xe1,0x8f,0x91,0x00, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x92,0x00,0x11,0xff,0xe1,0x8f,0x93,0x00,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x94,0x00,0x11,0xff,0xe1,0x8f,0x95,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x96,0x00,0x11,0xff,0xe1,0x8f,0x97,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0x98,0x00,0x11,0xff,0xe1,0x8f,0x99,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x9a,0x00,0x11,0xff,0xe1,0x8f,0x9b,0x00,0xd1,0x10,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0x9c,0x00,0x11,0xff,0xe1,0x8f,0x9d,0x00,0x10,0x08,0x11,0xff, + 0xe1,0x8f,0x9e,0x00,0x11,0xff,0xe1,0x8f,0x9f,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x11,0xff,0xe1,0x8f,0xa0,0x00,0x11,0xff,0xe1,0x8f,0xa1,0x00,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0xa2,0x00,0x11,0xff,0xe1,0x8f,0xa3,0x00,0xd1,0x10,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0xa4,0x00,0x11,0xff,0xe1,0x8f,0xa5,0x00,0x10,0x08,0x11,0xff, + 0xe1,0x8f,0xa6,0x00,0x11,0xff,0xe1,0x8f,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x11,0xff,0xe1,0x8f,0xa8,0x00,0x11,0xff,0xe1,0x8f,0xa9,0x00,0x10,0x08,0x11,0xff, + 0xe1,0x8f,0xaa,0x00,0x11,0xff,0xe1,0x8f,0xab,0x00,0xd1,0x10,0x10,0x08,0x11,0xff, + 0xe1,0x8f,0xac,0x00,0x11,0xff,0xe1,0x8f,0xad,0x00,0x10,0x08,0x11,0xff,0xe1,0x8f, + 0xae,0x00,0x11,0xff,0xe1,0x8f,0xaf,0x00,0xd1,0x0c,0xe0,0xeb,0x63,0xcf,0x86,0xcf, + 0x06,0x02,0xff,0xff,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x06, + 0xcf,0x06,0x01,0x00,0xd4,0xae,0xd3,0x09,0xe2,0x54,0x64,0xcf,0x06,0x01,0x00,0xd2, + 0x27,0xe1,0x1f,0x70,0xe0,0x26,0x6e,0xcf,0x86,0xe5,0x3f,0x6d,0xe4,0xce,0x6c,0xe3, + 0x99,0x6c,0xe2,0x78,0x6c,0xe1,0x67,0x6c,0x10,0x08,0x01,0xff,0xe5,0x88,0x87,0x00, + 0x01,0xff,0xe5,0xba,0xa6,0x00,0xe1,0x74,0x74,0xe0,0xe8,0x73,0xcf,0x86,0xe5,0x22, + 0x73,0xd4,0x3b,0x93,0x37,0xd2,0x1d,0xd1,0x0e,0x10,0x07,0x01,0xff,0x66,0x66,0x00, + 0x01,0xff,0x66,0x69,0x00,0x10,0x07,0x01,0xff,0x66,0x6c,0x00,0x01,0xff,0x66,0x66, + 0x69,0x00,0xd1,0x0f,0x10,0x08,0x01,0xff,0x66,0x66,0x6c,0x00,0x01,0xff,0x73,0x74, + 0x00,0x10,0x07,0x01,0xff,0x73,0x74,0x00,0x00,0x00,0x00,0x00,0xe3,0xc8,0x72,0xd2, + 0x11,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0xff,0xd5,0xb4,0xd5,0xb6,0x00, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xd5,0xb4,0xd5,0xa5,0x00,0x01,0xff,0xd5,0xb4,0xd5, + 0xab,0x00,0x10,0x09,0x01,0xff,0xd5,0xbe,0xd5,0xb6,0x00,0x01,0xff,0xd5,0xb4,0xd5, + 0xad,0x00,0xd3,0x09,0xe2,0x40,0x74,0xcf,0x06,0x01,0x00,0xd2,0x13,0xe1,0x30,0x75, + 0xe0,0xc1,0x74,0xcf,0x86,0xe5,0x9e,0x74,0x64,0x8d,0x74,0x06,0xff,0x00,0xe1,0x96, + 0x75,0xe0,0x63,0x75,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x7c, + 0xd3,0x3c,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0xef,0xbd,0x81,0x00, + 0x10,0x08,0x01,0xff,0xef,0xbd,0x82,0x00,0x01,0xff,0xef,0xbd,0x83,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xef,0xbd,0x84,0x00,0x01,0xff,0xef,0xbd,0x85,0x00,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x86,0x00,0x01,0xff,0xef,0xbd,0x87,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xef,0xbd,0x88,0x00,0x01,0xff,0xef,0xbd,0x89,0x00,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x8a,0x00,0x01,0xff,0xef,0xbd,0x8b,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x8c,0x00,0x01,0xff,0xef,0xbd,0x8d,0x00,0x10,0x08,0x01,0xff, + 0xef,0xbd,0x8e,0x00,0x01,0xff,0xef,0xbd,0x8f,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xef,0xbd,0x90,0x00,0x01,0xff,0xef,0xbd,0x91,0x00,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x92,0x00,0x01,0xff,0xef,0xbd,0x93,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x94,0x00,0x01,0xff,0xef,0xbd,0x95,0x00,0x10,0x08,0x01,0xff, + 0xef,0xbd,0x96,0x00,0x01,0xff,0xef,0xbd,0x97,0x00,0x92,0x1c,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xef,0xbd,0x98,0x00,0x01,0xff,0xef,0xbd,0x99,0x00,0x10,0x08,0x01,0xff, + 0xef,0xbd,0x9a,0x00,0x01,0x00,0x01,0x00,0x83,0xe2,0x87,0xb3,0xe1,0x60,0xb0,0xe0, + 0xdd,0xae,0xcf,0x86,0xe5,0x81,0x9b,0xc4,0xe3,0xc1,0x07,0xe2,0x62,0x06,0xe1,0x11, + 0x86,0xe0,0x09,0x05,0xcf,0x86,0xe5,0xfb,0x02,0xd4,0x1c,0xe3,0x7f,0x76,0xe2,0xd6, + 0x75,0xe1,0xb1,0x75,0xe0,0x8a,0x75,0xcf,0x86,0xe5,0x57,0x75,0x94,0x07,0x63,0x42, + 0x75,0x07,0x00,0x07,0x00,0xe3,0x2b,0x78,0xe2,0xf0,0x77,0xe1,0x77,0x01,0xe0,0x88, + 0x77,0xcf,0x86,0xe5,0x21,0x01,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09, + 0x05,0xff,0xf0,0x90,0x90,0xa8,0x00,0x05,0xff,0xf0,0x90,0x90,0xa9,0x00,0x10,0x09, + 0x05,0xff,0xf0,0x90,0x90,0xaa,0x00,0x05,0xff,0xf0,0x90,0x90,0xab,0x00,0xd1,0x12, + 0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xac,0x00,0x05,0xff,0xf0,0x90,0x90,0xad,0x00, + 0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xae,0x00,0x05,0xff,0xf0,0x90,0x90,0xaf,0x00, + 0xd2,0x24,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xb0,0x00,0x05,0xff,0xf0, + 0x90,0x90,0xb1,0x00,0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xb2,0x00,0x05,0xff,0xf0, + 0x90,0x90,0xb3,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xb4,0x00,0x05, + 0xff,0xf0,0x90,0x90,0xb5,0x00,0x10,0x09,0x05,0xff,0xf0,0x90,0x90,0xb6,0x00,0x05, + 0xff,0xf0,0x90,0x90,0xb7,0x00,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x05,0xff, + 0xf0,0x90,0x90,0xb8,0x00,0x05,0xff,0xf0,0x90,0x90,0xb9,0x00,0x10,0x09,0x05,0xff, + 0xf0,0x90,0x90,0xba,0x00,0x05,0xff,0xf0,0x90,0x90,0xbb,0x00,0xd1,0x12,0x10,0x09, + 0x05,0xff,0xf0,0x90,0x90,0xbc,0x00,0x05,0xff,0xf0,0x90,0x90,0xbd,0x00,0x10,0x09, + 0x05,0xff,0xf0,0x90,0x90,0xbe,0x00,0x05,0xff,0xf0,0x90,0x90,0xbf,0x00,0xd2,0x24, + 0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0x90,0x91,0x80,0x00,0x05,0xff,0xf0,0x90,0x91, + 0x81,0x00,0x10,0x09,0x05,0xff,0xf0,0x90,0x91,0x82,0x00,0x05,0xff,0xf0,0x90,0x91, + 0x83,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0x90,0x91,0x84,0x00,0x05,0xff,0xf0, + 0x90,0x91,0x85,0x00,0x10,0x09,0x05,0xff,0xf0,0x90,0x91,0x86,0x00,0x05,0xff,0xf0, + 0x90,0x91,0x87,0x00,0x94,0x4c,0x93,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x05,0xff, + 0xf0,0x90,0x91,0x88,0x00,0x05,0xff,0xf0,0x90,0x91,0x89,0x00,0x10,0x09,0x05,0xff, + 0xf0,0x90,0x91,0x8a,0x00,0x05,0xff,0xf0,0x90,0x91,0x8b,0x00,0xd1,0x12,0x10,0x09, + 0x05,0xff,0xf0,0x90,0x91,0x8c,0x00,0x05,0xff,0xf0,0x90,0x91,0x8d,0x00,0x10,0x09, + 0x07,0xff,0xf0,0x90,0x91,0x8e,0x00,0x07,0xff,0xf0,0x90,0x91,0x8f,0x00,0x05,0x00, + 0x05,0x00,0xd0,0xa0,0xcf,0x86,0xd5,0x07,0x64,0x30,0x76,0x07,0x00,0xd4,0x07,0x63, + 0x3d,0x76,0x07,0x00,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x90, + 0x93,0x98,0x00,0x12,0xff,0xf0,0x90,0x93,0x99,0x00,0x10,0x09,0x12,0xff,0xf0,0x90, + 0x93,0x9a,0x00,0x12,0xff,0xf0,0x90,0x93,0x9b,0x00,0xd1,0x12,0x10,0x09,0x12,0xff, + 0xf0,0x90,0x93,0x9c,0x00,0x12,0xff,0xf0,0x90,0x93,0x9d,0x00,0x10,0x09,0x12,0xff, + 0xf0,0x90,0x93,0x9e,0x00,0x12,0xff,0xf0,0x90,0x93,0x9f,0x00,0xd2,0x24,0xd1,0x12, + 0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xa0,0x00,0x12,0xff,0xf0,0x90,0x93,0xa1,0x00, + 0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xa2,0x00,0x12,0xff,0xf0,0x90,0x93,0xa3,0x00, + 0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xa4,0x00,0x12,0xff,0xf0,0x90,0x93, + 0xa5,0x00,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xa6,0x00,0x12,0xff,0xf0,0x90,0x93, + 0xa7,0x00,0xcf,0x86,0xe5,0xc6,0x75,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10, + 0x09,0x12,0xff,0xf0,0x90,0x93,0xa8,0x00,0x12,0xff,0xf0,0x90,0x93,0xa9,0x00,0x10, + 0x09,0x12,0xff,0xf0,0x90,0x93,0xaa,0x00,0x12,0xff,0xf0,0x90,0x93,0xab,0x00,0xd1, + 0x12,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xac,0x00,0x12,0xff,0xf0,0x90,0x93,0xad, + 0x00,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xae,0x00,0x12,0xff,0xf0,0x90,0x93,0xaf, + 0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xb0,0x00,0x12,0xff, + 0xf0,0x90,0x93,0xb1,0x00,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xb2,0x00,0x12,0xff, + 0xf0,0x90,0x93,0xb3,0x00,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xb4,0x00, + 0x12,0xff,0xf0,0x90,0x93,0xb5,0x00,0x10,0x09,0x12,0xff,0xf0,0x90,0x93,0xb6,0x00, + 0x12,0xff,0xf0,0x90,0x93,0xb7,0x00,0x93,0x28,0x92,0x24,0xd1,0x12,0x10,0x09,0x12, + 0xff,0xf0,0x90,0x93,0xb8,0x00,0x12,0xff,0xf0,0x90,0x93,0xb9,0x00,0x10,0x09,0x12, + 0xff,0xf0,0x90,0x93,0xba,0x00,0x12,0xff,0xf0,0x90,0x93,0xbb,0x00,0x00,0x00,0x12, + 0x00,0xd4,0x1f,0xe3,0xdf,0x76,0xe2,0x6a,0x76,0xe1,0x09,0x76,0xe0,0xea,0x75,0xcf, + 0x86,0xe5,0xb7,0x75,0x94,0x0a,0xe3,0xa2,0x75,0x62,0x99,0x75,0x07,0x00,0x07,0x00, + 0xe3,0xde,0x78,0xe2,0xaf,0x78,0xd1,0x09,0xe0,0x4c,0x78,0xcf,0x06,0x0b,0x00,0xe0, + 0x7f,0x78,0xcf,0x86,0xe5,0x21,0x01,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0x80,0x00,0x11,0xff,0xf0,0x90,0xb3,0x81,0x00,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0x82,0x00,0x11,0xff,0xf0,0x90,0xb3,0x83,0x00,0xd1, + 0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x84,0x00,0x11,0xff,0xf0,0x90,0xb3,0x85, + 0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x86,0x00,0x11,0xff,0xf0,0x90,0xb3,0x87, + 0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x88,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0x89,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x8a,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0x8b,0x00,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x8c,0x00, + 0x11,0xff,0xf0,0x90,0xb3,0x8d,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x8e,0x00, + 0x11,0xff,0xf0,0x90,0xb3,0x8f,0x00,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x11, + 0xff,0xf0,0x90,0xb3,0x90,0x00,0x11,0xff,0xf0,0x90,0xb3,0x91,0x00,0x10,0x09,0x11, + 0xff,0xf0,0x90,0xb3,0x92,0x00,0x11,0xff,0xf0,0x90,0xb3,0x93,0x00,0xd1,0x12,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0x94,0x00,0x11,0xff,0xf0,0x90,0xb3,0x95,0x00,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0x96,0x00,0x11,0xff,0xf0,0x90,0xb3,0x97,0x00,0xd2, + 0x24,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x98,0x00,0x11,0xff,0xf0,0x90, + 0xb3,0x99,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x9a,0x00,0x11,0xff,0xf0,0x90, + 0xb3,0x9b,0x00,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x9c,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0x9d,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0x9e,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0x9f,0x00,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x11, + 0xff,0xf0,0x90,0xb3,0xa0,0x00,0x11,0xff,0xf0,0x90,0xb3,0xa1,0x00,0x10,0x09,0x11, + 0xff,0xf0,0x90,0xb3,0xa2,0x00,0x11,0xff,0xf0,0x90,0xb3,0xa3,0x00,0xd1,0x12,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0xa4,0x00,0x11,0xff,0xf0,0x90,0xb3,0xa5,0x00,0x10, + 0x09,0x11,0xff,0xf0,0x90,0xb3,0xa6,0x00,0x11,0xff,0xf0,0x90,0xb3,0xa7,0x00,0xd2, + 0x24,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0xa8,0x00,0x11,0xff,0xf0,0x90, + 0xb3,0xa9,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0xaa,0x00,0x11,0xff,0xf0,0x90, + 0xb3,0xab,0x00,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0xac,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0xad,0x00,0x10,0x09,0x11,0xff,0xf0,0x90,0xb3,0xae,0x00,0x11,0xff, + 0xf0,0x90,0xb3,0xaf,0x00,0x93,0x23,0x92,0x1f,0xd1,0x12,0x10,0x09,0x11,0xff,0xf0, + 0x90,0xb3,0xb0,0x00,0x11,0xff,0xf0,0x90,0xb3,0xb1,0x00,0x10,0x09,0x11,0xff,0xf0, + 0x90,0xb3,0xb2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x15,0xe4,0x91, + 0x7b,0xe3,0x9b,0x79,0xe2,0x94,0x78,0xe1,0xe4,0x77,0xe0,0x9d,0x77,0xcf,0x06,0x0c, + 0x00,0xe4,0xeb,0x7e,0xe3,0x44,0x7e,0xe2,0xed,0x7d,0xd1,0x0c,0xe0,0xb2,0x7d,0xcf, + 0x86,0x65,0x93,0x7d,0x14,0x00,0xe0,0xb6,0x7d,0xcf,0x86,0x55,0x04,0x00,0x00,0xd4, + 0x90,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x80,0x00, + 0x10,0xff,0xf0,0x91,0xa3,0x81,0x00,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x82,0x00, + 0x10,0xff,0xf0,0x91,0xa3,0x83,0x00,0xd1,0x12,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3, + 0x84,0x00,0x10,0xff,0xf0,0x91,0xa3,0x85,0x00,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3, + 0x86,0x00,0x10,0xff,0xf0,0x91,0xa3,0x87,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x10, + 0xff,0xf0,0x91,0xa3,0x88,0x00,0x10,0xff,0xf0,0x91,0xa3,0x89,0x00,0x10,0x09,0x10, + 0xff,0xf0,0x91,0xa3,0x8a,0x00,0x10,0xff,0xf0,0x91,0xa3,0x8b,0x00,0xd1,0x12,0x10, + 0x09,0x10,0xff,0xf0,0x91,0xa3,0x8c,0x00,0x10,0xff,0xf0,0x91,0xa3,0x8d,0x00,0x10, + 0x09,0x10,0xff,0xf0,0x91,0xa3,0x8e,0x00,0x10,0xff,0xf0,0x91,0xa3,0x8f,0x00,0xd3, + 0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x90,0x00,0x10,0xff, + 0xf0,0x91,0xa3,0x91,0x00,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x92,0x00,0x10,0xff, + 0xf0,0x91,0xa3,0x93,0x00,0xd1,0x12,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x94,0x00, + 0x10,0xff,0xf0,0x91,0xa3,0x95,0x00,0x10,0x09,0x10,0xff,0xf0,0x91,0xa3,0x96,0x00, + 0x10,0xff,0xf0,0x91,0xa3,0x97,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x10,0xff,0xf0, + 0x91,0xa3,0x98,0x00,0x10,0xff,0xf0,0x91,0xa3,0x99,0x00,0x10,0x09,0x10,0xff,0xf0, + 0x91,0xa3,0x9a,0x00,0x10,0xff,0xf0,0x91,0xa3,0x9b,0x00,0xd1,0x12,0x10,0x09,0x10, + 0xff,0xf0,0x91,0xa3,0x9c,0x00,0x10,0xff,0xf0,0x91,0xa3,0x9d,0x00,0x10,0x09,0x10, + 0xff,0xf0,0x91,0xa3,0x9e,0x00,0x10,0xff,0xf0,0x91,0xa3,0x9f,0x00,0xd1,0x11,0xe0, + 0x12,0x81,0xcf,0x86,0xe5,0x09,0x81,0xe4,0xd2,0x80,0xcf,0x06,0x00,0x00,0xe0,0xdb, + 0x82,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x09,0xe3,0x10,0x81,0xcf,0x06, + 0x0c,0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xe2,0x3b,0x82,0xe1,0x16,0x82,0xd0,0x06, + 0xcf,0x06,0x00,0x00,0xcf,0x86,0xa5,0x21,0x01,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1, + 0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xa0,0x00,0x14,0xff,0xf0,0x96,0xb9,0xa1, + 0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xa2,0x00,0x14,0xff,0xf0,0x96,0xb9,0xa3, + 0x00,0xd1,0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xa4,0x00,0x14,0xff,0xf0,0x96, + 0xb9,0xa5,0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xa6,0x00,0x14,0xff,0xf0,0x96, + 0xb9,0xa7,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xa8,0x00, + 0x14,0xff,0xf0,0x96,0xb9,0xa9,0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xaa,0x00, + 0x14,0xff,0xf0,0x96,0xb9,0xab,0x00,0xd1,0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9, + 0xac,0x00,0x14,0xff,0xf0,0x96,0xb9,0xad,0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9, + 0xae,0x00,0x14,0xff,0xf0,0x96,0xb9,0xaf,0x00,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10, + 0x09,0x14,0xff,0xf0,0x96,0xb9,0xb0,0x00,0x14,0xff,0xf0,0x96,0xb9,0xb1,0x00,0x10, + 0x09,0x14,0xff,0xf0,0x96,0xb9,0xb2,0x00,0x14,0xff,0xf0,0x96,0xb9,0xb3,0x00,0xd1, + 0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xb4,0x00,0x14,0xff,0xf0,0x96,0xb9,0xb5, + 0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xb6,0x00,0x14,0xff,0xf0,0x96,0xb9,0xb7, + 0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xb8,0x00,0x14,0xff, + 0xf0,0x96,0xb9,0xb9,0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xba,0x00,0x14,0xff, + 0xf0,0x96,0xb9,0xbb,0x00,0xd1,0x12,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xbc,0x00, + 0x14,0xff,0xf0,0x96,0xb9,0xbd,0x00,0x10,0x09,0x14,0xff,0xf0,0x96,0xb9,0xbe,0x00, + 0x14,0xff,0xf0,0x96,0xb9,0xbf,0x00,0x14,0x00,0xd2,0x14,0xe1,0x25,0x82,0xe0,0x1c, + 0x82,0xcf,0x86,0xe5,0xdd,0x81,0xe4,0x9a,0x81,0xcf,0x06,0x12,0x00,0xd1,0x0b,0xe0, + 0x51,0x83,0xcf,0x86,0xcf,0x06,0x00,0x00,0xe0,0x95,0x8b,0xcf,0x86,0xd5,0x22,0xe4, + 0xd0,0x88,0xe3,0x93,0x88,0xe2,0x38,0x88,0xe1,0x31,0x88,0xe0,0x2a,0x88,0xcf,0x86, + 0xe5,0xfb,0x87,0xe4,0xe2,0x87,0x93,0x07,0x62,0xd1,0x87,0x12,0xe6,0x12,0xe6,0xe4, + 0x36,0x89,0xe3,0x2f,0x89,0xd2,0x09,0xe1,0xb8,0x88,0xcf,0x06,0x10,0x00,0xe1,0x1f, + 0x89,0xe0,0xec,0x88,0xcf,0x86,0xe5,0x21,0x01,0xd4,0x90,0xd3,0x48,0xd2,0x24,0xd1, + 0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xa2,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xa3, + 0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xa4,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xa5, + 0x00,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xa6,0x00,0x12,0xff,0xf0,0x9e, + 0xa4,0xa7,0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xa8,0x00,0x12,0xff,0xf0,0x9e, + 0xa4,0xa9,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xaa,0x00, + 0x12,0xff,0xf0,0x9e,0xa4,0xab,0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xac,0x00, + 0x12,0xff,0xf0,0x9e,0xa4,0xad,0x00,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4, + 0xae,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xaf,0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4, + 0xb0,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xb1,0x00,0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10, + 0x09,0x12,0xff,0xf0,0x9e,0xa4,0xb2,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xb3,0x00,0x10, + 0x09,0x12,0xff,0xf0,0x9e,0xa4,0xb4,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xb5,0x00,0xd1, + 0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xb6,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xb7, + 0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xb8,0x00,0x12,0xff,0xf0,0x9e,0xa4,0xb9, + 0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xba,0x00,0x12,0xff, + 0xf0,0x9e,0xa4,0xbb,0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xbc,0x00,0x12,0xff, + 0xf0,0x9e,0xa4,0xbd,0x00,0xd1,0x12,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa4,0xbe,0x00, + 0x12,0xff,0xf0,0x9e,0xa4,0xbf,0x00,0x10,0x09,0x12,0xff,0xf0,0x9e,0xa5,0x80,0x00, + 0x12,0xff,0xf0,0x9e,0xa5,0x81,0x00,0x94,0x1e,0x93,0x1a,0x92,0x16,0x91,0x12,0x10, + 0x09,0x12,0xff,0xf0,0x9e,0xa5,0x82,0x00,0x12,0xff,0xf0,0x9e,0xa5,0x83,0x00,0x12, + 0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + /* nfdi_c0100 */ + 0x57,0x04,0x01,0x00,0xc6,0xe5,0xac,0x13,0xe4,0x41,0x0c,0xe3,0x7a,0x07,0xe2,0xf3, + 0x01,0xc1,0xd0,0x1f,0xcf,0x86,0x55,0x04,0x01,0x00,0x94,0x15,0x53,0x04,0x01,0x00, + 0x52,0x04,0x01,0x00,0x91,0x09,0x10,0x04,0x01,0x00,0x01,0xff,0x00,0x01,0x00,0x01, + 0x00,0xcf,0x86,0xd5,0xe4,0xd4,0x7c,0xd3,0x3c,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x41,0xcc,0x80,0x00,0x01,0xff,0x41,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x41, + 0xcc,0x82,0x00,0x01,0xff,0x41,0xcc,0x83,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x41, + 0xcc,0x88,0x00,0x01,0xff,0x41,0xcc,0x8a,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0x43, + 0xcc,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x45,0xcc,0x80,0x00,0x01, + 0xff,0x45,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x45,0xcc,0x82,0x00,0x01,0xff,0x45, + 0xcc,0x88,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x49,0xcc,0x80,0x00,0x01,0xff,0x49, + 0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x49,0xcc,0x82,0x00,0x01,0xff,0x49,0xcc,0x88, + 0x00,0xd3,0x38,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x4e,0xcc,0x83, + 0x00,0x10,0x08,0x01,0xff,0x4f,0xcc,0x80,0x00,0x01,0xff,0x4f,0xcc,0x81,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x4f,0xcc,0x82,0x00,0x01,0xff,0x4f,0xcc,0x83,0x00,0x10, + 0x08,0x01,0xff,0x4f,0xcc,0x88,0x00,0x01,0x00,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01, + 0x00,0x01,0xff,0x55,0xcc,0x80,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0x81,0x00,0x01, + 0xff,0x55,0xcc,0x82,0x00,0x91,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0x88,0x00,0x01, + 0xff,0x59,0xcc,0x81,0x00,0x01,0x00,0xd4,0x7c,0xd3,0x3c,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x61,0xcc,0x80,0x00,0x01,0xff,0x61,0xcc,0x81,0x00,0x10,0x08,0x01, + 0xff,0x61,0xcc,0x82,0x00,0x01,0xff,0x61,0xcc,0x83,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x61,0xcc,0x88,0x00,0x01,0xff,0x61,0xcc,0x8a,0x00,0x10,0x04,0x01,0x00,0x01, + 0xff,0x63,0xcc,0xa7,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x65,0xcc,0x80, + 0x00,0x01,0xff,0x65,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x65,0xcc,0x82,0x00,0x01, + 0xff,0x65,0xcc,0x88,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc,0x80,0x00,0x01, + 0xff,0x69,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x69,0xcc,0x82,0x00,0x01,0xff,0x69, + 0xcc,0x88,0x00,0xd3,0x38,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x6e, + 0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x80,0x00,0x01,0xff,0x6f,0xcc,0x81, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x6f,0xcc,0x82,0x00,0x01,0xff,0x6f,0xcc,0x83, + 0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x88,0x00,0x01,0x00,0xd2,0x1c,0xd1,0x0c,0x10, + 0x04,0x01,0x00,0x01,0xff,0x75,0xcc,0x80,0x00,0x10,0x08,0x01,0xff,0x75,0xcc,0x81, + 0x00,0x01,0xff,0x75,0xcc,0x82,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x75,0xcc,0x88, + 0x00,0x01,0xff,0x79,0xcc,0x81,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0x79,0xcc,0x88, + 0x00,0xe1,0x9a,0x03,0xe0,0xd3,0x01,0xcf,0x86,0xd5,0xf4,0xd4,0x80,0xd3,0x40,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x41,0xcc,0x84,0x00,0x01,0xff,0x61,0xcc,0x84, + 0x00,0x10,0x08,0x01,0xff,0x41,0xcc,0x86,0x00,0x01,0xff,0x61,0xcc,0x86,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x41,0xcc,0xa8,0x00,0x01,0xff,0x61,0xcc,0xa8,0x00,0x10, + 0x08,0x01,0xff,0x43,0xcc,0x81,0x00,0x01,0xff,0x63,0xcc,0x81,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x43,0xcc,0x82,0x00,0x01,0xff,0x63,0xcc,0x82,0x00,0x10, + 0x08,0x01,0xff,0x43,0xcc,0x87,0x00,0x01,0xff,0x63,0xcc,0x87,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x43,0xcc,0x8c,0x00,0x01,0xff,0x63,0xcc,0x8c,0x00,0x10,0x08,0x01, + 0xff,0x44,0xcc,0x8c,0x00,0x01,0xff,0x64,0xcc,0x8c,0x00,0xd3,0x34,0xd2,0x14,0x51, + 0x04,0x01,0x00,0x10,0x08,0x01,0xff,0x45,0xcc,0x84,0x00,0x01,0xff,0x65,0xcc,0x84, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x45,0xcc,0x86,0x00,0x01,0xff,0x65,0xcc,0x86, + 0x00,0x10,0x08,0x01,0xff,0x45,0xcc,0x87,0x00,0x01,0xff,0x65,0xcc,0x87,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x45,0xcc,0xa8,0x00,0x01,0xff,0x65,0xcc,0xa8, + 0x00,0x10,0x08,0x01,0xff,0x45,0xcc,0x8c,0x00,0x01,0xff,0x65,0xcc,0x8c,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x47,0xcc,0x82,0x00,0x01,0xff,0x67,0xcc,0x82,0x00,0x10, + 0x08,0x01,0xff,0x47,0xcc,0x86,0x00,0x01,0xff,0x67,0xcc,0x86,0x00,0xd4,0x74,0xd3, + 0x34,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x47,0xcc,0x87,0x00,0x01,0xff,0x67, + 0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x47,0xcc,0xa7,0x00,0x01,0xff,0x67,0xcc,0xa7, + 0x00,0x91,0x10,0x10,0x08,0x01,0xff,0x48,0xcc,0x82,0x00,0x01,0xff,0x68,0xcc,0x82, + 0x00,0x01,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x49,0xcc,0x83,0x00,0x01, + 0xff,0x69,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x49,0xcc,0x84,0x00,0x01,0xff,0x69, + 0xcc,0x84,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x49,0xcc,0x86,0x00,0x01,0xff,0x69, + 0xcc,0x86,0x00,0x10,0x08,0x01,0xff,0x49,0xcc,0xa8,0x00,0x01,0xff,0x69,0xcc,0xa8, + 0x00,0xd3,0x30,0xd2,0x10,0x91,0x0c,0x10,0x08,0x01,0xff,0x49,0xcc,0x87,0x00,0x01, + 0x00,0x01,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x4a,0xcc,0x82,0x00,0x01,0xff,0x6a, + 0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x4b,0xcc,0xa7,0x00,0x01,0xff,0x6b,0xcc,0xa7, + 0x00,0xd2,0x1c,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x4c,0xcc,0x81,0x00,0x10, + 0x08,0x01,0xff,0x6c,0xcc,0x81,0x00,0x01,0xff,0x4c,0xcc,0xa7,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x6c,0xcc,0xa7,0x00,0x01,0xff,0x4c,0xcc,0x8c,0x00,0x10,0x08,0x01, + 0xff,0x6c,0xcc,0x8c,0x00,0x01,0x00,0xcf,0x86,0xd5,0xd4,0xd4,0x60,0xd3,0x30,0xd2, + 0x10,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0x4e,0xcc,0x81,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x6e,0xcc,0x81,0x00,0x01,0xff,0x4e,0xcc,0xa7,0x00,0x10, + 0x08,0x01,0xff,0x6e,0xcc,0xa7,0x00,0x01,0xff,0x4e,0xcc,0x8c,0x00,0xd2,0x10,0x91, + 0x0c,0x10,0x08,0x01,0xff,0x6e,0xcc,0x8c,0x00,0x01,0x00,0x01,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x4f,0xcc,0x84,0x00,0x01,0xff,0x6f,0xcc,0x84,0x00,0x10,0x08,0x01, + 0xff,0x4f,0xcc,0x86,0x00,0x01,0xff,0x6f,0xcc,0x86,0x00,0xd3,0x34,0xd2,0x14,0x91, + 0x10,0x10,0x08,0x01,0xff,0x4f,0xcc,0x8b,0x00,0x01,0xff,0x6f,0xcc,0x8b,0x00,0x01, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x52,0xcc,0x81,0x00,0x01,0xff,0x72,0xcc,0x81, + 0x00,0x10,0x08,0x01,0xff,0x52,0xcc,0xa7,0x00,0x01,0xff,0x72,0xcc,0xa7,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x52,0xcc,0x8c,0x00,0x01,0xff,0x72,0xcc,0x8c, + 0x00,0x10,0x08,0x01,0xff,0x53,0xcc,0x81,0x00,0x01,0xff,0x73,0xcc,0x81,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x53,0xcc,0x82,0x00,0x01,0xff,0x73,0xcc,0x82,0x00,0x10, + 0x08,0x01,0xff,0x53,0xcc,0xa7,0x00,0x01,0xff,0x73,0xcc,0xa7,0x00,0xd4,0x74,0xd3, + 0x34,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x53,0xcc,0x8c,0x00,0x01,0xff,0x73, + 0xcc,0x8c,0x00,0x10,0x08,0x01,0xff,0x54,0xcc,0xa7,0x00,0x01,0xff,0x74,0xcc,0xa7, + 0x00,0x91,0x10,0x10,0x08,0x01,0xff,0x54,0xcc,0x8c,0x00,0x01,0xff,0x74,0xcc,0x8c, + 0x00,0x01,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0x83,0x00,0x01, + 0xff,0x75,0xcc,0x83,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0x84,0x00,0x01,0xff,0x75, + 0xcc,0x84,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0x86,0x00,0x01,0xff,0x75, + 0xcc,0x86,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0x8a,0x00,0x01,0xff,0x75,0xcc,0x8a, + 0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0x8b,0x00,0x01, + 0xff,0x75,0xcc,0x8b,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0xa8,0x00,0x01,0xff,0x75, + 0xcc,0xa8,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x57,0xcc,0x82,0x00,0x01,0xff,0x77, + 0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x59,0xcc,0x82,0x00,0x01,0xff,0x79,0xcc,0x82, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x59,0xcc,0x88,0x00,0x01,0xff,0x5a, + 0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x7a,0xcc,0x81,0x00,0x01,0xff,0x5a,0xcc,0x87, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x7a,0xcc,0x87,0x00,0x01,0xff,0x5a,0xcc,0x8c, + 0x00,0x10,0x08,0x01,0xff,0x7a,0xcc,0x8c,0x00,0x01,0x00,0xd0,0x4a,0xcf,0x86,0x55, + 0x04,0x01,0x00,0xd4,0x2c,0xd3,0x18,0x92,0x14,0x91,0x10,0x10,0x08,0x01,0xff,0x4f, + 0xcc,0x9b,0x00,0x01,0xff,0x6f,0xcc,0x9b,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01, + 0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0x55,0xcc,0x9b,0x00,0x93, + 0x14,0x92,0x10,0x91,0x0c,0x10,0x08,0x01,0xff,0x75,0xcc,0x9b,0x00,0x01,0x00,0x01, + 0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0xb4,0xd4,0x24,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0x41,0xcc,0x8c,0x00,0x10, + 0x08,0x01,0xff,0x61,0xcc,0x8c,0x00,0x01,0xff,0x49,0xcc,0x8c,0x00,0xd3,0x46,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x69,0xcc,0x8c,0x00,0x01,0xff,0x4f,0xcc,0x8c, + 0x00,0x10,0x08,0x01,0xff,0x6f,0xcc,0x8c,0x00,0x01,0xff,0x55,0xcc,0x8c,0x00,0xd1, + 0x12,0x10,0x08,0x01,0xff,0x75,0xcc,0x8c,0x00,0x01,0xff,0x55,0xcc,0x88,0xcc,0x84, + 0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88,0xcc,0x84,0x00,0x01,0xff,0x55,0xcc,0x88, + 0xcc,0x81,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88,0xcc,0x81, + 0x00,0x01,0xff,0x55,0xcc,0x88,0xcc,0x8c,0x00,0x10,0x0a,0x01,0xff,0x75,0xcc,0x88, + 0xcc,0x8c,0x00,0x01,0xff,0x55,0xcc,0x88,0xcc,0x80,0x00,0xd1,0x0e,0x10,0x0a,0x01, + 0xff,0x75,0xcc,0x88,0xcc,0x80,0x00,0x01,0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x88, + 0xcc,0x84,0x00,0x01,0xff,0x61,0xcc,0x88,0xcc,0x84,0x00,0xd4,0x80,0xd3,0x3a,0xd2, + 0x26,0xd1,0x14,0x10,0x0a,0x01,0xff,0x41,0xcc,0x87,0xcc,0x84,0x00,0x01,0xff,0x61, + 0xcc,0x87,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xc3,0x86,0xcc,0x84,0x00,0x01,0xff, + 0xc3,0xa6,0xcc,0x84,0x00,0x51,0x04,0x01,0x00,0x10,0x08,0x01,0xff,0x47,0xcc,0x8c, + 0x00,0x01,0xff,0x67,0xcc,0x8c,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x4b, + 0xcc,0x8c,0x00,0x01,0xff,0x6b,0xcc,0x8c,0x00,0x10,0x08,0x01,0xff,0x4f,0xcc,0xa8, + 0x00,0x01,0xff,0x6f,0xcc,0xa8,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc,0xa8, + 0xcc,0x84,0x00,0x01,0xff,0x6f,0xcc,0xa8,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xc6, + 0xb7,0xcc,0x8c,0x00,0x01,0xff,0xca,0x92,0xcc,0x8c,0x00,0xd3,0x24,0xd2,0x10,0x91, + 0x0c,0x10,0x08,0x01,0xff,0x6a,0xcc,0x8c,0x00,0x01,0x00,0x01,0x00,0x91,0x10,0x10, + 0x08,0x01,0xff,0x47,0xcc,0x81,0x00,0x01,0xff,0x67,0xcc,0x81,0x00,0x04,0x00,0xd2, + 0x24,0xd1,0x10,0x10,0x08,0x04,0xff,0x4e,0xcc,0x80,0x00,0x04,0xff,0x6e,0xcc,0x80, + 0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x8a,0xcc,0x81,0x00,0x01,0xff,0x61,0xcc,0x8a, + 0xcc,0x81,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xc3,0x86,0xcc,0x81,0x00,0x01,0xff, + 0xc3,0xa6,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xc3,0x98,0xcc,0x81,0x00,0x01,0xff, + 0xc3,0xb8,0xcc,0x81,0x00,0xe2,0x07,0x02,0xe1,0xae,0x01,0xe0,0x93,0x01,0xcf,0x86, + 0xd5,0xf4,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x41,0xcc, + 0x8f,0x00,0x01,0xff,0x61,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x41,0xcc,0x91,0x00, + 0x01,0xff,0x61,0xcc,0x91,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x45,0xcc,0x8f,0x00, + 0x01,0xff,0x65,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x45,0xcc,0x91,0x00,0x01,0xff, + 0x65,0xcc,0x91,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x49,0xcc,0x8f,0x00, + 0x01,0xff,0x69,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x49,0xcc,0x91,0x00,0x01,0xff, + 0x69,0xcc,0x91,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x4f,0xcc,0x8f,0x00,0x01,0xff, + 0x6f,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x4f,0xcc,0x91,0x00,0x01,0xff,0x6f,0xcc, + 0x91,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x52,0xcc,0x8f,0x00, + 0x01,0xff,0x72,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x52,0xcc,0x91,0x00,0x01,0xff, + 0x72,0xcc,0x91,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0x8f,0x00,0x01,0xff, + 0x75,0xcc,0x8f,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0x91,0x00,0x01,0xff,0x75,0xcc, + 0x91,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x04,0xff,0x53,0xcc,0xa6,0x00,0x04,0xff, + 0x73,0xcc,0xa6,0x00,0x10,0x08,0x04,0xff,0x54,0xcc,0xa6,0x00,0x04,0xff,0x74,0xcc, + 0xa6,0x00,0x51,0x04,0x04,0x00,0x10,0x08,0x04,0xff,0x48,0xcc,0x8c,0x00,0x04,0xff, + 0x68,0xcc,0x8c,0x00,0xd4,0x68,0xd3,0x20,0xd2,0x0c,0x91,0x08,0x10,0x04,0x06,0x00, + 0x07,0x00,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x08,0x04,0xff,0x41,0xcc,0x87,0x00, + 0x04,0xff,0x61,0xcc,0x87,0x00,0xd2,0x24,0xd1,0x10,0x10,0x08,0x04,0xff,0x45,0xcc, + 0xa7,0x00,0x04,0xff,0x65,0xcc,0xa7,0x00,0x10,0x0a,0x04,0xff,0x4f,0xcc,0x88,0xcc, + 0x84,0x00,0x04,0xff,0x6f,0xcc,0x88,0xcc,0x84,0x00,0xd1,0x14,0x10,0x0a,0x04,0xff, + 0x4f,0xcc,0x83,0xcc,0x84,0x00,0x04,0xff,0x6f,0xcc,0x83,0xcc,0x84,0x00,0x10,0x08, + 0x04,0xff,0x4f,0xcc,0x87,0x00,0x04,0xff,0x6f,0xcc,0x87,0x00,0x93,0x30,0xd2,0x24, + 0xd1,0x14,0x10,0x0a,0x04,0xff,0x4f,0xcc,0x87,0xcc,0x84,0x00,0x04,0xff,0x6f,0xcc, + 0x87,0xcc,0x84,0x00,0x10,0x08,0x04,0xff,0x59,0xcc,0x84,0x00,0x04,0xff,0x79,0xcc, + 0x84,0x00,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00,0x08,0x00,0x08,0x00,0xcf,0x86, + 0x95,0x14,0x94,0x10,0x93,0x0c,0x92,0x08,0x11,0x04,0x08,0x00,0x09,0x00,0x09,0x00, + 0x09,0x00,0x01,0x00,0x01,0x00,0xd0,0x22,0xcf,0x86,0x55,0x04,0x01,0x00,0x94,0x18, + 0x53,0x04,0x01,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x04,0x00,0x04,0x00, + 0x11,0x04,0x04,0x00,0x07,0x00,0x01,0x00,0xcf,0x86,0xd5,0x18,0x54,0x04,0x01,0x00, + 0x53,0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00, + 0x04,0x00,0x94,0x18,0x53,0x04,0x01,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x04,0x00, + 0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x07,0x00,0x07,0x00,0xe1,0x35,0x01,0xd0, + 0x72,0xcf,0x86,0xd5,0x24,0x54,0x04,0x01,0xe6,0xd3,0x10,0x52,0x04,0x01,0xe6,0x91, + 0x08,0x10,0x04,0x01,0xe6,0x01,0xe8,0x01,0xdc,0x92,0x0c,0x51,0x04,0x01,0xdc,0x10, + 0x04,0x01,0xe8,0x01,0xd8,0x01,0xdc,0xd4,0x2c,0xd3,0x1c,0xd2,0x10,0xd1,0x08,0x10, + 0x04,0x01,0xdc,0x01,0xca,0x10,0x04,0x01,0xca,0x01,0xdc,0x51,0x04,0x01,0xdc,0x10, + 0x04,0x01,0xdc,0x01,0xca,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0xca,0x01,0xdc,0x01, + 0xdc,0x01,0xdc,0xd3,0x08,0x12,0x04,0x01,0xdc,0x01,0x01,0xd2,0x0c,0x91,0x08,0x10, + 0x04,0x01,0x01,0x01,0xdc,0x01,0xdc,0x91,0x08,0x10,0x04,0x01,0xdc,0x01,0xe6,0x01, + 0xe6,0xcf,0x86,0xd5,0x7f,0xd4,0x47,0xd3,0x2e,0xd2,0x19,0xd1,0x0e,0x10,0x07,0x01, + 0xff,0xcc,0x80,0x00,0x01,0xff,0xcc,0x81,0x00,0x10,0x04,0x01,0xe6,0x01,0xff,0xcc, + 0x93,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xcc,0x88,0xcc,0x81,0x00,0x01,0xf0,0x10, + 0x04,0x04,0xe6,0x04,0xdc,0xd2,0x08,0x11,0x04,0x04,0xdc,0x04,0xe6,0xd1,0x08,0x10, + 0x04,0x04,0xe6,0x04,0xdc,0x10,0x04,0x04,0xdc,0x06,0xff,0x00,0xd3,0x18,0xd2,0x0c, + 0x51,0x04,0x07,0xe6,0x10,0x04,0x07,0xe6,0x07,0xdc,0x51,0x04,0x07,0xdc,0x10,0x04, + 0x07,0xdc,0x07,0xe6,0xd2,0x10,0xd1,0x08,0x10,0x04,0x08,0xe8,0x08,0xdc,0x10,0x04, + 0x08,0xdc,0x08,0xe6,0xd1,0x08,0x10,0x04,0x08,0xe9,0x07,0xea,0x10,0x04,0x07,0xea, + 0x07,0xe9,0xd4,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x01,0xea,0x10,0x04,0x04,0xe9, + 0x06,0xe6,0x06,0xe6,0x06,0xe6,0xd3,0x13,0x52,0x04,0x0a,0x00,0x91,0x0b,0x10,0x07, + 0x01,0xff,0xca,0xb9,0x00,0x01,0x00,0x0a,0x00,0xd2,0x0c,0x51,0x04,0x00,0x00,0x10, + 0x04,0x01,0x00,0x09,0x00,0x51,0x04,0x09,0x00,0x10,0x06,0x01,0xff,0x3b,0x00,0x10, + 0x00,0xd0,0xe1,0xcf,0x86,0xd5,0x7a,0xd4,0x5f,0xd3,0x21,0x52,0x04,0x00,0x00,0xd1, + 0x0d,0x10,0x04,0x01,0x00,0x01,0xff,0xc2,0xa8,0xcc,0x81,0x00,0x10,0x09,0x01,0xff, + 0xce,0x91,0xcc,0x81,0x00,0x01,0xff,0xc2,0xb7,0x00,0xd2,0x1f,0xd1,0x12,0x10,0x09, + 0x01,0xff,0xce,0x95,0xcc,0x81,0x00,0x01,0xff,0xce,0x97,0xcc,0x81,0x00,0x10,0x09, + 0x01,0xff,0xce,0x99,0xcc,0x81,0x00,0x00,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xce, + 0x9f,0xcc,0x81,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xce,0xa5,0xcc,0x81,0x00,0x01, + 0xff,0xce,0xa9,0xcc,0x81,0x00,0x93,0x17,0x92,0x13,0x91,0x0f,0x10,0x0b,0x01,0xff, + 0xce,0xb9,0xcc,0x88,0xcc,0x81,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4, + 0x4a,0xd3,0x10,0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x01, + 0x00,0xd2,0x16,0x51,0x04,0x01,0x00,0x10,0x09,0x01,0xff,0xce,0x99,0xcc,0x88,0x00, + 0x01,0xff,0xce,0xa5,0xcc,0x88,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc, + 0x81,0x00,0x01,0xff,0xce,0xb5,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce,0xb7,0xcc, + 0x81,0x00,0x01,0xff,0xce,0xb9,0xcc,0x81,0x00,0x93,0x17,0x92,0x13,0x91,0x0f,0x10, + 0x0b,0x01,0xff,0xcf,0x85,0xcc,0x88,0xcc,0x81,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0xcf,0x86,0xd5,0x7b,0xd4,0x39,0x53,0x04,0x01,0x00,0xd2,0x16,0x51,0x04, + 0x01,0x00,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x88,0x00,0x01,0xff,0xcf,0x85,0xcc, + 0x88,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xbf,0xcc,0x81,0x00,0x01,0xff,0xcf, + 0x85,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xcf,0x89,0xcc,0x81,0x00,0x0a,0x00,0xd3, + 0x26,0xd2,0x11,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xcf,0x92,0xcc, + 0x81,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xcf,0x92,0xcc,0x88,0x00,0x01,0x00,0x10, + 0x04,0x01,0x00,0x04,0x00,0xd2,0x0c,0x51,0x04,0x06,0x00,0x10,0x04,0x01,0x00,0x04, + 0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x04,0x00,0x10,0x04,0x01,0x00,0x04,0x00,0xd4, + 0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x04,0x00,0x01,0x00,0x01, + 0x00,0x01,0x00,0xd3,0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x05,0x00,0x10,0x04,0x06, + 0x00,0x07,0x00,0x12,0x04,0x07,0x00,0x08,0x00,0xe3,0x47,0x04,0xe2,0xbe,0x02,0xe1, + 0x07,0x01,0xd0,0x8b,0xcf,0x86,0xd5,0x6c,0xd4,0x53,0xd3,0x30,0xd2,0x1f,0xd1,0x12, + 0x10,0x09,0x04,0xff,0xd0,0x95,0xcc,0x80,0x00,0x01,0xff,0xd0,0x95,0xcc,0x88,0x00, + 0x10,0x04,0x01,0x00,0x01,0xff,0xd0,0x93,0xcc,0x81,0x00,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x01,0xff,0xd0,0x86,0xcc,0x88,0x00,0x52,0x04,0x01,0x00,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xd0,0x9a,0xcc,0x81,0x00,0x04,0xff,0xd0,0x98,0xcc,0x80,0x00, + 0x10,0x09,0x01,0xff,0xd0,0xa3,0xcc,0x86,0x00,0x01,0x00,0x53,0x04,0x01,0x00,0x92, + 0x11,0x91,0x0d,0x10,0x04,0x01,0x00,0x01,0xff,0xd0,0x98,0xcc,0x86,0x00,0x01,0x00, + 0x01,0x00,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0x92,0x11,0x91,0x0d,0x10,0x04, + 0x01,0x00,0x01,0xff,0xd0,0xb8,0xcc,0x86,0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0xd5, + 0x57,0x54,0x04,0x01,0x00,0xd3,0x30,0xd2,0x1f,0xd1,0x12,0x10,0x09,0x04,0xff,0xd0, + 0xb5,0xcc,0x80,0x00,0x01,0xff,0xd0,0xb5,0xcc,0x88,0x00,0x10,0x04,0x01,0x00,0x01, + 0xff,0xd0,0xb3,0xcc,0x81,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff, + 0xd1,0x96,0xcc,0x88,0x00,0x52,0x04,0x01,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd0, + 0xba,0xcc,0x81,0x00,0x04,0xff,0xd0,0xb8,0xcc,0x80,0x00,0x10,0x09,0x01,0xff,0xd1, + 0x83,0xcc,0x86,0x00,0x01,0x00,0x54,0x04,0x01,0x00,0x93,0x1a,0x52,0x04,0x01,0x00, + 0x51,0x04,0x01,0x00,0x10,0x09,0x01,0xff,0xd1,0xb4,0xcc,0x8f,0x00,0x01,0xff,0xd1, + 0xb5,0xcc,0x8f,0x00,0x01,0x00,0xd0,0x2e,0xcf,0x86,0x95,0x28,0x94,0x24,0xd3,0x18, + 0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xe6,0x51,0x04,0x01,0xe6, + 0x10,0x04,0x01,0xe6,0x0a,0xe6,0x92,0x08,0x11,0x04,0x04,0x00,0x06,0x00,0x04,0x00, + 0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0xbe,0xd4,0x4a,0xd3,0x2a,0xd2,0x1a,0xd1,0x0d, + 0x10,0x04,0x01,0x00,0x01,0xff,0xd0,0x96,0xcc,0x86,0x00,0x10,0x09,0x01,0xff,0xd0, + 0xb6,0xcc,0x86,0x00,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x06,0x00,0x10,0x04, + 0x06,0x00,0x01,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x06,0x00,0x10,0x04, + 0x06,0x00,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x06,0x00,0x10,0x04,0x06,0x00, + 0x09,0x00,0xd3,0x3a,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd0,0x90,0xcc,0x86, + 0x00,0x01,0xff,0xd0,0xb0,0xcc,0x86,0x00,0x10,0x09,0x01,0xff,0xd0,0x90,0xcc,0x88, + 0x00,0x01,0xff,0xd0,0xb0,0xcc,0x88,0x00,0x51,0x04,0x01,0x00,0x10,0x09,0x01,0xff, + 0xd0,0x95,0xcc,0x86,0x00,0x01,0xff,0xd0,0xb5,0xcc,0x86,0x00,0xd2,0x16,0x51,0x04, + 0x01,0x00,0x10,0x09,0x01,0xff,0xd3,0x98,0xcc,0x88,0x00,0x01,0xff,0xd3,0x99,0xcc, + 0x88,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd0,0x96,0xcc,0x88,0x00,0x01,0xff,0xd0, + 0xb6,0xcc,0x88,0x00,0x10,0x09,0x01,0xff,0xd0,0x97,0xcc,0x88,0x00,0x01,0xff,0xd0, + 0xb7,0xcc,0x88,0x00,0xd4,0x74,0xd3,0x3a,0xd2,0x16,0x51,0x04,0x01,0x00,0x10,0x09, + 0x01,0xff,0xd0,0x98,0xcc,0x84,0x00,0x01,0xff,0xd0,0xb8,0xcc,0x84,0x00,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xd0,0x98,0xcc,0x88,0x00,0x01,0xff,0xd0,0xb8,0xcc,0x88,0x00, + 0x10,0x09,0x01,0xff,0xd0,0x9e,0xcc,0x88,0x00,0x01,0xff,0xd0,0xbe,0xcc,0x88,0x00, + 0xd2,0x16,0x51,0x04,0x01,0x00,0x10,0x09,0x01,0xff,0xd3,0xa8,0xcc,0x88,0x00,0x01, + 0xff,0xd3,0xa9,0xcc,0x88,0x00,0xd1,0x12,0x10,0x09,0x04,0xff,0xd0,0xad,0xcc,0x88, + 0x00,0x04,0xff,0xd1,0x8d,0xcc,0x88,0x00,0x10,0x09,0x01,0xff,0xd0,0xa3,0xcc,0x84, + 0x00,0x01,0xff,0xd1,0x83,0xcc,0x84,0x00,0xd3,0x3a,0xd2,0x24,0xd1,0x12,0x10,0x09, + 0x01,0xff,0xd0,0xa3,0xcc,0x88,0x00,0x01,0xff,0xd1,0x83,0xcc,0x88,0x00,0x10,0x09, + 0x01,0xff,0xd0,0xa3,0xcc,0x8b,0x00,0x01,0xff,0xd1,0x83,0xcc,0x8b,0x00,0x91,0x12, + 0x10,0x09,0x01,0xff,0xd0,0xa7,0xcc,0x88,0x00,0x01,0xff,0xd1,0x87,0xcc,0x88,0x00, + 0x08,0x00,0x92,0x16,0x91,0x12,0x10,0x09,0x01,0xff,0xd0,0xab,0xcc,0x88,0x00,0x01, + 0xff,0xd1,0x8b,0xcc,0x88,0x00,0x09,0x00,0x09,0x00,0xd1,0x74,0xd0,0x36,0xcf,0x86, + 0xd5,0x10,0x54,0x04,0x06,0x00,0x93,0x08,0x12,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00, + 0xd4,0x10,0x93,0x0c,0x52,0x04,0x0a,0x00,0x11,0x04,0x0b,0x00,0x0c,0x00,0x10,0x00, + 0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0xcf,0x86,0xd5,0x24,0x54,0x04,0x01,0x00,0xd3,0x10,0x52,0x04,0x01,0x00, + 0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x14,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd0,0xba, + 0xcf,0x86,0xd5,0x4c,0xd4,0x24,0x53,0x04,0x01,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04, + 0x14,0x00,0x01,0x00,0x10,0x04,0x04,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x00,0x00, + 0x10,0x00,0x10,0x04,0x10,0x00,0x0d,0x00,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04, + 0x00,0x00,0x02,0xdc,0x02,0xe6,0x51,0x04,0x02,0xe6,0x10,0x04,0x02,0xdc,0x02,0xe6, + 0x92,0x0c,0x51,0x04,0x02,0xe6,0x10,0x04,0x02,0xde,0x02,0xdc,0x02,0xe6,0xd4,0x2c, + 0xd3,0x10,0x92,0x0c,0x51,0x04,0x02,0xe6,0x10,0x04,0x08,0xdc,0x02,0xdc,0x02,0xdc, + 0xd2,0x0c,0x51,0x04,0x02,0xe6,0x10,0x04,0x02,0xdc,0x02,0xe6,0xd1,0x08,0x10,0x04, + 0x02,0xe6,0x02,0xde,0x10,0x04,0x02,0xe4,0x02,0xe6,0xd3,0x20,0xd2,0x10,0xd1,0x08, + 0x10,0x04,0x01,0x0a,0x01,0x0b,0x10,0x04,0x01,0x0c,0x01,0x0d,0xd1,0x08,0x10,0x04, + 0x01,0x0e,0x01,0x0f,0x10,0x04,0x01,0x10,0x01,0x11,0xd2,0x10,0xd1,0x08,0x10,0x04, + 0x01,0x12,0x01,0x13,0x10,0x04,0x09,0x13,0x01,0x14,0xd1,0x08,0x10,0x04,0x01,0x15, + 0x01,0x16,0x10,0x04,0x01,0x00,0x01,0x17,0xcf,0x86,0xd5,0x28,0x94,0x24,0x93,0x20, + 0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x01,0x18,0x10,0x04,0x01,0x19,0x01,0x00, + 0xd1,0x08,0x10,0x04,0x02,0xe6,0x08,0xdc,0x10,0x04,0x08,0x00,0x08,0x12,0x00,0x00, + 0x01,0x00,0xd4,0x1c,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04, + 0x01,0x00,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x14,0x00,0x93,0x10, + 0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe2,0xfb,0x01,0xe1,0x2b,0x01,0xd0,0xa8,0xcf,0x86,0xd5,0x55,0xd4,0x28,0xd3,0x10, + 0x52,0x04,0x07,0x00,0x91,0x08,0x10,0x04,0x0d,0x00,0x10,0x00,0x0a,0x00,0xd2,0x0c, + 0x51,0x04,0x0a,0x00,0x10,0x04,0x0a,0x00,0x08,0x00,0x91,0x08,0x10,0x04,0x01,0x00, + 0x07,0x00,0x07,0x00,0xd3,0x0c,0x52,0x04,0x07,0xe6,0x11,0x04,0x07,0xe6,0x0a,0xe6, + 0xd2,0x10,0xd1,0x08,0x10,0x04,0x0a,0x1e,0x0a,0x1f,0x10,0x04,0x0a,0x20,0x01,0x00, + 0xd1,0x09,0x10,0x05,0x0f,0xff,0x00,0x00,0x00,0x10,0x04,0x08,0x00,0x01,0x00,0xd4, + 0x3d,0x93,0x39,0xd2,0x1a,0xd1,0x08,0x10,0x04,0x0c,0x00,0x01,0x00,0x10,0x09,0x01, + 0xff,0xd8,0xa7,0xd9,0x93,0x00,0x01,0xff,0xd8,0xa7,0xd9,0x94,0x00,0xd1,0x12,0x10, + 0x09,0x01,0xff,0xd9,0x88,0xd9,0x94,0x00,0x01,0xff,0xd8,0xa7,0xd9,0x95,0x00,0x10, + 0x09,0x01,0xff,0xd9,0x8a,0xd9,0x94,0x00,0x01,0x00,0x01,0x00,0x53,0x04,0x01,0x00, + 0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x0a,0x00,0x0a,0x00,0xcf,0x86, + 0xd5,0x5c,0xd4,0x20,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04, + 0x01,0x00,0x01,0x1b,0xd1,0x08,0x10,0x04,0x01,0x1c,0x01,0x1d,0x10,0x04,0x01,0x1e, + 0x01,0x1f,0xd3,0x20,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x20,0x01,0x21,0x10,0x04, + 0x01,0x22,0x04,0xe6,0xd1,0x08,0x10,0x04,0x04,0xe6,0x04,0xdc,0x10,0x04,0x07,0xdc, + 0x07,0xe6,0xd2,0x0c,0x91,0x08,0x10,0x04,0x07,0xe6,0x08,0xe6,0x08,0xe6,0xd1,0x08, + 0x10,0x04,0x08,0xdc,0x08,0xe6,0x10,0x04,0x08,0xe6,0x0c,0xdc,0xd4,0x10,0x53,0x04, + 0x01,0x00,0x52,0x04,0x01,0x00,0x11,0x04,0x01,0x00,0x06,0x00,0x93,0x10,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x01,0x23,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd0,0x22, + 0xcf,0x86,0x55,0x04,0x01,0x00,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x08, + 0x11,0x04,0x04,0x00,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x04,0x00, + 0xcf,0x86,0xd5,0x5b,0xd4,0x2e,0xd3,0x1e,0x92,0x1a,0xd1,0x0d,0x10,0x09,0x01,0xff, + 0xdb,0x95,0xd9,0x94,0x00,0x01,0x00,0x10,0x09,0x01,0xff,0xdb,0x81,0xd9,0x94,0x00, + 0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00, + 0x04,0x00,0xd3,0x19,0xd2,0x11,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff, + 0xdb,0x92,0xd9,0x94,0x00,0x11,0x04,0x01,0x00,0x01,0xe6,0x52,0x04,0x01,0xe6,0xd1, + 0x08,0x10,0x04,0x01,0xe6,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xe6,0xd4,0x38,0xd3, + 0x1c,0xd2,0x0c,0x51,0x04,0x01,0xe6,0x10,0x04,0x01,0xe6,0x01,0xdc,0xd1,0x08,0x10, + 0x04,0x01,0xe6,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xe6,0xd2,0x10,0xd1,0x08,0x10, + 0x04,0x01,0xe6,0x01,0x00,0x10,0x04,0x01,0xdc,0x01,0xe6,0x91,0x08,0x10,0x04,0x01, + 0xe6,0x01,0xdc,0x07,0x00,0x53,0x04,0x01,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x04, + 0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x07,0x00,0xd1,0xc8,0xd0,0x76,0xcf, + 0x86,0xd5,0x28,0xd4,0x14,0x53,0x04,0x04,0x00,0x52,0x04,0x04,0x00,0x51,0x04,0x04, + 0x00,0x10,0x04,0x00,0x00,0x04,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x04, + 0x00,0x04,0x24,0x04,0x00,0x04,0x00,0x04,0x00,0xd4,0x14,0x53,0x04,0x04,0x00,0x52, + 0x04,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x07,0x00,0x07,0x00,0xd3,0x1c,0xd2, + 0x0c,0x91,0x08,0x10,0x04,0x04,0xe6,0x04,0xdc,0x04,0xe6,0xd1,0x08,0x10,0x04,0x04, + 0xdc,0x04,0xe6,0x10,0x04,0x04,0xe6,0x04,0xdc,0xd2,0x0c,0x51,0x04,0x04,0xdc,0x10, + 0x04,0x04,0xe6,0x04,0xdc,0xd1,0x08,0x10,0x04,0x04,0xdc,0x04,0xe6,0x10,0x04,0x04, + 0xdc,0x04,0xe6,0xcf,0x86,0xd5,0x3c,0x94,0x38,0xd3,0x1c,0xd2,0x0c,0x51,0x04,0x04, + 0xe6,0x10,0x04,0x04,0xdc,0x04,0xe6,0xd1,0x08,0x10,0x04,0x04,0xdc,0x04,0xe6,0x10, + 0x04,0x04,0xdc,0x04,0xe6,0xd2,0x10,0xd1,0x08,0x10,0x04,0x04,0xdc,0x04,0xe6,0x10, + 0x04,0x04,0xe6,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x07,0x00,0x07,0x00,0x08, + 0x00,0x94,0x10,0x53,0x04,0x08,0x00,0x52,0x04,0x08,0x00,0x11,0x04,0x08,0x00,0x0a, + 0x00,0x0a,0x00,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x04,0x00,0x54,0x04,0x04,0x00,0x93, + 0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x04,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xcf,0x86,0x55,0x04,0x09,0x00,0xd4,0x14,0x53,0x04,0x09,0x00,0x92,0x0c,0x51, + 0x04,0x09,0x00,0x10,0x04,0x09,0x00,0x09,0xe6,0x09,0xe6,0xd3,0x10,0x92,0x0c,0x51, + 0x04,0x09,0xe6,0x10,0x04,0x09,0xdc,0x09,0xe6,0x09,0x00,0xd2,0x0c,0x51,0x04,0x09, + 0x00,0x10,0x04,0x09,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x14,0xdc,0x14, + 0x00,0xe4,0xf8,0x57,0xe3,0x45,0x3f,0xe2,0xf4,0x3e,0xe1,0xc7,0x2c,0xe0,0x21,0x10, + 0xcf,0x86,0xc5,0xe4,0x80,0x08,0xe3,0xcb,0x03,0xe2,0x61,0x01,0xd1,0x94,0xd0,0x5a, + 0xcf,0x86,0xd5,0x20,0x54,0x04,0x0b,0x00,0xd3,0x0c,0x52,0x04,0x0b,0x00,0x11,0x04, + 0x0b,0x00,0x0b,0xe6,0x92,0x0c,0x51,0x04,0x0b,0xe6,0x10,0x04,0x0b,0x00,0x0b,0xe6, + 0x0b,0xe6,0xd4,0x24,0xd3,0x10,0x52,0x04,0x0b,0xe6,0x91,0x08,0x10,0x04,0x0b,0x00, + 0x0b,0xe6,0x0b,0xe6,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0b,0x00,0x0b,0xe6,0x0b,0xe6, + 0x11,0x04,0x0b,0xe6,0x00,0x00,0x53,0x04,0x0b,0x00,0x52,0x04,0x0b,0x00,0x51,0x04, + 0x0b,0x00,0x10,0x04,0x0b,0x00,0x00,0x00,0xcf,0x86,0xd5,0x20,0x54,0x04,0x0c,0x00, + 0x53,0x04,0x0c,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x0c,0xdc,0x0c,0xdc, + 0x51,0x04,0x00,0x00,0x10,0x04,0x0c,0x00,0x00,0x00,0x94,0x14,0x53,0x04,0x13,0x00, + 0x92,0x0c,0x51,0x04,0x13,0x00,0x10,0x04,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd0,0x4a,0xcf,0x86,0x55,0x04,0x00,0x00,0xd4,0x20,0xd3,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0d,0x00,0x10,0x00,0x0d,0x00,0x0d,0x00,0x52,0x04,0x0d,0x00,0x91,0x08, + 0x10,0x04,0x0d,0x00,0x10,0x00,0x10,0x00,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x10,0x00, + 0x10,0x04,0x10,0x00,0x11,0x00,0x91,0x08,0x10,0x04,0x11,0x00,0x00,0x00,0x12,0x00, + 0x52,0x04,0x12,0x00,0x11,0x04,0x12,0x00,0x00,0x00,0xcf,0x86,0xd5,0x18,0x54,0x04, + 0x00,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x14,0xdc, + 0x12,0xe6,0x12,0xe6,0xd4,0x30,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x12,0xe6,0x10,0x04, + 0x12,0x00,0x11,0xdc,0x51,0x04,0x0d,0xe6,0x10,0x04,0x0d,0xdc,0x0d,0xe6,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x0d,0xe6,0x0d,0xdc,0x0d,0xe6,0x91,0x08,0x10,0x04,0x0d,0xe6, + 0x0d,0xdc,0x0d,0xdc,0xd3,0x1c,0xd2,0x10,0xd1,0x08,0x10,0x04,0x0d,0x1b,0x0d,0x1c, + 0x10,0x04,0x0d,0x1d,0x0d,0xe6,0x51,0x04,0x0d,0xe6,0x10,0x04,0x0d,0xdc,0x0d,0xe6, + 0xd2,0x10,0xd1,0x08,0x10,0x04,0x0d,0xe6,0x0d,0xdc,0x10,0x04,0x0d,0xdc,0x0d,0xe6, + 0x51,0x04,0x0d,0xe6,0x10,0x04,0x0d,0xe6,0x10,0xe6,0xe1,0x3a,0x01,0xd0,0x77,0xcf, + 0x86,0xd5,0x20,0x94,0x1c,0x93,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0b,0x00,0x01, + 0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x07,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, + 0x00,0xd4,0x1b,0x53,0x04,0x01,0x00,0x92,0x13,0x91,0x0f,0x10,0x04,0x01,0x00,0x01, + 0xff,0xe0,0xa4,0xa8,0xe0,0xa4,0xbc,0x00,0x01,0x00,0x01,0x00,0xd3,0x26,0xd2,0x13, + 0x91,0x0f,0x10,0x04,0x01,0x00,0x01,0xff,0xe0,0xa4,0xb0,0xe0,0xa4,0xbc,0x00,0x01, + 0x00,0x91,0x0f,0x10,0x0b,0x01,0xff,0xe0,0xa4,0xb3,0xe0,0xa4,0xbc,0x00,0x01,0x00, + 0x01,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x0c,0x00,0x91,0x08,0x10,0x04,0x01,0x07, + 0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0x8c,0xd4,0x18,0x53,0x04,0x01,0x00,0x52,0x04, + 0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x01,0x09,0x10,0x04,0x0b,0x00,0x0c,0x00, + 0xd3,0x1c,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x01,0xe6,0x10,0x04,0x01,0xdc, + 0x01,0xe6,0x91,0x08,0x10,0x04,0x01,0xe6,0x0b,0x00,0x0c,0x00,0xd2,0x2c,0xd1,0x16, + 0x10,0x0b,0x01,0xff,0xe0,0xa4,0x95,0xe0,0xa4,0xbc,0x00,0x01,0xff,0xe0,0xa4,0x96, + 0xe0,0xa4,0xbc,0x00,0x10,0x0b,0x01,0xff,0xe0,0xa4,0x97,0xe0,0xa4,0xbc,0x00,0x01, + 0xff,0xe0,0xa4,0x9c,0xe0,0xa4,0xbc,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xe0,0xa4, + 0xa1,0xe0,0xa4,0xbc,0x00,0x01,0xff,0xe0,0xa4,0xa2,0xe0,0xa4,0xbc,0x00,0x10,0x0b, + 0x01,0xff,0xe0,0xa4,0xab,0xe0,0xa4,0xbc,0x00,0x01,0xff,0xe0,0xa4,0xaf,0xe0,0xa4, + 0xbc,0x00,0x54,0x04,0x01,0x00,0xd3,0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x01,0x00, + 0x0a,0x00,0x10,0x04,0x0a,0x00,0x0c,0x00,0x0c,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04, + 0x10,0x00,0x0b,0x00,0x10,0x04,0x0b,0x00,0x09,0x00,0x91,0x08,0x10,0x04,0x09,0x00, + 0x08,0x00,0x09,0x00,0xd0,0x86,0xcf,0x86,0xd5,0x44,0xd4,0x2c,0xd3,0x18,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x10,0x00,0x01,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00, + 0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00, + 0x10,0x04,0x00,0x00,0x01,0x00,0x93,0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x01,0x00, + 0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04, + 0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0xd3,0x18,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x01,0x00, + 0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00, + 0x91,0x08,0x10,0x04,0x01,0x07,0x07,0x00,0x01,0x00,0xcf,0x86,0xd5,0x7b,0xd4,0x42, + 0xd3,0x14,0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04, + 0x00,0x00,0x01,0x00,0xd2,0x17,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04, + 0x00,0x00,0x01,0xff,0xe0,0xa7,0x87,0xe0,0xa6,0xbe,0x00,0xd1,0x0f,0x10,0x0b,0x01, + 0xff,0xe0,0xa7,0x87,0xe0,0xa7,0x97,0x00,0x01,0x09,0x10,0x04,0x08,0x00,0x00,0x00, + 0xd3,0x10,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00, + 0x52,0x04,0x00,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xe0,0xa6,0xa1,0xe0,0xa6,0xbc, + 0x00,0x01,0xff,0xe0,0xa6,0xa2,0xe0,0xa6,0xbc,0x00,0x10,0x04,0x00,0x00,0x01,0xff, + 0xe0,0xa6,0xaf,0xe0,0xa6,0xbc,0x00,0xd4,0x10,0x93,0x0c,0x52,0x04,0x01,0x00,0x11, + 0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x01,0x00,0x0b,0x00,0x51,0x04,0x13,0x00,0x10,0x04,0x14,0xe6,0x00, + 0x00,0xe2,0x48,0x02,0xe1,0x4f,0x01,0xd0,0xa4,0xcf,0x86,0xd5,0x4c,0xd4,0x34,0xd3, + 0x1c,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x07,0x00,0x10,0x04,0x01,0x00,0x07, + 0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01, + 0x00,0x93,0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x00, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01,0x00,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd3,0x2e,0xd2,0x17,0xd1, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xe0,0xa8,0xb2, + 0xe0,0xa8,0xbc,0x00,0xd1,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x10,0x0b,0x01,0xff, + 0xe0,0xa8,0xb8,0xe0,0xa8,0xbc,0x00,0x00,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x00, + 0x00,0x91,0x08,0x10,0x04,0x01,0x07,0x00,0x00,0x01,0x00,0xcf,0x86,0xd5,0x80,0xd4, + 0x34,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x51, + 0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01, + 0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x01, + 0x09,0x00,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0a,0x00,0x00, + 0x00,0x00,0x00,0xd2,0x25,0xd1,0x0f,0x10,0x04,0x00,0x00,0x01,0xff,0xe0,0xa8,0x96, + 0xe0,0xa8,0xbc,0x00,0x10,0x0b,0x01,0xff,0xe0,0xa8,0x97,0xe0,0xa8,0xbc,0x00,0x01, + 0xff,0xe0,0xa8,0x9c,0xe0,0xa8,0xbc,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00, + 0x10,0x0b,0x01,0xff,0xe0,0xa8,0xab,0xe0,0xa8,0xbc,0x00,0x00,0x00,0xd4,0x10,0x93, + 0x0c,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x93,0x14,0x52, + 0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x0a,0x00,0x10,0x04,0x14,0x00,0x00, + 0x00,0x00,0x00,0xd0,0x82,0xcf,0x86,0xd5,0x40,0xd4,0x2c,0xd3,0x18,0xd2,0x0c,0x91, + 0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01, + 0x00,0x01,0x00,0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x07,0x00,0x01,0x00,0x10, + 0x04,0x00,0x00,0x01,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x00, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01,0x00,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd3,0x18,0xd2,0x0c,0x91, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01, + 0x00,0x01,0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x01, + 0x07,0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0x3c,0xd4,0x28,0xd3,0x10,0x52,0x04,0x01, + 0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x01,0x09,0x00, + 0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0xd4,0x18,0x93,0x14,0xd2,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x07, + 0x00,0x07,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd3,0x10,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x0d,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x11,0x00,0x13,0x00,0x13,0x00,0xe1,0x24,0x01,0xd0,0x86,0xcf,0x86, + 0xd5,0x44,0xd4,0x2c,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00, + 0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00, + 0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x93,0x14, + 0x92,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04, + 0x01,0x00,0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x07,0x00,0x01,0x00, + 0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x01,0x07,0x01,0x00, + 0x01,0x00,0xcf,0x86,0xd5,0x73,0xd4,0x45,0xd3,0x14,0x52,0x04,0x01,0x00,0xd1,0x08, + 0x10,0x04,0x0a,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0xd2,0x1e,0xd1,0x0f, + 0x10,0x0b,0x01,0xff,0xe0,0xad,0x87,0xe0,0xad,0x96,0x00,0x00,0x00,0x10,0x04,0x00, + 0x00,0x01,0xff,0xe0,0xad,0x87,0xe0,0xac,0xbe,0x00,0x91,0x0f,0x10,0x0b,0x01,0xff, + 0xe0,0xad,0x87,0xe0,0xad,0x97,0x00,0x01,0x09,0x00,0x00,0xd3,0x0c,0x52,0x04,0x00, + 0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x52,0x04,0x00,0x00,0xd1,0x16,0x10,0x0b,0x01, + 0xff,0xe0,0xac,0xa1,0xe0,0xac,0xbc,0x00,0x01,0xff,0xe0,0xac,0xa2,0xe0,0xac,0xbc, + 0x00,0x10,0x04,0x00,0x00,0x01,0x00,0xd4,0x14,0x93,0x10,0xd2,0x08,0x11,0x04,0x01, + 0x00,0x0a,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x93,0x10,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x01,0x00,0x07,0x00,0x0c,0x00,0x0c,0x00,0x00,0x00,0xd0,0xb1,0xcf, + 0x86,0xd5,0x63,0xd4,0x28,0xd3,0x14,0xd2,0x08,0x11,0x04,0x00,0x00,0x01,0x00,0x91, + 0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0xd3,0x1f,0xd2,0x0c,0x91, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x91,0x0f,0x10,0x0b,0x01,0xff,0xe0, + 0xae,0x92,0xe0,0xaf,0x97,0x00,0x01,0x00,0x00,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04, + 0x00,0x00,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x01,0x00, + 0x00,0x00,0x01,0x00,0xd4,0x2c,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x00,0x00,0x10,0x04, + 0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0xd2,0x0c, + 0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00, + 0xd3,0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x08,0x00,0x01,0x00, + 0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0xcf,0x86, + 0xd5,0x61,0xd4,0x45,0xd3,0x14,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00, + 0x00,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0xd2,0x1e,0xd1,0x08,0x10,0x04,0x01,0x00, + 0x00,0x00,0x10,0x0b,0x01,0xff,0xe0,0xaf,0x86,0xe0,0xae,0xbe,0x00,0x01,0xff,0xe0, + 0xaf,0x87,0xe0,0xae,0xbe,0x00,0x91,0x0f,0x10,0x0b,0x01,0xff,0xe0,0xaf,0x86,0xe0, + 0xaf,0x97,0x00,0x01,0x09,0x00,0x00,0x93,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0x00, + 0x00,0xd4,0x14,0x93,0x10,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x08, + 0x00,0x01,0x00,0x01,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x07,0x00,0x07,0x00,0x92,0x0c,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00,0x00, + 0x00,0x00,0x00,0xe3,0x1c,0x04,0xe2,0x1a,0x02,0xd1,0xf3,0xd0,0x76,0xcf,0x86,0xd5, + 0x3c,0xd4,0x28,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x10,0x00,0x01,0x00,0x01, + 0x00,0x91,0x08,0x10,0x04,0x14,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0x91, + 0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01, + 0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd3, + 0x10,0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04,0x10,0x00,0x01,0x00,0x01,0x00,0xd2, + 0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x0a,0x00,0x01, + 0x00,0xcf,0x86,0xd5,0x53,0xd4,0x2f,0xd3,0x10,0x52,0x04,0x01,0x00,0x91,0x08,0x10, + 0x04,0x01,0x00,0x00,0x00,0x01,0x00,0xd2,0x13,0x91,0x0f,0x10,0x0b,0x01,0xff,0xe0, + 0xb1,0x86,0xe0,0xb1,0x96,0x00,0x00,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00, + 0x01,0x09,0x00,0x00,0xd3,0x14,0x52,0x04,0x00,0x00,0xd1,0x08,0x10,0x04,0x00,0x00, + 0x01,0x54,0x10,0x04,0x01,0x5b,0x00,0x00,0x92,0x0c,0x51,0x04,0x0a,0x00,0x10,0x04, + 0x11,0x00,0x00,0x00,0x00,0x00,0xd4,0x14,0x93,0x10,0xd2,0x08,0x11,0x04,0x01,0x00, + 0x0a,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x93,0x10,0x52,0x04,0x00,0x00, + 0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x15,0x00,0x0a,0x00,0xd0,0x76,0xcf,0x86, + 0xd5,0x3c,0xd4,0x28,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x12,0x00,0x10,0x00, + 0x01,0x00,0x91,0x08,0x10,0x04,0x14,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00, + 0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x14,0x53,0x04, + 0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0xd3,0x10,0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00, + 0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x07,0x07,0x07,0x00, + 0x01,0x00,0xcf,0x86,0xd5,0x82,0xd4,0x5e,0xd3,0x2a,0xd2,0x13,0x91,0x0f,0x10,0x0b, + 0x01,0xff,0xe0,0xb2,0xbf,0xe0,0xb3,0x95,0x00,0x01,0x00,0x01,0x00,0xd1,0x08,0x10, + 0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xe0,0xb3,0x86,0xe0,0xb3, + 0x95,0x00,0xd2,0x28,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe0,0xb3,0x86,0xe0,0xb3,0x96, + 0x00,0x00,0x00,0x10,0x0b,0x01,0xff,0xe0,0xb3,0x86,0xe0,0xb3,0x82,0x00,0x01,0xff, + 0xe0,0xb3,0x86,0xe0,0xb3,0x82,0xe0,0xb3,0x95,0x00,0x91,0x08,0x10,0x04,0x01,0x00, + 0x01,0x09,0x00,0x00,0xd3,0x14,0x52,0x04,0x00,0x00,0xd1,0x08,0x10,0x04,0x00,0x00, + 0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00, + 0x10,0x04,0x01,0x00,0x00,0x00,0xd4,0x14,0x93,0x10,0xd2,0x08,0x11,0x04,0x01,0x00, + 0x09,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x93,0x14,0x92,0x10,0xd1,0x08, + 0x10,0x04,0x00,0x00,0x09,0x00,0x10,0x04,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xe1,0x06,0x01,0xd0,0x6e,0xcf,0x86,0xd5,0x3c,0xd4,0x28,0xd3,0x18,0xd2,0x0c,0x91, + 0x08,0x10,0x04,0x13,0x00,0x10,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x01, + 0x00,0x01,0x00,0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01, + 0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01, + 0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x01, + 0x00,0x0c,0x00,0x01,0x00,0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x0c,0x00,0x13,0x09,0x91,0x08,0x10,0x04,0x13,0x09,0x0a,0x00,0x01, + 0x00,0xcf,0x86,0xd5,0x65,0xd4,0x45,0xd3,0x10,0x52,0x04,0x01,0x00,0x91,0x08,0x10, + 0x04,0x0a,0x00,0x00,0x00,0x01,0x00,0xd2,0x1e,0xd1,0x08,0x10,0x04,0x01,0x00,0x00, + 0x00,0x10,0x0b,0x01,0xff,0xe0,0xb5,0x86,0xe0,0xb4,0xbe,0x00,0x01,0xff,0xe0,0xb5, + 0x87,0xe0,0xb4,0xbe,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe0,0xb5,0x86,0xe0,0xb5, + 0x97,0x00,0x01,0x09,0x10,0x04,0x0c,0x00,0x12,0x00,0xd3,0x10,0x52,0x04,0x00,0x00, + 0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x01,0x00,0x52,0x04,0x12,0x00,0x51,0x04, + 0x12,0x00,0x10,0x04,0x12,0x00,0x11,0x00,0xd4,0x14,0x93,0x10,0xd2,0x08,0x11,0x04, + 0x01,0x00,0x0a,0x00,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd3,0x0c,0x52,0x04, + 0x0a,0x00,0x11,0x04,0x0a,0x00,0x12,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x12,0x00, + 0x0a,0x00,0x0a,0x00,0x0a,0x00,0xd0,0x5a,0xcf,0x86,0xd5,0x34,0xd4,0x18,0x93,0x14, + 0xd2,0x08,0x11,0x04,0x00,0x00,0x04,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x04,0x00, + 0x04,0x00,0x04,0x00,0xd3,0x10,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04, + 0x04,0x00,0x00,0x00,0x92,0x08,0x11,0x04,0x00,0x00,0x04,0x00,0x04,0x00,0x54,0x04, + 0x04,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x04,0x00,0x10,0x04,0x00,0x00,0x04,0x00, + 0x04,0x00,0x52,0x04,0x04,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x04,0x00,0x00,0x00, + 0xcf,0x86,0xd5,0x77,0xd4,0x28,0xd3,0x10,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00, + 0x10,0x04,0x04,0x00,0x00,0x00,0xd2,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x04,0x09, + 0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x04,0x00,0xd3,0x14,0x52,0x04, + 0x04,0x00,0xd1,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x10,0x04,0x04,0x00,0x00,0x00, + 0xd2,0x13,0x51,0x04,0x04,0x00,0x10,0x0b,0x04,0xff,0xe0,0xb7,0x99,0xe0,0xb7,0x8a, + 0x00,0x04,0x00,0xd1,0x19,0x10,0x0b,0x04,0xff,0xe0,0xb7,0x99,0xe0,0xb7,0x8f,0x00, + 0x04,0xff,0xe0,0xb7,0x99,0xe0,0xb7,0x8f,0xe0,0xb7,0x8a,0x00,0x10,0x0b,0x04,0xff, + 0xe0,0xb7,0x99,0xe0,0xb7,0x9f,0x00,0x04,0x00,0xd4,0x10,0x93,0x0c,0x52,0x04,0x00, + 0x00,0x11,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x93,0x14,0xd2,0x08,0x11,0x04,0x00, + 0x00,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe2, + 0x31,0x01,0xd1,0x58,0xd0,0x3a,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x67,0x10,0x04, + 0x01,0x09,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x01,0x00,0xcf,0x86, + 0x95,0x18,0xd4,0x0c,0x53,0x04,0x01,0x00,0x12,0x04,0x01,0x6b,0x01,0x00,0x53,0x04, + 0x01,0x00,0x12,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0xd0,0x9e,0xcf,0x86,0xd5,0x54, + 0xd4,0x3c,0xd3,0x20,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x10,0x04, + 0x01,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x15,0x00, + 0x01,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x15,0x00,0x10,0x04,0x01,0x00, + 0x00,0x00,0x91,0x08,0x10,0x04,0x15,0x00,0x01,0x00,0x15,0x00,0xd3,0x08,0x12,0x04, + 0x15,0x00,0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x15,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0xd4,0x30,0xd3,0x1c,0xd2,0x0c,0x91,0x08,0x10,0x04,0x15,0x00,0x01,0x00, + 0x01,0x00,0xd1,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x10,0x04,0x00,0x00,0x01,0x00, + 0xd2,0x08,0x11,0x04,0x15,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x15,0x00,0x01,0x00, + 0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x76,0x10,0x04,0x15,0x09, + 0x01,0x00,0x11,0x04,0x01,0x00,0x00,0x00,0xcf,0x86,0x95,0x34,0xd4,0x20,0xd3,0x14, + 0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x01,0x00, + 0x00,0x00,0x52,0x04,0x01,0x7a,0x11,0x04,0x01,0x00,0x00,0x00,0x53,0x04,0x01,0x00, + 0xd2,0x08,0x11,0x04,0x01,0x00,0x00,0x00,0x11,0x04,0x01,0x00,0x0d,0x00,0x00,0x00, + 0xe1,0x2b,0x01,0xd0,0x3e,0xcf,0x86,0xd5,0x14,0x54,0x04,0x02,0x00,0x53,0x04,0x02, + 0x00,0x92,0x08,0x11,0x04,0x02,0xdc,0x02,0x00,0x02,0x00,0x54,0x04,0x02,0x00,0xd3, + 0x14,0x52,0x04,0x02,0x00,0xd1,0x08,0x10,0x04,0x02,0x00,0x02,0xdc,0x10,0x04,0x02, + 0x00,0x02,0xdc,0x92,0x0c,0x91,0x08,0x10,0x04,0x02,0x00,0x02,0xd8,0x02,0x00,0x02, + 0x00,0xcf,0x86,0xd5,0x73,0xd4,0x36,0xd3,0x17,0x92,0x13,0x51,0x04,0x02,0x00,0x10, + 0x04,0x02,0x00,0x02,0xff,0xe0,0xbd,0x82,0xe0,0xbe,0xb7,0x00,0x02,0x00,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x00,0x00,0x02,0x00,0x02,0x00,0x91,0x0f,0x10,0x04,0x02,0x00, + 0x02,0xff,0xe0,0xbd,0x8c,0xe0,0xbe,0xb7,0x00,0x02,0x00,0xd3,0x26,0xd2,0x13,0x51, + 0x04,0x02,0x00,0x10,0x0b,0x02,0xff,0xe0,0xbd,0x91,0xe0,0xbe,0xb7,0x00,0x02,0x00, + 0x51,0x04,0x02,0x00,0x10,0x04,0x02,0x00,0x02,0xff,0xe0,0xbd,0x96,0xe0,0xbe,0xb7, + 0x00,0x52,0x04,0x02,0x00,0x91,0x0f,0x10,0x0b,0x02,0xff,0xe0,0xbd,0x9b,0xe0,0xbe, + 0xb7,0x00,0x02,0x00,0x02,0x00,0xd4,0x27,0x53,0x04,0x02,0x00,0xd2,0x17,0xd1,0x0f, + 0x10,0x04,0x02,0x00,0x02,0xff,0xe0,0xbd,0x80,0xe0,0xbe,0xb5,0x00,0x10,0x04,0x04, + 0x00,0x0a,0x00,0x91,0x08,0x10,0x04,0x0a,0x00,0x00,0x00,0x00,0x00,0xd3,0x35,0xd2, + 0x17,0xd1,0x08,0x10,0x04,0x00,0x00,0x02,0x81,0x10,0x04,0x02,0x82,0x02,0xff,0xe0, + 0xbd,0xb1,0xe0,0xbd,0xb2,0x00,0xd1,0x0f,0x10,0x04,0x02,0x84,0x02,0xff,0xe0,0xbd, + 0xb1,0xe0,0xbd,0xb4,0x00,0x10,0x0b,0x02,0xff,0xe0,0xbe,0xb2,0xe0,0xbe,0x80,0x00, + 0x02,0x00,0xd2,0x13,0x91,0x0f,0x10,0x0b,0x02,0xff,0xe0,0xbe,0xb3,0xe0,0xbe,0x80, + 0x00,0x02,0x00,0x02,0x82,0x11,0x04,0x02,0x82,0x02,0x00,0xd0,0xd3,0xcf,0x86,0xd5, + 0x65,0xd4,0x27,0xd3,0x1f,0xd2,0x13,0x91,0x0f,0x10,0x04,0x02,0x82,0x02,0xff,0xe0, + 0xbd,0xb1,0xe0,0xbe,0x80,0x00,0x02,0xe6,0x91,0x08,0x10,0x04,0x02,0x09,0x02,0x00, + 0x02,0xe6,0x12,0x04,0x02,0x00,0x0c,0x00,0xd3,0x1f,0xd2,0x13,0x51,0x04,0x02,0x00, + 0x10,0x04,0x02,0x00,0x02,0xff,0xe0,0xbe,0x92,0xe0,0xbe,0xb7,0x00,0x51,0x04,0x02, + 0x00,0x10,0x04,0x04,0x00,0x02,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x02, + 0x00,0x02,0x00,0x91,0x0f,0x10,0x04,0x02,0x00,0x02,0xff,0xe0,0xbe,0x9c,0xe0,0xbe, + 0xb7,0x00,0x02,0x00,0xd4,0x3d,0xd3,0x26,0xd2,0x13,0x51,0x04,0x02,0x00,0x10,0x0b, + 0x02,0xff,0xe0,0xbe,0xa1,0xe0,0xbe,0xb7,0x00,0x02,0x00,0x51,0x04,0x02,0x00,0x10, + 0x04,0x02,0x00,0x02,0xff,0xe0,0xbe,0xa6,0xe0,0xbe,0xb7,0x00,0x52,0x04,0x02,0x00, + 0x91,0x0f,0x10,0x0b,0x02,0xff,0xe0,0xbe,0xab,0xe0,0xbe,0xb7,0x00,0x02,0x00,0x04, + 0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x04,0x00,0x02,0x00,0x02,0x00,0x02, + 0x00,0xd2,0x13,0x91,0x0f,0x10,0x04,0x04,0x00,0x02,0xff,0xe0,0xbe,0x90,0xe0,0xbe, + 0xb5,0x00,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0xcf,0x86, + 0x95,0x4c,0xd4,0x24,0xd3,0x10,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04, + 0x04,0xdc,0x04,0x00,0x52,0x04,0x04,0x00,0xd1,0x08,0x10,0x04,0x04,0x00,0x00,0x00, + 0x10,0x04,0x0a,0x00,0x04,0x00,0xd3,0x14,0xd2,0x08,0x11,0x04,0x08,0x00,0x0a,0x00, + 0x91,0x08,0x10,0x04,0x0a,0x00,0x0b,0x00,0x0b,0x00,0x92,0x10,0xd1,0x08,0x10,0x04, + 0x0b,0x00,0x0c,0x00,0x10,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86, + 0xe5,0xf7,0x04,0xe4,0x79,0x03,0xe3,0x7b,0x01,0xe2,0x04,0x01,0xd1,0x7f,0xd0,0x65, + 0xcf,0x86,0x55,0x04,0x04,0x00,0xd4,0x33,0xd3,0x1f,0xd2,0x0c,0x51,0x04,0x04,0x00, + 0x10,0x04,0x0a,0x00,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x0b,0x04,0xff,0xe1,0x80, + 0xa5,0xe1,0x80,0xae,0x00,0x04,0x00,0x92,0x10,0xd1,0x08,0x10,0x04,0x0a,0x00,0x04, + 0x00,0x10,0x04,0x04,0x00,0x0a,0x00,0x04,0x00,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x04, + 0x00,0x10,0x04,0x04,0x00,0x0a,0x00,0x51,0x04,0x0a,0x00,0x10,0x04,0x04,0x00,0x04, + 0x07,0x92,0x10,0xd1,0x08,0x10,0x04,0x04,0x00,0x04,0x09,0x10,0x04,0x0a,0x09,0x0a, + 0x00,0x0a,0x00,0xcf,0x86,0x95,0x14,0x54,0x04,0x04,0x00,0x53,0x04,0x04,0x00,0x92, + 0x08,0x11,0x04,0x04,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00,0xd0,0x2e,0xcf,0x86,0x95, + 0x28,0xd4,0x14,0x53,0x04,0x0a,0x00,0x52,0x04,0x0a,0x00,0x91,0x08,0x10,0x04,0x0a, + 0x00,0x0a,0xdc,0x0a,0x00,0x53,0x04,0x0a,0x00,0xd2,0x08,0x11,0x04,0x0a,0x00,0x0b, + 0x00,0x11,0x04,0x0b,0x00,0x0a,0x00,0x01,0x00,0xcf,0x86,0xd5,0x24,0x94,0x20,0xd3, + 0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0x52, + 0x04,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x00,0x00,0x01,0x00,0x54, + 0x04,0x01,0x00,0xd3,0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x06,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x06,0x00,0x08,0x00,0x10,0x04,0x08, + 0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x08,0x00,0x0d,0x00,0x0d,0x00,0xd1,0x3e,0xd0, + 0x06,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x1d,0x54,0x04,0x01,0x00,0x53,0x04,0x01, + 0x00,0xd2,0x08,0x11,0x04,0x01,0x00,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b, + 0x00,0x01,0xff,0x00,0x94,0x15,0x93,0x11,0x92,0x0d,0x91,0x09,0x10,0x05,0x01,0xff, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd0,0x1e,0xcf,0x86,0x55, + 0x04,0x01,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x0b,0x00,0x0b,0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0x54, + 0x04,0x01,0x00,0x53,0x04,0x01,0x00,0x92,0x08,0x11,0x04,0x01,0x00,0x0b,0x00,0x0b, + 0x00,0xe2,0x21,0x01,0xd1,0x6c,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x94,0x14,0x93,0x10, + 0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0x04,0x00, + 0x04,0x00,0x04,0x00,0xcf,0x86,0x95,0x48,0xd4,0x24,0xd3,0x10,0x52,0x04,0x04,0x00, + 0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04, + 0x04,0x00,0x00,0x00,0x04,0x00,0x11,0x04,0x04,0x00,0x00,0x00,0xd3,0x10,0x52,0x04, + 0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x00,0x00,0xd2,0x0c,0x91,0x08, + 0x10,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0x11,0x04,0x04,0x00,0x00,0x00,0x04,0x00, + 0xd0,0x62,0xcf,0x86,0xd5,0x28,0x94,0x24,0xd3,0x10,0x52,0x04,0x04,0x00,0x51,0x04, + 0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x04,0x00, + 0x00,0x00,0x04,0x00,0x11,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0xd4,0x14,0x53,0x04, + 0x04,0x00,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00, + 0xd3,0x14,0xd2,0x0c,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0x11,0x04, + 0x04,0x00,0x00,0x00,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00, + 0x00,0x00,0xcf,0x86,0xd5,0x38,0xd4,0x24,0xd3,0x14,0xd2,0x0c,0x91,0x08,0x10,0x04, + 0x04,0x00,0x00,0x00,0x04,0x00,0x11,0x04,0x04,0x00,0x00,0x00,0x52,0x04,0x04,0x00, + 0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0x93,0x10,0x52,0x04,0x04,0x00, + 0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0x94,0x14,0x53,0x04, + 0x04,0x00,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00, + 0x04,0x00,0xd1,0x9c,0xd0,0x3e,0xcf,0x86,0x95,0x38,0xd4,0x14,0x53,0x04,0x04,0x00, + 0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0xd3,0x14, + 0xd2,0x0c,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x04,0x00,0x11,0x04,0x04,0x00, + 0x00,0x00,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00, + 0x04,0x00,0xcf,0x86,0xd5,0x34,0xd4,0x14,0x93,0x10,0x52,0x04,0x04,0x00,0x51,0x04, + 0x04,0x00,0x10,0x04,0x04,0x00,0x08,0x00,0x04,0x00,0x53,0x04,0x04,0x00,0xd2,0x0c, + 0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x00,0x00, + 0x0c,0xe6,0x10,0x04,0x0c,0xe6,0x08,0xe6,0xd4,0x14,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x08,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x53,0x04,0x04,0x00, + 0x52,0x04,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0xd0,0x1a, + 0xcf,0x86,0x95,0x14,0x54,0x04,0x08,0x00,0x53,0x04,0x08,0x00,0x92,0x08,0x11,0x04, + 0x08,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0xcf,0x86,0x55,0x04,0x04,0x00,0x54,0x04, + 0x04,0x00,0xd3,0x10,0x52,0x04,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x11,0x00, + 0x00,0x00,0x52,0x04,0x11,0x00,0x11,0x04,0x11,0x00,0x00,0x00,0xd3,0x30,0xd2,0x2a, + 0xd1,0x24,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0b,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00, + 0xcf,0x06,0x04,0x00,0xcf,0x06,0x04,0x00,0xcf,0x06,0x04,0x00,0xd2,0x6c,0xd1,0x24, + 0xd0,0x06,0xcf,0x06,0x04,0x00,0xcf,0x86,0x55,0x04,0x04,0x00,0x54,0x04,0x04,0x00, + 0x93,0x10,0x52,0x04,0x04,0x00,0x51,0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x0b,0x00, + 0x0b,0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04,0x04,0x00,0x53,0x04,0x04,0x00, + 0x52,0x04,0x04,0x00,0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00, + 0xcf,0x86,0x55,0x04,0x04,0x00,0x54,0x04,0x04,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x04,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x80,0xd0,0x46,0xcf,0x86,0xd5,0x28, + 0xd4,0x14,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0x91,0x08,0x10,0x04,0x06,0x00, + 0x00,0x00,0x06,0x00,0x93,0x10,0x52,0x04,0x06,0x00,0x91,0x08,0x10,0x04,0x06,0x09, + 0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x04,0x06,0x00,0x93,0x14,0x52,0x04,0x06,0x00, + 0xd1,0x08,0x10,0x04,0x06,0x09,0x06,0x00,0x10,0x04,0x06,0x00,0x00,0x00,0x00,0x00, + 0xcf,0x86,0xd5,0x10,0x54,0x04,0x06,0x00,0x93,0x08,0x12,0x04,0x06,0x00,0x00,0x00, + 0x00,0x00,0xd4,0x14,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0x91,0x08,0x10,0x04, + 0x06,0x00,0x00,0x00,0x06,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x06,0x00, + 0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0xd0,0x1b,0xcf,0x86,0x55,0x04,0x04,0x00, + 0x54,0x04,0x04,0x00,0x93,0x0d,0x52,0x04,0x04,0x00,0x11,0x05,0x04,0xff,0x00,0x04, + 0x00,0x04,0x00,0xcf,0x86,0xd5,0x24,0x54,0x04,0x04,0x00,0xd3,0x10,0x92,0x0c,0x51, + 0x04,0x04,0x00,0x10,0x04,0x04,0x09,0x04,0x00,0x04,0x00,0x52,0x04,0x04,0x00,0x91, + 0x08,0x10,0x04,0x04,0x00,0x07,0xe6,0x00,0x00,0xd4,0x10,0x53,0x04,0x04,0x00,0x92, + 0x08,0x11,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x07,0x00,0x92,0x08,0x11, + 0x04,0x07,0x00,0x00,0x00,0x00,0x00,0xe4,0xb7,0x03,0xe3,0x58,0x01,0xd2,0x8f,0xd1, + 0x53,0xd0,0x35,0xcf,0x86,0x95,0x2f,0xd4,0x1f,0x53,0x04,0x04,0x00,0xd2,0x0d,0x51, + 0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x04,0xff,0x00,0x51,0x05,0x04,0xff,0x00,0x10, + 0x05,0x04,0xff,0x00,0x00,0x00,0x53,0x04,0x04,0x00,0x92,0x08,0x11,0x04,0x04,0x00, + 0x00,0x00,0x00,0x00,0x04,0x00,0xcf,0x86,0x55,0x04,0x04,0x00,0x54,0x04,0x04,0x00, + 0x53,0x04,0x04,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xd0,0x22,0xcf,0x86,0x55,0x04,0x04,0x00,0x94,0x18,0x53,0x04,0x04,0x00, + 0x92,0x10,0xd1,0x08,0x10,0x04,0x04,0x00,0x04,0xe4,0x10,0x04,0x0a,0x00,0x00,0x00, + 0x00,0x00,0x0b,0x00,0xcf,0x86,0x55,0x04,0x0b,0x00,0x54,0x04,0x0b,0x00,0x93,0x0c, + 0x52,0x04,0x0b,0x00,0x11,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0xd1,0x80,0xd0,0x42, + 0xcf,0x86,0xd5,0x1c,0x54,0x04,0x07,0x00,0x53,0x04,0x07,0x00,0x52,0x04,0x07,0x00, + 0xd1,0x08,0x10,0x04,0x07,0x00,0x10,0x00,0x10,0x04,0x10,0x00,0x00,0x00,0xd4,0x0c, + 0x53,0x04,0x07,0x00,0x12,0x04,0x07,0x00,0x00,0x00,0x53,0x04,0x07,0x00,0x92,0x10, + 0xd1,0x08,0x10,0x04,0x07,0x00,0x07,0xde,0x10,0x04,0x07,0xe6,0x07,0xdc,0x00,0x00, + 0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x07,0x00, + 0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0xd4,0x10,0x53,0x04,0x07,0x00, + 0x52,0x04,0x07,0x00,0x11,0x04,0x07,0x00,0x00,0x00,0x93,0x10,0x52,0x04,0x07,0x00, + 0x91,0x08,0x10,0x04,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x1a,0xcf,0x86, + 0x55,0x04,0x08,0x00,0x94,0x10,0x53,0x04,0x08,0x00,0x92,0x08,0x11,0x04,0x08,0x00, + 0x0b,0x00,0x00,0x00,0x08,0x00,0xcf,0x86,0x95,0x28,0xd4,0x10,0x53,0x04,0x08,0x00, + 0x92,0x08,0x11,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x08,0x00,0xd2,0x0c, + 0x51,0x04,0x08,0x00,0x10,0x04,0x0b,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x08,0x00, + 0x07,0x00,0xd2,0xe4,0xd1,0x80,0xd0,0x2e,0xcf,0x86,0x95,0x28,0x54,0x04,0x08,0x00, + 0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x08,0xe6, + 0xd2,0x0c,0x91,0x08,0x10,0x04,0x08,0xdc,0x08,0x00,0x08,0x00,0x11,0x04,0x00,0x00, + 0x08,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x18,0x54,0x04,0x0b,0x00,0x53,0x04,0x0b,0x00, + 0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00,0x00,0x00,0xd4,0x14, + 0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0b,0x09,0x0b,0x00,0x0b,0x00,0x0b,0x00, + 0x0b,0x00,0xd3,0x10,0x52,0x04,0x0b,0x00,0x91,0x08,0x10,0x04,0x0b,0x00,0x0b,0xe6, + 0x0b,0xe6,0x52,0x04,0x0b,0xe6,0xd1,0x08,0x10,0x04,0x0b,0xe6,0x00,0x00,0x10,0x04, + 0x00,0x00,0x0b,0xdc,0xd0,0x5e,0xcf,0x86,0xd5,0x20,0xd4,0x10,0x53,0x04,0x0b,0x00, + 0x92,0x08,0x11,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x0b,0x00,0x92,0x08, + 0x11,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0xd4,0x10,0x53,0x04,0x0b,0x00,0x52,0x04, + 0x0b,0x00,0x11,0x04,0x0b,0x00,0x00,0x00,0xd3,0x10,0x52,0x04,0x10,0xe6,0x91,0x08, + 0x10,0x04,0x10,0xe6,0x10,0xdc,0x10,0xdc,0xd2,0x0c,0x51,0x04,0x10,0xdc,0x10,0x04, + 0x10,0xdc,0x10,0xe6,0xd1,0x08,0x10,0x04,0x10,0xe6,0x10,0xdc,0x10,0x04,0x10,0x00, + 0x00,0x00,0xcf,0x06,0x00,0x00,0xe1,0x1e,0x01,0xd0,0xaa,0xcf,0x86,0xd5,0x6e,0xd4, + 0x53,0xd3,0x17,0x52,0x04,0x09,0x00,0x51,0x04,0x09,0x00,0x10,0x0b,0x09,0xff,0xe1, + 0xac,0x85,0xe1,0xac,0xb5,0x00,0x09,0x00,0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x09,0xff, + 0xe1,0xac,0x87,0xe1,0xac,0xb5,0x00,0x09,0x00,0x10,0x0b,0x09,0xff,0xe1,0xac,0x89, + 0xe1,0xac,0xb5,0x00,0x09,0x00,0xd1,0x0f,0x10,0x0b,0x09,0xff,0xe1,0xac,0x8b,0xe1, + 0xac,0xb5,0x00,0x09,0x00,0x10,0x0b,0x09,0xff,0xe1,0xac,0x8d,0xe1,0xac,0xb5,0x00, + 0x09,0x00,0x93,0x17,0x92,0x13,0x51,0x04,0x09,0x00,0x10,0x0b,0x09,0xff,0xe1,0xac, + 0x91,0xe1,0xac,0xb5,0x00,0x09,0x00,0x09,0x00,0x09,0x00,0x54,0x04,0x09,0x00,0xd3, + 0x10,0x52,0x04,0x09,0x00,0x91,0x08,0x10,0x04,0x09,0x07,0x09,0x00,0x09,0x00,0xd2, + 0x13,0x51,0x04,0x09,0x00,0x10,0x04,0x09,0x00,0x09,0xff,0xe1,0xac,0xba,0xe1,0xac, + 0xb5,0x00,0x91,0x0f,0x10,0x04,0x09,0x00,0x09,0xff,0xe1,0xac,0xbc,0xe1,0xac,0xb5, + 0x00,0x09,0x00,0xcf,0x86,0xd5,0x3d,0x94,0x39,0xd3,0x31,0xd2,0x25,0xd1,0x16,0x10, + 0x0b,0x09,0xff,0xe1,0xac,0xbe,0xe1,0xac,0xb5,0x00,0x09,0xff,0xe1,0xac,0xbf,0xe1, + 0xac,0xb5,0x00,0x10,0x04,0x09,0x00,0x09,0xff,0xe1,0xad,0x82,0xe1,0xac,0xb5,0x00, + 0x91,0x08,0x10,0x04,0x09,0x09,0x09,0x00,0x09,0x00,0x12,0x04,0x09,0x00,0x00,0x00, + 0x09,0x00,0xd4,0x1c,0x53,0x04,0x09,0x00,0xd2,0x0c,0x51,0x04,0x09,0x00,0x10,0x04, + 0x09,0x00,0x09,0xe6,0x91,0x08,0x10,0x04,0x09,0xdc,0x09,0xe6,0x09,0xe6,0xd3,0x08, + 0x12,0x04,0x09,0xe6,0x09,0x00,0x52,0x04,0x09,0x00,0x91,0x08,0x10,0x04,0x09,0x00, + 0x00,0x00,0x00,0x00,0xd0,0x2e,0xcf,0x86,0x55,0x04,0x0a,0x00,0xd4,0x18,0x53,0x04, + 0x0a,0x00,0xd2,0x0c,0x51,0x04,0x0a,0x00,0x10,0x04,0x0a,0x09,0x0d,0x09,0x11,0x04, + 0x0d,0x00,0x0a,0x00,0x53,0x04,0x0a,0x00,0x92,0x08,0x11,0x04,0x0a,0x00,0x0d,0x00, + 0x0d,0x00,0xcf,0x86,0x55,0x04,0x0c,0x00,0xd4,0x14,0x93,0x10,0x52,0x04,0x0c,0x00, + 0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x07,0x0c,0x00,0x0c,0x00,0xd3,0x0c,0x92,0x08, + 0x11,0x04,0x0c,0x00,0x0c,0x09,0x00,0x00,0x12,0x04,0x00,0x00,0x0c,0x00,0xe3,0xb2, + 0x01,0xe2,0x09,0x01,0xd1,0x4c,0xd0,0x2a,0xcf,0x86,0x55,0x04,0x0a,0x00,0x54,0x04, + 0x0a,0x00,0xd3,0x10,0x52,0x04,0x0a,0x00,0x51,0x04,0x0a,0x00,0x10,0x04,0x0a,0x00, + 0x0a,0x07,0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0a,0x00,0x0a,0x00, + 0xcf,0x86,0x95,0x1c,0x94,0x18,0x53,0x04,0x0a,0x00,0xd2,0x08,0x11,0x04,0x0a,0x00, + 0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00, + 0xd0,0x3a,0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x12,0x00,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x14,0x00,0x54,0x04,0x14,0x00, + 0x53,0x04,0x14,0x00,0xd2,0x0c,0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00, + 0x91,0x08,0x10,0x04,0x00,0x00,0x14,0x00,0x14,0x00,0xcf,0x86,0xd5,0x2c,0xd4,0x08, + 0x13,0x04,0x0d,0x00,0x00,0x00,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x0b,0xe6,0x10,0x04, + 0x0b,0xe6,0x0b,0x00,0x91,0x08,0x10,0x04,0x0b,0x01,0x0b,0xdc,0x0b,0xdc,0x92,0x08, + 0x11,0x04,0x0b,0xdc,0x0b,0xe6,0x0b,0xdc,0xd4,0x28,0xd3,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0b,0xe6,0x0b,0x00,0x0b,0x01,0x0b,0x01,0xd2,0x0c,0x91,0x08,0x10,0x04, + 0x0b,0x01,0x0b,0x00,0x0b,0x00,0x91,0x08,0x10,0x04,0x0b,0x00,0x0b,0xdc,0x0b,0x00, + 0xd3,0x1c,0xd2,0x0c,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00,0x0d,0x00,0xd1,0x08, + 0x10,0x04,0x0d,0xe6,0x0d,0x00,0x10,0x04,0x0d,0x00,0x13,0x00,0x92,0x0c,0x51,0x04, + 0x10,0xe6,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0xd1,0x1c,0xd0,0x06,0xcf,0x06, + 0x07,0x00,0xcf,0x86,0x55,0x04,0x07,0x00,0x94,0x0c,0x53,0x04,0x07,0x00,0x12,0x04, + 0x07,0x00,0x08,0x00,0x08,0x00,0xd0,0x06,0xcf,0x06,0x08,0x00,0xcf,0x86,0xd5,0x40, + 0xd4,0x2c,0xd3,0x10,0x92,0x0c,0x51,0x04,0x08,0xe6,0x10,0x04,0x08,0xdc,0x08,0xe6, + 0x09,0xe6,0xd2,0x0c,0x51,0x04,0x09,0xe6,0x10,0x04,0x09,0xdc,0x0a,0xe6,0xd1,0x08, + 0x10,0x04,0x0a,0xe6,0x0a,0xea,0x10,0x04,0x0a,0xd6,0x0a,0xdc,0x93,0x10,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x0a,0xca,0x0a,0xe6,0x0a,0xe6,0x0a,0xe6,0x0a,0xe6,0xd4,0x14, + 0x93,0x10,0x52,0x04,0x0a,0xe6,0x51,0x04,0x0a,0xe6,0x10,0x04,0x0a,0xe6,0x10,0xe6, + 0x10,0xe6,0xd3,0x10,0x52,0x04,0x10,0xe6,0x51,0x04,0x10,0xe6,0x10,0x04,0x13,0xe8, + 0x13,0xe4,0xd2,0x10,0xd1,0x08,0x10,0x04,0x13,0xe4,0x13,0xdc,0x10,0x04,0x00,0x00, + 0x12,0xe6,0xd1,0x08,0x10,0x04,0x0c,0xe9,0x0b,0xdc,0x10,0x04,0x09,0xe6,0x09,0xdc, + 0xe2,0x80,0x08,0xe1,0x48,0x04,0xe0,0x1c,0x02,0xcf,0x86,0xe5,0x11,0x01,0xd4,0x84, + 0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x41,0xcc,0xa5,0x00,0x01,0xff, + 0x61,0xcc,0xa5,0x00,0x10,0x08,0x01,0xff,0x42,0xcc,0x87,0x00,0x01,0xff,0x62,0xcc, + 0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x42,0xcc,0xa3,0x00,0x01,0xff,0x62,0xcc, + 0xa3,0x00,0x10,0x08,0x01,0xff,0x42,0xcc,0xb1,0x00,0x01,0xff,0x62,0xcc,0xb1,0x00, + 0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff,0x43,0xcc,0xa7,0xcc,0x81,0x00,0x01,0xff, + 0x63,0xcc,0xa7,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x44,0xcc,0x87,0x00,0x01,0xff, + 0x64,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x44,0xcc,0xa3,0x00,0x01,0xff, + 0x64,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x44,0xcc,0xb1,0x00,0x01,0xff,0x64,0xcc, + 0xb1,0x00,0xd3,0x48,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x44,0xcc,0xa7,0x00, + 0x01,0xff,0x64,0xcc,0xa7,0x00,0x10,0x08,0x01,0xff,0x44,0xcc,0xad,0x00,0x01,0xff, + 0x64,0xcc,0xad,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x45,0xcc,0x84,0xcc,0x80,0x00, + 0x01,0xff,0x65,0xcc,0x84,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x45,0xcc,0x84,0xcc, + 0x81,0x00,0x01,0xff,0x65,0xcc,0x84,0xcc,0x81,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0x45,0xcc,0xad,0x00,0x01,0xff,0x65,0xcc,0xad,0x00,0x10,0x08,0x01,0xff, + 0x45,0xcc,0xb0,0x00,0x01,0xff,0x65,0xcc,0xb0,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff, + 0x45,0xcc,0xa7,0xcc,0x86,0x00,0x01,0xff,0x65,0xcc,0xa7,0xcc,0x86,0x00,0x10,0x08, + 0x01,0xff,0x46,0xcc,0x87,0x00,0x01,0xff,0x66,0xcc,0x87,0x00,0xd4,0x84,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x47,0xcc,0x84,0x00,0x01,0xff,0x67,0xcc, + 0x84,0x00,0x10,0x08,0x01,0xff,0x48,0xcc,0x87,0x00,0x01,0xff,0x68,0xcc,0x87,0x00, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x48,0xcc,0xa3,0x00,0x01,0xff,0x68,0xcc,0xa3,0x00, + 0x10,0x08,0x01,0xff,0x48,0xcc,0x88,0x00,0x01,0xff,0x68,0xcc,0x88,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0x48,0xcc,0xa7,0x00,0x01,0xff,0x68,0xcc,0xa7,0x00, + 0x10,0x08,0x01,0xff,0x48,0xcc,0xae,0x00,0x01,0xff,0x68,0xcc,0xae,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0x49,0xcc,0xb0,0x00,0x01,0xff,0x69,0xcc,0xb0,0x00,0x10,0x0a, + 0x01,0xff,0x49,0xcc,0x88,0xcc,0x81,0x00,0x01,0xff,0x69,0xcc,0x88,0xcc,0x81,0x00, + 0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x4b,0xcc,0x81,0x00,0x01,0xff, + 0x6b,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x4b,0xcc,0xa3,0x00,0x01,0xff,0x6b,0xcc, + 0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x4b,0xcc,0xb1,0x00,0x01,0xff,0x6b,0xcc, + 0xb1,0x00,0x10,0x08,0x01,0xff,0x4c,0xcc,0xa3,0x00,0x01,0xff,0x6c,0xcc,0xa3,0x00, + 0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4c,0xcc,0xa3,0xcc,0x84,0x00,0x01,0xff, + 0x6c,0xcc,0xa3,0xcc,0x84,0x00,0x10,0x08,0x01,0xff,0x4c,0xcc,0xb1,0x00,0x01,0xff, + 0x6c,0xcc,0xb1,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x4c,0xcc,0xad,0x00,0x01,0xff, + 0x6c,0xcc,0xad,0x00,0x10,0x08,0x01,0xff,0x4d,0xcc,0x81,0x00,0x01,0xff,0x6d,0xcc, + 0x81,0x00,0xcf,0x86,0xe5,0x15,0x01,0xd4,0x88,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x4d,0xcc,0x87,0x00,0x01,0xff,0x6d,0xcc,0x87,0x00,0x10,0x08,0x01, + 0xff,0x4d,0xcc,0xa3,0x00,0x01,0xff,0x6d,0xcc,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x4e,0xcc,0x87,0x00,0x01,0xff,0x6e,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x4e, + 0xcc,0xa3,0x00,0x01,0xff,0x6e,0xcc,0xa3,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x4e,0xcc,0xb1,0x00,0x01,0xff,0x6e,0xcc,0xb1,0x00,0x10,0x08,0x01,0xff,0x4e, + 0xcc,0xad,0x00,0x01,0xff,0x6e,0xcc,0xad,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f, + 0xcc,0x83,0xcc,0x81,0x00,0x01,0xff,0x6f,0xcc,0x83,0xcc,0x81,0x00,0x10,0x0a,0x01, + 0xff,0x4f,0xcc,0x83,0xcc,0x88,0x00,0x01,0xff,0x6f,0xcc,0x83,0xcc,0x88,0x00,0xd3, + 0x48,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x84,0xcc,0x80,0x00,0x01, + 0xff,0x6f,0xcc,0x84,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x84,0xcc,0x81, + 0x00,0x01,0xff,0x6f,0xcc,0x84,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x50, + 0xcc,0x81,0x00,0x01,0xff,0x70,0xcc,0x81,0x00,0x10,0x08,0x01,0xff,0x50,0xcc,0x87, + 0x00,0x01,0xff,0x70,0xcc,0x87,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x52, + 0xcc,0x87,0x00,0x01,0xff,0x72,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x52,0xcc,0xa3, + 0x00,0x01,0xff,0x72,0xcc,0xa3,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x52,0xcc,0xa3, + 0xcc,0x84,0x00,0x01,0xff,0x72,0xcc,0xa3,0xcc,0x84,0x00,0x10,0x08,0x01,0xff,0x52, + 0xcc,0xb1,0x00,0x01,0xff,0x72,0xcc,0xb1,0x00,0xd4,0x8c,0xd3,0x48,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0x53,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x87,0x00,0x10, + 0x08,0x01,0xff,0x53,0xcc,0xa3,0x00,0x01,0xff,0x73,0xcc,0xa3,0x00,0xd1,0x14,0x10, + 0x0a,0x01,0xff,0x53,0xcc,0x81,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x81,0xcc,0x87, + 0x00,0x10,0x0a,0x01,0xff,0x53,0xcc,0x8c,0xcc,0x87,0x00,0x01,0xff,0x73,0xcc,0x8c, + 0xcc,0x87,0x00,0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff,0x53,0xcc,0xa3,0xcc,0x87, + 0x00,0x01,0xff,0x73,0xcc,0xa3,0xcc,0x87,0x00,0x10,0x08,0x01,0xff,0x54,0xcc,0x87, + 0x00,0x01,0xff,0x74,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x54,0xcc,0xa3, + 0x00,0x01,0xff,0x74,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x54,0xcc,0xb1,0x00,0x01, + 0xff,0x74,0xcc,0xb1,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x54, + 0xcc,0xad,0x00,0x01,0xff,0x74,0xcc,0xad,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0xa4, + 0x00,0x01,0xff,0x75,0xcc,0xa4,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x55,0xcc,0xb0, + 0x00,0x01,0xff,0x75,0xcc,0xb0,0x00,0x10,0x08,0x01,0xff,0x55,0xcc,0xad,0x00,0x01, + 0xff,0x75,0xcc,0xad,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x55,0xcc,0x83, + 0xcc,0x81,0x00,0x01,0xff,0x75,0xcc,0x83,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x55, + 0xcc,0x84,0xcc,0x88,0x00,0x01,0xff,0x75,0xcc,0x84,0xcc,0x88,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0x56,0xcc,0x83,0x00,0x01,0xff,0x76,0xcc,0x83,0x00,0x10,0x08,0x01, + 0xff,0x56,0xcc,0xa3,0x00,0x01,0xff,0x76,0xcc,0xa3,0x00,0xe0,0x10,0x02,0xcf,0x86, + 0xd5,0xe1,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x57,0xcc, + 0x80,0x00,0x01,0xff,0x77,0xcc,0x80,0x00,0x10,0x08,0x01,0xff,0x57,0xcc,0x81,0x00, + 0x01,0xff,0x77,0xcc,0x81,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x57,0xcc,0x88,0x00, + 0x01,0xff,0x77,0xcc,0x88,0x00,0x10,0x08,0x01,0xff,0x57,0xcc,0x87,0x00,0x01,0xff, + 0x77,0xcc,0x87,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x57,0xcc,0xa3,0x00, + 0x01,0xff,0x77,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x58,0xcc,0x87,0x00,0x01,0xff, + 0x78,0xcc,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x58,0xcc,0x88,0x00,0x01,0xff, + 0x78,0xcc,0x88,0x00,0x10,0x08,0x01,0xff,0x59,0xcc,0x87,0x00,0x01,0xff,0x79,0xcc, + 0x87,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x5a,0xcc,0x82,0x00, + 0x01,0xff,0x7a,0xcc,0x82,0x00,0x10,0x08,0x01,0xff,0x5a,0xcc,0xa3,0x00,0x01,0xff, + 0x7a,0xcc,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x5a,0xcc,0xb1,0x00,0x01,0xff, + 0x7a,0xcc,0xb1,0x00,0x10,0x08,0x01,0xff,0x68,0xcc,0xb1,0x00,0x01,0xff,0x74,0xcc, + 0x88,0x00,0x92,0x1d,0xd1,0x10,0x10,0x08,0x01,0xff,0x77,0xcc,0x8a,0x00,0x01,0xff, + 0x79,0xcc,0x8a,0x00,0x10,0x04,0x01,0x00,0x02,0xff,0xc5,0xbf,0xcc,0x87,0x00,0x0a, + 0x00,0xd4,0x98,0xd3,0x48,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x41,0xcc,0xa3, + 0x00,0x01,0xff,0x61,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x41,0xcc,0x89,0x00,0x01, + 0xff,0x61,0xcc,0x89,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x41,0xcc,0x82,0xcc,0x81, + 0x00,0x01,0xff,0x61,0xcc,0x82,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x82, + 0xcc,0x80,0x00,0x01,0xff,0x61,0xcc,0x82,0xcc,0x80,0x00,0xd2,0x28,0xd1,0x14,0x10, + 0x0a,0x01,0xff,0x41,0xcc,0x82,0xcc,0x89,0x00,0x01,0xff,0x61,0xcc,0x82,0xcc,0x89, + 0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x61,0xcc,0x82, + 0xcc,0x83,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x41,0xcc,0xa3,0xcc,0x82,0x00,0x01, + 0xff,0x61,0xcc,0xa3,0xcc,0x82,0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x86,0xcc,0x81, + 0x00,0x01,0xff,0x61,0xcc,0x86,0xcc,0x81,0x00,0xd3,0x50,0xd2,0x28,0xd1,0x14,0x10, + 0x0a,0x01,0xff,0x41,0xcc,0x86,0xcc,0x80,0x00,0x01,0xff,0x61,0xcc,0x86,0xcc,0x80, + 0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0x86,0xcc,0x89,0x00,0x01,0xff,0x61,0xcc,0x86, + 0xcc,0x89,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x41,0xcc,0x86,0xcc,0x83,0x00,0x01, + 0xff,0x61,0xcc,0x86,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x41,0xcc,0xa3,0xcc,0x86, + 0x00,0x01,0xff,0x61,0xcc,0xa3,0xcc,0x86,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0x45,0xcc,0xa3,0x00,0x01,0xff,0x65,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x45, + 0xcc,0x89,0x00,0x01,0xff,0x65,0xcc,0x89,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x45, + 0xcc,0x83,0x00,0x01,0xff,0x65,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x45,0xcc,0x82, + 0xcc,0x81,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x81,0x00,0xcf,0x86,0xe5,0x31,0x01, + 0xd4,0x90,0xd3,0x50,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x45,0xcc,0x82,0xcc, + 0x80,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0x45,0xcc, + 0x82,0xcc,0x89,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x89,0x00,0xd1,0x14,0x10,0x0a, + 0x01,0xff,0x45,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x65,0xcc,0x82,0xcc,0x83,0x00, + 0x10,0x0a,0x01,0xff,0x45,0xcc,0xa3,0xcc,0x82,0x00,0x01,0xff,0x65,0xcc,0xa3,0xcc, + 0x82,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0x49,0xcc,0x89,0x00,0x01,0xff, + 0x69,0xcc,0x89,0x00,0x10,0x08,0x01,0xff,0x49,0xcc,0xa3,0x00,0x01,0xff,0x69,0xcc, + 0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0x4f,0xcc,0xa3,0x00,0x01,0xff,0x6f,0xcc, + 0xa3,0x00,0x10,0x08,0x01,0xff,0x4f,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x89,0x00, + 0xd3,0x50,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x82,0xcc,0x81,0x00, + 0x01,0xff,0x6f,0xcc,0x82,0xcc,0x81,0x00,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x82,0xcc, + 0x80,0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x80,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff, + 0x4f,0xcc,0x82,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x89,0x00,0x10,0x0a, + 0x01,0xff,0x4f,0xcc,0x82,0xcc,0x83,0x00,0x01,0xff,0x6f,0xcc,0x82,0xcc,0x83,0x00, + 0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc,0xa3,0xcc,0x82,0x00,0x01,0xff, + 0x6f,0xcc,0xa3,0xcc,0x82,0x00,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x9b,0xcc,0x81,0x00, + 0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x81,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc, + 0x9b,0xcc,0x80,0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff, + 0x4f,0xcc,0x9b,0xcc,0x89,0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x89,0x00,0xd4,0x98, + 0xd3,0x48,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x9b,0xcc,0x83,0x00, + 0x01,0xff,0x6f,0xcc,0x9b,0xcc,0x83,0x00,0x10,0x0a,0x01,0xff,0x4f,0xcc,0x9b,0xcc, + 0xa3,0x00,0x01,0xff,0x6f,0xcc,0x9b,0xcc,0xa3,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0x55,0xcc,0xa3,0x00,0x01,0xff,0x75,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff,0x55,0xcc, + 0x89,0x00,0x01,0xff,0x75,0xcc,0x89,0x00,0xd2,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff, + 0x55,0xcc,0x9b,0xcc,0x81,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x81,0x00,0x10,0x0a, + 0x01,0xff,0x55,0xcc,0x9b,0xcc,0x80,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0x80,0x00, + 0xd1,0x14,0x10,0x0a,0x01,0xff,0x55,0xcc,0x9b,0xcc,0x89,0x00,0x01,0xff,0x75,0xcc, + 0x9b,0xcc,0x89,0x00,0x10,0x0a,0x01,0xff,0x55,0xcc,0x9b,0xcc,0x83,0x00,0x01,0xff, + 0x75,0xcc,0x9b,0xcc,0x83,0x00,0xd3,0x44,0xd2,0x24,0xd1,0x14,0x10,0x0a,0x01,0xff, + 0x55,0xcc,0x9b,0xcc,0xa3,0x00,0x01,0xff,0x75,0xcc,0x9b,0xcc,0xa3,0x00,0x10,0x08, + 0x01,0xff,0x59,0xcc,0x80,0x00,0x01,0xff,0x79,0xcc,0x80,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0x59,0xcc,0xa3,0x00,0x01,0xff,0x79,0xcc,0xa3,0x00,0x10,0x08,0x01,0xff, + 0x59,0xcc,0x89,0x00,0x01,0xff,0x79,0xcc,0x89,0x00,0x92,0x14,0x91,0x10,0x10,0x08, + 0x01,0xff,0x59,0xcc,0x83,0x00,0x01,0xff,0x79,0xcc,0x83,0x00,0x0a,0x00,0x0a,0x00, + 0xe1,0xc0,0x04,0xe0,0x80,0x02,0xcf,0x86,0xe5,0x2d,0x01,0xd4,0xa8,0xd3,0x54,0xd2, + 0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x93,0x00,0x01,0xff,0xce,0xb1, + 0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff, + 0xce,0xb1,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc, + 0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01, + 0xff,0xce,0xb1,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcd,0x82, + 0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0x91,0xcc,0x93,0x00,0x01,0xff, + 0xce,0x91,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0x91,0xcc,0x93,0xcc,0x80,0x00, + 0x01,0xff,0xce,0x91,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce, + 0x91,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0x91,0xcc,0x94,0xcc,0x81,0x00,0x10, + 0x0b,0x01,0xff,0xce,0x91,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0x91,0xcc,0x94, + 0xcd,0x82,0x00,0xd3,0x42,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb5,0xcc, + 0x93,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xb5,0xcc, + 0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94,0xcc,0x80,0x00,0x91,0x16,0x10, + 0x0b,0x01,0xff,0xce,0xb5,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0xb5,0xcc,0x94, + 0xcc,0x81,0x00,0x00,0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0x95,0xcc, + 0x93,0x00,0x01,0xff,0xce,0x95,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0x95,0xcc, + 0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0x95,0xcc,0x94,0xcc,0x80,0x00,0x91,0x16,0x10, + 0x0b,0x01,0xff,0xce,0x95,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0x95,0xcc,0x94, + 0xcc,0x81,0x00,0x00,0x00,0xd4,0xa8,0xd3,0x54,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01, + 0xff,0xce,0xb7,0xcc,0x93,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0x00,0x10,0x0b,0x01, + 0xff,0xce,0xb7,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x80, + 0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff, + 0xce,0xb7,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcd, + 0x82,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcd,0x82,0x00,0xd2,0x28,0xd1,0x12,0x10, + 0x09,0x01,0xff,0xce,0x97,0xcc,0x93,0x00,0x01,0xff,0xce,0x97,0xcc,0x94,0x00,0x10, + 0x0b,0x01,0xff,0xce,0x97,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0x97,0xcc,0x94, + 0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0x97,0xcc,0x93,0xcc,0x81,0x00, + 0x01,0xff,0xce,0x97,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff,0xce,0x97,0xcc, + 0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0x97,0xcc,0x94,0xcd,0x82,0x00,0xd3,0x54,0xd2, + 0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x93,0x00,0x01,0xff,0xce,0xb9, + 0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xb9,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff, + 0xce,0xb9,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb9,0xcc, + 0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01, + 0xff,0xce,0xb9,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xb9,0xcc,0x94,0xcd,0x82, + 0x00,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0x99,0xcc,0x93,0x00,0x01,0xff, + 0xce,0x99,0xcc,0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0x99,0xcc,0x93,0xcc,0x80,0x00, + 0x01,0xff,0xce,0x99,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce, + 0x99,0xcc,0x93,0xcc,0x81,0x00,0x01,0xff,0xce,0x99,0xcc,0x94,0xcc,0x81,0x00,0x10, + 0x0b,0x01,0xff,0xce,0x99,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0x99,0xcc,0x94, + 0xcd,0x82,0x00,0xcf,0x86,0xe5,0x13,0x01,0xd4,0x84,0xd3,0x42,0xd2,0x28,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xce,0xbf,0xcc,0x93,0x00,0x01,0xff,0xce,0xbf,0xcc,0x94,0x00, + 0x10,0x0b,0x01,0xff,0xce,0xbf,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0xbf,0xcc, + 0x94,0xcc,0x80,0x00,0x91,0x16,0x10,0x0b,0x01,0xff,0xce,0xbf,0xcc,0x93,0xcc,0x81, + 0x00,0x01,0xff,0xce,0xbf,0xcc,0x94,0xcc,0x81,0x00,0x00,0x00,0xd2,0x28,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xce,0x9f,0xcc,0x93,0x00,0x01,0xff,0xce,0x9f,0xcc,0x94,0x00, + 0x10,0x0b,0x01,0xff,0xce,0x9f,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce,0x9f,0xcc, + 0x94,0xcc,0x80,0x00,0x91,0x16,0x10,0x0b,0x01,0xff,0xce,0x9f,0xcc,0x93,0xcc,0x81, + 0x00,0x01,0xff,0xce,0x9f,0xcc,0x94,0xcc,0x81,0x00,0x00,0x00,0xd3,0x54,0xd2,0x28, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x93,0x00,0x01,0xff,0xcf,0x85,0xcc, + 0x94,0x00,0x10,0x0b,0x01,0xff,0xcf,0x85,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xcf, + 0x85,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xcf,0x85,0xcc,0x93, + 0xcc,0x81,0x00,0x01,0xff,0xcf,0x85,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff, + 0xcf,0x85,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xcf,0x85,0xcc,0x94,0xcd,0x82,0x00, + 0xd2,0x1c,0xd1,0x0d,0x10,0x04,0x00,0x00,0x01,0xff,0xce,0xa5,0xcc,0x94,0x00,0x10, + 0x04,0x00,0x00,0x01,0xff,0xce,0xa5,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x0f,0x10,0x04, + 0x00,0x00,0x01,0xff,0xce,0xa5,0xcc,0x94,0xcc,0x81,0x00,0x10,0x04,0x00,0x00,0x01, + 0xff,0xce,0xa5,0xcc,0x94,0xcd,0x82,0x00,0xd4,0xa8,0xd3,0x54,0xd2,0x28,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xcf,0x89,0xcc,0x93,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0x00, + 0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xcf,0x89,0xcc, + 0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x81, + 0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff,0xcf,0x89, + 0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcd,0x82,0x00,0xd2,0x28, + 0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xa9,0xcc,0x93,0x00,0x01,0xff,0xce,0xa9,0xcc, + 0x94,0x00,0x10,0x0b,0x01,0xff,0xce,0xa9,0xcc,0x93,0xcc,0x80,0x00,0x01,0xff,0xce, + 0xa9,0xcc,0x94,0xcc,0x80,0x00,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xa9,0xcc,0x93, + 0xcc,0x81,0x00,0x01,0xff,0xce,0xa9,0xcc,0x94,0xcc,0x81,0x00,0x10,0x0b,0x01,0xff, + 0xce,0xa9,0xcc,0x93,0xcd,0x82,0x00,0x01,0xff,0xce,0xa9,0xcc,0x94,0xcd,0x82,0x00, + 0xd3,0x48,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x80,0x00,0x01, + 0xff,0xce,0xb1,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce,0xb5,0xcc,0x80,0x00,0x01, + 0xff,0xce,0xb5,0xcc,0x81,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb7,0xcc,0x80, + 0x00,0x01,0xff,0xce,0xb7,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce,0xb9,0xcc,0x80, + 0x00,0x01,0xff,0xce,0xb9,0xcc,0x81,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff, + 0xce,0xbf,0xcc,0x80,0x00,0x01,0xff,0xce,0xbf,0xcc,0x81,0x00,0x10,0x09,0x01,0xff, + 0xcf,0x85,0xcc,0x80,0x00,0x01,0xff,0xcf,0x85,0xcc,0x81,0x00,0x91,0x12,0x10,0x09, + 0x01,0xff,0xcf,0x89,0xcc,0x80,0x00,0x01,0xff,0xcf,0x89,0xcc,0x81,0x00,0x00,0x00, + 0xe0,0xe1,0x02,0xcf,0x86,0xe5,0x91,0x01,0xd4,0xc8,0xd3,0x64,0xd2,0x30,0xd1,0x16, + 0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcd,0x85,0x00,0x01,0xff,0xce,0xb1,0xcc, + 0x94,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x80,0xcd,0x85, + 0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcc,0x80,0xcd,0x85,0x00,0xd1,0x1a,0x10,0x0d, + 0x01,0xff,0xce,0xb1,0xcc,0x93,0xcc,0x81,0xcd,0x85,0x00,0x01,0xff,0xce,0xb1,0xcc, + 0x94,0xcc,0x81,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0xb1,0xcc,0x93,0xcd,0x82, + 0xcd,0x85,0x00,0x01,0xff,0xce,0xb1,0xcc,0x94,0xcd,0x82,0xcd,0x85,0x00,0xd2,0x30, + 0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0x91,0xcc,0x93,0xcd,0x85,0x00,0x01,0xff,0xce, + 0x91,0xcc,0x94,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0x91,0xcc,0x93,0xcc,0x80, + 0xcd,0x85,0x00,0x01,0xff,0xce,0x91,0xcc,0x94,0xcc,0x80,0xcd,0x85,0x00,0xd1,0x1a, + 0x10,0x0d,0x01,0xff,0xce,0x91,0xcc,0x93,0xcc,0x81,0xcd,0x85,0x00,0x01,0xff,0xce, + 0x91,0xcc,0x94,0xcc,0x81,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0x91,0xcc,0x93, + 0xcd,0x82,0xcd,0x85,0x00,0x01,0xff,0xce,0x91,0xcc,0x94,0xcd,0x82,0xcd,0x85,0x00, + 0xd3,0x64,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcd,0x85, + 0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0xb7, + 0xcc,0x93,0xcc,0x80,0xcd,0x85,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x80,0xcd, + 0x85,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xce,0xb7,0xcc,0x93,0xcc,0x81,0xcd,0x85, + 0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcc,0x81,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff, + 0xce,0xb7,0xcc,0x93,0xcd,0x82,0xcd,0x85,0x00,0x01,0xff,0xce,0xb7,0xcc,0x94,0xcd, + 0x82,0xcd,0x85,0x00,0xd2,0x30,0xd1,0x16,0x10,0x0b,0x01,0xff,0xce,0x97,0xcc,0x93, + 0xcd,0x85,0x00,0x01,0xff,0xce,0x97,0xcc,0x94,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff, + 0xce,0x97,0xcc,0x93,0xcc,0x80,0xcd,0x85,0x00,0x01,0xff,0xce,0x97,0xcc,0x94,0xcc, + 0x80,0xcd,0x85,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff,0xce,0x97,0xcc,0x93,0xcc,0x81, + 0xcd,0x85,0x00,0x01,0xff,0xce,0x97,0xcc,0x94,0xcc,0x81,0xcd,0x85,0x00,0x10,0x0d, + 0x01,0xff,0xce,0x97,0xcc,0x93,0xcd,0x82,0xcd,0x85,0x00,0x01,0xff,0xce,0x97,0xcc, + 0x94,0xcd,0x82,0xcd,0x85,0x00,0xd4,0xc8,0xd3,0x64,0xd2,0x30,0xd1,0x16,0x10,0x0b, + 0x01,0xff,0xcf,0x89,0xcc,0x93,0xcd,0x85,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcd, + 0x85,0x00,0x10,0x0d,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcc,0x80,0xcd,0x85,0x00,0x01, + 0xff,0xcf,0x89,0xcc,0x94,0xcc,0x80,0xcd,0x85,0x00,0xd1,0x1a,0x10,0x0d,0x01,0xff, + 0xcf,0x89,0xcc,0x93,0xcc,0x81,0xcd,0x85,0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcc, + 0x81,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xcf,0x89,0xcc,0x93,0xcd,0x82,0xcd,0x85, + 0x00,0x01,0xff,0xcf,0x89,0xcc,0x94,0xcd,0x82,0xcd,0x85,0x00,0xd2,0x30,0xd1,0x16, + 0x10,0x0b,0x01,0xff,0xce,0xa9,0xcc,0x93,0xcd,0x85,0x00,0x01,0xff,0xce,0xa9,0xcc, + 0x94,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0xa9,0xcc,0x93,0xcc,0x80,0xcd,0x85, + 0x00,0x01,0xff,0xce,0xa9,0xcc,0x94,0xcc,0x80,0xcd,0x85,0x00,0xd1,0x1a,0x10,0x0d, + 0x01,0xff,0xce,0xa9,0xcc,0x93,0xcc,0x81,0xcd,0x85,0x00,0x01,0xff,0xce,0xa9,0xcc, + 0x94,0xcc,0x81,0xcd,0x85,0x00,0x10,0x0d,0x01,0xff,0xce,0xa9,0xcc,0x93,0xcd,0x82, + 0xcd,0x85,0x00,0x01,0xff,0xce,0xa9,0xcc,0x94,0xcd,0x82,0xcd,0x85,0x00,0xd3,0x49, + 0xd2,0x26,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0xb1,0xcc,0x86,0x00,0x01,0xff,0xce, + 0xb1,0xcc,0x84,0x00,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x80,0xcd,0x85,0x00,0x01, + 0xff,0xce,0xb1,0xcd,0x85,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xce,0xb1,0xcc,0x81, + 0xcd,0x85,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xce,0xb1,0xcd,0x82,0x00,0x01,0xff, + 0xce,0xb1,0xcd,0x82,0xcd,0x85,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xce, + 0x91,0xcc,0x86,0x00,0x01,0xff,0xce,0x91,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xce, + 0x91,0xcc,0x80,0x00,0x01,0xff,0xce,0x91,0xcc,0x81,0x00,0xd1,0x0d,0x10,0x09,0x01, + 0xff,0xce,0x91,0xcd,0x85,0x00,0x01,0x00,0x10,0x07,0x01,0xff,0xce,0xb9,0x00,0x01, + 0x00,0xcf,0x86,0xe5,0x16,0x01,0xd4,0x8f,0xd3,0x44,0xd2,0x21,0xd1,0x0d,0x10,0x04, + 0x01,0x00,0x01,0xff,0xc2,0xa8,0xcd,0x82,0x00,0x10,0x0b,0x01,0xff,0xce,0xb7,0xcc, + 0x80,0xcd,0x85,0x00,0x01,0xff,0xce,0xb7,0xcd,0x85,0x00,0xd1,0x0f,0x10,0x0b,0x01, + 0xff,0xce,0xb7,0xcc,0x81,0xcd,0x85,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xce,0xb7, + 0xcd,0x82,0x00,0x01,0xff,0xce,0xb7,0xcd,0x82,0xcd,0x85,0x00,0xd2,0x24,0xd1,0x12, + 0x10,0x09,0x01,0xff,0xce,0x95,0xcc,0x80,0x00,0x01,0xff,0xce,0x95,0xcc,0x81,0x00, + 0x10,0x09,0x01,0xff,0xce,0x97,0xcc,0x80,0x00,0x01,0xff,0xce,0x97,0xcc,0x81,0x00, + 0xd1,0x13,0x10,0x09,0x01,0xff,0xce,0x97,0xcd,0x85,0x00,0x01,0xff,0xe1,0xbe,0xbf, + 0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0xe1,0xbe,0xbf,0xcc,0x81,0x00,0x01,0xff,0xe1, + 0xbe,0xbf,0xcd,0x82,0x00,0xd3,0x40,0xd2,0x28,0xd1,0x12,0x10,0x09,0x01,0xff,0xce, + 0xb9,0xcc,0x86,0x00,0x01,0xff,0xce,0xb9,0xcc,0x84,0x00,0x10,0x0b,0x01,0xff,0xce, + 0xb9,0xcc,0x88,0xcc,0x80,0x00,0x01,0xff,0xce,0xb9,0xcc,0x88,0xcc,0x81,0x00,0x51, + 0x04,0x00,0x00,0x10,0x09,0x01,0xff,0xce,0xb9,0xcd,0x82,0x00,0x01,0xff,0xce,0xb9, + 0xcc,0x88,0xcd,0x82,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xce,0x99,0xcc, + 0x86,0x00,0x01,0xff,0xce,0x99,0xcc,0x84,0x00,0x10,0x09,0x01,0xff,0xce,0x99,0xcc, + 0x80,0x00,0x01,0xff,0xce,0x99,0xcc,0x81,0x00,0xd1,0x0e,0x10,0x04,0x00,0x00,0x01, + 0xff,0xe1,0xbf,0xbe,0xcc,0x80,0x00,0x10,0x0a,0x01,0xff,0xe1,0xbf,0xbe,0xcc,0x81, + 0x00,0x01,0xff,0xe1,0xbf,0xbe,0xcd,0x82,0x00,0xd4,0x93,0xd3,0x4e,0xd2,0x28,0xd1, + 0x12,0x10,0x09,0x01,0xff,0xcf,0x85,0xcc,0x86,0x00,0x01,0xff,0xcf,0x85,0xcc,0x84, + 0x00,0x10,0x0b,0x01,0xff,0xcf,0x85,0xcc,0x88,0xcc,0x80,0x00,0x01,0xff,0xcf,0x85, + 0xcc,0x88,0xcc,0x81,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xcf,0x81,0xcc,0x93,0x00, + 0x01,0xff,0xcf,0x81,0xcc,0x94,0x00,0x10,0x09,0x01,0xff,0xcf,0x85,0xcd,0x82,0x00, + 0x01,0xff,0xcf,0x85,0xcc,0x88,0xcd,0x82,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01, + 0xff,0xce,0xa5,0xcc,0x86,0x00,0x01,0xff,0xce,0xa5,0xcc,0x84,0x00,0x10,0x09,0x01, + 0xff,0xce,0xa5,0xcc,0x80,0x00,0x01,0xff,0xce,0xa5,0xcc,0x81,0x00,0xd1,0x12,0x10, + 0x09,0x01,0xff,0xce,0xa1,0xcc,0x94,0x00,0x01,0xff,0xc2,0xa8,0xcc,0x80,0x00,0x10, + 0x09,0x01,0xff,0xc2,0xa8,0xcc,0x81,0x00,0x01,0xff,0x60,0x00,0xd3,0x3b,0xd2,0x18, + 0x51,0x04,0x00,0x00,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x80,0xcd,0x85,0x00,0x01, + 0xff,0xcf,0x89,0xcd,0x85,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xcf,0x89,0xcc,0x81, + 0xcd,0x85,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xcf,0x89,0xcd,0x82,0x00,0x01,0xff, + 0xcf,0x89,0xcd,0x82,0xcd,0x85,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xce, + 0x9f,0xcc,0x80,0x00,0x01,0xff,0xce,0x9f,0xcc,0x81,0x00,0x10,0x09,0x01,0xff,0xce, + 0xa9,0xcc,0x80,0x00,0x01,0xff,0xce,0xa9,0xcc,0x81,0x00,0xd1,0x10,0x10,0x09,0x01, + 0xff,0xce,0xa9,0xcd,0x85,0x00,0x01,0xff,0xc2,0xb4,0x00,0x10,0x04,0x01,0x00,0x00, + 0x00,0xe0,0x7e,0x0c,0xcf,0x86,0xe5,0xbb,0x08,0xe4,0x14,0x06,0xe3,0xf7,0x02,0xe2, + 0xbd,0x01,0xd1,0xd0,0xd0,0x4f,0xcf,0x86,0xd5,0x2e,0x94,0x2a,0xd3,0x18,0x92,0x14, + 0x91,0x10,0x10,0x08,0x01,0xff,0xe2,0x80,0x82,0x00,0x01,0xff,0xe2,0x80,0x83,0x00, + 0x01,0x00,0x01,0x00,0x92,0x0d,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff, + 0x00,0x01,0xff,0x00,0x01,0x00,0x94,0x1b,0x53,0x04,0x01,0x00,0xd2,0x09,0x11,0x04, + 0x01,0x00,0x01,0xff,0x00,0x51,0x05,0x01,0xff,0x00,0x10,0x05,0x01,0xff,0x00,0x04, + 0x00,0x01,0x00,0xcf,0x86,0xd5,0x48,0xd4,0x1c,0xd3,0x10,0x52,0x04,0x01,0x00,0x51, + 0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x06,0x00,0x52,0x04,0x04,0x00,0x11,0x04,0x04, + 0x00,0x06,0x00,0xd3,0x1c,0xd2,0x0c,0x51,0x04,0x06,0x00,0x10,0x04,0x06,0x00,0x07, + 0x00,0xd1,0x08,0x10,0x04,0x07,0x00,0x08,0x00,0x10,0x04,0x08,0x00,0x06,0x00,0x52, + 0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x06,0x00,0xd4,0x23,0xd3, + 0x14,0x52,0x05,0x06,0xff,0x00,0x91,0x0a,0x10,0x05,0x0a,0xff,0x00,0x00,0xff,0x00, + 0x0f,0xff,0x00,0x92,0x0a,0x11,0x05,0x0f,0xff,0x00,0x01,0xff,0x00,0x01,0xff,0x00, + 0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x06,0x00,0x00,0x00,0x01,0x00, + 0x01,0x00,0xd0,0x7e,0xcf,0x86,0xd5,0x34,0xd4,0x14,0x53,0x04,0x01,0x00,0x52,0x04, + 0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0xd3,0x10,0x52,0x04, + 0x08,0x00,0x91,0x08,0x10,0x04,0x08,0x00,0x0c,0x00,0x0c,0x00,0x52,0x04,0x0c,0x00, + 0x91,0x08,0x10,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0xd4,0x1c,0x53,0x04,0x01,0x00, + 0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x02,0x00,0x91,0x08,0x10,0x04, + 0x03,0x00,0x04,0x00,0x04,0x00,0xd3,0x10,0xd2,0x08,0x11,0x04,0x06,0x00,0x08,0x00, + 0x11,0x04,0x08,0x00,0x0b,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x0b,0x00,0x0c,0x00, + 0x10,0x04,0x0e,0x00,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x11,0x00,0x13,0x00, + 0xcf,0x86,0xd5,0x28,0x54,0x04,0x00,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04,0x01,0xe6, + 0x01,0x01,0x01,0xe6,0xd2,0x0c,0x51,0x04,0x01,0x01,0x10,0x04,0x01,0x01,0x01,0xe6, + 0x91,0x08,0x10,0x04,0x01,0xe6,0x01,0x00,0x01,0x00,0xd4,0x30,0xd3,0x1c,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x01,0x00,0x01,0xe6,0x04,0x00,0xd1,0x08,0x10,0x04,0x06,0x00, + 0x06,0x01,0x10,0x04,0x06,0x01,0x06,0xe6,0x92,0x10,0xd1,0x08,0x10,0x04,0x06,0xdc, + 0x06,0xe6,0x10,0x04,0x06,0x01,0x08,0x01,0x09,0xdc,0x93,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0a,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x81,0xd0,0x4f, + 0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x29,0xd3,0x13,0x52,0x04,0x01,0x00,0x51,0x04, + 0x01,0x00,0x10,0x07,0x01,0xff,0xce,0xa9,0x00,0x01,0x00,0x92,0x12,0x51,0x04,0x01, + 0x00,0x10,0x06,0x01,0xff,0x4b,0x00,0x01,0xff,0x41,0xcc,0x8a,0x00,0x01,0x00,0x53, + 0x04,0x01,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x01,0x00,0x04,0x00,0x10,0x04,0x04, + 0x00,0x07,0x00,0x91,0x08,0x10,0x04,0x08,0x00,0x06,0x00,0x06,0x00,0xcf,0x86,0x95, + 0x2c,0xd4,0x18,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0xd1,0x08,0x10,0x04,0x08, + 0x00,0x09,0x00,0x10,0x04,0x09,0x00,0x0a,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x0b, + 0x00,0x10,0x04,0x0b,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd0,0x68,0xcf, + 0x86,0xd5,0x48,0xd4,0x28,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x04,0x00,0x91,0x08,0x10,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x0a,0x00,0x0b,0x00,0x11,0x00,0x00,0x00,0x53,0x04,0x01,0x00,0x92, + 0x18,0x51,0x04,0x01,0x00,0x10,0x0a,0x01,0xff,0xe2,0x86,0x90,0xcc,0xb8,0x00,0x01, + 0xff,0xe2,0x86,0x92,0xcc,0xb8,0x00,0x01,0x00,0x94,0x1a,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x0a,0x01,0xff,0xe2,0x86,0x94,0xcc,0xb8, + 0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0x2e,0x94,0x2a,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0xd1,0x0e,0x10,0x04,0x01,0x00,0x01,0xff,0xe2,0x87,0x90,0xcc,0xb8, + 0x00,0x10,0x0a,0x01,0xff,0xe2,0x87,0x94,0xcc,0xb8,0x00,0x01,0xff,0xe2,0x87,0x92, + 0xcc,0xb8,0x00,0x01,0x00,0xd4,0x14,0x53,0x04,0x01,0x00,0x92,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x01,0x00,0x04,0x00,0x04,0x00,0x93,0x08,0x12,0x04,0x04,0x00,0x06, + 0x00,0x06,0x00,0xe2,0x38,0x02,0xe1,0x3f,0x01,0xd0,0x68,0xcf,0x86,0xd5,0x3e,0x94, + 0x3a,0xd3,0x16,0x52,0x04,0x01,0x00,0x91,0x0e,0x10,0x0a,0x01,0xff,0xe2,0x88,0x83, + 0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0xd2,0x12,0x91,0x0e,0x10,0x04,0x01,0x00,0x01, + 0xff,0xe2,0x88,0x88,0xcc,0xb8,0x00,0x01,0x00,0x91,0x0e,0x10,0x0a,0x01,0xff,0xe2, + 0x88,0x8b,0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x94,0x24,0x93,0x20,0x52, + 0x04,0x01,0x00,0xd1,0x0e,0x10,0x0a,0x01,0xff,0xe2,0x88,0xa3,0xcc,0xb8,0x00,0x01, + 0x00,0x10,0x0a,0x01,0xff,0xe2,0x88,0xa5,0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0x01, + 0x00,0xcf,0x86,0xd5,0x48,0x94,0x44,0xd3,0x2e,0xd2,0x12,0x91,0x0e,0x10,0x04,0x01, + 0x00,0x01,0xff,0xe2,0x88,0xbc,0xcc,0xb8,0x00,0x01,0x00,0xd1,0x0e,0x10,0x0a,0x01, + 0xff,0xe2,0x89,0x83,0xcc,0xb8,0x00,0x01,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xe2, + 0x89,0x85,0xcc,0xb8,0x00,0x92,0x12,0x91,0x0e,0x10,0x04,0x01,0x00,0x01,0xff,0xe2, + 0x89,0x88,0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x40,0xd3,0x1e,0x92, + 0x1a,0xd1,0x0c,0x10,0x08,0x01,0xff,0x3d,0xcc,0xb8,0x00,0x01,0x00,0x10,0x0a,0x01, + 0xff,0xe2,0x89,0xa1,0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0xd1, + 0x0e,0x10,0x04,0x01,0x00,0x01,0xff,0xe2,0x89,0x8d,0xcc,0xb8,0x00,0x10,0x08,0x01, + 0xff,0x3c,0xcc,0xb8,0x00,0x01,0xff,0x3e,0xcc,0xb8,0x00,0xd3,0x30,0xd2,0x18,0x91, + 0x14,0x10,0x0a,0x01,0xff,0xe2,0x89,0xa4,0xcc,0xb8,0x00,0x01,0xff,0xe2,0x89,0xa5, + 0xcc,0xb8,0x00,0x01,0x00,0x91,0x14,0x10,0x0a,0x01,0xff,0xe2,0x89,0xb2,0xcc,0xb8, + 0x00,0x01,0xff,0xe2,0x89,0xb3,0xcc,0xb8,0x00,0x01,0x00,0x92,0x18,0x91,0x14,0x10, + 0x0a,0x01,0xff,0xe2,0x89,0xb6,0xcc,0xb8,0x00,0x01,0xff,0xe2,0x89,0xb7,0xcc,0xb8, + 0x00,0x01,0x00,0x01,0x00,0xd0,0x86,0xcf,0x86,0xd5,0x50,0x94,0x4c,0xd3,0x30,0xd2, + 0x18,0x91,0x14,0x10,0x0a,0x01,0xff,0xe2,0x89,0xba,0xcc,0xb8,0x00,0x01,0xff,0xe2, + 0x89,0xbb,0xcc,0xb8,0x00,0x01,0x00,0x91,0x14,0x10,0x0a,0x01,0xff,0xe2,0x8a,0x82, + 0xcc,0xb8,0x00,0x01,0xff,0xe2,0x8a,0x83,0xcc,0xb8,0x00,0x01,0x00,0x92,0x18,0x91, + 0x14,0x10,0x0a,0x01,0xff,0xe2,0x8a,0x86,0xcc,0xb8,0x00,0x01,0xff,0xe2,0x8a,0x87, + 0xcc,0xb8,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x94,0x30,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0xd1,0x14,0x10,0x0a,0x01,0xff,0xe2,0x8a,0xa2,0xcc,0xb8,0x00,0x01, + 0xff,0xe2,0x8a,0xa8,0xcc,0xb8,0x00,0x10,0x0a,0x01,0xff,0xe2,0x8a,0xa9,0xcc,0xb8, + 0x00,0x01,0xff,0xe2,0x8a,0xab,0xcc,0xb8,0x00,0x01,0x00,0xcf,0x86,0x55,0x04,0x01, + 0x00,0xd4,0x5c,0xd3,0x2c,0x92,0x28,0xd1,0x14,0x10,0x0a,0x01,0xff,0xe2,0x89,0xbc, + 0xcc,0xb8,0x00,0x01,0xff,0xe2,0x89,0xbd,0xcc,0xb8,0x00,0x10,0x0a,0x01,0xff,0xe2, + 0x8a,0x91,0xcc,0xb8,0x00,0x01,0xff,0xe2,0x8a,0x92,0xcc,0xb8,0x00,0x01,0x00,0xd2, + 0x18,0x51,0x04,0x01,0x00,0x10,0x0a,0x01,0xff,0xe2,0x8a,0xb2,0xcc,0xb8,0x00,0x01, + 0xff,0xe2,0x8a,0xb3,0xcc,0xb8,0x00,0x91,0x14,0x10,0x0a,0x01,0xff,0xe2,0x8a,0xb4, + 0xcc,0xb8,0x00,0x01,0xff,0xe2,0x8a,0xb5,0xcc,0xb8,0x00,0x01,0x00,0x93,0x0c,0x92, + 0x08,0x11,0x04,0x01,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xd1,0x64,0xd0,0x3e,0xcf, + 0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01,0x00,0x04, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x94,0x20,0x53,0x04,0x01,0x00,0x92, + 0x18,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x80,0x88,0x00,0x10,0x08,0x01, + 0xff,0xe3,0x80,0x89,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0x55,0x04,0x01, + 0x00,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x04,0x00,0x91,0x08,0x10,0x04,0x06,0x00,0x04,0x00,0x04,0x00,0xd0, + 0x1e,0xcf,0x86,0x95,0x18,0x54,0x04,0x04,0x00,0x53,0x04,0x04,0x00,0x92,0x0c,0x51, + 0x04,0x04,0x00,0x10,0x04,0x04,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xcf,0x86,0xd5, + 0x2c,0xd4,0x14,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0x51,0x04,0x06,0x00,0x10, + 0x04,0x06,0x00,0x07,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x07,0x00,0x08, + 0x00,0x08,0x00,0x08,0x00,0x12,0x04,0x08,0x00,0x09,0x00,0xd4,0x14,0x53,0x04,0x09, + 0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x0b,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0xd3, + 0x08,0x12,0x04,0x0c,0x00,0x10,0x00,0xd2,0x0c,0x51,0x04,0x10,0x00,0x10,0x04,0x10, + 0x00,0x12,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x13,0x00,0xd3,0xa6,0xd2, + 0x74,0xd1,0x40,0xd0,0x22,0xcf,0x86,0x55,0x04,0x01,0x00,0x94,0x18,0x93,0x14,0x52, + 0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x04,0x00,0x10,0x04,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0x95,0x18,0x94,0x14,0x53,0x04,0x01,0x00,0x92, + 0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x00,0xd0,0x06,0xcf,0x06,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x14,0x53, + 0x04,0x01,0x00,0x92,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x06,0x00,0x06, + 0x00,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0x51,0x04,0x06,0x00,0x10,0x04,0x06, + 0x00,0x07,0x00,0xd1,0x06,0xcf,0x06,0x01,0x00,0xd0,0x1a,0xcf,0x86,0x95,0x14,0x54, + 0x04,0x01,0x00,0x93,0x0c,0x52,0x04,0x01,0x00,0x11,0x04,0x01,0x00,0x06,0x00,0x06, + 0x00,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0x54,0x04,0x01,0x00,0x13,0x04,0x04, + 0x00,0x06,0x00,0xd2,0xdc,0xd1,0x48,0xd0,0x26,0xcf,0x86,0x95,0x20,0x54,0x04,0x01, + 0x00,0xd3,0x0c,0x52,0x04,0x01,0x00,0x11,0x04,0x07,0x00,0x06,0x00,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x08,0x00,0x04,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0x55, + 0x04,0x01,0x00,0x54,0x04,0x01,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04,0x04,0x00,0x06, + 0x00,0x06,0x00,0x52,0x04,0x06,0x00,0x11,0x04,0x06,0x00,0x08,0x00,0xd0,0x5e,0xcf, + 0x86,0xd5,0x2c,0xd4,0x10,0x53,0x04,0x06,0x00,0x92,0x08,0x11,0x04,0x06,0x00,0x07, + 0x00,0x07,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04,0x07,0x00,0x08,0x00,0x08,0x00,0x52, + 0x04,0x08,0x00,0x91,0x08,0x10,0x04,0x08,0x00,0x0a,0x00,0x0b,0x00,0xd4,0x10,0x93, + 0x0c,0x92,0x08,0x11,0x04,0x07,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0xd3,0x10,0x92, + 0x0c,0x51,0x04,0x08,0x00,0x10,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0x52,0x04,0x0a, + 0x00,0x91,0x08,0x10,0x04,0x0a,0x00,0x0b,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x1c,0x94, + 0x18,0xd3,0x08,0x12,0x04,0x0a,0x00,0x0b,0x00,0x52,0x04,0x0b,0x00,0x51,0x04,0x0b, + 0x00,0x10,0x04,0x0c,0x00,0x0b,0x00,0x0b,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x51, + 0x04,0x0b,0x00,0x10,0x04,0x0c,0x00,0x0b,0x00,0x0c,0x00,0x0b,0x00,0x0b,0x00,0xd1, + 0xa8,0xd0,0x42,0xcf,0x86,0xd5,0x28,0x94,0x24,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10, + 0x04,0x10,0x00,0x01,0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x0c,0x00,0x01, + 0x00,0x92,0x08,0x11,0x04,0x01,0x00,0x0c,0x00,0x01,0x00,0x01,0x00,0x94,0x14,0x53, + 0x04,0x01,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x01,0x00,0x01,0x00,0x01, + 0x00,0x01,0x00,0xcf,0x86,0xd5,0x40,0xd4,0x18,0x53,0x04,0x01,0x00,0x52,0x04,0x01, + 0x00,0xd1,0x08,0x10,0x04,0x0c,0x00,0x01,0x00,0x10,0x04,0x0c,0x00,0x01,0x00,0xd3, + 0x18,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x0c,0x00,0x51,0x04,0x0c, + 0x00,0x10,0x04,0x01,0x00,0x0b,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x0c,0x00,0xd4,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x06,0x00,0x93,0x0c,0x52,0x04,0x06,0x00,0x11, + 0x04,0x06,0x00,0x01,0x00,0x01,0x00,0xd0,0x3e,0xcf,0x86,0xd5,0x18,0x54,0x04,0x01, + 0x00,0x93,0x10,0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x0c,0x00,0x0c, + 0x00,0x01,0x00,0x54,0x04,0x01,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c, + 0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10, + 0x04,0x01,0x00,0x0c,0x00,0xcf,0x86,0xd5,0x2c,0x94,0x28,0xd3,0x10,0x52,0x04,0x08, + 0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x09,0x00,0xd2,0x0c,0x51,0x04,0x09, + 0x00,0x10,0x04,0x09,0x00,0x0d,0x00,0x91,0x08,0x10,0x04,0x0a,0x00,0x0d,0x00,0x0c, + 0x00,0x06,0x00,0x94,0x0c,0x53,0x04,0x06,0x00,0x12,0x04,0x06,0x00,0x0a,0x00,0x06, + 0x00,0xe4,0x39,0x01,0xd3,0x0c,0xd2,0x06,0xcf,0x06,0x04,0x00,0xcf,0x06,0x06,0x00, + 0xd2,0x30,0xd1,0x06,0xcf,0x06,0x06,0x00,0xd0,0x06,0xcf,0x06,0x06,0x00,0xcf,0x86, + 0x95,0x1e,0x54,0x04,0x06,0x00,0x53,0x04,0x06,0x00,0x52,0x04,0x06,0x00,0x91,0x0e, + 0x10,0x0a,0x06,0xff,0xe2,0xab,0x9d,0xcc,0xb8,0x00,0x06,0x00,0x06,0x00,0x06,0x00, + 0xd1,0x80,0xd0,0x3a,0xcf,0x86,0xd5,0x28,0xd4,0x10,0x53,0x04,0x07,0x00,0x52,0x04, + 0x07,0x00,0x11,0x04,0x07,0x00,0x08,0x00,0xd3,0x08,0x12,0x04,0x08,0x00,0x09,0x00, + 0x92,0x0c,0x51,0x04,0x09,0x00,0x10,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0x94,0x0c, + 0x93,0x08,0x12,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00,0xcf,0x86,0xd5,0x30, + 0xd4,0x14,0x53,0x04,0x0a,0x00,0x52,0x04,0x0a,0x00,0x91,0x08,0x10,0x04,0x0a,0x00, + 0x10,0x00,0x10,0x00,0xd3,0x10,0x52,0x04,0x0a,0x00,0x91,0x08,0x10,0x04,0x0a,0x00, + 0x0b,0x00,0x0b,0x00,0x92,0x08,0x11,0x04,0x0b,0x00,0x10,0x00,0x10,0x00,0x54,0x04, + 0x10,0x00,0x93,0x0c,0x52,0x04,0x10,0x00,0x11,0x04,0x00,0x00,0x10,0x00,0x10,0x00, + 0xd0,0x32,0xcf,0x86,0xd5,0x14,0x54,0x04,0x10,0x00,0x93,0x0c,0x52,0x04,0x10,0x00, + 0x11,0x04,0x10,0x00,0x00,0x00,0x10,0x00,0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00, + 0xd2,0x08,0x11,0x04,0x10,0x00,0x14,0x00,0x91,0x08,0x10,0x04,0x14,0x00,0x10,0x00, + 0x10,0x00,0xcf,0x86,0xd5,0x28,0xd4,0x14,0x53,0x04,0x10,0x00,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x10,0x00,0x15,0x00,0x10,0x00,0x10,0x00,0x93,0x10,0x92,0x0c,0x51,0x04, + 0x10,0x00,0x10,0x04,0x13,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0xd4,0x0c,0x53,0x04, + 0x14,0x00,0x12,0x04,0x14,0x00,0x11,0x00,0x53,0x04,0x14,0x00,0x52,0x04,0x14,0x00, + 0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x15,0x00,0xe3,0xb9,0x01,0xd2,0xac,0xd1, + 0x68,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x08,0x00,0x94,0x14,0x53,0x04,0x08,0x00,0x52, + 0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00,0x00,0x08,0x00,0xcf, + 0x86,0xd5,0x18,0x54,0x04,0x08,0x00,0x53,0x04,0x08,0x00,0x52,0x04,0x08,0x00,0x51, + 0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00,0x00,0xd4,0x14,0x53,0x04,0x09,0x00,0x52, + 0x04,0x09,0x00,0x91,0x08,0x10,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0xd3,0x10,0x92, + 0x0c,0x91,0x08,0x10,0x04,0x0b,0x00,0x0a,0x00,0x0a,0x00,0x09,0x00,0x52,0x04,0x0a, + 0x00,0x11,0x04,0x0a,0x00,0x0b,0x00,0xd0,0x06,0xcf,0x06,0x08,0x00,0xcf,0x86,0x55, + 0x04,0x08,0x00,0xd4,0x1c,0x53,0x04,0x08,0x00,0xd2,0x0c,0x51,0x04,0x08,0x00,0x10, + 0x04,0x08,0x00,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00,0x0b,0xe6,0xd3, + 0x0c,0x92,0x08,0x11,0x04,0x0b,0xe6,0x0d,0x00,0x00,0x00,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x08,0x00,0x08,0x00,0x08,0x00,0xd1,0x6c,0xd0,0x2a,0xcf,0x86,0x55, + 0x04,0x08,0x00,0x94,0x20,0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10, + 0x04,0x00,0x00,0x0d,0x00,0x52,0x04,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x0d, + 0x00,0x00,0x00,0x08,0x00,0xcf,0x86,0x55,0x04,0x08,0x00,0xd4,0x1c,0xd3,0x0c,0x52, + 0x04,0x08,0x00,0x11,0x04,0x08,0x00,0x0d,0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00, + 0x00,0x10,0x04,0x00,0x00,0x08,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10, + 0x04,0x00,0x00,0x0c,0x09,0xd0,0x5a,0xcf,0x86,0xd5,0x18,0x54,0x04,0x08,0x00,0x93, + 0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00,0x00,0x00, + 0x00,0xd4,0x20,0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08, + 0x00,0x00,0x00,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00, + 0x00,0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00, + 0x00,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00,0x00,0xcf, + 0x86,0x95,0x40,0xd4,0x20,0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10, + 0x04,0x08,0x00,0x00,0x00,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08, + 0x00,0x00,0x00,0xd3,0x10,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08, + 0x00,0x00,0x00,0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x00, + 0x00,0x0a,0xe6,0xd2,0x9c,0xd1,0x68,0xd0,0x32,0xcf,0x86,0xd5,0x14,0x54,0x04,0x08, + 0x00,0x53,0x04,0x08,0x00,0x52,0x04,0x0a,0x00,0x11,0x04,0x08,0x00,0x0a,0x00,0x54, + 0x04,0x0a,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0a,0x00,0x0b,0x00,0x0d, + 0x00,0x0d,0x00,0x12,0x04,0x0d,0x00,0x10,0x00,0xcf,0x86,0x95,0x30,0x94,0x2c,0xd3, + 0x18,0xd2,0x0c,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x12,0x00,0x91,0x08,0x10, + 0x04,0x12,0x00,0x13,0x00,0x13,0x00,0xd2,0x08,0x11,0x04,0x13,0x00,0x14,0x00,0x51, + 0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0xd0,0x1e,0xcf, + 0x86,0x95,0x18,0x54,0x04,0x04,0x00,0x53,0x04,0x04,0x00,0x92,0x0c,0x51,0x04,0x04, + 0x00,0x10,0x04,0x00,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xcf,0x86,0x55,0x04,0x04, + 0x00,0x54,0x04,0x04,0x00,0x93,0x08,0x12,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0xd1, + 0x06,0xcf,0x06,0x04,0x00,0xd0,0x06,0xcf,0x06,0x04,0x00,0xcf,0x86,0xd5,0x14,0x54, + 0x04,0x04,0x00,0x93,0x0c,0x52,0x04,0x04,0x00,0x11,0x04,0x04,0x00,0x00,0x00,0x00, + 0x00,0x54,0x04,0x00,0x00,0x53,0x04,0x04,0x00,0x12,0x04,0x04,0x00,0x00,0x00,0xcf, + 0x86,0xe5,0xa6,0x05,0xe4,0x9f,0x05,0xe3,0x96,0x04,0xe2,0xe4,0x03,0xe1,0xc0,0x01, + 0xd0,0x3e,0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x1c,0x53,0x04,0x01,0x00,0xd2,0x0c, + 0x51,0x04,0x01,0x00,0x10,0x04,0x01,0xda,0x01,0xe4,0x91,0x08,0x10,0x04,0x01,0xe8, + 0x01,0xde,0x01,0xe0,0x53,0x04,0x01,0x00,0xd2,0x0c,0x51,0x04,0x04,0x00,0x10,0x04, + 0x04,0x00,0x06,0x00,0x51,0x04,0x06,0x00,0x10,0x04,0x04,0x00,0x01,0x00,0xcf,0x86, + 0xd5,0xaa,0xd4,0x32,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81, + 0x8b,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0x8d,0xe3,0x82, + 0x99,0x00,0x01,0x00,0xd3,0x3c,0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81, + 0x8f,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0x91,0xe3,0x82, + 0x99,0x00,0x01,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81,0x93,0xe3,0x82,0x99, + 0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0x95,0xe3,0x82,0x99,0x00,0x01,0x00, + 0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81,0x97,0xe3,0x82,0x99,0x00,0x01, + 0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0x99,0xe3,0x82,0x99,0x00,0x01,0x00,0xd1,0x0f, + 0x10,0x0b,0x01,0xff,0xe3,0x81,0x9b,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b,0x01, + 0xff,0xe3,0x81,0x9d,0xe3,0x82,0x99,0x00,0x01,0x00,0xd4,0x53,0xd3,0x3c,0xd2,0x1e, + 0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81,0x9f,0xe3,0x82,0x99,0x00,0x01,0x00,0x10, + 0x0b,0x01,0xff,0xe3,0x81,0xa1,0xe3,0x82,0x99,0x00,0x01,0x00,0xd1,0x0f,0x10,0x04, + 0x01,0x00,0x01,0xff,0xe3,0x81,0xa4,0xe3,0x82,0x99,0x00,0x10,0x04,0x01,0x00,0x01, + 0xff,0xe3,0x81,0xa6,0xe3,0x82,0x99,0x00,0x92,0x13,0x91,0x0f,0x10,0x04,0x01,0x00, + 0x01,0xff,0xe3,0x81,0xa8,0xe3,0x82,0x99,0x00,0x01,0x00,0x01,0x00,0xd3,0x4a,0xd2, + 0x25,0xd1,0x16,0x10,0x0b,0x01,0xff,0xe3,0x81,0xaf,0xe3,0x82,0x99,0x00,0x01,0xff, + 0xe3,0x81,0xaf,0xe3,0x82,0x9a,0x00,0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x81,0xb2, + 0xe3,0x82,0x99,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x81,0xb2,0xe3,0x82,0x9a, + 0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0xb5,0xe3,0x82,0x99,0x00,0x01,0xff, + 0xe3,0x81,0xb5,0xe3,0x82,0x9a,0x00,0xd2,0x1e,0xd1,0x0f,0x10,0x04,0x01,0x00,0x01, + 0xff,0xe3,0x81,0xb8,0xe3,0x82,0x99,0x00,0x10,0x0b,0x01,0xff,0xe3,0x81,0xb8,0xe3, + 0x82,0x9a,0x00,0x01,0x00,0x91,0x16,0x10,0x0b,0x01,0xff,0xe3,0x81,0xbb,0xe3,0x82, + 0x99,0x00,0x01,0xff,0xe3,0x81,0xbb,0xe3,0x82,0x9a,0x00,0x01,0x00,0xd0,0xee,0xcf, + 0x86,0xd5,0x42,0x54,0x04,0x01,0x00,0xd3,0x1b,0x52,0x04,0x01,0x00,0xd1,0x0f,0x10, + 0x0b,0x01,0xff,0xe3,0x81,0x86,0xe3,0x82,0x99,0x00,0x06,0x00,0x10,0x04,0x06,0x00, + 0x00,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x01,0x08,0x10,0x04,0x01,0x08, + 0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x82,0x9d,0xe3,0x82,0x99, + 0x00,0x06,0x00,0xd4,0x32,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x06,0x00,0x01, + 0x00,0x01,0x00,0x01,0x00,0x52,0x04,0x01,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3, + 0x82,0xab,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x82,0xad,0xe3, + 0x82,0x99,0x00,0x01,0x00,0xd3,0x3c,0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3, + 0x82,0xaf,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x82,0xb1,0xe3, + 0x82,0x99,0x00,0x01,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x82,0xb3,0xe3,0x82, + 0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x82,0xb5,0xe3,0x82,0x99,0x00,0x01, + 0x00,0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x82,0xb7,0xe3,0x82,0x99,0x00, + 0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x82,0xb9,0xe3,0x82,0x99,0x00,0x01,0x00,0xd1, + 0x0f,0x10,0x0b,0x01,0xff,0xe3,0x82,0xbb,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x0b, + 0x01,0xff,0xe3,0x82,0xbd,0xe3,0x82,0x99,0x00,0x01,0x00,0xcf,0x86,0xd5,0xd5,0xd4, + 0x53,0xd3,0x3c,0xd2,0x1e,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3,0x82,0xbf,0xe3,0x82, + 0x99,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x83,0x81,0xe3,0x82,0x99,0x00,0x01, + 0x00,0xd1,0x0f,0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x83,0x84,0xe3,0x82,0x99,0x00, + 0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x83,0x86,0xe3,0x82,0x99,0x00,0x92,0x13,0x91, + 0x0f,0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x83,0x88,0xe3,0x82,0x99,0x00,0x01,0x00, + 0x01,0x00,0xd3,0x4a,0xd2,0x25,0xd1,0x16,0x10,0x0b,0x01,0xff,0xe3,0x83,0x8f,0xe3, + 0x82,0x99,0x00,0x01,0xff,0xe3,0x83,0x8f,0xe3,0x82,0x9a,0x00,0x10,0x04,0x01,0x00, + 0x01,0xff,0xe3,0x83,0x92,0xe3,0x82,0x99,0x00,0xd1,0x0f,0x10,0x0b,0x01,0xff,0xe3, + 0x83,0x92,0xe3,0x82,0x9a,0x00,0x01,0x00,0x10,0x0b,0x01,0xff,0xe3,0x83,0x95,0xe3, + 0x82,0x99,0x00,0x01,0xff,0xe3,0x83,0x95,0xe3,0x82,0x9a,0x00,0xd2,0x1e,0xd1,0x0f, + 0x10,0x04,0x01,0x00,0x01,0xff,0xe3,0x83,0x98,0xe3,0x82,0x99,0x00,0x10,0x0b,0x01, + 0xff,0xe3,0x83,0x98,0xe3,0x82,0x9a,0x00,0x01,0x00,0x91,0x16,0x10,0x0b,0x01,0xff, + 0xe3,0x83,0x9b,0xe3,0x82,0x99,0x00,0x01,0xff,0xe3,0x83,0x9b,0xe3,0x82,0x9a,0x00, + 0x01,0x00,0x54,0x04,0x01,0x00,0xd3,0x22,0x52,0x04,0x01,0x00,0xd1,0x0f,0x10,0x0b, + 0x01,0xff,0xe3,0x82,0xa6,0xe3,0x82,0x99,0x00,0x01,0x00,0x10,0x04,0x01,0x00,0x01, + 0xff,0xe3,0x83,0xaf,0xe3,0x82,0x99,0x00,0xd2,0x25,0xd1,0x16,0x10,0x0b,0x01,0xff, + 0xe3,0x83,0xb0,0xe3,0x82,0x99,0x00,0x01,0xff,0xe3,0x83,0xb1,0xe3,0x82,0x99,0x00, + 0x10,0x0b,0x01,0xff,0xe3,0x83,0xb2,0xe3,0x82,0x99,0x00,0x01,0x00,0x51,0x04,0x01, + 0x00,0x10,0x0b,0x01,0xff,0xe3,0x83,0xbd,0xe3,0x82,0x99,0x00,0x06,0x00,0xd1,0x65, + 0xd0,0x46,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x52,0x04,0x00,0x00,0x91,0x08, + 0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd4,0x18,0x53,0x04, + 0x01,0x00,0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x0a,0x00,0x10,0x04, + 0x13,0x00,0x14,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0x94,0x15,0x93,0x11, + 0x52,0x04,0x01,0x00,0x91,0x09,0x10,0x05,0x01,0xff,0x00,0x01,0x00,0x01,0x00,0x01, + 0x00,0x01,0x00,0xd0,0x32,0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x54, + 0x04,0x04,0x00,0x53,0x04,0x04,0x00,0x92,0x0c,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x08,0x14,0x04,0x08,0x00,0x0a,0x00,0x94, + 0x0c,0x93,0x08,0x12,0x04,0x0a,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0xd2,0xa4,0xd1, + 0x5c,0xd0,0x22,0xcf,0x86,0x95,0x1c,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0x52, + 0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x07,0x00,0x10,0x04,0x07,0x00,0x00, + 0x00,0x01,0x00,0xcf,0x86,0xd5,0x20,0xd4,0x0c,0x93,0x08,0x12,0x04,0x01,0x00,0x0b, + 0x00,0x0b,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x07,0x00,0x06,0x00,0x06, + 0x00,0x06,0x00,0x06,0x00,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00,0x52,0x04,0x01, + 0x00,0x51,0x04,0x07,0x00,0x10,0x04,0x08,0x00,0x01,0x00,0xd0,0x1e,0xcf,0x86,0x55, + 0x04,0x01,0x00,0x54,0x04,0x01,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x01, + 0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0xcf,0x86,0xd5,0x10,0x94,0x0c,0x53, + 0x04,0x01,0x00,0x12,0x04,0x01,0x00,0x07,0x00,0x01,0x00,0x54,0x04,0x01,0x00,0x53, + 0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x16, + 0x00,0xd1,0x30,0xd0,0x06,0xcf,0x06,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0x54, + 0x04,0x01,0x00,0xd3,0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x07,0x00,0x92,0x0c,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00,0x01,0x00,0x01, + 0x00,0xd0,0x06,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x14,0x54,0x04,0x01,0x00,0x53, + 0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x11,0x04,0x01,0x00,0x07,0x00,0x54,0x04,0x01, + 0x00,0x53,0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x07,0x00,0xcf,0x06,0x04,0x00,0xcf,0x06,0x04,0x00,0xd1,0x48,0xd0,0x40,0xcf, + 0x86,0xd5,0x06,0xcf,0x06,0x04,0x00,0xd4,0x06,0xcf,0x06,0x04,0x00,0xd3,0x2c,0xd2, + 0x06,0xcf,0x06,0x04,0x00,0xd1,0x06,0xcf,0x06,0x04,0x00,0xd0,0x1a,0xcf,0x86,0x55, + 0x04,0x04,0x00,0x54,0x04,0x04,0x00,0x93,0x0c,0x52,0x04,0x04,0x00,0x11,0x04,0x04, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x07,0x00,0xcf,0x06,0x01,0x00,0xcf,0x86,0xcf, + 0x06,0x01,0x00,0xcf,0x86,0xcf,0x06,0x01,0x00,0xe2,0x71,0x05,0xd1,0x8c,0xd0,0x08, + 0xcf,0x86,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x01,0x00,0xd4,0x06, + 0xcf,0x06,0x01,0x00,0xd3,0x06,0xcf,0x06,0x01,0x00,0xd2,0x06,0xcf,0x06,0x01,0x00, + 0xd1,0x06,0xcf,0x06,0x01,0x00,0xd0,0x22,0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x10, + 0x93,0x0c,0x52,0x04,0x01,0x00,0x11,0x04,0x01,0x00,0x08,0x00,0x08,0x00,0x53,0x04, + 0x08,0x00,0x12,0x04,0x08,0x00,0x0a,0x00,0xcf,0x86,0xd5,0x28,0xd4,0x18,0xd3,0x08, + 0x12,0x04,0x0a,0x00,0x0b,0x00,0x52,0x04,0x0b,0x00,0x91,0x08,0x10,0x04,0x0d,0x00, + 0x11,0x00,0x11,0x00,0x93,0x0c,0x52,0x04,0x11,0x00,0x11,0x04,0x11,0x00,0x13,0x00, + 0x13,0x00,0x94,0x14,0x53,0x04,0x13,0x00,0x92,0x0c,0x51,0x04,0x13,0x00,0x10,0x04, + 0x13,0x00,0x14,0x00,0x14,0x00,0x00,0x00,0xe0,0xdb,0x04,0xcf,0x86,0xe5,0xdf,0x01, + 0xd4,0x06,0xcf,0x06,0x04,0x00,0xd3,0x74,0xd2,0x6e,0xd1,0x06,0xcf,0x06,0x04,0x00, + 0xd0,0x3e,0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x04,0x00,0x52,0x04,0x04,0x00, + 0x91,0x08,0x10,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0xd4,0x10,0x93,0x0c, + 0x92,0x08,0x11,0x04,0x04,0x00,0x06,0x00,0x04,0x00,0x04,0x00,0x93,0x10,0x52,0x04, + 0x04,0x00,0x91,0x08,0x10,0x04,0x06,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0xcf,0x86, + 0x95,0x24,0x94,0x20,0x93,0x1c,0xd2,0x0c,0x91,0x08,0x10,0x04,0x04,0x00,0x06,0x00, + 0x04,0x00,0xd1,0x08,0x10,0x04,0x04,0x00,0x06,0x00,0x10,0x04,0x04,0x00,0x00,0x00, + 0x00,0x00,0x0b,0x00,0x0b,0x00,0xcf,0x06,0x0a,0x00,0xd2,0x84,0xd1,0x4c,0xd0,0x16, + 0xcf,0x86,0x55,0x04,0x0a,0x00,0x94,0x0c,0x53,0x04,0x0a,0x00,0x12,0x04,0x0a,0x00, + 0x00,0x00,0x00,0x00,0xcf,0x86,0x55,0x04,0x0a,0x00,0xd4,0x1c,0xd3,0x0c,0x92,0x08, + 0x11,0x04,0x0c,0x00,0x0a,0x00,0x0a,0x00,0x52,0x04,0x0a,0x00,0x51,0x04,0x0a,0x00, + 0x10,0x04,0x0a,0x00,0x0a,0xe6,0xd3,0x08,0x12,0x04,0x0a,0x00,0x0d,0xe6,0x52,0x04, + 0x0d,0xe6,0x11,0x04,0x0a,0xe6,0x0a,0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04, + 0x0a,0x00,0x53,0x04,0x0a,0x00,0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04, + 0x11,0xe6,0x0d,0xe6,0x0b,0x00,0xcf,0x86,0x55,0x04,0x0b,0x00,0x54,0x04,0x0b,0x00, + 0x93,0x0c,0x92,0x08,0x11,0x04,0x0b,0xe6,0x0b,0x00,0x0b,0x00,0x00,0x00,0xd1,0x40, + 0xd0,0x3a,0xcf,0x86,0xd5,0x24,0x54,0x04,0x08,0x00,0xd3,0x10,0x52,0x04,0x08,0x00, + 0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x09,0x00,0x92,0x0c,0x51,0x04,0x09,0x00, + 0x10,0x04,0x09,0x00,0x0a,0x00,0x0a,0x00,0x94,0x10,0x93,0x0c,0x92,0x08,0x11,0x04, + 0x09,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00,0x0a,0x00,0xcf,0x06,0x0a,0x00,0xd0,0x5e, + 0xcf,0x86,0xd5,0x28,0xd4,0x18,0x53,0x04,0x0a,0x00,0x52,0x04,0x0a,0x00,0xd1,0x08, + 0x10,0x04,0x0a,0x00,0x0c,0x00,0x10,0x04,0x0c,0x00,0x11,0x00,0x93,0x0c,0x92,0x08, + 0x11,0x04,0x0c,0x00,0x0d,0x00,0x10,0x00,0x10,0x00,0xd4,0x1c,0x53,0x04,0x0c,0x00, + 0xd2,0x0c,0x51,0x04,0x0c,0x00,0x10,0x04,0x0d,0x00,0x10,0x00,0x51,0x04,0x10,0x00, + 0x10,0x04,0x12,0x00,0x14,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04,0x10,0x00,0x11,0x00, + 0x11,0x00,0x92,0x08,0x11,0x04,0x14,0x00,0x15,0x00,0x15,0x00,0xcf,0x86,0xd5,0x1c, + 0x94,0x18,0x93,0x14,0xd2,0x08,0x11,0x04,0x00,0x00,0x15,0x00,0x51,0x04,0x15,0x00, + 0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x04,0x00,0x00,0xd3,0x10, + 0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x92,0x0c, + 0x51,0x04,0x0d,0x00,0x10,0x04,0x0c,0x00,0x0a,0x00,0x0a,0x00,0xe4,0xf2,0x02,0xe3, + 0x65,0x01,0xd2,0x98,0xd1,0x48,0xd0,0x36,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10, + 0x52,0x04,0x08,0x00,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x09,0x08,0x00,0x08,0x00, + 0x08,0x00,0xd4,0x0c,0x53,0x04,0x08,0x00,0x12,0x04,0x08,0x00,0x00,0x00,0x53,0x04, + 0x0b,0x00,0x92,0x08,0x11,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0x55,0x04, + 0x09,0x00,0x54,0x04,0x09,0x00,0x13,0x04,0x09,0x00,0x00,0x00,0xd0,0x06,0xcf,0x06, + 0x0a,0x00,0xcf,0x86,0xd5,0x2c,0xd4,0x1c,0xd3,0x10,0x52,0x04,0x0a,0x00,0x91,0x08, + 0x10,0x04,0x0a,0x09,0x12,0x00,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00, + 0x0a,0x00,0x53,0x04,0x0a,0x00,0x92,0x08,0x11,0x04,0x0a,0x00,0x00,0x00,0x00,0x00, + 0x54,0x04,0x0b,0xe6,0xd3,0x0c,0x92,0x08,0x11,0x04,0x0b,0xe6,0x0b,0x00,0x0b,0x00, + 0x52,0x04,0x0b,0x00,0x11,0x04,0x11,0x00,0x14,0x00,0xd1,0x60,0xd0,0x22,0xcf,0x86, + 0x55,0x04,0x0a,0x00,0x94,0x18,0x53,0x04,0x0a,0x00,0xd2,0x0c,0x51,0x04,0x0a,0x00, + 0x10,0x04,0x0a,0x00,0x0a,0xdc,0x11,0x04,0x0a,0xdc,0x0a,0x00,0x0a,0x00,0xcf,0x86, + 0xd5,0x24,0x54,0x04,0x0a,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x0a,0x00,0x10,0x04, + 0x0a,0x00,0x0a,0x09,0x00,0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04, + 0x00,0x00,0x0a,0x00,0x54,0x04,0x0b,0x00,0x53,0x04,0x0b,0x00,0x52,0x04,0x0b,0x00, + 0x91,0x08,0x10,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0xd0,0x1e,0xcf,0x86,0x55,0x04, + 0x0b,0x00,0x54,0x04,0x0b,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x0b,0x00,0x10,0x04, + 0x0b,0x00,0x0b,0x07,0x0b,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x34,0xd4,0x20,0xd3,0x10, + 0x92,0x0c,0x91,0x08,0x10,0x04,0x0b,0x09,0x0b,0x00,0x0b,0x00,0x0b,0x00,0x52,0x04, + 0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x00,0x00,0x0b,0x00,0x53,0x04,0x0b,0x00, + 0xd2,0x08,0x11,0x04,0x0b,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x0b,0x00,0x54,0x04, + 0x10,0x00,0x53,0x04,0x10,0x00,0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04, + 0x10,0x00,0x00,0x00,0xd2,0xd0,0xd1,0x50,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x0a,0x00, + 0x54,0x04,0x0a,0x00,0x93,0x10,0x52,0x04,0x0a,0x00,0x51,0x04,0x0a,0x00,0x10,0x04, + 0x0a,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x20,0xd4,0x10,0x53,0x04,0x0a,0x00, + 0x52,0x04,0x0a,0x00,0x11,0x04,0x0a,0x00,0x00,0x00,0x53,0x04,0x0a,0x00,0x92,0x08, + 0x11,0x04,0x0a,0x00,0x00,0x00,0x0a,0x00,0x54,0x04,0x0b,0x00,0x53,0x04,0x0b,0x00, + 0x12,0x04,0x0b,0x00,0x10,0x00,0xd0,0x3a,0xcf,0x86,0x55,0x04,0x0b,0x00,0x54,0x04, + 0x0b,0x00,0xd3,0x1c,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0b,0xe6,0x0b,0x00,0x0b,0xe6, + 0xd1,0x08,0x10,0x04,0x0b,0xdc,0x0b,0x00,0x10,0x04,0x0b,0x00,0x0b,0xe6,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x0b,0xe6,0x0b,0x00,0x0b,0x00,0x11,0x04,0x0b,0x00,0x0b,0xe6, + 0xcf,0x86,0xd5,0x2c,0xd4,0x18,0x93,0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x0b,0x00, + 0x0b,0xe6,0x10,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x00,0x00, + 0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0b,0x00,0x0b,0x00,0x54,0x04, + 0x0d,0x00,0x93,0x10,0x52,0x04,0x0d,0x00,0x51,0x04,0x0d,0x00,0x10,0x04,0x0d,0x09, + 0x00,0x00,0x00,0x00,0xd1,0x8c,0xd0,0x72,0xcf,0x86,0xd5,0x4c,0xd4,0x30,0xd3,0x18, + 0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00,0x0c,0x00,0x51,0x04,0x0c,0x00, + 0x10,0x04,0x0c,0x00,0x00,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00, + 0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x00,0x00,0x93,0x18,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x94,0x20,0xd3,0x10,0x52,0x04,0x0c,0x00,0x51,0x04, + 0x0c,0x00,0x10,0x04,0x0c,0x00,0x00,0x00,0x52,0x04,0x0c,0x00,0x51,0x04,0x0c,0x00, + 0x10,0x04,0x0c,0x00,0x00,0x00,0x10,0x00,0xcf,0x86,0x55,0x04,0x10,0x00,0x94,0x10, + 0x93,0x0c,0x52,0x04,0x11,0x00,0x11,0x04,0x10,0x00,0x15,0x00,0x00,0x00,0x11,0x00, + 0xd0,0x06,0xcf,0x06,0x11,0x00,0xcf,0x86,0x55,0x04,0x0b,0x00,0xd4,0x14,0x53,0x04, + 0x0b,0x00,0x52,0x04,0x0b,0x00,0x91,0x08,0x10,0x04,0x0b,0x00,0x0b,0x09,0x00,0x00, + 0x53,0x04,0x0b,0x00,0x92,0x08,0x11,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0xcf,0x06, + 0x02,0xff,0xff,0xcf,0x86,0xcf,0x06,0x02,0xff,0xff,0xd1,0x76,0xd0,0x09,0xcf,0x86, + 0xcf,0x06,0x02,0xff,0xff,0xcf,0x86,0x85,0xd4,0x07,0xcf,0x06,0x02,0xff,0xff,0xd3, + 0x07,0xcf,0x06,0x02,0xff,0xff,0xd2,0x07,0xcf,0x06,0x02,0xff,0xff,0xd1,0x07,0xcf, + 0x06,0x02,0xff,0xff,0xd0,0x18,0xcf,0x86,0x55,0x05,0x02,0xff,0xff,0x94,0x0d,0x93, + 0x09,0x12,0x05,0x02,0xff,0xff,0x00,0x00,0x00,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x24, + 0x94,0x20,0xd3,0x10,0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00, + 0x00,0x00,0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0b,0x00,0x0b,0x00, + 0x0b,0x00,0x54,0x04,0x0b,0x00,0x53,0x04,0x0b,0x00,0x12,0x04,0x0b,0x00,0x00,0x00, + 0xd0,0x08,0xcf,0x86,0xcf,0x06,0x01,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x01,0x00, + 0xe4,0x9c,0x10,0xe3,0x16,0x08,0xd2,0x06,0xcf,0x06,0x01,0x00,0xe1,0x08,0x04,0xe0, + 0x04,0x02,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe8,0xb1,0x88,0x00,0x01,0xff,0xe6,0x9b,0xb4,0x00,0x10,0x08,0x01, + 0xff,0xe8,0xbb,0x8a,0x00,0x01,0xff,0xe8,0xb3,0x88,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe6,0xbb,0x91,0x00,0x01,0xff,0xe4,0xb8,0xb2,0x00,0x10,0x08,0x01,0xff,0xe5, + 0x8f,0xa5,0x00,0x01,0xff,0xe9,0xbe,0x9c,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe9,0xbe,0x9c,0x00,0x01,0xff,0xe5,0xa5,0x91,0x00,0x10,0x08,0x01,0xff,0xe9, + 0x87,0x91,0x00,0x01,0xff,0xe5,0x96,0x87,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5, + 0xa5,0x88,0x00,0x01,0xff,0xe6,0x87,0xb6,0x00,0x10,0x08,0x01,0xff,0xe7,0x99,0xa9, + 0x00,0x01,0xff,0xe7,0xbe,0x85,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe8,0x98,0xbf,0x00,0x01,0xff,0xe8,0x9e,0xba,0x00,0x10,0x08,0x01,0xff,0xe8, + 0xa3,0xb8,0x00,0x01,0xff,0xe9,0x82,0x8f,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe6, + 0xa8,0x82,0x00,0x01,0xff,0xe6,0xb4,0x9b,0x00,0x10,0x08,0x01,0xff,0xe7,0x83,0x99, + 0x00,0x01,0xff,0xe7,0x8f,0x9e,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe8, + 0x90,0xbd,0x00,0x01,0xff,0xe9,0x85,0xaa,0x00,0x10,0x08,0x01,0xff,0xe9,0xa7,0xb1, + 0x00,0x01,0xff,0xe4,0xba,0x82,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5,0x8d,0xb5, + 0x00,0x01,0xff,0xe6,0xac,0x84,0x00,0x10,0x08,0x01,0xff,0xe7,0x88,0x9b,0x00,0x01, + 0xff,0xe8,0x98,0xad,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe9,0xb8,0x9e,0x00,0x01,0xff,0xe5,0xb5,0x90,0x00,0x10,0x08,0x01,0xff,0xe6, + 0xbf,0xab,0x00,0x01,0xff,0xe8,0x97,0x8d,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe8, + 0xa5,0xa4,0x00,0x01,0xff,0xe6,0x8b,0x89,0x00,0x10,0x08,0x01,0xff,0xe8,0x87,0x98, + 0x00,0x01,0xff,0xe8,0xa0,0x9f,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5, + 0xbb,0x8a,0x00,0x01,0xff,0xe6,0x9c,0x97,0x00,0x10,0x08,0x01,0xff,0xe6,0xb5,0xaa, + 0x00,0x01,0xff,0xe7,0x8b,0xbc,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe9,0x83,0x8e, + 0x00,0x01,0xff,0xe4,0xbe,0x86,0x00,0x10,0x08,0x01,0xff,0xe5,0x86,0xb7,0x00,0x01, + 0xff,0xe5,0x8b,0x9e,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe6, + 0x93,0x84,0x00,0x01,0xff,0xe6,0xab,0x93,0x00,0x10,0x08,0x01,0xff,0xe7,0x88,0x90, + 0x00,0x01,0xff,0xe7,0x9b,0xa7,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe8,0x80,0x81, + 0x00,0x01,0xff,0xe8,0x98,0x86,0x00,0x10,0x08,0x01,0xff,0xe8,0x99,0x9c,0x00,0x01, + 0xff,0xe8,0xb7,0xaf,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe9,0x9c,0xb2, + 0x00,0x01,0xff,0xe9,0xad,0xaf,0x00,0x10,0x08,0x01,0xff,0xe9,0xb7,0xba,0x00,0x01, + 0xff,0xe7,0xa2,0x8c,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe7,0xa5,0xbf,0x00,0x01, + 0xff,0xe7,0xb6,0xa0,0x00,0x10,0x08,0x01,0xff,0xe8,0x8f,0x89,0x00,0x01,0xff,0xe9, + 0x8c,0x84,0x00,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe9,0xb9,0xbf,0x00,0x01,0xff,0xe8,0xab,0x96,0x00,0x10,0x08, + 0x01,0xff,0xe5,0xa3,0x9f,0x00,0x01,0xff,0xe5,0xbc,0x84,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe7,0xb1,0xa0,0x00,0x01,0xff,0xe8,0x81,0xbe,0x00,0x10,0x08,0x01,0xff, + 0xe7,0x89,0xa2,0x00,0x01,0xff,0xe7,0xa3,0x8a,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe8,0xb3,0x82,0x00,0x01,0xff,0xe9,0x9b,0xb7,0x00,0x10,0x08,0x01,0xff, + 0xe5,0xa3,0x98,0x00,0x01,0xff,0xe5,0xb1,0xa2,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe6,0xa8,0x93,0x00,0x01,0xff,0xe6,0xb7,0x9a,0x00,0x10,0x08,0x01,0xff,0xe6,0xbc, + 0x8f,0x00,0x01,0xff,0xe7,0xb4,0xaf,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe7,0xb8,0xb7,0x00,0x01,0xff,0xe9,0x99,0x8b,0x00,0x10,0x08,0x01,0xff, + 0xe5,0x8b,0x92,0x00,0x01,0xff,0xe8,0x82,0x8b,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe5,0x87,0x9c,0x00,0x01,0xff,0xe5,0x87,0x8c,0x00,0x10,0x08,0x01,0xff,0xe7,0xa8, + 0x9c,0x00,0x01,0xff,0xe7,0xb6,0xbe,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe8,0x8f,0xb1,0x00,0x01,0xff,0xe9,0x99,0xb5,0x00,0x10,0x08,0x01,0xff,0xe8,0xae, + 0x80,0x00,0x01,0xff,0xe6,0x8b,0x8f,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe6,0xa8, + 0x82,0x00,0x01,0xff,0xe8,0xab,0xbe,0x00,0x10,0x08,0x01,0xff,0xe4,0xb8,0xb9,0x00, + 0x01,0xff,0xe5,0xaf,0xa7,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe6,0x80,0x92,0x00,0x01,0xff,0xe7,0x8e,0x87,0x00,0x10,0x08,0x01,0xff, + 0xe7,0x95,0xb0,0x00,0x01,0xff,0xe5,0x8c,0x97,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe7,0xa3,0xbb,0x00,0x01,0xff,0xe4,0xbe,0xbf,0x00,0x10,0x08,0x01,0xff,0xe5,0xbe, + 0xa9,0x00,0x01,0xff,0xe4,0xb8,0x8d,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe6,0xb3,0x8c,0x00,0x01,0xff,0xe6,0x95,0xb8,0x00,0x10,0x08,0x01,0xff,0xe7,0xb4, + 0xa2,0x00,0x01,0xff,0xe5,0x8f,0x83,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5,0xa1, + 0x9e,0x00,0x01,0xff,0xe7,0x9c,0x81,0x00,0x10,0x08,0x01,0xff,0xe8,0x91,0x89,0x00, + 0x01,0xff,0xe8,0xaa,0xaa,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe6,0xae,0xba,0x00,0x01,0xff,0xe8,0xbe,0xb0,0x00,0x10,0x08,0x01,0xff,0xe6,0xb2, + 0x88,0x00,0x01,0xff,0xe6,0x8b,0xbe,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe8,0x8b, + 0xa5,0x00,0x01,0xff,0xe6,0x8e,0xa0,0x00,0x10,0x08,0x01,0xff,0xe7,0x95,0xa5,0x00, + 0x01,0xff,0xe4,0xba,0xae,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5,0x85, + 0xa9,0x00,0x01,0xff,0xe5,0x87,0x89,0x00,0x10,0x08,0x01,0xff,0xe6,0xa2,0x81,0x00, + 0x01,0xff,0xe7,0xb3,0xa7,0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe8,0x89,0xaf,0x00, + 0x01,0xff,0xe8,0xab,0x92,0x00,0x10,0x08,0x01,0xff,0xe9,0x87,0x8f,0x00,0x01,0xff, + 0xe5,0x8b,0xb5,0x00,0xe0,0x04,0x02,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe5,0x91,0x82,0x00,0x01,0xff,0xe5,0xa5, + 0xb3,0x00,0x10,0x08,0x01,0xff,0xe5,0xbb,0xac,0x00,0x01,0xff,0xe6,0x97,0x85,0x00, + 0xd1,0x10,0x10,0x08,0x01,0xff,0xe6,0xbf,0xbe,0x00,0x01,0xff,0xe7,0xa4,0xaa,0x00, + 0x10,0x08,0x01,0xff,0xe9,0x96,0xad,0x00,0x01,0xff,0xe9,0xa9,0xaa,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0xe9,0xba,0x97,0x00,0x01,0xff,0xe9,0xbb,0x8e,0x00, + 0x10,0x08,0x01,0xff,0xe5,0x8a,0x9b,0x00,0x01,0xff,0xe6,0x9b,0x86,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe6,0xad,0xb7,0x00,0x01,0xff,0xe8,0xbd,0xa2,0x00,0x10,0x08, + 0x01,0xff,0xe5,0xb9,0xb4,0x00,0x01,0xff,0xe6,0x86,0x90,0x00,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0xe6,0x88,0x80,0x00,0x01,0xff,0xe6,0x92,0x9a,0x00, + 0x10,0x08,0x01,0xff,0xe6,0xbc,0xa3,0x00,0x01,0xff,0xe7,0x85,0x89,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe7,0x92,0x89,0x00,0x01,0xff,0xe7,0xa7,0x8a,0x00,0x10,0x08, + 0x01,0xff,0xe7,0xb7,0xb4,0x00,0x01,0xff,0xe8,0x81,0xaf,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe8,0xbc,0xa6,0x00,0x01,0xff,0xe8,0x93,0xae,0x00,0x10,0x08, + 0x01,0xff,0xe9,0x80,0xa3,0x00,0x01,0xff,0xe9,0x8d,0x8a,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe5,0x88,0x97,0x00,0x01,0xff,0xe5,0x8a,0xa3,0x00,0x10,0x08,0x01,0xff, + 0xe5,0x92,0xbd,0x00,0x01,0xff,0xe7,0x83,0x88,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0xe8,0xa3,0x82,0x00,0x01,0xff,0xe8,0xaa,0xaa,0x00, + 0x10,0x08,0x01,0xff,0xe5,0xbb,0x89,0x00,0x01,0xff,0xe5,0xbf,0xb5,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe6,0x8d,0xbb,0x00,0x01,0xff,0xe6,0xae,0xae,0x00,0x10,0x08, + 0x01,0xff,0xe7,0xb0,0xbe,0x00,0x01,0xff,0xe7,0x8d,0xb5,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe4,0xbb,0xa4,0x00,0x01,0xff,0xe5,0x9b,0xb9,0x00,0x10,0x08, + 0x01,0xff,0xe5,0xaf,0xa7,0x00,0x01,0xff,0xe5,0xb6,0xba,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe6,0x80,0x9c,0x00,0x01,0xff,0xe7,0x8e,0xb2,0x00,0x10,0x08,0x01,0xff, + 0xe7,0x91,0xa9,0x00,0x01,0xff,0xe7,0xbe,0x9a,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe8,0x81,0x86,0x00,0x01,0xff,0xe9,0x88,0xb4,0x00,0x10,0x08, + 0x01,0xff,0xe9,0x9b,0xb6,0x00,0x01,0xff,0xe9,0x9d,0x88,0x00,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe9,0xa0,0x98,0x00,0x01,0xff,0xe4,0xbe,0x8b,0x00,0x10,0x08,0x01,0xff, + 0xe7,0xa6,0xae,0x00,0x01,0xff,0xe9,0x86,0xb4,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe9,0x9a,0xb8,0x00,0x01,0xff,0xe6,0x83,0xa1,0x00,0x10,0x08,0x01,0xff, + 0xe4,0xba,0x86,0x00,0x01,0xff,0xe5,0x83,0x9a,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe5,0xaf,0xae,0x00,0x01,0xff,0xe5,0xb0,0xbf,0x00,0x10,0x08,0x01,0xff,0xe6,0x96, + 0x99,0x00,0x01,0xff,0xe6,0xa8,0x82,0x00,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe7,0x87,0x8e,0x00,0x01,0xff,0xe7, + 0x99,0x82,0x00,0x10,0x08,0x01,0xff,0xe8,0x93,0xbc,0x00,0x01,0xff,0xe9,0x81,0xbc, + 0x00,0xd1,0x10,0x10,0x08,0x01,0xff,0xe9,0xbe,0x8d,0x00,0x01,0xff,0xe6,0x9a,0x88, + 0x00,0x10,0x08,0x01,0xff,0xe9,0x98,0xae,0x00,0x01,0xff,0xe5,0x8a,0x89,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe6,0x9d,0xbb,0x00,0x01,0xff,0xe6,0x9f,0xb3, + 0x00,0x10,0x08,0x01,0xff,0xe6,0xb5,0x81,0x00,0x01,0xff,0xe6,0xba,0x9c,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe7,0x90,0x89,0x00,0x01,0xff,0xe7,0x95,0x99,0x00,0x10, + 0x08,0x01,0xff,0xe7,0xa1,0xab,0x00,0x01,0xff,0xe7,0xb4,0x90,0x00,0xd3,0x40,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe9,0xa1,0x9e,0x00,0x01,0xff,0xe5,0x85,0xad, + 0x00,0x10,0x08,0x01,0xff,0xe6,0x88,0xae,0x00,0x01,0xff,0xe9,0x99,0xb8,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe5,0x80,0xab,0x00,0x01,0xff,0xe5,0xb4,0x99,0x00,0x10, + 0x08,0x01,0xff,0xe6,0xb7,0xaa,0x00,0x01,0xff,0xe8,0xbc,0xaa,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe5,0xbe,0x8b,0x00,0x01,0xff,0xe6,0x85,0x84,0x00,0x10, + 0x08,0x01,0xff,0xe6,0xa0,0x97,0x00,0x01,0xff,0xe7,0x8e,0x87,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe9,0x9a,0x86,0x00,0x01,0xff,0xe5,0x88,0xa9,0x00,0x10,0x08,0x01, + 0xff,0xe5,0x90,0x8f,0x00,0x01,0xff,0xe5,0xb1,0xa5,0x00,0xd4,0x80,0xd3,0x40,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x01,0xff,0xe6,0x98,0x93,0x00,0x01,0xff,0xe6,0x9d,0x8e, + 0x00,0x10,0x08,0x01,0xff,0xe6,0xa2,0xa8,0x00,0x01,0xff,0xe6,0xb3,0xa5,0x00,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe7,0x90,0x86,0x00,0x01,0xff,0xe7,0x97,0xa2,0x00,0x10, + 0x08,0x01,0xff,0xe7,0xbd,0xb9,0x00,0x01,0xff,0xe8,0xa3,0x8f,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe8,0xa3,0xa1,0x00,0x01,0xff,0xe9,0x87,0x8c,0x00,0x10, + 0x08,0x01,0xff,0xe9,0x9b,0xa2,0x00,0x01,0xff,0xe5,0x8c,0xbf,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe6,0xba,0xba,0x00,0x01,0xff,0xe5,0x90,0x9d,0x00,0x10,0x08,0x01, + 0xff,0xe7,0x87,0x90,0x00,0x01,0xff,0xe7,0x92,0x98,0x00,0xd3,0x40,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x01,0xff,0xe8,0x97,0xba,0x00,0x01,0xff,0xe9,0x9a,0xa3,0x00,0x10, + 0x08,0x01,0xff,0xe9,0xb1,0x97,0x00,0x01,0xff,0xe9,0xba,0x9f,0x00,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe6,0x9e,0x97,0x00,0x01,0xff,0xe6,0xb7,0x8b,0x00,0x10,0x08,0x01, + 0xff,0xe8,0x87,0xa8,0x00,0x01,0xff,0xe7,0xab,0x8b,0x00,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x01,0xff,0xe7,0xac,0xa0,0x00,0x01,0xff,0xe7,0xb2,0x92,0x00,0x10,0x08,0x01, + 0xff,0xe7,0x8b,0x80,0x00,0x01,0xff,0xe7,0x82,0x99,0x00,0xd1,0x10,0x10,0x08,0x01, + 0xff,0xe8,0xad,0x98,0x00,0x01,0xff,0xe4,0xbb,0x80,0x00,0x10,0x08,0x01,0xff,0xe8, + 0x8c,0xb6,0x00,0x01,0xff,0xe5,0x88,0xba,0x00,0xe2,0xad,0x06,0xe1,0xc4,0x03,0xe0, + 0xcb,0x01,0xcf,0x86,0xd5,0xe4,0xd4,0x74,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x01,0xff,0xe5,0x88,0x87,0x00,0x01,0xff,0xe5,0xba,0xa6,0x00,0x10,0x08,0x01,0xff, + 0xe6,0x8b,0x93,0x00,0x01,0xff,0xe7,0xb3,0x96,0x00,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe5,0xae,0x85,0x00,0x01,0xff,0xe6,0xb4,0x9e,0x00,0x10,0x08,0x01,0xff,0xe6,0x9a, + 0xb4,0x00,0x01,0xff,0xe8,0xbc,0xbb,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x01,0xff, + 0xe8,0xa1,0x8c,0x00,0x01,0xff,0xe9,0x99,0x8d,0x00,0x10,0x08,0x01,0xff,0xe8,0xa6, + 0x8b,0x00,0x01,0xff,0xe5,0xbb,0x93,0x00,0x91,0x10,0x10,0x08,0x01,0xff,0xe5,0x85, + 0x80,0x00,0x01,0xff,0xe5,0x97,0x80,0x00,0x01,0x00,0xd3,0x34,0xd2,0x18,0xd1,0x0c, + 0x10,0x08,0x01,0xff,0xe5,0xa1,0x9a,0x00,0x01,0x00,0x10,0x08,0x01,0xff,0xe6,0x99, + 0xb4,0x00,0x01,0x00,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0xe5,0x87,0x9e,0x00, + 0x10,0x08,0x01,0xff,0xe7,0x8c,0xaa,0x00,0x01,0xff,0xe7,0x9b,0x8a,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x01,0xff,0xe7,0xa4,0xbc,0x00,0x01,0xff,0xe7,0xa5,0x9e,0x00, + 0x10,0x08,0x01,0xff,0xe7,0xa5,0xa5,0x00,0x01,0xff,0xe7,0xa6,0x8f,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe9,0x9d,0x96,0x00,0x01,0xff,0xe7,0xb2,0xbe,0x00,0x10,0x08, + 0x01,0xff,0xe7,0xbe,0xbd,0x00,0x01,0x00,0xd4,0x64,0xd3,0x30,0xd2,0x18,0xd1,0x0c, + 0x10,0x08,0x01,0xff,0xe8,0x98,0x92,0x00,0x01,0x00,0x10,0x08,0x01,0xff,0xe8,0xab, + 0xb8,0x00,0x01,0x00,0xd1,0x0c,0x10,0x04,0x01,0x00,0x01,0xff,0xe9,0x80,0xb8,0x00, + 0x10,0x08,0x01,0xff,0xe9,0x83,0xbd,0x00,0x01,0x00,0xd2,0x14,0x51,0x04,0x01,0x00, + 0x10,0x08,0x01,0xff,0xe9,0xa3,0xaf,0x00,0x01,0xff,0xe9,0xa3,0xbc,0x00,0xd1,0x10, + 0x10,0x08,0x01,0xff,0xe9,0xa4,0xa8,0x00,0x01,0xff,0xe9,0xb6,0xb4,0x00,0x10,0x08, + 0x0d,0xff,0xe9,0x83,0x9e,0x00,0x0d,0xff,0xe9,0x9a,0xb7,0x00,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x06,0xff,0xe4,0xbe,0xae,0x00,0x06,0xff,0xe5,0x83,0xa7,0x00, + 0x10,0x08,0x06,0xff,0xe5,0x85,0x8d,0x00,0x06,0xff,0xe5,0x8b,0x89,0x00,0xd1,0x10, + 0x10,0x08,0x06,0xff,0xe5,0x8b,0xa4,0x00,0x06,0xff,0xe5,0x8d,0x91,0x00,0x10,0x08, + 0x06,0xff,0xe5,0x96,0x9d,0x00,0x06,0xff,0xe5,0x98,0x86,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x06,0xff,0xe5,0x99,0xa8,0x00,0x06,0xff,0xe5,0xa1,0x80,0x00,0x10,0x08, + 0x06,0xff,0xe5,0xa2,0xa8,0x00,0x06,0xff,0xe5,0xb1,0xa4,0x00,0xd1,0x10,0x10,0x08, + 0x06,0xff,0xe5,0xb1,0xae,0x00,0x06,0xff,0xe6,0x82,0x94,0x00,0x10,0x08,0x06,0xff, + 0xe6,0x85,0xa8,0x00,0x06,0xff,0xe6,0x86,0x8e,0x00,0xcf,0x86,0xe5,0x01,0x01,0xd4, + 0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe6,0x87,0xb2,0x00,0x06, + 0xff,0xe6,0x95,0x8f,0x00,0x10,0x08,0x06,0xff,0xe6,0x97,0xa2,0x00,0x06,0xff,0xe6, + 0x9a,0x91,0x00,0xd1,0x10,0x10,0x08,0x06,0xff,0xe6,0xa2,0x85,0x00,0x06,0xff,0xe6, + 0xb5,0xb7,0x00,0x10,0x08,0x06,0xff,0xe6,0xb8,0x9a,0x00,0x06,0xff,0xe6,0xbc,0xa2, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe7,0x85,0xae,0x00,0x06,0xff,0xe7, + 0x88,0xab,0x00,0x10,0x08,0x06,0xff,0xe7,0x90,0xa2,0x00,0x06,0xff,0xe7,0xa2,0x91, + 0x00,0xd1,0x10,0x10,0x08,0x06,0xff,0xe7,0xa4,0xbe,0x00,0x06,0xff,0xe7,0xa5,0x89, + 0x00,0x10,0x08,0x06,0xff,0xe7,0xa5,0x88,0x00,0x06,0xff,0xe7,0xa5,0x90,0x00,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe7,0xa5,0x96,0x00,0x06,0xff,0xe7, + 0xa5,0x9d,0x00,0x10,0x08,0x06,0xff,0xe7,0xa6,0x8d,0x00,0x06,0xff,0xe7,0xa6,0x8e, + 0x00,0xd1,0x10,0x10,0x08,0x06,0xff,0xe7,0xa9,0x80,0x00,0x06,0xff,0xe7,0xaa,0x81, + 0x00,0x10,0x08,0x06,0xff,0xe7,0xaf,0x80,0x00,0x06,0xff,0xe7,0xb7,0xb4,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe7,0xb8,0x89,0x00,0x06,0xff,0xe7,0xb9,0x81, + 0x00,0x10,0x08,0x06,0xff,0xe7,0xbd,0xb2,0x00,0x06,0xff,0xe8,0x80,0x85,0x00,0xd1, + 0x10,0x10,0x08,0x06,0xff,0xe8,0x87,0xad,0x00,0x06,0xff,0xe8,0x89,0xb9,0x00,0x10, + 0x08,0x06,0xff,0xe8,0x89,0xb9,0x00,0x06,0xff,0xe8,0x91,0x97,0x00,0xd4,0x75,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe8,0xa4,0x90,0x00,0x06,0xff,0xe8, + 0xa6,0x96,0x00,0x10,0x08,0x06,0xff,0xe8,0xac,0x81,0x00,0x06,0xff,0xe8,0xac,0xb9, + 0x00,0xd1,0x10,0x10,0x08,0x06,0xff,0xe8,0xb3,0x93,0x00,0x06,0xff,0xe8,0xb4,0x88, + 0x00,0x10,0x08,0x06,0xff,0xe8,0xbe,0xb6,0x00,0x06,0xff,0xe9,0x80,0xb8,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x06,0xff,0xe9,0x9b,0xa3,0x00,0x06,0xff,0xe9,0x9f,0xbf, + 0x00,0x10,0x08,0x06,0xff,0xe9,0xa0,0xbb,0x00,0x0b,0xff,0xe6,0x81,0xb5,0x00,0x91, + 0x11,0x10,0x09,0x0b,0xff,0xf0,0xa4,0x8b,0xae,0x00,0x0b,0xff,0xe8,0x88,0x98,0x00, + 0x00,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff,0xe4,0xb8,0xa6,0x00, + 0x08,0xff,0xe5,0x86,0xb5,0x00,0x10,0x08,0x08,0xff,0xe5,0x85,0xa8,0x00,0x08,0xff, + 0xe4,0xbe,0x80,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe5,0x85,0x85,0x00,0x08,0xff, + 0xe5,0x86,0x80,0x00,0x10,0x08,0x08,0xff,0xe5,0x8b,0x87,0x00,0x08,0xff,0xe5,0x8b, + 0xba,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff,0xe5,0x96,0x9d,0x00,0x08,0xff, + 0xe5,0x95,0x95,0x00,0x10,0x08,0x08,0xff,0xe5,0x96,0x99,0x00,0x08,0xff,0xe5,0x97, + 0xa2,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe5,0xa1,0x9a,0x00,0x08,0xff,0xe5,0xa2, + 0xb3,0x00,0x10,0x08,0x08,0xff,0xe5,0xa5,0x84,0x00,0x08,0xff,0xe5,0xa5,0x94,0x00, + 0xe0,0x04,0x02,0xcf,0x86,0xe5,0x01,0x01,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x08,0xff,0xe5,0xa9,0xa2,0x00,0x08,0xff,0xe5,0xac,0xa8,0x00,0x10,0x08, + 0x08,0xff,0xe5,0xbb,0x92,0x00,0x08,0xff,0xe5,0xbb,0x99,0x00,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe5,0xbd,0xa9,0x00,0x08,0xff,0xe5,0xbe,0xad,0x00,0x10,0x08,0x08,0xff, + 0xe6,0x83,0x98,0x00,0x08,0xff,0xe6,0x85,0x8e,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe6,0x84,0x88,0x00,0x08,0xff,0xe6,0x86,0x8e,0x00,0x10,0x08,0x08,0xff, + 0xe6,0x85,0xa0,0x00,0x08,0xff,0xe6,0x87,0xb2,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe6,0x88,0xb4,0x00,0x08,0xff,0xe6,0x8f,0x84,0x00,0x10,0x08,0x08,0xff,0xe6,0x90, + 0x9c,0x00,0x08,0xff,0xe6,0x91,0x92,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe6,0x95,0x96,0x00,0x08,0xff,0xe6,0x99,0xb4,0x00,0x10,0x08,0x08,0xff, + 0xe6,0x9c,0x97,0x00,0x08,0xff,0xe6,0x9c,0x9b,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe6,0x9d,0x96,0x00,0x08,0xff,0xe6,0xad,0xb9,0x00,0x10,0x08,0x08,0xff,0xe6,0xae, + 0xba,0x00,0x08,0xff,0xe6,0xb5,0x81,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe6,0xbb,0x9b,0x00,0x08,0xff,0xe6,0xbb,0x8b,0x00,0x10,0x08,0x08,0xff,0xe6,0xbc, + 0xa2,0x00,0x08,0xff,0xe7,0x80,0x9e,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe7,0x85, + 0xae,0x00,0x08,0xff,0xe7,0x9e,0xa7,0x00,0x10,0x08,0x08,0xff,0xe7,0x88,0xb5,0x00, + 0x08,0xff,0xe7,0x8a,0xaf,0x00,0xd4,0x80,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe7,0x8c,0xaa,0x00,0x08,0xff,0xe7,0x91,0xb1,0x00,0x10,0x08,0x08,0xff, + 0xe7,0x94,0x86,0x00,0x08,0xff,0xe7,0x94,0xbb,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe7,0x98,0x9d,0x00,0x08,0xff,0xe7,0x98,0x9f,0x00,0x10,0x08,0x08,0xff,0xe7,0x9b, + 0x8a,0x00,0x08,0xff,0xe7,0x9b,0x9b,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe7,0x9b,0xb4,0x00,0x08,0xff,0xe7,0x9d,0x8a,0x00,0x10,0x08,0x08,0xff,0xe7,0x9d, + 0x80,0x00,0x08,0xff,0xe7,0xa3,0x8c,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe7,0xaa, + 0xb1,0x00,0x08,0xff,0xe7,0xaf,0x80,0x00,0x10,0x08,0x08,0xff,0xe7,0xb1,0xbb,0x00, + 0x08,0xff,0xe7,0xb5,0x9b,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe7,0xb7,0xb4,0x00,0x08,0xff,0xe7,0xbc,0xbe,0x00,0x10,0x08,0x08,0xff,0xe8,0x80, + 0x85,0x00,0x08,0xff,0xe8,0x8d,0x92,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe8,0x8f, + 0xaf,0x00,0x08,0xff,0xe8,0x9d,0xb9,0x00,0x10,0x08,0x08,0xff,0xe8,0xa5,0x81,0x00, + 0x08,0xff,0xe8,0xa6,0x86,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x08,0xff,0xe8,0xa6, + 0x96,0x00,0x08,0xff,0xe8,0xaa,0xbf,0x00,0x10,0x08,0x08,0xff,0xe8,0xab,0xb8,0x00, + 0x08,0xff,0xe8,0xab,0x8b,0x00,0xd1,0x10,0x10,0x08,0x08,0xff,0xe8,0xac,0x81,0x00, + 0x08,0xff,0xe8,0xab,0xbe,0x00,0x10,0x08,0x08,0xff,0xe8,0xab,0xad,0x00,0x08,0xff, + 0xe8,0xac,0xb9,0x00,0xcf,0x86,0x95,0xde,0xd4,0x81,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x08,0xff,0xe8,0xae,0x8a,0x00,0x08,0xff,0xe8,0xb4,0x88,0x00,0x10,0x08, + 0x08,0xff,0xe8,0xbc,0xb8,0x00,0x08,0xff,0xe9,0x81,0xb2,0x00,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe9,0x86,0x99,0x00,0x08,0xff,0xe9,0x89,0xb6,0x00,0x10,0x08,0x08,0xff, + 0xe9,0x99,0xbc,0x00,0x08,0xff,0xe9,0x9b,0xa3,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x08,0xff,0xe9,0x9d,0x96,0x00,0x08,0xff,0xe9,0x9f,0x9b,0x00,0x10,0x08,0x08,0xff, + 0xe9,0x9f,0xbf,0x00,0x08,0xff,0xe9,0xa0,0x8b,0x00,0xd1,0x10,0x10,0x08,0x08,0xff, + 0xe9,0xa0,0xbb,0x00,0x08,0xff,0xe9,0xac,0x92,0x00,0x10,0x08,0x08,0xff,0xe9,0xbe, + 0x9c,0x00,0x08,0xff,0xf0,0xa2,0xa1,0x8a,0x00,0xd3,0x45,0xd2,0x22,0xd1,0x12,0x10, + 0x09,0x08,0xff,0xf0,0xa2,0xa1,0x84,0x00,0x08,0xff,0xf0,0xa3,0x8f,0x95,0x00,0x10, + 0x08,0x08,0xff,0xe3,0xae,0x9d,0x00,0x08,0xff,0xe4,0x80,0x98,0x00,0xd1,0x11,0x10, + 0x08,0x08,0xff,0xe4,0x80,0xb9,0x00,0x08,0xff,0xf0,0xa5,0x89,0x89,0x00,0x10,0x09, + 0x08,0xff,0xf0,0xa5,0xb3,0x90,0x00,0x08,0xff,0xf0,0xa7,0xbb,0x93,0x00,0x92,0x14, + 0x91,0x10,0x10,0x08,0x08,0xff,0xe9,0xbd,0x83,0x00,0x08,0xff,0xe9,0xbe,0x8e,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xe1,0x94,0x01,0xe0,0x08,0x01,0xcf,0x86,0xd5,0x42, + 0xd4,0x14,0x93,0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00, + 0x00,0x00,0x00,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00, + 0x01,0x00,0x01,0x00,0x52,0x04,0x00,0x00,0xd1,0x0d,0x10,0x04,0x00,0x00,0x04,0xff, + 0xd7,0x99,0xd6,0xb4,0x00,0x10,0x04,0x01,0x1a,0x01,0xff,0xd7,0xb2,0xd6,0xb7,0x00, + 0xd4,0x42,0x53,0x04,0x01,0x00,0xd2,0x16,0x51,0x04,0x01,0x00,0x10,0x09,0x01,0xff, + 0xd7,0xa9,0xd7,0x81,0x00,0x01,0xff,0xd7,0xa9,0xd7,0x82,0x00,0xd1,0x16,0x10,0x0b, + 0x01,0xff,0xd7,0xa9,0xd6,0xbc,0xd7,0x81,0x00,0x01,0xff,0xd7,0xa9,0xd6,0xbc,0xd7, + 0x82,0x00,0x10,0x09,0x01,0xff,0xd7,0x90,0xd6,0xb7,0x00,0x01,0xff,0xd7,0x90,0xd6, + 0xb8,0x00,0xd3,0x43,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd7,0x90,0xd6,0xbc, + 0x00,0x01,0xff,0xd7,0x91,0xd6,0xbc,0x00,0x10,0x09,0x01,0xff,0xd7,0x92,0xd6,0xbc, + 0x00,0x01,0xff,0xd7,0x93,0xd6,0xbc,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd7,0x94, + 0xd6,0xbc,0x00,0x01,0xff,0xd7,0x95,0xd6,0xbc,0x00,0x10,0x09,0x01,0xff,0xd7,0x96, + 0xd6,0xbc,0x00,0x00,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd7,0x98,0xd6, + 0xbc,0x00,0x01,0xff,0xd7,0x99,0xd6,0xbc,0x00,0x10,0x09,0x01,0xff,0xd7,0x9a,0xd6, + 0xbc,0x00,0x01,0xff,0xd7,0x9b,0xd6,0xbc,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xd7, + 0x9c,0xd6,0xbc,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xd7,0x9e,0xd6,0xbc,0x00,0x00, + 0x00,0xcf,0x86,0x95,0x85,0x94,0x81,0xd3,0x3e,0xd2,0x1f,0xd1,0x12,0x10,0x09,0x01, + 0xff,0xd7,0xa0,0xd6,0xbc,0x00,0x01,0xff,0xd7,0xa1,0xd6,0xbc,0x00,0x10,0x04,0x00, + 0x00,0x01,0xff,0xd7,0xa3,0xd6,0xbc,0x00,0xd1,0x0d,0x10,0x09,0x01,0xff,0xd7,0xa4, + 0xd6,0xbc,0x00,0x00,0x00,0x10,0x09,0x01,0xff,0xd7,0xa6,0xd6,0xbc,0x00,0x01,0xff, + 0xd7,0xa7,0xd6,0xbc,0x00,0xd2,0x24,0xd1,0x12,0x10,0x09,0x01,0xff,0xd7,0xa8,0xd6, + 0xbc,0x00,0x01,0xff,0xd7,0xa9,0xd6,0xbc,0x00,0x10,0x09,0x01,0xff,0xd7,0xaa,0xd6, + 0xbc,0x00,0x01,0xff,0xd7,0x95,0xd6,0xb9,0x00,0xd1,0x12,0x10,0x09,0x01,0xff,0xd7, + 0x91,0xd6,0xbf,0x00,0x01,0xff,0xd7,0x9b,0xd6,0xbf,0x00,0x10,0x09,0x01,0xff,0xd7, + 0xa4,0xd6,0xbf,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd0,0x1a,0xcf,0x86,0x55,0x04, + 0x01,0x00,0x54,0x04,0x01,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x01,0x00,0x0c,0x00, + 0x0c,0x00,0x0c,0x00,0xcf,0x86,0x95,0x24,0xd4,0x10,0x93,0x0c,0x92,0x08,0x11,0x04, + 0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x00,0x00, + 0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0xd3,0x5a,0xd2,0x06, + 0xcf,0x06,0x01,0x00,0xd1,0x14,0xd0,0x06,0xcf,0x06,0x01,0x00,0xcf,0x86,0x95,0x08, + 0x14,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd0,0x1a,0xcf,0x86,0x95,0x14,0x54,0x04, + 0x01,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0xcf,0x86,0xd5,0x0c,0x94,0x08,0x13,0x04,0x01,0x00,0x00,0x00,0x05,0x00, + 0x54,0x04,0x05,0x00,0x53,0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x91,0x08,0x10,0x04, + 0x06,0x00,0x07,0x00,0x00,0x00,0xd2,0xce,0xd1,0xa5,0xd0,0x37,0xcf,0x86,0xd5,0x15, + 0x54,0x05,0x06,0xff,0x00,0x53,0x04,0x08,0x00,0x92,0x08,0x11,0x04,0x08,0x00,0x00, + 0x00,0x00,0x00,0x94,0x1c,0xd3,0x10,0x52,0x04,0x01,0xe6,0x51,0x04,0x0a,0xe6,0x10, + 0x04,0x0a,0xe6,0x10,0xdc,0x52,0x04,0x10,0xdc,0x11,0x04,0x10,0xdc,0x11,0xe6,0x01, + 0x00,0xcf,0x86,0xd5,0x38,0xd4,0x24,0xd3,0x14,0x52,0x04,0x01,0x00,0xd1,0x08,0x10, + 0x04,0x01,0x00,0x06,0x00,0x10,0x04,0x06,0x00,0x07,0x00,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x07,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x93,0x10,0x92,0x0c,0x51,0x04,0x01, + 0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd4,0x18,0xd3,0x10,0x52, + 0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x12,0x04,0x01, + 0x00,0x00,0x00,0x93,0x18,0xd2,0x0c,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x06, + 0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0xd0,0x06,0xcf, + 0x06,0x01,0x00,0xcf,0x86,0x55,0x04,0x01,0x00,0x54,0x04,0x01,0x00,0x53,0x04,0x01, + 0x00,0x52,0x04,0x01,0x00,0xd1,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x10,0x04,0x00, + 0x00,0x01,0xff,0x00,0xd1,0x50,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x94,0x14,0x93,0x10, + 0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0xcf,0x86,0xd5,0x18,0x54,0x04,0x01,0x00,0x53,0x04,0x01,0x00, + 0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x06,0x00,0x94,0x14, + 0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x06,0x00,0x01,0x00,0x01,0x00,0x01,0x00, + 0x01,0x00,0x01,0x00,0xd0,0x2f,0xcf,0x86,0x55,0x04,0x01,0x00,0xd4,0x15,0x93,0x11, + 0x92,0x0d,0x91,0x09,0x10,0x05,0x01,0xff,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01, + 0x00,0x53,0x04,0x01,0x00,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01, + 0x00,0x00,0x00,0xcf,0x86,0xd5,0x38,0xd4,0x18,0xd3,0x0c,0x92,0x08,0x11,0x04,0x00, + 0x00,0x01,0x00,0x01,0x00,0x92,0x08,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd3, + 0x0c,0x92,0x08,0x11,0x04,0x00,0x00,0x01,0x00,0x01,0x00,0xd2,0x08,0x11,0x04,0x00, + 0x00,0x01,0x00,0x91,0x08,0x10,0x04,0x01,0x00,0x00,0x00,0x00,0x00,0xd4,0x20,0xd3, + 0x10,0x52,0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x52, + 0x04,0x01,0x00,0x51,0x04,0x01,0x00,0x10,0x04,0x01,0x00,0x00,0x00,0x53,0x05,0x00, + 0xff,0x00,0xd2,0x0d,0x91,0x09,0x10,0x05,0x00,0xff,0x00,0x04,0x00,0x04,0x00,0x91, + 0x08,0x10,0x04,0x03,0x00,0x01,0x00,0x01,0x00,0x83,0xe2,0x46,0x3e,0xe1,0x1f,0x3b, + 0xe0,0x9c,0x39,0xcf,0x86,0xe5,0x40,0x26,0xc4,0xe3,0x16,0x14,0xe2,0xef,0x11,0xe1, + 0xd0,0x10,0xe0,0x60,0x07,0xcf,0x86,0xe5,0x53,0x03,0xe4,0x4c,0x02,0xe3,0x3d,0x01, + 0xd2,0x94,0xd1,0x70,0xd0,0x4a,0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x07,0x00, + 0x52,0x04,0x07,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00, + 0xd4,0x14,0x93,0x10,0x52,0x04,0x07,0x00,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00, + 0x00,0x00,0x07,0x00,0x53,0x04,0x07,0x00,0xd2,0x0c,0x51,0x04,0x07,0x00,0x10,0x04, + 0x07,0x00,0x00,0x00,0x51,0x04,0x07,0x00,0x10,0x04,0x00,0x00,0x07,0x00,0xcf,0x86, + 0x95,0x20,0xd4,0x10,0x53,0x04,0x07,0x00,0x52,0x04,0x07,0x00,0x11,0x04,0x07,0x00, + 0x00,0x00,0x53,0x04,0x07,0x00,0x52,0x04,0x07,0x00,0x11,0x04,0x07,0x00,0x00,0x00, + 0x00,0x00,0xd0,0x06,0xcf,0x06,0x07,0x00,0xcf,0x86,0x55,0x04,0x07,0x00,0x54,0x04, + 0x07,0x00,0x53,0x04,0x07,0x00,0x92,0x0c,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00, + 0x00,0x00,0x00,0x00,0xd1,0x40,0xd0,0x3a,0xcf,0x86,0xd5,0x20,0x94,0x1c,0x93,0x18, + 0xd2,0x0c,0x51,0x04,0x07,0x00,0x10,0x04,0x07,0x00,0x00,0x00,0x51,0x04,0x00,0x00, + 0x10,0x04,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x54,0x04,0x07,0x00,0x93,0x10, + 0x52,0x04,0x07,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x07,0x00,0x07,0x00, + 0xcf,0x06,0x08,0x00,0xd0,0x46,0xcf,0x86,0xd5,0x2c,0xd4,0x20,0x53,0x04,0x08,0x00, + 0xd2,0x0c,0x51,0x04,0x08,0x00,0x10,0x04,0x08,0x00,0x10,0x00,0xd1,0x08,0x10,0x04, + 0x10,0x00,0x12,0x00,0x10,0x04,0x12,0x00,0x00,0x00,0x53,0x04,0x0a,0x00,0x12,0x04, + 0x0a,0x00,0x00,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x08,0x14,0x04, + 0x00,0x00,0x0a,0x00,0x54,0x04,0x0a,0x00,0x53,0x04,0x0a,0x00,0x52,0x04,0x0a,0x00, + 0x91,0x08,0x10,0x04,0x0a,0x00,0x0a,0xdc,0x00,0x00,0xd2,0x5e,0xd1,0x06,0xcf,0x06, + 0x00,0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04,0x0a,0x00,0x53,0x04,0x0a,0x00, + 0x52,0x04,0x0a,0x00,0x91,0x08,0x10,0x04,0x0a,0x00,0x00,0x00,0x00,0x00,0x0a,0x00, + 0xcf,0x86,0xd5,0x18,0x54,0x04,0x0a,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd4,0x14,0x93,0x10,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x10,0xdc,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x53,0x04, + 0x10,0x00,0x12,0x04,0x10,0x00,0x00,0x00,0xd1,0x70,0xd0,0x36,0xcf,0x86,0xd5,0x18, + 0x54,0x04,0x05,0x00,0x53,0x04,0x05,0x00,0x52,0x04,0x05,0x00,0x51,0x04,0x05,0x00, + 0x10,0x04,0x05,0x00,0x10,0x00,0x94,0x18,0xd3,0x08,0x12,0x04,0x05,0x00,0x00,0x00, + 0x52,0x04,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x13,0x00,0x13,0x00,0x05,0x00, + 0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x05,0x00,0x92,0x0c,0x51,0x04,0x05,0x00, + 0x10,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x54,0x04,0x10,0x00,0xd3,0x0c, + 0x52,0x04,0x10,0x00,0x11,0x04,0x10,0x00,0x10,0xe6,0x92,0x0c,0x51,0x04,0x10,0xe6, + 0x10,0x04,0x10,0xe6,0x00,0x00,0x00,0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04, + 0x07,0x00,0x53,0x04,0x07,0x00,0x52,0x04,0x07,0x00,0x51,0x04,0x07,0x00,0x10,0x04, + 0x00,0x00,0x07,0x00,0x08,0x00,0xcf,0x86,0x95,0x1c,0xd4,0x0c,0x93,0x08,0x12,0x04, + 0x08,0x00,0x00,0x00,0x08,0x00,0x93,0x0c,0x52,0x04,0x08,0x00,0x11,0x04,0x08,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xd3,0xba,0xd2,0x80,0xd1,0x34,0xd0,0x1a,0xcf,0x86, + 0x55,0x04,0x05,0x00,0x94,0x10,0x93,0x0c,0x52,0x04,0x05,0x00,0x11,0x04,0x05,0x00, + 0x07,0x00,0x05,0x00,0x05,0x00,0xcf,0x86,0x95,0x14,0x94,0x10,0x53,0x04,0x05,0x00, + 0x52,0x04,0x05,0x00,0x11,0x04,0x05,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0xd0,0x2a, + 0xcf,0x86,0xd5,0x14,0x54,0x04,0x07,0x00,0x53,0x04,0x07,0x00,0x52,0x04,0x07,0x00, + 0x11,0x04,0x07,0x00,0x00,0x00,0x94,0x10,0x53,0x04,0x07,0x00,0x92,0x08,0x11,0x04, + 0x07,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0xcf,0x86,0xd5,0x10,0x54,0x04,0x12,0x00, + 0x93,0x08,0x12,0x04,0x12,0x00,0x00,0x00,0x12,0x00,0x54,0x04,0x12,0x00,0x53,0x04, + 0x12,0x00,0x12,0x04,0x12,0x00,0x00,0x00,0xd1,0x34,0xd0,0x12,0xcf,0x86,0x55,0x04, + 0x10,0x00,0x94,0x08,0x13,0x04,0x10,0x00,0x00,0x00,0x10,0x00,0xcf,0x86,0x55,0x04, + 0x10,0x00,0x94,0x18,0xd3,0x08,0x12,0x04,0x10,0x00,0x00,0x00,0x52,0x04,0x00,0x00, + 0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x00,0x00,0xcf,0x06,0x00,0x00, + 0xd2,0x06,0xcf,0x06,0x10,0x00,0xd1,0x40,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x10,0x00, + 0x54,0x04,0x10,0x00,0x93,0x10,0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04, + 0x10,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x14,0x54,0x04,0x10,0x00,0x93,0x0c, + 0x52,0x04,0x10,0x00,0x11,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x94,0x08,0x13,0x04, + 0x10,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xe4,0xce,0x02,0xe3,0x45,0x01, + 0xd2,0xd0,0xd1,0x70,0xd0,0x52,0xcf,0x86,0xd5,0x20,0x94,0x1c,0xd3,0x0c,0x52,0x04, + 0x07,0x00,0x11,0x04,0x07,0x00,0x00,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x07,0x00, + 0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x54,0x04,0x07,0x00,0xd3,0x10,0x52,0x04, + 0x07,0x00,0x51,0x04,0x07,0x00,0x10,0x04,0x00,0x00,0x07,0x00,0xd2,0x0c,0x91,0x08, + 0x10,0x04,0x07,0x00,0x00,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x07,0x00,0x00,0x00, + 0x10,0x04,0x00,0x00,0x07,0x00,0xcf,0x86,0x95,0x18,0x54,0x04,0x0b,0x00,0x93,0x10, + 0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x00,0x00,0x0b,0x00,0x0b,0x00, + 0x10,0x00,0xd0,0x32,0xcf,0x86,0xd5,0x18,0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00, + 0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x00,0x00,0x94,0x14, + 0x93,0x10,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00, + 0x10,0x00,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x11,0x00,0xd3,0x14, + 0xd2,0x0c,0x51,0x04,0x11,0x00,0x10,0x04,0x11,0x00,0x00,0x00,0x11,0x04,0x11,0x00, + 0x00,0x00,0x92,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x11,0x00,0x11,0x00, + 0xd1,0x40,0xd0,0x3a,0xcf,0x86,0xd5,0x1c,0x54,0x04,0x09,0x00,0x53,0x04,0x09,0x00, + 0xd2,0x08,0x11,0x04,0x09,0x00,0x0b,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00, + 0x09,0x00,0x54,0x04,0x0a,0x00,0x53,0x04,0x0a,0x00,0xd2,0x08,0x11,0x04,0x0a,0x00, + 0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0a,0x00,0xcf,0x06,0x00,0x00, + 0xd0,0x1a,0xcf,0x86,0x55,0x04,0x0d,0x00,0x54,0x04,0x0d,0x00,0x53,0x04,0x0d,0x00, + 0x52,0x04,0x00,0x00,0x11,0x04,0x11,0x00,0x0d,0x00,0xcf,0x86,0x95,0x14,0x54,0x04, + 0x11,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x00,0x00,0x11,0x00,0x11,0x00,0x11,0x00, + 0x11,0x00,0xd2,0xec,0xd1,0xa4,0xd0,0x76,0xcf,0x86,0xd5,0x48,0xd4,0x28,0xd3,0x14, + 0x52,0x04,0x08,0x00,0xd1,0x08,0x10,0x04,0x00,0x00,0x08,0x00,0x10,0x04,0x08,0x00, + 0x00,0x00,0x52,0x04,0x00,0x00,0xd1,0x08,0x10,0x04,0x08,0x00,0x08,0xdc,0x10,0x04, + 0x08,0x00,0x08,0xe6,0xd3,0x10,0x52,0x04,0x08,0x00,0x91,0x08,0x10,0x04,0x00,0x00, + 0x08,0x00,0x08,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x08,0x00,0x08,0x00, + 0x08,0x00,0x54,0x04,0x08,0x00,0xd3,0x0c,0x52,0x04,0x08,0x00,0x11,0x04,0x14,0x00, + 0x00,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x08,0xe6,0x08,0x01,0x10,0x04,0x08,0xdc, + 0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x08,0x09,0xcf,0x86,0x95,0x28, + 0xd4,0x14,0x53,0x04,0x08,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x53,0x04,0x08,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x08,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0xd0,0x0a,0xcf,0x86,0x15,0x04,0x10,0x00, + 0x00,0x00,0xcf,0x86,0x55,0x04,0x10,0x00,0xd4,0x24,0xd3,0x14,0x52,0x04,0x10,0x00, + 0xd1,0x08,0x10,0x04,0x10,0x00,0x10,0xe6,0x10,0x04,0x10,0xdc,0x00,0x00,0x92,0x0c, + 0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x93,0x10,0x52,0x04, + 0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd1,0x54, + 0xd0,0x26,0xcf,0x86,0x55,0x04,0x0b,0x00,0x54,0x04,0x0b,0x00,0xd3,0x0c,0x52,0x04, + 0x0b,0x00,0x11,0x04,0x0b,0x00,0x00,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00, + 0x0b,0x00,0x0b,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x14,0x54,0x04,0x0b,0x00,0x93,0x0c, + 0x52,0x04,0x0b,0x00,0x11,0x04,0x0b,0x00,0x00,0x00,0x0b,0x00,0x54,0x04,0x0b,0x00, + 0x93,0x10,0x92,0x0c,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00,0x00,0x00,0x00,0x00, + 0x0b,0x00,0xd0,0x42,0xcf,0x86,0xd5,0x28,0x54,0x04,0x10,0x00,0xd3,0x0c,0x92,0x08, + 0x11,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00, + 0x10,0x00,0x10,0x00,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x94,0x14, + 0x53,0x04,0x00,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00, + 0x10,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd3,0x96,0xd2,0x68,0xd1,0x24,0xd0,0x06, + 0xcf,0x06,0x0b,0x00,0xcf,0x86,0x95,0x18,0x94,0x14,0x53,0x04,0x0b,0x00,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd0,0x1e,0xcf,0x86,0x55,0x04,0x11,0x00,0x54,0x04,0x11,0x00,0x93,0x10,0x92,0x0c, + 0x51,0x04,0x11,0x00,0x10,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86, + 0x55,0x04,0x11,0x00,0x54,0x04,0x11,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x11,0x00, + 0x10,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0x92,0x08,0x11,0x04,0x00,0x00,0x11,0x00, + 0x11,0x00,0xd1,0x28,0xd0,0x22,0xcf,0x86,0x55,0x04,0x14,0x00,0xd4,0x0c,0x93,0x08, + 0x12,0x04,0x14,0x00,0x14,0xe6,0x00,0x00,0x53,0x04,0x14,0x00,0x92,0x08,0x11,0x04, + 0x14,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xd2,0x2a, + 0xd1,0x24,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04, + 0x0b,0x00,0x53,0x04,0x0b,0x00,0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04, + 0x0b,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1,0x58,0xd0,0x12,0xcf,0x86,0x55,0x04, + 0x14,0x00,0x94,0x08,0x13,0x04,0x14,0x00,0x00,0x00,0x14,0x00,0xcf,0x86,0x95,0x40, + 0xd4,0x24,0xd3,0x0c,0x52,0x04,0x14,0x00,0x11,0x04,0x14,0x00,0x14,0xdc,0xd2,0x0c, + 0x51,0x04,0x14,0xe6,0x10,0x04,0x14,0xe6,0x14,0xdc,0x91,0x08,0x10,0x04,0x14,0xe6, + 0x14,0xdc,0x14,0xdc,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0xdc,0x14,0x00, + 0x14,0x00,0x14,0x00,0x92,0x08,0x11,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x15,0x00, + 0x93,0x10,0x52,0x04,0x15,0x00,0x51,0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00,0x00, + 0x00,0x00,0xcf,0x86,0xe5,0x0f,0x06,0xe4,0xf8,0x03,0xe3,0x02,0x02,0xd2,0xfb,0xd1, + 0x4c,0xd0,0x06,0xcf,0x06,0x0c,0x00,0xcf,0x86,0xd5,0x2c,0xd4,0x1c,0xd3,0x10,0x52, + 0x04,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x09,0x0c,0x00,0x52,0x04,0x0c, + 0x00,0x11,0x04,0x0c,0x00,0x00,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x00,0x00,0x0c, + 0x00,0x0c,0x00,0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00, + 0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x09,0xd0,0x69,0xcf,0x86,0xd5, + 0x32,0x54,0x04,0x0b,0x00,0x53,0x04,0x0b,0x00,0xd2,0x15,0x51,0x04,0x0b,0x00,0x10, + 0x0d,0x0b,0xff,0xf0,0x91,0x82,0x99,0xf0,0x91,0x82,0xba,0x00,0x0b,0x00,0x91,0x11, + 0x10,0x0d,0x0b,0xff,0xf0,0x91,0x82,0x9b,0xf0,0x91,0x82,0xba,0x00,0x0b,0x00,0x0b, + 0x00,0xd4,0x1d,0x53,0x04,0x0b,0x00,0x92,0x15,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b, + 0x00,0x0b,0xff,0xf0,0x91,0x82,0xa5,0xf0,0x91,0x82,0xba,0x00,0x0b,0x00,0x53,0x04, + 0x0b,0x00,0x92,0x10,0xd1,0x08,0x10,0x04,0x0b,0x00,0x0b,0x09,0x10,0x04,0x0b,0x07, + 0x0b,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x20,0x94,0x1c,0xd3,0x0c,0x92,0x08,0x11,0x04, + 0x0b,0x00,0x00,0x00,0x00,0x00,0x52,0x04,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00, + 0x14,0x00,0x00,0x00,0x0d,0x00,0xd4,0x14,0x53,0x04,0x0d,0x00,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x0d,0x00,0x92,0x08, + 0x11,0x04,0x0d,0x00,0x00,0x00,0x00,0x00,0xd1,0x96,0xd0,0x5c,0xcf,0x86,0xd5,0x18, + 0x94,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x0d,0xe6,0x10,0x04,0x0d,0xe6,0x0d,0x00, + 0x0d,0x00,0x0d,0x00,0x0d,0x00,0xd4,0x26,0x53,0x04,0x0d,0x00,0x52,0x04,0x0d,0x00, + 0x51,0x04,0x0d,0x00,0x10,0x0d,0x0d,0xff,0xf0,0x91,0x84,0xb1,0xf0,0x91,0x84,0xa7, + 0x00,0x0d,0xff,0xf0,0x91,0x84,0xb2,0xf0,0x91,0x84,0xa7,0x00,0x93,0x18,0xd2,0x0c, + 0x51,0x04,0x0d,0x00,0x10,0x04,0x0d,0x00,0x0d,0x09,0x91,0x08,0x10,0x04,0x0d,0x09, + 0x00,0x00,0x0d,0x00,0x0d,0x00,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x52,0x04, + 0x0d,0x00,0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x10,0x00, + 0x54,0x04,0x10,0x00,0x93,0x18,0xd2,0x0c,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00, + 0x10,0x07,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd0,0x06, + 0xcf,0x06,0x0d,0x00,0xcf,0x86,0xd5,0x40,0xd4,0x2c,0xd3,0x10,0x92,0x0c,0x91,0x08, + 0x10,0x04,0x0d,0x09,0x0d,0x00,0x0d,0x00,0x0d,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04, + 0x0d,0x00,0x11,0x00,0x10,0x04,0x11,0x07,0x11,0x00,0x91,0x08,0x10,0x04,0x11,0x00, + 0x10,0x00,0x00,0x00,0x53,0x04,0x0d,0x00,0x92,0x0c,0x51,0x04,0x0d,0x00,0x10,0x04, + 0x10,0x00,0x11,0x00,0x11,0x00,0xd4,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x93,0x10,0x52,0x04,0x10,0x00, + 0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0xc8,0xd1,0x48, + 0xd0,0x42,0xcf,0x86,0xd5,0x18,0x54,0x04,0x10,0x00,0x93,0x10,0x92,0x0c,0x51,0x04, + 0x10,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x54,0x04,0x10,0x00, + 0xd3,0x14,0x52,0x04,0x10,0x00,0xd1,0x08,0x10,0x04,0x10,0x00,0x10,0x09,0x10,0x04, + 0x10,0x07,0x10,0x00,0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x12,0x00, + 0x00,0x00,0xcf,0x06,0x00,0x00,0xd0,0x52,0xcf,0x86,0xd5,0x3c,0xd4,0x28,0xd3,0x10, + 0x52,0x04,0x11,0x00,0x51,0x04,0x11,0x00,0x10,0x04,0x11,0x00,0x00,0x00,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x11,0x00,0x00,0x00,0x11,0x00,0x51,0x04,0x11,0x00,0x10,0x04, + 0x00,0x00,0x11,0x00,0x53,0x04,0x11,0x00,0x52,0x04,0x11,0x00,0x51,0x04,0x11,0x00, + 0x10,0x04,0x00,0x00,0x11,0x00,0x94,0x10,0x53,0x04,0x11,0x00,0x92,0x08,0x11,0x04, + 0x11,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0xcf,0x86,0x55,0x04,0x10,0x00,0xd4,0x18, + 0x53,0x04,0x10,0x00,0x92,0x10,0xd1,0x08,0x10,0x04,0x10,0x00,0x10,0x07,0x10,0x04, + 0x10,0x09,0x00,0x00,0x00,0x00,0x53,0x04,0x10,0x00,0x92,0x08,0x11,0x04,0x10,0x00, + 0x00,0x00,0x00,0x00,0xe1,0x27,0x01,0xd0,0x8a,0xcf,0x86,0xd5,0x44,0xd4,0x2c,0xd3, + 0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x11,0x00,0x10,0x00,0x10,0x00,0x91,0x08,0x10, + 0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x52,0x04,0x10,0x00,0xd1,0x08,0x10,0x04,0x10, + 0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x93,0x14,0x92,0x10,0xd1,0x08,0x10, + 0x04,0x10,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0xd4, + 0x14,0x53,0x04,0x10,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x10, + 0x00,0x10,0x00,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x10, + 0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0xd2,0x0c,0x51,0x04,0x10, + 0x00,0x10,0x04,0x00,0x00,0x14,0x07,0x91,0x08,0x10,0x04,0x10,0x07,0x10,0x00,0x10, + 0x00,0xcf,0x86,0xd5,0x6a,0xd4,0x42,0xd3,0x14,0x52,0x04,0x10,0x00,0xd1,0x08,0x10, + 0x04,0x10,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0xd2,0x19,0xd1,0x08,0x10, + 0x04,0x10,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0xff,0xf0,0x91,0x8d,0x87,0xf0, + 0x91,0x8c,0xbe,0x00,0x91,0x11,0x10,0x0d,0x10,0xff,0xf0,0x91,0x8d,0x87,0xf0,0x91, + 0x8d,0x97,0x00,0x10,0x09,0x00,0x00,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x11, + 0x00,0x00,0x00,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x52, + 0x04,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0xd4,0x1c,0xd3, + 0x0c,0x52,0x04,0x10,0x00,0x11,0x04,0x00,0x00,0x10,0xe6,0x52,0x04,0x10,0xe6,0x91, + 0x08,0x10,0x04,0x10,0xe6,0x00,0x00,0x00,0x00,0x93,0x10,0x52,0x04,0x10,0xe6,0x91, + 0x08,0x10,0x04,0x10,0xe6,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xe3, + 0x30,0x01,0xd2,0xb7,0xd1,0x48,0xd0,0x06,0xcf,0x06,0x12,0x00,0xcf,0x86,0x95,0x3c, + 0xd4,0x1c,0x93,0x18,0xd2,0x0c,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x09,0x12,0x00, + 0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x07,0x12,0x00,0x12,0x00,0x53,0x04,0x12,0x00, + 0xd2,0x0c,0x51,0x04,0x12,0x00,0x10,0x04,0x00,0x00,0x12,0x00,0xd1,0x08,0x10,0x04, + 0x00,0x00,0x12,0x00,0x10,0x04,0x14,0xe6,0x15,0x00,0x00,0x00,0xd0,0x45,0xcf,0x86, + 0x55,0x04,0x10,0x00,0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00,0xd2,0x15,0x51,0x04, + 0x10,0x00,0x10,0x04,0x10,0x00,0x10,0xff,0xf0,0x91,0x92,0xb9,0xf0,0x91,0x92,0xba, + 0x00,0xd1,0x11,0x10,0x0d,0x10,0xff,0xf0,0x91,0x92,0xb9,0xf0,0x91,0x92,0xb0,0x00, + 0x10,0x00,0x10,0x0d,0x10,0xff,0xf0,0x91,0x92,0xb9,0xf0,0x91,0x92,0xbd,0x00,0x10, + 0x00,0xcf,0x86,0x95,0x24,0xd4,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x10,0x00,0x10, + 0x04,0x10,0x09,0x10,0x07,0x10,0x00,0x00,0x00,0x53,0x04,0x10,0x00,0x92,0x08,0x11, + 0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0, + 0x40,0xcf,0x86,0x55,0x04,0x10,0x00,0x54,0x04,0x10,0x00,0xd3,0x0c,0x52,0x04,0x10, + 0x00,0x11,0x04,0x10,0x00,0x00,0x00,0xd2,0x1e,0x51,0x04,0x10,0x00,0x10,0x0d,0x10, + 0xff,0xf0,0x91,0x96,0xb8,0xf0,0x91,0x96,0xaf,0x00,0x10,0xff,0xf0,0x91,0x96,0xb9, + 0xf0,0x91,0x96,0xaf,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x10,0x09,0xcf, + 0x86,0x95,0x2c,0xd4,0x1c,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x10,0x07,0x10, + 0x00,0x10,0x00,0x10,0x00,0x92,0x08,0x11,0x04,0x10,0x00,0x11,0x00,0x11,0x00,0x53, + 0x04,0x11,0x00,0x52,0x04,0x11,0x00,0x11,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0xd2, + 0xa0,0xd1,0x5c,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x10,0x00,0x54,0x04,0x10,0x00,0x53, + 0x04,0x10,0x00,0x52,0x04,0x10,0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x10, + 0x09,0xcf,0x86,0xd5,0x24,0xd4,0x14,0x93,0x10,0x52,0x04,0x10,0x00,0x91,0x08,0x10, + 0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x10,0x00,0x92,0x08,0x11, + 0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x94,0x14,0x53,0x04,0x12,0x00,0x52,0x04,0x12, + 0x00,0x91,0x08,0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x2a,0xcf, + 0x86,0x55,0x04,0x0d,0x00,0x54,0x04,0x0d,0x00,0xd3,0x10,0x52,0x04,0x0d,0x00,0x51, + 0x04,0x0d,0x00,0x10,0x04,0x0d,0x09,0x0d,0x07,0x92,0x0c,0x91,0x08,0x10,0x04,0x15, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0x95,0x14,0x94,0x10,0x53,0x04,0x0d, + 0x00,0x92,0x08,0x11,0x04,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1, + 0x40,0xd0,0x3a,0xcf,0x86,0xd5,0x20,0x54,0x04,0x11,0x00,0x53,0x04,0x11,0x00,0xd2, + 0x0c,0x51,0x04,0x11,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x00, + 0x00,0x11,0x00,0x11,0x00,0x94,0x14,0x53,0x04,0x11,0x00,0x92,0x0c,0x51,0x04,0x11, + 0x00,0x10,0x04,0x11,0x00,0x11,0x09,0x00,0x00,0x11,0x00,0xcf,0x06,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xe4,0x59,0x01,0xd3,0xb2,0xd2,0x5c,0xd1,0x28,0xd0,0x22,0xcf,0x86, + 0x55,0x04,0x14,0x00,0x54,0x04,0x14,0x00,0x53,0x04,0x14,0x00,0x92,0x10,0xd1,0x08, + 0x10,0x04,0x14,0x00,0x14,0x09,0x10,0x04,0x14,0x07,0x14,0x00,0x00,0x00,0xcf,0x06, + 0x00,0x00,0xd0,0x0a,0xcf,0x86,0x15,0x04,0x00,0x00,0x10,0x00,0xcf,0x86,0x55,0x04, + 0x10,0x00,0x54,0x04,0x10,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x10,0x00,0x10,0x04, + 0x10,0x00,0x00,0x00,0x00,0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04, + 0x00,0x00,0x10,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x1a,0xcf,0x86,0x55,0x04, + 0x00,0x00,0x94,0x10,0x53,0x04,0x15,0x00,0x92,0x08,0x11,0x04,0x00,0x00,0x15,0x00, + 0x15,0x00,0x15,0x00,0xcf,0x86,0xd5,0x14,0x54,0x04,0x15,0x00,0x53,0x04,0x15,0x00, + 0x92,0x08,0x11,0x04,0x00,0x00,0x15,0x00,0x15,0x00,0x94,0x1c,0x93,0x18,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x15,0x09,0x15,0x00,0x15,0x00,0x91,0x08,0x10,0x04,0x15,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd2,0xa0,0xd1,0x3c,0xd0,0x1e,0xcf,0x86, + 0x55,0x04,0x13,0x00,0x54,0x04,0x13,0x00,0x93,0x10,0x52,0x04,0x13,0x00,0x91,0x08, + 0x10,0x04,0x13,0x09,0x13,0x00,0x13,0x00,0x13,0x00,0xcf,0x86,0x95,0x18,0x94,0x14, + 0x93,0x10,0x52,0x04,0x13,0x00,0x51,0x04,0x13,0x00,0x10,0x04,0x13,0x00,0x13,0x09, + 0x00,0x00,0x13,0x00,0x13,0x00,0xd0,0x46,0xcf,0x86,0xd5,0x2c,0xd4,0x10,0x93,0x0c, + 0x52,0x04,0x13,0x00,0x11,0x04,0x15,0x00,0x13,0x00,0x13,0x00,0x53,0x04,0x13,0x00, + 0xd2,0x0c,0x91,0x08,0x10,0x04,0x13,0x00,0x13,0x09,0x13,0x00,0x91,0x08,0x10,0x04, + 0x13,0x00,0x14,0x00,0x13,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x13,0x00, + 0x10,0x04,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0x55,0x04, + 0x10,0x00,0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xe3,0xa9,0x01,0xd2, + 0xb0,0xd1,0x6c,0xd0,0x3e,0xcf,0x86,0xd5,0x18,0x94,0x14,0x53,0x04,0x12,0x00,0x92, + 0x0c,0x91,0x08,0x10,0x04,0x12,0x00,0x00,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x54, + 0x04,0x12,0x00,0xd3,0x10,0x52,0x04,0x12,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12, + 0x00,0x00,0x00,0x52,0x04,0x12,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x12, + 0x09,0xcf,0x86,0xd5,0x14,0x94,0x10,0x93,0x0c,0x52,0x04,0x12,0x00,0x11,0x04,0x12, + 0x00,0x00,0x00,0x00,0x00,0x12,0x00,0x94,0x14,0x53,0x04,0x12,0x00,0x52,0x04,0x12, + 0x00,0x91,0x08,0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00,0x12,0x00,0xd0,0x3e,0xcf, + 0x86,0xd5,0x14,0x54,0x04,0x12,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x00,0x00,0x12, + 0x00,0x12,0x00,0x12,0x00,0xd4,0x14,0x53,0x04,0x12,0x00,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x12,0x00,0x12,0x00,0x12,0x00,0x93,0x10,0x52,0x04,0x12,0x00,0x51, + 0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1, + 0xa0,0xd0,0x52,0xcf,0x86,0xd5,0x24,0x94,0x20,0xd3,0x10,0x52,0x04,0x13,0x00,0x51, + 0x04,0x13,0x00,0x10,0x04,0x13,0x00,0x00,0x00,0x92,0x0c,0x51,0x04,0x13,0x00,0x10, + 0x04,0x00,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x54,0x04,0x13,0x00,0xd3,0x10,0x52, + 0x04,0x13,0x00,0x51,0x04,0x13,0x00,0x10,0x04,0x13,0x00,0x00,0x00,0xd2,0x0c,0x51, + 0x04,0x00,0x00,0x10,0x04,0x13,0x00,0x00,0x00,0x51,0x04,0x13,0x00,0x10,0x04,0x00, + 0x00,0x13,0x00,0xcf,0x86,0xd5,0x28,0xd4,0x18,0x93,0x14,0xd2,0x0c,0x51,0x04,0x13, + 0x00,0x10,0x04,0x13,0x07,0x13,0x00,0x11,0x04,0x13,0x09,0x13,0x00,0x00,0x00,0x53, + 0x04,0x13,0x00,0x92,0x08,0x11,0x04,0x13,0x00,0x00,0x00,0x00,0x00,0x94,0x20,0xd3, + 0x10,0x52,0x04,0x14,0x00,0x51,0x04,0x14,0x00,0x10,0x04,0x00,0x00,0x14,0x00,0x92, + 0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0xd0, + 0x52,0xcf,0x86,0xd5,0x3c,0xd4,0x14,0x53,0x04,0x14,0x00,0x52,0x04,0x14,0x00,0x51, + 0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x14, + 0x00,0x10,0x04,0x00,0x00,0x14,0x00,0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x14, + 0x09,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94, + 0x10,0x53,0x04,0x14,0x00,0x92,0x08,0x11,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xd2,0x2a,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x14,0x00,0x53,0x04,0x14, + 0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd1, + 0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x15, + 0x00,0x54,0x04,0x15,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04,0x15,0x00,0x00,0x00,0x00, + 0x00,0x52,0x04,0x00,0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x15,0x00,0xd0, + 0xca,0xcf,0x86,0xd5,0xc2,0xd4,0x54,0xd3,0x06,0xcf,0x06,0x09,0x00,0xd2,0x06,0xcf, + 0x06,0x09,0x00,0xd1,0x24,0xd0,0x06,0xcf,0x06,0x09,0x00,0xcf,0x86,0x55,0x04,0x09, + 0x00,0x94,0x14,0x53,0x04,0x09,0x00,0x52,0x04,0x09,0x00,0x51,0x04,0x09,0x00,0x10, + 0x04,0x09,0x00,0x10,0x00,0x10,0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04,0x10, + 0x00,0x53,0x04,0x10,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x10,0x00,0x11,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd3,0x68,0xd2,0x46,0xd1,0x40,0xd0, + 0x06,0xcf,0x06,0x09,0x00,0xcf,0x86,0x55,0x04,0x09,0x00,0xd4,0x20,0xd3,0x10,0x92, + 0x0c,0x51,0x04,0x09,0x00,0x10,0x04,0x09,0x00,0x10,0x00,0x10,0x00,0x52,0x04,0x10, + 0x00,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x00,0x00,0x93,0x10,0x52,0x04,0x09, + 0x00,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x11, + 0x00,0xd1,0x1c,0xd0,0x06,0xcf,0x06,0x11,0x00,0xcf,0x86,0x95,0x10,0x94,0x0c,0x93, + 0x08,0x12,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x86,0xd5,0x4c,0xd4,0x06,0xcf, + 0x06,0x0b,0x00,0xd3,0x40,0xd2,0x3a,0xd1,0x34,0xd0,0x2e,0xcf,0x86,0x55,0x04,0x0b, + 0x00,0xd4,0x14,0x53,0x04,0x0b,0x00,0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10, + 0x04,0x0b,0x00,0x00,0x00,0x53,0x04,0x15,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x15, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1,0x4c,0xd0,0x44,0xcf, + 0x86,0xd5,0x3c,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf,0x06,0x11,0x00,0xd2, + 0x2a,0xd1,0x24,0xd0,0x06,0xcf,0x06,0x11,0x00,0xcf,0x86,0x95,0x18,0x94,0x14,0x93, + 0x10,0x52,0x04,0x11,0x00,0x51,0x04,0x11,0x00,0x10,0x04,0x11,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00, + 0x00,0xcf,0x86,0xcf,0x06,0x00,0x00,0xe0,0xd2,0x01,0xcf,0x86,0xd5,0x06,0xcf,0x06, + 0x00,0x00,0xe4,0x0b,0x01,0xd3,0x06,0xcf,0x06,0x0c,0x00,0xd2,0x84,0xd1,0x50,0xd0, + 0x1e,0xcf,0x86,0x55,0x04,0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x0c,0x00,0x92, + 0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5, + 0x18,0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00,0x52,0x04,0x10,0x00,0x51,0x04,0x10, + 0x00,0x10,0x04,0x10,0x00,0x00,0x00,0x94,0x14,0x53,0x04,0x10,0x00,0xd2,0x08,0x11, + 0x04,0x10,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x10,0x00,0x00,0x00,0xd0,0x06,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0xd5,0x08,0x14,0x04,0x00,0x00,0x10,0x00,0xd4,0x10,0x53, + 0x04,0x10,0x00,0x52,0x04,0x10,0x00,0x11,0x04,0x10,0x00,0x00,0x00,0x93,0x10,0x52, + 0x04,0x10,0x01,0x91,0x08,0x10,0x04,0x10,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0xd1, + 0x6c,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x10,0x00,0x54,0x04,0x10,0x00,0x93,0x10,0x52, + 0x04,0x10,0xe6,0x51,0x04,0x10,0xe6,0x10,0x04,0x10,0xe6,0x10,0x00,0x10,0x00,0xcf, + 0x86,0xd5,0x24,0xd4,0x10,0x93,0x0c,0x52,0x04,0x10,0x00,0x11,0x04,0x10,0x00,0x00, + 0x00,0x00,0x00,0x53,0x04,0x10,0x00,0x92,0x0c,0x51,0x04,0x10,0x00,0x10,0x04,0x00, + 0x00,0x10,0x00,0x10,0x00,0xd4,0x14,0x93,0x10,0x92,0x0c,0x51,0x04,0x10,0x00,0x10, + 0x04,0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x53,0x04,0x10,0x00,0x52,0x04,0x00, + 0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x10,0x00,0x10,0x00,0xd0,0x0e,0xcf,0x86,0x95, + 0x08,0x14,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf, + 0x06,0x00,0x00,0xd2,0x30,0xd1,0x0c,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x06,0x14, + 0x00,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04,0x14,0x00,0x53,0x04,0x14,0x00,0x92, + 0x0c,0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xd1,0x4c,0xd0,0x06,0xcf,0x06,0x0d,0x00,0xcf,0x86,0xd5,0x2c,0x94, + 0x28,0xd3,0x10,0x52,0x04,0x0d,0x00,0x91,0x08,0x10,0x04,0x0d,0x00,0x15,0x00,0x15, + 0x00,0xd2,0x0c,0x51,0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00,0x00,0x51,0x04,0x00, + 0x00,0x10,0x04,0x00,0x00,0x15,0x00,0x0d,0x00,0x54,0x04,0x0d,0x00,0x53,0x04,0x0d, + 0x00,0x52,0x04,0x0d,0x00,0x51,0x04,0x0d,0x00,0x10,0x04,0x0d,0x00,0x15,0x00,0xd0, + 0x1e,0xcf,0x86,0x95,0x18,0x94,0x14,0x53,0x04,0x15,0x00,0x52,0x04,0x00,0x00,0x51, + 0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0x00,0x00,0xcf,0x86,0x55, + 0x04,0x00,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x12,0x00,0x13, + 0x00,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xcf,0x06,0x12,0x00,0xe2, + 0xc6,0x01,0xd1,0x8e,0xd0,0x86,0xcf,0x86,0xd5,0x48,0xd4,0x06,0xcf,0x06,0x12,0x00, + 0xd3,0x06,0xcf,0x06,0x12,0x00,0xd2,0x06,0xcf,0x06,0x12,0x00,0xd1,0x06,0xcf,0x06, + 0x12,0x00,0xd0,0x06,0xcf,0x06,0x12,0x00,0xcf,0x86,0x55,0x04,0x12,0x00,0xd4,0x14, + 0x53,0x04,0x12,0x00,0x52,0x04,0x12,0x00,0x91,0x08,0x10,0x04,0x12,0x00,0x14,0x00, + 0x14,0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x14,0x00,0x15,0x00,0x15,0x00,0x00,0x00, + 0xd4,0x36,0xd3,0x06,0xcf,0x06,0x12,0x00,0xd2,0x2a,0xd1,0x06,0xcf,0x06,0x12,0x00, + 0xd0,0x06,0xcf,0x06,0x12,0x00,0xcf,0x86,0x55,0x04,0x12,0x00,0x54,0x04,0x12,0x00, + 0x93,0x10,0x92,0x0c,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86,0xd5,0xa2,0xd4,0x9c,0xd3,0x74, + 0xd2,0x26,0xd1,0x20,0xd0,0x1a,0xcf,0x86,0x95,0x14,0x94,0x10,0x93,0x0c,0x92,0x08, + 0x11,0x04,0x0c,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0xcf,0x06, + 0x13,0x00,0xcf,0x06,0x13,0x00,0xd1,0x48,0xd0,0x1e,0xcf,0x86,0x95,0x18,0x54,0x04, + 0x13,0x00,0x53,0x04,0x13,0x00,0x52,0x04,0x13,0x00,0x51,0x04,0x13,0x00,0x10,0x04, + 0x13,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0xd5,0x18,0x54,0x04,0x00,0x00,0x93,0x10, + 0x92,0x0c,0x51,0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x94,0x0c,0x93,0x08,0x12,0x04,0x00,0x00,0x15,0x00,0x00,0x00,0x13,0x00,0xcf,0x06, + 0x13,0x00,0xd2,0x22,0xd1,0x06,0xcf,0x06,0x13,0x00,0xd0,0x06,0xcf,0x06,0x13,0x00, + 0xcf,0x86,0x55,0x04,0x13,0x00,0x54,0x04,0x13,0x00,0x53,0x04,0x13,0x00,0x12,0x04, + 0x13,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06, + 0x00,0x00,0xd3,0x7f,0xd2,0x79,0xd1,0x34,0xd0,0x06,0xcf,0x06,0x10,0x00,0xcf,0x86, + 0x55,0x04,0x10,0x00,0xd4,0x14,0x53,0x04,0x10,0x00,0x92,0x0c,0x51,0x04,0x10,0x00, + 0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x10,0x00,0x52,0x04,0x10,0x00, + 0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd0,0x3f,0xcf,0x86,0xd5,0x2c, + 0xd4,0x14,0x53,0x04,0x10,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x53,0x04,0x10,0x00,0xd2,0x08,0x11,0x04,0x10,0x00,0x00,0x00, + 0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x01,0x10,0x00,0x94,0x0d,0x93,0x09,0x12,0x05, + 0x10,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xe1,0x96,0x04,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xcf,0x86,0xe5,0x33,0x04,0xe4,0x83,0x02,0xe3,0xf8,0x01,0xd2,0x26,0xd1,0x06,0xcf, + 0x06,0x05,0x00,0xd0,0x06,0xcf,0x06,0x05,0x00,0xcf,0x86,0x55,0x04,0x05,0x00,0x54, + 0x04,0x05,0x00,0x93,0x0c,0x52,0x04,0x05,0x00,0x11,0x04,0x05,0x00,0x00,0x00,0x00, + 0x00,0xd1,0xef,0xd0,0x2a,0xcf,0x86,0x55,0x04,0x05,0x00,0x94,0x20,0xd3,0x10,0x52, + 0x04,0x05,0x00,0x51,0x04,0x05,0x00,0x10,0x04,0x05,0x00,0x00,0x00,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x00,0x00,0x0a,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0xcf,0x86,0xd5, + 0x2a,0x54,0x04,0x05,0x00,0x53,0x04,0x05,0x00,0x52,0x04,0x05,0x00,0x51,0x04,0x05, + 0x00,0x10,0x0d,0x05,0xff,0xf0,0x9d,0x85,0x97,0xf0,0x9d,0x85,0xa5,0x00,0x05,0xff, + 0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0x00,0xd4,0x75,0xd3,0x61,0xd2,0x44,0xd1, + 0x22,0x10,0x11,0x05,0xff,0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0xf0,0x9d,0x85, + 0xae,0x00,0x05,0xff,0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0xf0,0x9d,0x85,0xaf, + 0x00,0x10,0x11,0x05,0xff,0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0xf0,0x9d,0x85, + 0xb0,0x00,0x05,0xff,0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0xf0,0x9d,0x85,0xb1, + 0x00,0xd1,0x15,0x10,0x11,0x05,0xff,0xf0,0x9d,0x85,0x98,0xf0,0x9d,0x85,0xa5,0xf0, + 0x9d,0x85,0xb2,0x00,0x05,0xd8,0x10,0x04,0x05,0xd8,0x05,0x01,0xd2,0x08,0x11,0x04, + 0x05,0x01,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x05,0xe2,0x05,0xd8,0xd3,0x12, + 0x92,0x0d,0x51,0x04,0x05,0xd8,0x10,0x04,0x05,0xd8,0x05,0xff,0x00,0x05,0xff,0x00, + 0x92,0x0e,0x51,0x05,0x05,0xff,0x00,0x10,0x05,0x05,0xff,0x00,0x05,0xdc,0x05,0xdc, + 0xd0,0x97,0xcf,0x86,0xd5,0x28,0x94,0x24,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x05,0xdc, + 0x10,0x04,0x05,0xdc,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x05,0xe6,0x05,0xe6, + 0x92,0x08,0x11,0x04,0x05,0xe6,0x05,0xdc,0x05,0x00,0x05,0x00,0xd4,0x14,0x53,0x04, + 0x05,0x00,0xd2,0x08,0x11,0x04,0x05,0x00,0x05,0xe6,0x11,0x04,0x05,0xe6,0x05,0x00, + 0x53,0x04,0x05,0x00,0xd2,0x15,0x51,0x04,0x05,0x00,0x10,0x04,0x05,0x00,0x05,0xff, + 0xf0,0x9d,0x86,0xb9,0xf0,0x9d,0x85,0xa5,0x00,0xd1,0x1e,0x10,0x0d,0x05,0xff,0xf0, + 0x9d,0x86,0xba,0xf0,0x9d,0x85,0xa5,0x00,0x05,0xff,0xf0,0x9d,0x86,0xb9,0xf0,0x9d, + 0x85,0xa5,0xf0,0x9d,0x85,0xae,0x00,0x10,0x11,0x05,0xff,0xf0,0x9d,0x86,0xba,0xf0, + 0x9d,0x85,0xa5,0xf0,0x9d,0x85,0xae,0x00,0x05,0xff,0xf0,0x9d,0x86,0xb9,0xf0,0x9d, + 0x85,0xa5,0xf0,0x9d,0x85,0xaf,0x00,0xcf,0x86,0xd5,0x31,0xd4,0x21,0x93,0x1d,0x92, + 0x19,0x91,0x15,0x10,0x11,0x05,0xff,0xf0,0x9d,0x86,0xba,0xf0,0x9d,0x85,0xa5,0xf0, + 0x9d,0x85,0xaf,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x53,0x04,0x05,0x00, + 0x52,0x04,0x05,0x00,0x11,0x04,0x05,0x00,0x11,0x00,0x94,0x14,0x53,0x04,0x11,0x00, + 0x92,0x0c,0x91,0x08,0x10,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xd2,0x44,0xd1,0x28,0xd0,0x06,0xcf,0x06,0x08,0x00,0xcf,0x86,0x95,0x1c,0x94,0x18, + 0x93,0x14,0xd2,0x08,0x11,0x04,0x08,0x00,0x08,0xe6,0x91,0x08,0x10,0x04,0x08,0xe6, + 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00, + 0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x14,0x00,0x93,0x08,0x12,0x04,0x14,0x00, + 0x00,0x00,0x00,0x00,0xd1,0x40,0xd0,0x06,0xcf,0x06,0x07,0x00,0xcf,0x86,0xd5,0x18, + 0x54,0x04,0x07,0x00,0x93,0x10,0x52,0x04,0x07,0x00,0x51,0x04,0x07,0x00,0x10,0x04, + 0x07,0x00,0x00,0x00,0x00,0x00,0x54,0x04,0x09,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04, + 0x09,0x00,0x14,0x00,0x14,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x14,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xe3,0x5f,0x01,0xd2,0xb4,0xd1,0x24,0xd0, + 0x06,0xcf,0x06,0x05,0x00,0xcf,0x86,0x95,0x18,0x54,0x04,0x05,0x00,0x93,0x10,0x52, + 0x04,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x05, + 0x00,0xd0,0x6a,0xcf,0x86,0xd5,0x18,0x54,0x04,0x05,0x00,0x53,0x04,0x05,0x00,0x52, + 0x04,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05,0x00,0xd4,0x34,0xd3, + 0x1c,0xd2,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x05,0x00,0x00,0x00,0xd1,0x08,0x10, + 0x04,0x00,0x00,0x05,0x00,0x10,0x04,0x05,0x00,0x00,0x00,0xd2,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x05,0x00,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05, + 0x00,0x53,0x04,0x05,0x00,0xd2,0x0c,0x51,0x04,0x05,0x00,0x10,0x04,0x00,0x00,0x05, + 0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x05,0x00,0x05,0x00,0xcf,0x86,0x95,0x20,0x94, + 0x1c,0x93,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x05,0x00,0x07,0x00,0x05,0x00,0x91, + 0x08,0x10,0x04,0x00,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0x05,0x00,0xd1, + 0xa4,0xd0,0x6a,0xcf,0x86,0xd5,0x48,0xd4,0x28,0xd3,0x10,0x52,0x04,0x05,0x00,0x51, + 0x04,0x05,0x00,0x10,0x04,0x00,0x00,0x05,0x00,0xd2,0x0c,0x51,0x04,0x05,0x00,0x10, + 0x04,0x05,0x00,0x00,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x05,0x00,0x05,0x00,0xd3, + 0x10,0x52,0x04,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05,0x00,0x52, + 0x04,0x05,0x00,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05,0x00,0x54,0x04,0x05, + 0x00,0x53,0x04,0x05,0x00,0xd2,0x0c,0x51,0x04,0x05,0x00,0x10,0x04,0x00,0x00,0x05, + 0x00,0x51,0x04,0x05,0x00,0x10,0x04,0x05,0x00,0x00,0x00,0xcf,0x86,0x95,0x34,0xd4, + 0x20,0xd3,0x14,0x52,0x04,0x05,0x00,0xd1,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x10, + 0x04,0x05,0x00,0x00,0x00,0x92,0x08,0x11,0x04,0x00,0x00,0x05,0x00,0x05,0x00,0x93, + 0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x05,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0x05, + 0x00,0x05,0x00,0xcf,0x06,0x05,0x00,0xd2,0x26,0xd1,0x06,0xcf,0x06,0x05,0x00,0xd0, + 0x1a,0xcf,0x86,0x55,0x04,0x05,0x00,0x94,0x10,0x93,0x0c,0x52,0x04,0x05,0x00,0x11, + 0x04,0x08,0x00,0x00,0x00,0x05,0x00,0x05,0x00,0xcf,0x06,0x05,0x00,0xd1,0x06,0xcf, + 0x06,0x05,0x00,0xd0,0x06,0xcf,0x06,0x05,0x00,0xcf,0x86,0x95,0x18,0x94,0x14,0x53, + 0x04,0x05,0x00,0xd2,0x08,0x11,0x04,0x05,0x00,0x09,0x00,0x11,0x04,0x00,0x00,0x05, + 0x00,0x05,0x00,0x05,0x00,0xd4,0x52,0xd3,0x06,0xcf,0x06,0x11,0x00,0xd2,0x46,0xd1, + 0x06,0xcf,0x06,0x11,0x00,0xd0,0x3a,0xcf,0x86,0xd5,0x20,0xd4,0x0c,0x53,0x04,0x11, + 0x00,0x12,0x04,0x11,0x00,0x00,0x00,0x53,0x04,0x00,0x00,0x92,0x0c,0x51,0x04,0x00, + 0x00,0x10,0x04,0x00,0x00,0x11,0x00,0x11,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x00,0x00,0x11,0x00,0x11,0x00,0x11,0x00,0x11,0x00,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xe0,0xc2,0x03,0xcf,0x86, + 0xe5,0x03,0x01,0xd4,0xfc,0xd3,0xc0,0xd2,0x66,0xd1,0x60,0xd0,0x5a,0xcf,0x86,0xd5, + 0x2c,0xd4,0x14,0x93,0x10,0x52,0x04,0x12,0xe6,0x51,0x04,0x12,0xe6,0x10,0x04,0x12, + 0xe6,0x00,0x00,0x12,0xe6,0x53,0x04,0x12,0xe6,0x92,0x10,0xd1,0x08,0x10,0x04,0x12, + 0xe6,0x00,0x00,0x10,0x04,0x00,0x00,0x12,0xe6,0x12,0xe6,0x94,0x28,0xd3,0x18,0xd2, + 0x0c,0x51,0x04,0x12,0xe6,0x10,0x04,0x00,0x00,0x12,0xe6,0x91,0x08,0x10,0x04,0x12, + 0xe6,0x00,0x00,0x12,0xe6,0x92,0x0c,0x51,0x04,0x12,0xe6,0x10,0x04,0x12,0xe6,0x00, + 0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1,0x54,0xd0, + 0x36,0xcf,0x86,0x55,0x04,0x15,0x00,0xd4,0x14,0x53,0x04,0x15,0x00,0x52,0x04,0x15, + 0x00,0x91,0x08,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0xd3,0x10,0x52,0x04,0x15, + 0xe6,0x51,0x04,0x15,0xe6,0x10,0x04,0x15,0xe6,0x15,0x00,0x52,0x04,0x15,0x00,0x11, + 0x04,0x15,0x00,0x00,0x00,0xcf,0x86,0x95,0x18,0x94,0x14,0x53,0x04,0x15,0x00,0xd2, + 0x08,0x11,0x04,0x15,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x15,0x00,0x00,0x00,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xd2,0x36,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x15,0x00,0xd4,0x0c,0x53,0x04,0x15,0x00,0x12, + 0x04,0x15,0x00,0x15,0xe6,0x53,0x04,0x15,0x00,0xd2,0x08,0x11,0x04,0x15,0x00,0x00, + 0x00,0x51,0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x15,0x00,0xcf,0x06,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xd4,0x82,0xd3,0x7c,0xd2,0x3e,0xd1,0x06,0xcf,0x06,0x10,0x00,0xd0, + 0x06,0xcf,0x06,0x10,0x00,0xcf,0x86,0x95,0x2c,0xd4,0x18,0x93,0x14,0x52,0x04,0x10, + 0x00,0xd1,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x10,0x00,0x10, + 0x00,0x93,0x10,0x52,0x04,0x10,0xdc,0x51,0x04,0x10,0xdc,0x10,0x04,0x10,0xdc,0x00, + 0x00,0x00,0x00,0x00,0x00,0xd1,0x38,0xd0,0x06,0xcf,0x06,0x12,0x00,0xcf,0x86,0x95, + 0x2c,0xd4,0x18,0xd3,0x08,0x12,0x04,0x12,0x00,0x12,0xe6,0x92,0x0c,0x51,0x04,0x12, + 0xe6,0x10,0x04,0x12,0x07,0x15,0x00,0x00,0x00,0x53,0x04,0x12,0x00,0xd2,0x08,0x11, + 0x04,0x12,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x12,0x00,0x00,0x00,0xcf,0x06,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xd3,0x82,0xd2,0x48,0xd1,0x24,0xd0,0x06,0xcf,0x06,0x00, + 0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x93,0x10,0x92,0x0c,0x91, + 0x08,0x10,0x04,0x00,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0x14,0x00,0xd0,0x1e,0xcf, + 0x86,0x55,0x04,0x14,0x00,0x54,0x04,0x14,0x00,0x93,0x10,0x52,0x04,0x14,0x00,0x91, + 0x08,0x10,0x04,0x14,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1, + 0x34,0xd0,0x2e,0xcf,0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x15,0x00,0x54,0x04,0x15, + 0x00,0x53,0x04,0x15,0x00,0x52,0x04,0x15,0x00,0x11,0x04,0x15,0x00,0x00,0x00,0xcf, + 0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xe2,0xb2,0x01,0xe1,0x41,0x01,0xd0,0x6e,0xcf, + 0x86,0xd5,0x18,0x94,0x14,0x93,0x10,0x52,0x04,0x0d,0x00,0x91,0x08,0x10,0x04,0x00, + 0x00,0x0d,0x00,0x0d,0x00,0x0d,0x00,0x0d,0x00,0xd4,0x30,0xd3,0x20,0xd2,0x10,0xd1, + 0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0xd1,0x08,0x10, + 0x04,0x0d,0x00,0x00,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0x92,0x0c,0x91,0x08,0x10, + 0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0x0d,0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x0d, + 0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0x0d,0x00,0x92,0x10,0xd1,0x08,0x10,0x04,0x00, + 0x00,0x0d,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0x00,0x00,0xcf,0x86,0xd5,0x74,0xd4, + 0x34,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x00,0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0x51, + 0x04,0x00,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00, + 0x00,0x0d,0x00,0x10,0x04,0x00,0x00,0x0d,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x0d, + 0x00,0x0d,0x00,0xd3,0x20,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x10, + 0x04,0x0d,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x0d,0x00,0x00,0x00,0x10,0x04,0x00, + 0x00,0x0d,0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x10,0x04,0x00, + 0x00,0x0d,0x00,0xd1,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x10,0x04,0x00,0x00,0x0d, + 0x00,0xd4,0x30,0xd3,0x20,0xd2,0x10,0xd1,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x10, + 0x04,0x0d,0x00,0x00,0x00,0xd1,0x08,0x10,0x04,0x0d,0x00,0x00,0x00,0x10,0x04,0x00, + 0x00,0x0d,0x00,0x92,0x0c,0x51,0x04,0x0d,0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0x0d, + 0x00,0xd3,0x10,0x92,0x0c,0x51,0x04,0x0d,0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0x0d, + 0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0xd1,0x08,0x10, + 0x04,0x0d,0x00,0x00,0x00,0x10,0x04,0x0d,0x00,0x00,0x00,0xd0,0x56,0xcf,0x86,0xd5, + 0x20,0xd4,0x14,0x53,0x04,0x0d,0x00,0x92,0x0c,0x51,0x04,0x0d,0x00,0x10,0x04,0x00, + 0x00,0x0d,0x00,0x0d,0x00,0x53,0x04,0x0d,0x00,0x12,0x04,0x0d,0x00,0x00,0x00,0xd4, + 0x28,0xd3,0x18,0xd2,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0x91, + 0x08,0x10,0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0x92,0x0c,0x51,0x04,0x0d,0x00,0x10, + 0x04,0x00,0x00,0x0d,0x00,0x0d,0x00,0x53,0x04,0x0d,0x00,0x12,0x04,0x0d,0x00,0x00, + 0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x93,0x0c,0x92,0x08,0x11, + 0x04,0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x86,0xe5, + 0x96,0x05,0xe4,0x28,0x03,0xe3,0xed,0x01,0xd2,0xa0,0xd1,0x1c,0xd0,0x16,0xcf,0x86, + 0x55,0x04,0x0a,0x00,0x94,0x0c,0x53,0x04,0x0a,0x00,0x12,0x04,0x0a,0x00,0x00,0x00, + 0x0a,0x00,0xcf,0x06,0x0a,0x00,0xd0,0x46,0xcf,0x86,0xd5,0x10,0x54,0x04,0x0a,0x00, + 0x93,0x08,0x12,0x04,0x0a,0x00,0x00,0x00,0x00,0x00,0xd4,0x14,0x53,0x04,0x0c,0x00, + 0x52,0x04,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x00,0x00,0xd3,0x10, + 0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x52,0x04, + 0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x10,0x00,0xcf,0x86,0xd5,0x28, + 0xd4,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00,0x0c,0x00, + 0x0c,0x00,0x0c,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x00,0x00,0x0c,0x00, + 0x0c,0x00,0x0c,0x00,0x0c,0x00,0x54,0x04,0x10,0x00,0x93,0x0c,0x52,0x04,0x10,0x00, + 0x11,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd1,0xe4,0xd0,0x5a,0xcf,0x86,0xd5,0x20, + 0x94,0x1c,0x53,0x04,0x0b,0x00,0xd2,0x0c,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00, + 0x10,0x00,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x0b,0x00,0xd4,0x14, + 0x53,0x04,0x0b,0x00,0x52,0x04,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04,0x0b,0x00, + 0x14,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x0b,0x00,0x0c,0x00, + 0x0c,0x00,0x52,0x04,0x0c,0x00,0xd1,0x08,0x10,0x04,0x0c,0x00,0x0b,0x00,0x10,0x04, + 0x0c,0x00,0x0b,0x00,0xcf,0x86,0xd5,0x4c,0xd4,0x2c,0xd3,0x18,0xd2,0x0c,0x51,0x04, + 0x0c,0x00,0x10,0x04,0x0b,0x00,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0b,0x00, + 0x0c,0x00,0xd2,0x08,0x11,0x04,0x0c,0x00,0x0b,0x00,0x51,0x04,0x0b,0x00,0x10,0x04, + 0x0b,0x00,0x0c,0x00,0xd3,0x10,0x52,0x04,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04, + 0x0c,0x00,0x0b,0x00,0x52,0x04,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00, + 0x0b,0x00,0xd4,0x18,0x53,0x04,0x0c,0x00,0xd2,0x08,0x11,0x04,0x0c,0x00,0x0d,0x00, + 0x91,0x08,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0x53,0x04,0x0c,0x00,0xd2,0x10, + 0xd1,0x08,0x10,0x04,0x0c,0x00,0x0b,0x00,0x10,0x04,0x0c,0x00,0x0b,0x00,0xd1,0x08, + 0x10,0x04,0x0b,0x00,0x0c,0x00,0x10,0x04,0x0c,0x00,0x0b,0x00,0xd0,0x4e,0xcf,0x86, + 0xd5,0x34,0xd4,0x14,0x53,0x04,0x0c,0x00,0xd2,0x08,0x11,0x04,0x0c,0x00,0x0b,0x00, + 0x11,0x04,0x0b,0x00,0x0c,0x00,0xd3,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0b,0x00, + 0x0c,0x00,0x0c,0x00,0x0c,0x00,0x92,0x0c,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00, + 0x12,0x00,0x12,0x00,0x94,0x14,0x53,0x04,0x12,0x00,0x52,0x04,0x12,0x00,0x91,0x08, + 0x10,0x04,0x12,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00, + 0x94,0x10,0x93,0x0c,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x0c,0x00,0x0c,0x00, + 0x0c,0x00,0xd2,0x7e,0xd1,0x78,0xd0,0x3e,0xcf,0x86,0xd5,0x1c,0x94,0x18,0x93,0x14, + 0x92,0x10,0xd1,0x08,0x10,0x04,0x0b,0x00,0x0c,0x00,0x10,0x04,0x0c,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x0b,0x00,0x54,0x04,0x0b,0x00,0xd3,0x0c,0x92,0x08,0x11,0x04, + 0x0b,0x00,0x0c,0x00,0x0c,0x00,0x92,0x0c,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00, + 0x12,0x00,0x00,0x00,0xcf,0x86,0xd5,0x24,0xd4,0x14,0x53,0x04,0x0b,0x00,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x0c,0x92,0x08, + 0x11,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x10,0x93,0x0c,0x52,0x04, + 0x13,0x00,0x11,0x04,0x13,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00, + 0xd1,0x58,0xd0,0x3a,0xcf,0x86,0x55,0x04,0x0c,0x00,0xd4,0x20,0xd3,0x10,0x92,0x0c, + 0x91,0x08,0x10,0x04,0x0c,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x52,0x04,0x10,0x00, + 0x91,0x08,0x10,0x04,0x10,0x00,0x11,0x00,0x11,0x00,0x93,0x10,0x52,0x04,0x0c,0x00, + 0x51,0x04,0x0c,0x00,0x10,0x04,0x10,0x00,0x0c,0x00,0x0c,0x00,0xcf,0x86,0x55,0x04, + 0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x0c,0x00,0x52,0x04,0x0c,0x00,0x91,0x08, + 0x10,0x04,0x0c,0x00,0x10,0x00,0x11,0x00,0xd0,0x16,0xcf,0x86,0x95,0x10,0x54,0x04, + 0x0c,0x00,0x93,0x08,0x12,0x04,0x0c,0x00,0x10,0x00,0x10,0x00,0x0c,0x00,0xcf,0x86, + 0xd5,0x34,0xd4,0x28,0xd3,0x10,0x52,0x04,0x0c,0x00,0x91,0x08,0x10,0x04,0x0c,0x00, + 0x10,0x00,0x0c,0x00,0xd2,0x0c,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x10,0x00, + 0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x11,0x00,0x93,0x08,0x12,0x04,0x11,0x00, + 0x10,0x00,0x10,0x00,0x54,0x04,0x0c,0x00,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04, + 0x0c,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x11,0x00,0xd3,0xfc,0xd2,0x6c,0xd1,0x3c, + 0xd0,0x1e,0xcf,0x86,0x55,0x04,0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x0c,0x00, + 0x52,0x04,0x0c,0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x10,0x00,0xcf,0x86, + 0x95,0x18,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x10,0x00, + 0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0xd0,0x06,0xcf,0x06,0x0c,0x00, + 0xcf,0x86,0x55,0x04,0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x0c,0x00,0xd2,0x0c, + 0x91,0x08,0x10,0x04,0x10,0x00,0x0c,0x00,0x0c,0x00,0xd1,0x08,0x10,0x04,0x0c,0x00, + 0x10,0x00,0x10,0x04,0x10,0x00,0x11,0x00,0xd1,0x54,0xd0,0x1a,0xcf,0x86,0x55,0x04, + 0x0c,0x00,0x54,0x04,0x0c,0x00,0x53,0x04,0x0c,0x00,0x52,0x04,0x0c,0x00,0x11,0x04, + 0x0c,0x00,0x10,0x00,0xcf,0x86,0xd5,0x1c,0x94,0x18,0xd3,0x08,0x12,0x04,0x0d,0x00, + 0x10,0x00,0x92,0x0c,0x51,0x04,0x10,0x00,0x10,0x04,0x10,0x00,0x11,0x00,0x11,0x00, + 0x0c,0x00,0xd4,0x08,0x13,0x04,0x0c,0x00,0x10,0x00,0x53,0x04,0x10,0x00,0x92,0x0c, + 0x51,0x04,0x10,0x00,0x10,0x04,0x12,0x00,0x10,0x00,0x10,0x00,0xd0,0x1e,0xcf,0x86, + 0x55,0x04,0x10,0x00,0x94,0x14,0x93,0x10,0x52,0x04,0x10,0x00,0x91,0x08,0x10,0x04, + 0x12,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0xcf,0x86,0x55,0x04,0x10,0x00, + 0x54,0x04,0x10,0x00,0x53,0x04,0x10,0x00,0x92,0x0c,0x51,0x04,0x10,0x00,0x10,0x04, + 0x10,0x00,0x0c,0x00,0x0c,0x00,0xe2,0x19,0x01,0xd1,0xa8,0xd0,0x7e,0xcf,0x86,0xd5, + 0x4c,0xd4,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x0d,0x00,0x0c,0x00,0x0c, + 0x00,0x0c,0x00,0x0c,0x00,0xd3,0x1c,0xd2,0x0c,0x91,0x08,0x10,0x04,0x0c,0x00,0x0d, + 0x00,0x0c,0x00,0xd1,0x08,0x10,0x04,0x0c,0x00,0x0d,0x00,0x10,0x04,0x0c,0x00,0x0d, + 0x00,0xd2,0x10,0xd1,0x08,0x10,0x04,0x0c,0x00,0x0d,0x00,0x10,0x04,0x0c,0x00,0x0d, + 0x00,0x51,0x04,0x0c,0x00,0x10,0x04,0x0c,0x00,0x0d,0x00,0xd4,0x1c,0xd3,0x0c,0x52, + 0x04,0x0c,0x00,0x11,0x04,0x0c,0x00,0x0d,0x00,0x52,0x04,0x0c,0x00,0x91,0x08,0x10, + 0x04,0x0d,0x00,0x0c,0x00,0x0d,0x00,0x93,0x10,0x52,0x04,0x0c,0x00,0x91,0x08,0x10, + 0x04,0x0d,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0xcf,0x86,0x95,0x24,0x94,0x20,0x93, + 0x1c,0xd2,0x10,0xd1,0x08,0x10,0x04,0x0c,0x00,0x10,0x00,0x10,0x04,0x10,0x00,0x11, + 0x00,0x91,0x08,0x10,0x04,0x11,0x00,0x0c,0x00,0x0c,0x00,0x0c,0x00,0x10,0x00,0x10, + 0x00,0xd0,0x06,0xcf,0x06,0x0c,0x00,0xcf,0x86,0xd5,0x30,0xd4,0x10,0x93,0x0c,0x52, + 0x04,0x0c,0x00,0x11,0x04,0x0c,0x00,0x10,0x00,0x10,0x00,0x93,0x1c,0xd2,0x10,0xd1, + 0x08,0x10,0x04,0x11,0x00,0x12,0x00,0x10,0x04,0x12,0x00,0x13,0x00,0x91,0x08,0x10, + 0x04,0x13,0x00,0x15,0x00,0x00,0x00,0x00,0x00,0xd4,0x14,0x53,0x04,0x10,0x00,0x52, + 0x04,0x10,0x00,0x91,0x08,0x10,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0xd3,0x10,0x52, + 0x04,0x10,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x13,0x00,0x92,0x10,0xd1, + 0x08,0x10,0x04,0x13,0x00,0x14,0x00,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0xd1, + 0x1c,0xd0,0x06,0xcf,0x06,0x0c,0x00,0xcf,0x86,0x55,0x04,0x0c,0x00,0x54,0x04,0x0c, + 0x00,0x93,0x08,0x12,0x04,0x0c,0x00,0x00,0x00,0x00,0x00,0xd0,0x06,0xcf,0x06,0x10, + 0x00,0xcf,0x86,0xd5,0x24,0x54,0x04,0x10,0x00,0xd3,0x10,0x52,0x04,0x10,0x00,0x91, + 0x08,0x10,0x04,0x10,0x00,0x14,0x00,0x14,0x00,0x92,0x0c,0x91,0x08,0x10,0x04,0x14, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x94,0x0c,0x53,0x04,0x15,0x00,0x12,0x04,0x15, + 0x00,0x00,0x00,0x00,0x00,0xe4,0x40,0x02,0xe3,0xc9,0x01,0xd2,0x5c,0xd1,0x34,0xd0, + 0x16,0xcf,0x86,0x95,0x10,0x94,0x0c,0x53,0x04,0x10,0x00,0x12,0x04,0x10,0x00,0x00, + 0x00,0x10,0x00,0x10,0x00,0xcf,0x86,0x95,0x18,0xd4,0x08,0x13,0x04,0x10,0x00,0x00, + 0x00,0x53,0x04,0x10,0x00,0x92,0x08,0x11,0x04,0x10,0x00,0x00,0x00,0x00,0x00,0x10, + 0x00,0xd0,0x22,0xcf,0x86,0xd5,0x0c,0x94,0x08,0x13,0x04,0x10,0x00,0x00,0x00,0x10, + 0x00,0x94,0x10,0x53,0x04,0x10,0x00,0x52,0x04,0x10,0x00,0x11,0x04,0x10,0x00,0x00, + 0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xd1,0xc0,0xd0,0x5e,0xcf,0x86,0xd5,0x30,0xd4, + 0x14,0x53,0x04,0x13,0x00,0x52,0x04,0x13,0x00,0x91,0x08,0x10,0x04,0x00,0x00,0x15, + 0x00,0x15,0x00,0x53,0x04,0x11,0x00,0xd2,0x0c,0x91,0x08,0x10,0x04,0x11,0x00,0x12, + 0x00,0x12,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x13,0x00,0xd4,0x08,0x13, + 0x04,0x12,0x00,0x13,0x00,0xd3,0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x12,0x00,0x13, + 0x00,0x10,0x04,0x13,0x00,0x12,0x00,0x12,0x00,0x52,0x04,0x12,0x00,0x51,0x04,0x12, + 0x00,0x10,0x04,0x12,0x00,0x15,0x00,0xcf,0x86,0xd5,0x28,0xd4,0x14,0x53,0x04,0x12, + 0x00,0x52,0x04,0x12,0x00,0x91,0x08,0x10,0x04,0x13,0x00,0x14,0x00,0x14,0x00,0x53, + 0x04,0x12,0x00,0x52,0x04,0x12,0x00,0x51,0x04,0x12,0x00,0x10,0x04,0x12,0x00,0x13, + 0x00,0xd4,0x0c,0x53,0x04,0x13,0x00,0x12,0x04,0x13,0x00,0x14,0x00,0xd3,0x1c,0xd2, + 0x10,0xd1,0x08,0x10,0x04,0x14,0x00,0x15,0x00,0x10,0x04,0x00,0x00,0x14,0x00,0x51, + 0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0x92,0x0c,0x51,0x04,0x00,0x00,0x10, + 0x04,0x14,0x00,0x15,0x00,0x14,0x00,0xd0,0x62,0xcf,0x86,0xd5,0x24,0xd4,0x14,0x93, + 0x10,0x52,0x04,0x11,0x00,0x91,0x08,0x10,0x04,0x11,0x00,0x12,0x00,0x12,0x00,0x12, + 0x00,0x93,0x0c,0x92,0x08,0x11,0x04,0x12,0x00,0x13,0x00,0x13,0x00,0x14,0x00,0xd4, + 0x2c,0xd3,0x18,0xd2,0x0c,0x51,0x04,0x14,0x00,0x10,0x04,0x14,0x00,0x00,0x00,0x91, + 0x08,0x10,0x04,0x00,0x00,0x15,0x00,0x15,0x00,0xd2,0x0c,0x51,0x04,0x15,0x00,0x10, + 0x04,0x15,0x00,0x00,0x00,0x11,0x04,0x00,0x00,0x15,0x00,0x53,0x04,0x14,0x00,0x92, + 0x08,0x11,0x04,0x14,0x00,0x15,0x00,0x15,0x00,0xcf,0x86,0xd5,0x30,0x94,0x2c,0xd3, + 0x14,0x92,0x10,0xd1,0x08,0x10,0x04,0x11,0x00,0x14,0x00,0x10,0x04,0x14,0x00,0x15, + 0x00,0x15,0x00,0xd2,0x0c,0x51,0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00,0x00,0x91, + 0x08,0x10,0x04,0x00,0x00,0x15,0x00,0x15,0x00,0x13,0x00,0x94,0x14,0x93,0x10,0x52, + 0x04,0x13,0x00,0x51,0x04,0x13,0x00,0x10,0x04,0x13,0x00,0x14,0x00,0x14,0x00,0x14, + 0x00,0xd2,0x70,0xd1,0x40,0xd0,0x06,0xcf,0x06,0x15,0x00,0xcf,0x86,0xd5,0x10,0x54, + 0x04,0x15,0x00,0x93,0x08,0x12,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0xd4,0x10,0x53, + 0x04,0x14,0x00,0x52,0x04,0x14,0x00,0x11,0x04,0x14,0x00,0x00,0x00,0xd3,0x08,0x12, + 0x04,0x15,0x00,0x00,0x00,0x92,0x0c,0x51,0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00, + 0x00,0x00,0x00,0xd0,0x2a,0xcf,0x86,0x95,0x24,0xd4,0x14,0x93,0x10,0x92,0x0c,0x51, + 0x04,0x15,0x00,0x10,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x93,0x0c,0x52, + 0x04,0x15,0x00,0x11,0x04,0x15,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00, + 0x00,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00, + 0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55, + 0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11, + 0x04,0x00,0x00,0x02,0x00,0xe4,0xf9,0x12,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00, + 0xd2,0xc2,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x05,0x00,0xd0,0x44,0xcf,0x86,0xd5,0x3c, + 0xd4,0x06,0xcf,0x06,0x05,0x00,0xd3,0x06,0xcf,0x06,0x05,0x00,0xd2,0x2a,0xd1,0x06, + 0xcf,0x06,0x05,0x00,0xd0,0x06,0xcf,0x06,0x05,0x00,0xcf,0x86,0x95,0x18,0x54,0x04, + 0x05,0x00,0x93,0x10,0x52,0x04,0x05,0x00,0x51,0x04,0x05,0x00,0x10,0x04,0x05,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x0b,0x00,0xcf,0x06,0x0b,0x00,0xcf,0x86, + 0xd5,0x3c,0xd4,0x06,0xcf,0x06,0x0b,0x00,0xd3,0x06,0xcf,0x06,0x0b,0x00,0xd2,0x06, + 0xcf,0x06,0x0b,0x00,0xd1,0x24,0xd0,0x1e,0xcf,0x86,0x55,0x04,0x0b,0x00,0x54,0x04, + 0x0b,0x00,0x93,0x10,0x52,0x04,0x0b,0x00,0x91,0x08,0x10,0x04,0x0b,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xcf,0x06,0x0c,0x00,0xcf,0x06,0x0c,0x00,0xd4,0x32,0xd3,0x2c, + 0xd2,0x26,0xd1,0x20,0xd0,0x1a,0xcf,0x86,0x95,0x14,0x54,0x04,0x0c,0x00,0x53,0x04, + 0x0c,0x00,0x52,0x04,0x0c,0x00,0x11,0x04,0x0c,0x00,0x00,0x00,0x11,0x00,0xcf,0x06, + 0x11,0x00,0xcf,0x06,0x11,0x00,0xcf,0x06,0x11,0x00,0xcf,0x06,0x11,0x00,0xcf,0x06, + 0x11,0x00,0xd1,0x48,0xd0,0x40,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x11,0x00,0xd4,0x06, + 0xcf,0x06,0x11,0x00,0xd3,0x06,0xcf,0x06,0x11,0x00,0xd2,0x26,0xd1,0x06,0xcf,0x06, + 0x11,0x00,0xd0,0x1a,0xcf,0x86,0x55,0x04,0x11,0x00,0x94,0x10,0x93,0x0c,0x92,0x08, + 0x11,0x04,0x11,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x13,0x00,0xcf,0x06,0x13,0x00, + 0xcf,0x06,0x13,0x00,0xcf,0x86,0xcf,0x06,0x13,0x00,0xd0,0x44,0xcf,0x86,0xd5,0x06, + 0xcf,0x06,0x13,0x00,0xd4,0x36,0xd3,0x06,0xcf,0x06,0x13,0x00,0xd2,0x06,0xcf,0x06, + 0x13,0x00,0xd1,0x06,0xcf,0x06,0x13,0x00,0xd0,0x06,0xcf,0x06,0x13,0x00,0xcf,0x86, + 0x55,0x04,0x13,0x00,0x94,0x14,0x93,0x10,0x92,0x0c,0x91,0x08,0x10,0x04,0x13,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x86, + 0xd5,0x06,0xcf,0x06,0x00,0x00,0xe4,0x68,0x11,0xe3,0x51,0x10,0xe2,0x17,0x08,0xe1, + 0x06,0x04,0xe0,0x03,0x02,0xcf,0x86,0xe5,0x06,0x01,0xd4,0x82,0xd3,0x41,0xd2,0x21, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe4,0xb8,0xbd,0x00,0x05,0xff,0xe4,0xb8,0xb8,0x00, + 0x10,0x08,0x05,0xff,0xe4,0xb9,0x81,0x00,0x05,0xff,0xf0,0xa0,0x84,0xa2,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe4,0xbd,0xa0,0x00,0x05,0xff,0xe4,0xbe,0xae,0x00,0x10, + 0x08,0x05,0xff,0xe4,0xbe,0xbb,0x00,0x05,0xff,0xe5,0x80,0x82,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe5,0x81,0xba,0x00,0x05,0xff,0xe5,0x82,0x99,0x00,0x10, + 0x08,0x05,0xff,0xe5,0x83,0xa7,0x00,0x05,0xff,0xe5,0x83,0x8f,0x00,0xd1,0x11,0x10, + 0x08,0x05,0xff,0xe3,0x92,0x9e,0x00,0x05,0xff,0xf0,0xa0,0x98,0xba,0x00,0x10,0x08, + 0x05,0xff,0xe5,0x85,0x8d,0x00,0x05,0xff,0xe5,0x85,0x94,0x00,0xd3,0x42,0xd2,0x21, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x85,0xa4,0x00,0x05,0xff,0xe5,0x85,0xb7,0x00, + 0x10,0x09,0x05,0xff,0xf0,0xa0,0x94,0x9c,0x00,0x05,0xff,0xe3,0x92,0xb9,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe5,0x85,0xa7,0x00,0x05,0xff,0xe5,0x86,0x8d,0x00,0x10, + 0x09,0x05,0xff,0xf0,0xa0,0x95,0x8b,0x00,0x05,0xff,0xe5,0x86,0x97,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x86,0xa4,0x00,0x05,0xff,0xe4,0xbb,0x8c,0x00, + 0x10,0x08,0x05,0xff,0xe5,0x86,0xac,0x00,0x05,0xff,0xe5,0x86,0xb5,0x00,0xd1,0x11, + 0x10,0x09,0x05,0xff,0xf0,0xa9,0x87,0x9f,0x00,0x05,0xff,0xe5,0x87,0xb5,0x00,0x10, + 0x08,0x05,0xff,0xe5,0x88,0x83,0x00,0x05,0xff,0xe3,0x93,0x9f,0x00,0xd4,0x80,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x88,0xbb,0x00,0x05,0xff,0xe5, + 0x89,0x86,0x00,0x10,0x08,0x05,0xff,0xe5,0x89,0xb2,0x00,0x05,0xff,0xe5,0x89,0xb7, + 0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe3,0x94,0x95,0x00,0x05,0xff,0xe5,0x8b,0x87, + 0x00,0x10,0x08,0x05,0xff,0xe5,0x8b,0x89,0x00,0x05,0xff,0xe5,0x8b,0xa4,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x8b,0xba,0x00,0x05,0xff,0xe5,0x8c,0x85, + 0x00,0x10,0x08,0x05,0xff,0xe5,0x8c,0x86,0x00,0x05,0xff,0xe5,0x8c,0x97,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe5,0x8d,0x89,0x00,0x05,0xff,0xe5,0x8d,0x91,0x00,0x10, + 0x08,0x05,0xff,0xe5,0x8d,0x9a,0x00,0x05,0xff,0xe5,0x8d,0xb3,0x00,0xd3,0x39,0xd2, + 0x18,0x91,0x10,0x10,0x08,0x05,0xff,0xe5,0x8d,0xbd,0x00,0x05,0xff,0xe5,0x8d,0xbf, + 0x00,0x05,0xff,0xe5,0x8d,0xbf,0x00,0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa0,0xa8, + 0xac,0x00,0x05,0xff,0xe7,0x81,0xb0,0x00,0x10,0x08,0x05,0xff,0xe5,0x8f,0x8a,0x00, + 0x05,0xff,0xe5,0x8f,0x9f,0x00,0xd2,0x21,0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa0, + 0xad,0xa3,0x00,0x05,0xff,0xe5,0x8f,0xab,0x00,0x10,0x08,0x05,0xff,0xe5,0x8f,0xb1, + 0x00,0x05,0xff,0xe5,0x90,0x86,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x92,0x9e, + 0x00,0x05,0xff,0xe5,0x90,0xb8,0x00,0x10,0x08,0x05,0xff,0xe5,0x91,0x88,0x00,0x05, + 0xff,0xe5,0x91,0xa8,0x00,0xcf,0x86,0xe5,0x02,0x01,0xd4,0x80,0xd3,0x40,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0x92,0xa2,0x00,0x05,0xff,0xe5,0x93,0xb6,0x00, + 0x10,0x08,0x05,0xff,0xe5,0x94,0x90,0x00,0x05,0xff,0xe5,0x95,0x93,0x00,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe5,0x95,0xa3,0x00,0x05,0xff,0xe5,0x96,0x84,0x00,0x10,0x08, + 0x05,0xff,0xe5,0x96,0x84,0x00,0x05,0xff,0xe5,0x96,0x99,0x00,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe5,0x96,0xab,0x00,0x05,0xff,0xe5,0x96,0xb3,0x00,0x10,0x08, + 0x05,0xff,0xe5,0x97,0x82,0x00,0x05,0xff,0xe5,0x9c,0x96,0x00,0xd1,0x10,0x10,0x08, + 0x05,0xff,0xe5,0x98,0x86,0x00,0x05,0xff,0xe5,0x9c,0x97,0x00,0x10,0x08,0x05,0xff, + 0xe5,0x99,0x91,0x00,0x05,0xff,0xe5,0x99,0xb4,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe5,0x88,0x87,0x00,0x05,0xff,0xe5,0xa3,0xae,0x00,0x10,0x08, + 0x05,0xff,0xe5,0x9f,0x8e,0x00,0x05,0xff,0xe5,0x9f,0xb4,0x00,0xd1,0x10,0x10,0x08, + 0x05,0xff,0xe5,0xa0,0x8d,0x00,0x05,0xff,0xe5,0x9e,0x8b,0x00,0x10,0x08,0x05,0xff, + 0xe5,0xa0,0xb2,0x00,0x05,0xff,0xe5,0xa0,0xb1,0x00,0xd2,0x21,0xd1,0x11,0x10,0x08, + 0x05,0xff,0xe5,0xa2,0xac,0x00,0x05,0xff,0xf0,0xa1,0x93,0xa4,0x00,0x10,0x08,0x05, + 0xff,0xe5,0xa3,0xb2,0x00,0x05,0xff,0xe5,0xa3,0xb7,0x00,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe5,0xa4,0x86,0x00,0x05,0xff,0xe5,0xa4,0x9a,0x00,0x10,0x08,0x05,0xff,0xe5, + 0xa4,0xa2,0x00,0x05,0xff,0xe5,0xa5,0xa2,0x00,0xd4,0x7b,0xd3,0x42,0xd2,0x22,0xd1, + 0x12,0x10,0x09,0x05,0xff,0xf0,0xa1,0x9a,0xa8,0x00,0x05,0xff,0xf0,0xa1,0x9b,0xaa, + 0x00,0x10,0x08,0x05,0xff,0xe5,0xa7,0xac,0x00,0x05,0xff,0xe5,0xa8,0x9b,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe5,0xa8,0xa7,0x00,0x05,0xff,0xe5,0xa7,0x98,0x00,0x10, + 0x08,0x05,0xff,0xe5,0xa9,0xa6,0x00,0x05,0xff,0xe3,0x9b,0xae,0x00,0xd2,0x18,0x91, + 0x10,0x10,0x08,0x05,0xff,0xe3,0x9b,0xbc,0x00,0x05,0xff,0xe5,0xac,0x88,0x00,0x05, + 0xff,0xe5,0xac,0xbe,0x00,0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa1,0xa7,0x88,0x00, + 0x05,0xff,0xe5,0xaf,0x83,0x00,0x10,0x08,0x05,0xff,0xe5,0xaf,0x98,0x00,0x05,0xff, + 0xe5,0xaf,0xa7,0x00,0xd3,0x41,0xd2,0x21,0xd1,0x11,0x10,0x08,0x05,0xff,0xe5,0xaf, + 0xb3,0x00,0x05,0xff,0xf0,0xa1,0xac,0x98,0x00,0x10,0x08,0x05,0xff,0xe5,0xaf,0xbf, + 0x00,0x05,0xff,0xe5,0xb0,0x86,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0xbd,0x93, + 0x00,0x05,0xff,0xe5,0xb0,0xa2,0x00,0x10,0x08,0x05,0xff,0xe3,0x9e,0x81,0x00,0x05, + 0xff,0xe5,0xb1,0xa0,0x00,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0xb1,0xae, + 0x00,0x05,0xff,0xe5,0xb3,0x80,0x00,0x10,0x08,0x05,0xff,0xe5,0xb2,0x8d,0x00,0x05, + 0xff,0xf0,0xa1,0xb7,0xa4,0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe5,0xb5,0x83,0x00, + 0x05,0xff,0xf0,0xa1,0xb7,0xa6,0x00,0x10,0x08,0x05,0xff,0xe5,0xb5,0xae,0x00,0x05, + 0xff,0xe5,0xb5,0xab,0x00,0xe0,0x04,0x02,0xcf,0x86,0xd5,0xfe,0xd4,0x82,0xd3,0x40, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0xb5,0xbc,0x00,0x05,0xff,0xe5,0xb7, + 0xa1,0x00,0x10,0x08,0x05,0xff,0xe5,0xb7,0xa2,0x00,0x05,0xff,0xe3,0xa0,0xaf,0x00, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0xb7,0xbd,0x00,0x05,0xff,0xe5,0xb8,0xa8,0x00, + 0x10,0x08,0x05,0xff,0xe5,0xb8,0xbd,0x00,0x05,0xff,0xe5,0xb9,0xa9,0x00,0xd2,0x21, + 0xd1,0x11,0x10,0x08,0x05,0xff,0xe3,0xa1,0xa2,0x00,0x05,0xff,0xf0,0xa2,0x86,0x83, + 0x00,0x10,0x08,0x05,0xff,0xe3,0xa1,0xbc,0x00,0x05,0xff,0xe5,0xba,0xb0,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe5,0xba,0xb3,0x00,0x05,0xff,0xe5,0xba,0xb6,0x00,0x10, + 0x08,0x05,0xff,0xe5,0xbb,0x8a,0x00,0x05,0xff,0xf0,0xaa,0x8e,0x92,0x00,0xd3,0x3b, + 0xd2,0x22,0xd1,0x11,0x10,0x08,0x05,0xff,0xe5,0xbb,0xbe,0x00,0x05,0xff,0xf0,0xa2, + 0x8c,0xb1,0x00,0x10,0x09,0x05,0xff,0xf0,0xa2,0x8c,0xb1,0x00,0x05,0xff,0xe8,0x88, + 0x81,0x00,0x51,0x08,0x05,0xff,0xe5,0xbc,0xa2,0x00,0x10,0x08,0x05,0xff,0xe3,0xa3, + 0x87,0x00,0x05,0xff,0xf0,0xa3,0x8a,0xb8,0x00,0xd2,0x21,0xd1,0x11,0x10,0x09,0x05, + 0xff,0xf0,0xa6,0x87,0x9a,0x00,0x05,0xff,0xe5,0xbd,0xa2,0x00,0x10,0x08,0x05,0xff, + 0xe5,0xbd,0xab,0x00,0x05,0xff,0xe3,0xa3,0xa3,0x00,0xd1,0x10,0x10,0x08,0x05,0xff, + 0xe5,0xbe,0x9a,0x00,0x05,0xff,0xe5,0xbf,0x8d,0x00,0x10,0x08,0x05,0xff,0xe5,0xbf, + 0x97,0x00,0x05,0xff,0xe5,0xbf,0xb9,0x00,0xd4,0x81,0xd3,0x41,0xd2,0x20,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe6,0x82,0x81,0x00,0x05,0xff,0xe3,0xa4,0xba,0x00,0x10,0x08, + 0x05,0xff,0xe3,0xa4,0x9c,0x00,0x05,0xff,0xe6,0x82,0x94,0x00,0xd1,0x11,0x10,0x09, + 0x05,0xff,0xf0,0xa2,0x9b,0x94,0x00,0x05,0xff,0xe6,0x83,0x87,0x00,0x10,0x08,0x05, + 0xff,0xe6,0x85,0x88,0x00,0x05,0xff,0xe6,0x85,0x8c,0x00,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe6,0x85,0x8e,0x00,0x05,0xff,0xe6,0x85,0x8c,0x00,0x10,0x08,0x05, + 0xff,0xe6,0x85,0xba,0x00,0x05,0xff,0xe6,0x86,0x8e,0x00,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe6,0x86,0xb2,0x00,0x05,0xff,0xe6,0x86,0xa4,0x00,0x10,0x08,0x05,0xff,0xe6, + 0x86,0xaf,0x00,0x05,0xff,0xe6,0x87,0x9e,0x00,0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe6,0x87,0xb2,0x00,0x05,0xff,0xe6,0x87,0xb6,0x00,0x10,0x08,0x05, + 0xff,0xe6,0x88,0x90,0x00,0x05,0xff,0xe6,0x88,0x9b,0x00,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe6,0x89,0x9d,0x00,0x05,0xff,0xe6,0x8a,0xb1,0x00,0x10,0x08,0x05,0xff,0xe6, + 0x8b,0x94,0x00,0x05,0xff,0xe6,0x8d,0x90,0x00,0xd2,0x21,0xd1,0x11,0x10,0x09,0x05, + 0xff,0xf0,0xa2,0xac,0x8c,0x00,0x05,0xff,0xe6,0x8c,0xbd,0x00,0x10,0x08,0x05,0xff, + 0xe6,0x8b,0xbc,0x00,0x05,0xff,0xe6,0x8d,0xa8,0x00,0xd1,0x10,0x10,0x08,0x05,0xff, + 0xe6,0x8e,0x83,0x00,0x05,0xff,0xe6,0x8f,0xa4,0x00,0x10,0x09,0x05,0xff,0xf0,0xa2, + 0xaf,0xb1,0x00,0x05,0xff,0xe6,0x90,0xa2,0x00,0xcf,0x86,0xe5,0x03,0x01,0xd4,0x81, + 0xd3,0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x8f,0x85,0x00,0x05,0xff, + 0xe6,0x8e,0xa9,0x00,0x10,0x08,0x05,0xff,0xe3,0xa8,0xae,0x00,0x05,0xff,0xe6,0x91, + 0xa9,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x91,0xbe,0x00,0x05,0xff,0xe6,0x92, + 0x9d,0x00,0x10,0x08,0x05,0xff,0xe6,0x91,0xb7,0x00,0x05,0xff,0xe3,0xa9,0xac,0x00, + 0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x95,0x8f,0x00,0x05,0xff,0xe6,0x95, + 0xac,0x00,0x10,0x09,0x05,0xff,0xf0,0xa3,0x80,0x8a,0x00,0x05,0xff,0xe6,0x97,0xa3, + 0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x9b,0xb8,0x00,0x05,0xff,0xe6,0x99,0x89, + 0x00,0x10,0x08,0x05,0xff,0xe3,0xac,0x99,0x00,0x05,0xff,0xe6,0x9a,0x91,0x00,0xd3, + 0x40,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe3,0xac,0x88,0x00,0x05,0xff,0xe3, + 0xab,0xa4,0x00,0x10,0x08,0x05,0xff,0xe5,0x86,0x92,0x00,0x05,0xff,0xe5,0x86,0x95, + 0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x9c,0x80,0x00,0x05,0xff,0xe6,0x9a,0x9c, + 0x00,0x10,0x08,0x05,0xff,0xe8,0x82,0xad,0x00,0x05,0xff,0xe4,0x8f,0x99,0x00,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x9c,0x97,0x00,0x05,0xff,0xe6,0x9c,0x9b, + 0x00,0x10,0x08,0x05,0xff,0xe6,0x9c,0xa1,0x00,0x05,0xff,0xe6,0x9d,0x9e,0x00,0xd1, + 0x11,0x10,0x08,0x05,0xff,0xe6,0x9d,0x93,0x00,0x05,0xff,0xf0,0xa3,0x8f,0x83,0x00, + 0x10,0x08,0x05,0xff,0xe3,0xad,0x89,0x00,0x05,0xff,0xe6,0x9f,0xba,0x00,0xd4,0x82, + 0xd3,0x41,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0x9e,0x85,0x00,0x05,0xff, + 0xe6,0xa1,0x92,0x00,0x10,0x08,0x05,0xff,0xe6,0xa2,0x85,0x00,0x05,0xff,0xf0,0xa3, + 0x91,0xad,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xa2,0x8e,0x00,0x05,0xff,0xe6, + 0xa0,0x9f,0x00,0x10,0x08,0x05,0xff,0xe6,0xa4,0x94,0x00,0x05,0xff,0xe3,0xae,0x9d, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xa5,0x82,0x00,0x05,0xff,0xe6, + 0xa6,0xa3,0x00,0x10,0x08,0x05,0xff,0xe6,0xa7,0xaa,0x00,0x05,0xff,0xe6,0xaa,0xa8, + 0x00,0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa3,0x9a,0xa3,0x00,0x05,0xff,0xe6,0xab, + 0x9b,0x00,0x10,0x08,0x05,0xff,0xe3,0xb0,0x98,0x00,0x05,0xff,0xe6,0xac,0xa1,0x00, + 0xd3,0x42,0xd2,0x21,0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa3,0xa2,0xa7,0x00,0x05, + 0xff,0xe6,0xad,0x94,0x00,0x10,0x08,0x05,0xff,0xe3,0xb1,0x8e,0x00,0x05,0xff,0xe6, + 0xad,0xb2,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xae,0x9f,0x00,0x05,0xff,0xe6, + 0xae,0xba,0x00,0x10,0x08,0x05,0xff,0xe6,0xae,0xbb,0x00,0x05,0xff,0xf0,0xa3,0xaa, + 0x8d,0x00,0xd2,0x23,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa1,0xb4,0x8b,0x00,0x05, + 0xff,0xf0,0xa3,0xab,0xba,0x00,0x10,0x08,0x05,0xff,0xe6,0xb1,0x8e,0x00,0x05,0xff, + 0xf0,0xa3,0xb2,0xbc,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xb2,0xbf,0x00,0x05, + 0xff,0xe6,0xb3,0x8d,0x00,0x10,0x08,0x05,0xff,0xe6,0xb1,0xa7,0x00,0x05,0xff,0xe6, + 0xb4,0x96,0x00,0xe1,0x1d,0x04,0xe0,0x0c,0x02,0xcf,0x86,0xe5,0x08,0x01,0xd4,0x82, + 0xd3,0x41,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xb4,0xbe,0x00,0x05,0xff, + 0xe6,0xb5,0xb7,0x00,0x10,0x08,0x05,0xff,0xe6,0xb5,0x81,0x00,0x05,0xff,0xe6,0xb5, + 0xa9,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xb5,0xb8,0x00,0x05,0xff,0xe6,0xb6, + 0x85,0x00,0x10,0x09,0x05,0xff,0xf0,0xa3,0xb4,0x9e,0x00,0x05,0xff,0xe6,0xb4,0xb4, + 0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe6,0xb8,0xaf,0x00,0x05,0xff,0xe6, + 0xb9,0xae,0x00,0x10,0x08,0x05,0xff,0xe3,0xb4,0xb3,0x00,0x05,0xff,0xe6,0xbb,0x8b, + 0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe6,0xbb,0x87,0x00,0x05,0xff,0xf0,0xa3,0xbb, + 0x91,0x00,0x10,0x08,0x05,0xff,0xe6,0xb7,0xb9,0x00,0x05,0xff,0xe6,0xbd,0xae,0x00, + 0xd3,0x42,0xd2,0x22,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa3,0xbd,0x9e,0x00,0x05, + 0xff,0xf0,0xa3,0xbe,0x8e,0x00,0x10,0x08,0x05,0xff,0xe6,0xbf,0x86,0x00,0x05,0xff, + 0xe7,0x80,0xb9,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0x80,0x9e,0x00,0x05,0xff, + 0xe7,0x80,0x9b,0x00,0x10,0x08,0x05,0xff,0xe3,0xb6,0x96,0x00,0x05,0xff,0xe7,0x81, + 0x8a,0x00,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0x81,0xbd,0x00,0x05,0xff, + 0xe7,0x81,0xb7,0x00,0x10,0x08,0x05,0xff,0xe7,0x82,0xad,0x00,0x05,0xff,0xf0,0xa0, + 0x94,0xa5,0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe7,0x85,0x85,0x00,0x05,0xff,0xf0, + 0xa4,0x89,0xa3,0x00,0x10,0x08,0x05,0xff,0xe7,0x86,0x9c,0x00,0x05,0xff,0xf0,0xa4, + 0x8e,0xab,0x00,0xd4,0x7b,0xd3,0x43,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7, + 0x88,0xa8,0x00,0x05,0xff,0xe7,0x88,0xb5,0x00,0x10,0x08,0x05,0xff,0xe7,0x89,0x90, + 0x00,0x05,0xff,0xf0,0xa4,0x98,0x88,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0x8a, + 0x80,0x00,0x05,0xff,0xe7,0x8a,0x95,0x00,0x10,0x09,0x05,0xff,0xf0,0xa4,0x9c,0xb5, + 0x00,0x05,0xff,0xf0,0xa4,0xa0,0x94,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff, + 0xe7,0x8d,0xba,0x00,0x05,0xff,0xe7,0x8e,0x8b,0x00,0x10,0x08,0x05,0xff,0xe3,0xba, + 0xac,0x00,0x05,0xff,0xe7,0x8e,0xa5,0x00,0x51,0x08,0x05,0xff,0xe3,0xba,0xb8,0x00, + 0x10,0x08,0x05,0xff,0xe7,0x91,0x87,0x00,0x05,0xff,0xe7,0x91,0x9c,0x00,0xd3,0x42, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0x91,0xb1,0x00,0x05,0xff,0xe7,0x92, + 0x85,0x00,0x10,0x08,0x05,0xff,0xe7,0x93,0x8a,0x00,0x05,0xff,0xe3,0xbc,0x9b,0x00, + 0xd1,0x11,0x10,0x08,0x05,0xff,0xe7,0x94,0xa4,0x00,0x05,0xff,0xf0,0xa4,0xb0,0xb6, + 0x00,0x10,0x08,0x05,0xff,0xe7,0x94,0xbe,0x00,0x05,0xff,0xf0,0xa4,0xb2,0x92,0x00, + 0xd2,0x22,0xd1,0x11,0x10,0x08,0x05,0xff,0xe7,0x95,0xb0,0x00,0x05,0xff,0xf0,0xa2, + 0x86,0x9f,0x00,0x10,0x08,0x05,0xff,0xe7,0x98,0x90,0x00,0x05,0xff,0xf0,0xa4,0xbe, + 0xa1,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa4,0xbe,0xb8,0x00,0x05,0xff,0xf0, + 0xa5,0x81,0x84,0x00,0x10,0x08,0x05,0xff,0xe3,0xbf,0xbc,0x00,0x05,0xff,0xe4,0x80, + 0x88,0x00,0xcf,0x86,0xe5,0x04,0x01,0xd4,0x7d,0xd3,0x3c,0xd2,0x23,0xd1,0x11,0x10, + 0x08,0x05,0xff,0xe7,0x9b,0xb4,0x00,0x05,0xff,0xf0,0xa5,0x83,0xb3,0x00,0x10,0x09, + 0x05,0xff,0xf0,0xa5,0x83,0xb2,0x00,0x05,0xff,0xf0,0xa5,0x84,0x99,0x00,0x91,0x11, + 0x10,0x09,0x05,0xff,0xf0,0xa5,0x84,0xb3,0x00,0x05,0xff,0xe7,0x9c,0x9e,0x00,0x05, + 0xff,0xe7,0x9c,0x9f,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0x9d,0x8a, + 0x00,0x05,0xff,0xe4,0x80,0xb9,0x00,0x10,0x08,0x05,0xff,0xe7,0x9e,0x8b,0x00,0x05, + 0xff,0xe4,0x81,0x86,0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe4,0x82,0x96,0x00,0x05, + 0xff,0xf0,0xa5,0x90,0x9d,0x00,0x10,0x08,0x05,0xff,0xe7,0xa1,0x8e,0x00,0x05,0xff, + 0xe7,0xa2,0x8c,0x00,0xd3,0x43,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0xa3, + 0x8c,0x00,0x05,0xff,0xe4,0x83,0xa3,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0x98,0xa6, + 0x00,0x05,0xff,0xe7,0xa5,0x96,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0x9a, + 0x9a,0x00,0x05,0xff,0xf0,0xa5,0x9b,0x85,0x00,0x10,0x08,0x05,0xff,0xe7,0xa6,0x8f, + 0x00,0x05,0xff,0xe7,0xa7,0xab,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe4, + 0x84,0xaf,0x00,0x05,0xff,0xe7,0xa9,0x80,0x00,0x10,0x08,0x05,0xff,0xe7,0xa9,0x8a, + 0x00,0x05,0xff,0xe7,0xa9,0x8f,0x00,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa5,0xa5, + 0xbc,0x00,0x05,0xff,0xf0,0xa5,0xaa,0xa7,0x00,0x10,0x09,0x05,0xff,0xf0,0xa5,0xaa, + 0xa7,0x00,0x05,0xff,0xe7,0xab,0xae,0x00,0xd4,0x83,0xd3,0x42,0xd2,0x21,0xd1,0x11, + 0x10,0x08,0x05,0xff,0xe4,0x88,0x82,0x00,0x05,0xff,0xf0,0xa5,0xae,0xab,0x00,0x10, + 0x08,0x05,0xff,0xe7,0xaf,0x86,0x00,0x05,0xff,0xe7,0xaf,0x89,0x00,0xd1,0x11,0x10, + 0x08,0x05,0xff,0xe4,0x88,0xa7,0x00,0x05,0xff,0xf0,0xa5,0xb2,0x80,0x00,0x10,0x08, + 0x05,0xff,0xe7,0xb3,0x92,0x00,0x05,0xff,0xe4,0x8a,0xa0,0x00,0xd2,0x21,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe7,0xb3,0xa8,0x00,0x05,0xff,0xe7,0xb3,0xa3,0x00,0x10,0x08, + 0x05,0xff,0xe7,0xb4,0x80,0x00,0x05,0xff,0xf0,0xa5,0xbe,0x86,0x00,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe7,0xb5,0xa3,0x00,0x05,0xff,0xe4,0x8c,0x81,0x00,0x10,0x08,0x05, + 0xff,0xe7,0xb7,0x87,0x00,0x05,0xff,0xe7,0xb8,0x82,0x00,0xd3,0x44,0xd2,0x22,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe7,0xb9,0x85,0x00,0x05,0xff,0xe4,0x8c,0xb4,0x00,0x10, + 0x09,0x05,0xff,0xf0,0xa6,0x88,0xa8,0x00,0x05,0xff,0xf0,0xa6,0x89,0x87,0x00,0xd1, + 0x11,0x10,0x08,0x05,0xff,0xe4,0x8d,0x99,0x00,0x05,0xff,0xf0,0xa6,0x8b,0x99,0x00, + 0x10,0x08,0x05,0xff,0xe7,0xbd,0xba,0x00,0x05,0xff,0xf0,0xa6,0x8c,0xbe,0x00,0xd2, + 0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe7,0xbe,0x95,0x00,0x05,0xff,0xe7,0xbf,0xba, + 0x00,0x10,0x08,0x05,0xff,0xe8,0x80,0x85,0x00,0x05,0xff,0xf0,0xa6,0x93,0x9a,0x00, + 0xd1,0x11,0x10,0x09,0x05,0xff,0xf0,0xa6,0x94,0xa3,0x00,0x05,0xff,0xe8,0x81,0xa0, + 0x00,0x10,0x09,0x05,0xff,0xf0,0xa6,0x96,0xa8,0x00,0x05,0xff,0xe8,0x81,0xb0,0x00, + 0xe0,0x11,0x02,0xcf,0x86,0xe5,0x07,0x01,0xd4,0x85,0xd3,0x42,0xd2,0x21,0xd1,0x11, + 0x10,0x09,0x05,0xff,0xf0,0xa3,0x8d,0x9f,0x00,0x05,0xff,0xe4,0x8f,0x95,0x00,0x10, + 0x08,0x05,0xff,0xe8,0x82,0xb2,0x00,0x05,0xff,0xe8,0x84,0x83,0x00,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe4,0x90,0x8b,0x00,0x05,0xff,0xe8,0x84,0xbe,0x00,0x10,0x08,0x05, + 0xff,0xe5,0xaa,0xb5,0x00,0x05,0xff,0xf0,0xa6,0x9e,0xa7,0x00,0xd2,0x23,0xd1,0x12, + 0x10,0x09,0x05,0xff,0xf0,0xa6,0x9e,0xb5,0x00,0x05,0xff,0xf0,0xa3,0x8e,0x93,0x00, + 0x10,0x09,0x05,0xff,0xf0,0xa3,0x8e,0x9c,0x00,0x05,0xff,0xe8,0x88,0x81,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe8,0x88,0x84,0x00,0x05,0xff,0xe8,0xbe,0x9e,0x00,0x10, + 0x08,0x05,0xff,0xe4,0x91,0xab,0x00,0x05,0xff,0xe8,0x8a,0x91,0x00,0xd3,0x41,0xd2, + 0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x8a,0x8b,0x00,0x05,0xff,0xe8,0x8a,0x9d, + 0x00,0x10,0x08,0x05,0xff,0xe5,0x8a,0xb3,0x00,0x05,0xff,0xe8,0x8a,0xb1,0x00,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe8,0x8a,0xb3,0x00,0x05,0xff,0xe8,0x8a,0xbd,0x00,0x10, + 0x08,0x05,0xff,0xe8,0x8b,0xa6,0x00,0x05,0xff,0xf0,0xa6,0xac,0xbc,0x00,0xd2,0x20, + 0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x8b,0xa5,0x00,0x05,0xff,0xe8,0x8c,0x9d,0x00, + 0x10,0x08,0x05,0xff,0xe8,0x8d,0xa3,0x00,0x05,0xff,0xe8,0x8e,0xad,0x00,0xd1,0x10, + 0x10,0x08,0x05,0xff,0xe8,0x8c,0xa3,0x00,0x05,0xff,0xe8,0x8e,0xbd,0x00,0x10,0x08, + 0x05,0xff,0xe8,0x8f,0xa7,0x00,0x05,0xff,0xe8,0x91,0x97,0x00,0xd4,0x85,0xd3,0x43, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x8d,0x93,0x00,0x05,0xff,0xe8,0x8f, + 0x8a,0x00,0x10,0x08,0x05,0xff,0xe8,0x8f,0x8c,0x00,0x05,0xff,0xe8,0x8f,0x9c,0x00, + 0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa6,0xb0,0xb6,0x00,0x05,0xff,0xf0,0xa6,0xb5, + 0xab,0x00,0x10,0x09,0x05,0xff,0xf0,0xa6,0xb3,0x95,0x00,0x05,0xff,0xe4,0x94,0xab, + 0x00,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x93,0xb1,0x00,0x05,0xff,0xe8, + 0x93,0xb3,0x00,0x10,0x08,0x05,0xff,0xe8,0x94,0x96,0x00,0x05,0xff,0xf0,0xa7,0x8f, + 0x8a,0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe8,0x95,0xa4,0x00,0x05,0xff,0xf0,0xa6, + 0xbc,0xac,0x00,0x10,0x08,0x05,0xff,0xe4,0x95,0x9d,0x00,0x05,0xff,0xe4,0x95,0xa1, + 0x00,0xd3,0x42,0xd2,0x22,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa6,0xbe,0xb1,0x00, + 0x05,0xff,0xf0,0xa7,0x83,0x92,0x00,0x10,0x08,0x05,0xff,0xe4,0x95,0xab,0x00,0x05, + 0xff,0xe8,0x99,0x90,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x99,0x9c,0x00,0x05, + 0xff,0xe8,0x99,0xa7,0x00,0x10,0x08,0x05,0xff,0xe8,0x99,0xa9,0x00,0x05,0xff,0xe8, + 0x9a,0xa9,0x00,0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x9a,0x88,0x00,0x05, + 0xff,0xe8,0x9c,0x8e,0x00,0x10,0x08,0x05,0xff,0xe8,0x9b,0xa2,0x00,0x05,0xff,0xe8, + 0x9d,0xb9,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe8,0x9c,0xa8,0x00,0x05,0xff,0xe8, + 0x9d,0xab,0x00,0x10,0x08,0x05,0xff,0xe8,0x9e,0x86,0x00,0x05,0xff,0xe4,0x97,0x97, + 0x00,0xcf,0x86,0xe5,0x08,0x01,0xd4,0x83,0xd3,0x41,0xd2,0x20,0xd1,0x10,0x10,0x08, + 0x05,0xff,0xe8,0x9f,0xa1,0x00,0x05,0xff,0xe8,0xa0,0x81,0x00,0x10,0x08,0x05,0xff, + 0xe4,0x97,0xb9,0x00,0x05,0xff,0xe8,0xa1,0xa0,0x00,0xd1,0x11,0x10,0x08,0x05,0xff, + 0xe8,0xa1,0xa3,0x00,0x05,0xff,0xf0,0xa7,0x99,0xa7,0x00,0x10,0x08,0x05,0xff,0xe8, + 0xa3,0x97,0x00,0x05,0xff,0xe8,0xa3,0x9e,0x00,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe4,0x98,0xb5,0x00,0x05,0xff,0xe8,0xa3,0xba,0x00,0x10,0x08,0x05,0xff,0xe3, + 0x92,0xbb,0x00,0x05,0xff,0xf0,0xa7,0xa2,0xae,0x00,0xd1,0x11,0x10,0x09,0x05,0xff, + 0xf0,0xa7,0xa5,0xa6,0x00,0x05,0xff,0xe4,0x9a,0xbe,0x00,0x10,0x08,0x05,0xff,0xe4, + 0x9b,0x87,0x00,0x05,0xff,0xe8,0xaa,0xa0,0x00,0xd3,0x41,0xd2,0x21,0xd1,0x10,0x10, + 0x08,0x05,0xff,0xe8,0xab,0xad,0x00,0x05,0xff,0xe8,0xae,0x8a,0x00,0x10,0x08,0x05, + 0xff,0xe8,0xb1,0x95,0x00,0x05,0xff,0xf0,0xa7,0xb2,0xa8,0x00,0xd1,0x10,0x10,0x08, + 0x05,0xff,0xe8,0xb2,0xab,0x00,0x05,0xff,0xe8,0xb3,0x81,0x00,0x10,0x08,0x05,0xff, + 0xe8,0xb4,0x9b,0x00,0x05,0xff,0xe8,0xb5,0xb7,0x00,0xd2,0x22,0xd1,0x12,0x10,0x09, + 0x05,0xff,0xf0,0xa7,0xbc,0xaf,0x00,0x05,0xff,0xf0,0xa0,0xa0,0x84,0x00,0x10,0x08, + 0x05,0xff,0xe8,0xb7,0x8b,0x00,0x05,0xff,0xe8,0xb6,0xbc,0x00,0xd1,0x11,0x10,0x08, + 0x05,0xff,0xe8,0xb7,0xb0,0x00,0x05,0xff,0xf0,0xa0,0xa3,0x9e,0x00,0x10,0x08,0x05, + 0xff,0xe8,0xbb,0x94,0x00,0x05,0xff,0xe8,0xbc,0xb8,0x00,0xd4,0x84,0xd3,0x43,0xd2, + 0x22,0xd1,0x12,0x10,0x09,0x05,0xff,0xf0,0xa8,0x97,0x92,0x00,0x05,0xff,0xf0,0xa8, + 0x97,0xad,0x00,0x10,0x08,0x05,0xff,0xe9,0x82,0x94,0x00,0x05,0xff,0xe9,0x83,0xb1, + 0x00,0xd1,0x11,0x10,0x08,0x05,0xff,0xe9,0x84,0x91,0x00,0x05,0xff,0xf0,0xa8,0x9c, + 0xae,0x00,0x10,0x08,0x05,0xff,0xe9,0x84,0x9b,0x00,0x05,0xff,0xe9,0x88,0xb8,0x00, + 0xd2,0x20,0xd1,0x10,0x10,0x08,0x05,0xff,0xe9,0x8b,0x97,0x00,0x05,0xff,0xe9,0x8b, + 0x98,0x00,0x10,0x08,0x05,0xff,0xe9,0x89,0xbc,0x00,0x05,0xff,0xe9,0x8f,0xb9,0x00, + 0xd1,0x11,0x10,0x08,0x05,0xff,0xe9,0x90,0x95,0x00,0x05,0xff,0xf0,0xa8,0xaf,0xba, + 0x00,0x10,0x08,0x05,0xff,0xe9,0x96,0x8b,0x00,0x05,0xff,0xe4,0xa6,0x95,0x00,0xd3, + 0x43,0xd2,0x21,0xd1,0x11,0x10,0x08,0x05,0xff,0xe9,0x96,0xb7,0x00,0x05,0xff,0xf0, + 0xa8,0xb5,0xb7,0x00,0x10,0x08,0x05,0xff,0xe4,0xa7,0xa6,0x00,0x05,0xff,0xe9,0x9b, + 0x83,0x00,0xd1,0x10,0x10,0x08,0x05,0xff,0xe5,0xb6,0xb2,0x00,0x05,0xff,0xe9,0x9c, + 0xa3,0x00,0x10,0x09,0x05,0xff,0xf0,0xa9,0x85,0x85,0x00,0x05,0xff,0xf0,0xa9,0x88, + 0x9a,0x00,0xd2,0x21,0xd1,0x10,0x10,0x08,0x05,0xff,0xe4,0xa9,0xae,0x00,0x05,0xff, + 0xe4,0xa9,0xb6,0x00,0x10,0x08,0x05,0xff,0xe9,0x9f,0xa0,0x00,0x05,0xff,0xf0,0xa9, + 0x90,0x8a,0x00,0x91,0x11,0x10,0x08,0x05,0xff,0xe4,0xaa,0xb2,0x00,0x05,0xff,0xf0, + 0xa9,0x92,0x96,0x00,0x05,0xff,0xe9,0xa0,0x8b,0x00,0xe2,0x10,0x01,0xe1,0x09,0x01, + 0xe0,0x02,0x01,0xcf,0x86,0x95,0xfb,0xd4,0x82,0xd3,0x41,0xd2,0x21,0xd1,0x11,0x10, + 0x08,0x05,0xff,0xe9,0xa0,0xa9,0x00,0x05,0xff,0xf0,0xa9,0x96,0xb6,0x00,0x10,0x08, + 0x05,0xff,0xe9,0xa3,0xa2,0x00,0x05,0xff,0xe4,0xac,0xb3,0x00,0xd1,0x10,0x10,0x08, + 0x05,0xff,0xe9,0xa4,0xa9,0x00,0x05,0xff,0xe9,0xa6,0xa7,0x00,0x10,0x08,0x05,0xff, + 0xe9,0xa7,0x82,0x00,0x05,0xff,0xe9,0xa7,0xbe,0x00,0xd2,0x21,0xd1,0x11,0x10,0x08, + 0x05,0xff,0xe4,0xaf,0x8e,0x00,0x05,0xff,0xf0,0xa9,0xac,0xb0,0x00,0x10,0x08,0x05, + 0xff,0xe9,0xac,0x92,0x00,0x05,0xff,0xe9,0xb1,0x80,0x00,0xd1,0x10,0x10,0x08,0x05, + 0xff,0xe9,0xb3,0xbd,0x00,0x05,0xff,0xe4,0xb3,0x8e,0x00,0x10,0x08,0x05,0xff,0xe4, + 0xb3,0xad,0x00,0x05,0xff,0xe9,0xb5,0xa7,0x00,0xd3,0x44,0xd2,0x23,0xd1,0x11,0x10, + 0x09,0x05,0xff,0xf0,0xaa,0x83,0x8e,0x00,0x05,0xff,0xe4,0xb3,0xb8,0x00,0x10,0x09, + 0x05,0xff,0xf0,0xaa,0x84,0x85,0x00,0x05,0xff,0xf0,0xaa,0x88,0x8e,0x00,0xd1,0x11, + 0x10,0x09,0x05,0xff,0xf0,0xaa,0x8a,0x91,0x00,0x05,0xff,0xe9,0xba,0xbb,0x00,0x10, + 0x08,0x05,0xff,0xe4,0xb5,0x96,0x00,0x05,0xff,0xe9,0xbb,0xb9,0x00,0xd2,0x20,0xd1, + 0x10,0x10,0x08,0x05,0xff,0xe9,0xbb,0xbe,0x00,0x05,0xff,0xe9,0xbc,0x85,0x00,0x10, + 0x08,0x05,0xff,0xe9,0xbc,0x8f,0x00,0x05,0xff,0xe9,0xbc,0x96,0x00,0x91,0x11,0x10, + 0x08,0x05,0xff,0xe9,0xbc,0xbb,0x00,0x05,0xff,0xf0,0xaa,0x98,0x80,0x00,0x00,0x00, + 0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xcf,0x06,0x00,0x00,0xd3,0x06, + 0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00, + 0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00, + 0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xd3,0x08, + 0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd1,0x08, + 0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86, + 0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf,0x06, + 0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06, + 0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x53,0x04, + 0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xcf,0x86,0xd5,0xc0, + 0xd4,0x60,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06, + 0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06, + 0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00, + 0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06, + 0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04, + 0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00, + 0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06, + 0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00, + 0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00, + 0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xd4,0x60, + 0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00, + 0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06, + 0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00, + 0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00, + 0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xd3,0x08, + 0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd1,0x08, + 0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86, + 0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf,0x06, + 0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06, + 0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x53,0x04, + 0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xe0,0x83,0x01,0xcf, + 0x86,0xd5,0xc0,0xd4,0x60,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf, + 0x86,0xcf,0x06,0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf, + 0x86,0xcf,0x06,0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf, + 0x06,0x00,0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1, + 0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00, + 0x00,0x54,0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00, + 0x00,0x02,0x00,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00, + 0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf, + 0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54, + 0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02, + 0x00,0xd4,0x60,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00, + 0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf, + 0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54, + 0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02, + 0x00,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00, + 0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00, + 0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3, + 0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00, + 0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00, + 0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xcf, + 0x86,0xd5,0xc0,0xd4,0x60,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf, + 0x86,0xcf,0x06,0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf, + 0x86,0xcf,0x06,0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf, + 0x06,0x00,0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1, + 0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00, + 0x00,0x54,0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00, + 0x00,0x02,0x00,0xd3,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xd1,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf, + 0x06,0x00,0x00,0xcf,0x86,0xd5,0x06,0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00, + 0x00,0xd3,0x06,0xcf,0x06,0x00,0x00,0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf, + 0x06,0x00,0x00,0xd0,0x06,0xcf,0x06,0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54, + 0x04,0x00,0x00,0x53,0x04,0x00,0x00,0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02, + 0x00,0xd4,0xd9,0xd3,0x81,0xd2,0x79,0xd1,0x71,0xd0,0x69,0xcf,0x86,0xd5,0x60,0xd4, + 0x59,0xd3,0x52,0xd2,0x33,0xd1,0x2c,0xd0,0x25,0xcf,0x86,0x95,0x1e,0x94,0x19,0x93, + 0x14,0x92,0x0f,0x91,0x0a,0x10,0x05,0x00,0xff,0x00,0x05,0xff,0x00,0x00,0xff,0x00, + 0x00,0xff,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x05,0xff,0x00,0xcf,0x06,0x05,0xff, + 0x00,0xcf,0x06,0x00,0xff,0x00,0xd1,0x07,0xcf,0x06,0x07,0xff,0x00,0xd0,0x07,0xcf, + 0x06,0x07,0xff,0x00,0xcf,0x86,0x55,0x05,0x07,0xff,0x00,0x14,0x05,0x07,0xff,0x00, + 0x00,0xff,0x00,0xcf,0x06,0x00,0xff,0x00,0xcf,0x06,0x00,0xff,0x00,0xcf,0x06,0x00, + 0xff,0x00,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86, + 0xcf,0x06,0x00,0x00,0xd2,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xd1,0x08,0xcf,0x86, + 0xcf,0x06,0x00,0x00,0xd0,0x08,0xcf,0x86,0xcf,0x06,0x00,0x00,0xcf,0x86,0xd5,0x06, + 0xcf,0x06,0x00,0x00,0xd4,0x06,0xcf,0x06,0x00,0x00,0xd3,0x06,0xcf,0x06,0x00,0x00, + 0xd2,0x06,0xcf,0x06,0x00,0x00,0xd1,0x06,0xcf,0x06,0x00,0x00,0xd0,0x06,0xcf,0x06, + 0x00,0x00,0xcf,0x86,0x55,0x04,0x00,0x00,0x54,0x04,0x00,0x00,0x53,0x04,0x00,0x00, + 0x52,0x04,0x00,0x00,0x11,0x04,0x00,0x00,0x02,0x00,0xcf,0x86,0xcf,0x06,0x02,0x00, + 0x81,0x80,0xcf,0x86,0x85,0x84,0xcf,0x86,0xcf,0x06,0x02,0x00,0x00,0x00,0x00,0x00 +}; diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/m4/.gitignore b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/m4/.gitignore new file mode 100644 index 00000000000..44701f542af --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/m4/.gitignore @@ -0,0 +1,2 @@ + +*.m4 diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/Makefile.am new file mode 100644 index 00000000000..b78344ad87a --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/Makefile.am @@ -0,0 +1,3 @@ +## Makefile.am + +dist_man_MANS = mkfs.f2fs.8 fsck.f2fs.8 dump.f2fs.8 defrag.f2fs.8 resize.f2fs.8 sload.f2fs.8 f2fs_io.8 f2fslabel.8 inject.f2fs.8 diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/defrag.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/defrag.f2fs.8 new file mode 100644 index 00000000000..fcbe3bcf14d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/defrag.f2fs.8 @@ -0,0 +1,82 @@ +.\" Copyright (c) 2015 Jaegeuk Kim +.\" +.TH DEFRAG.F2FS 8 +.SH NAME +defrag.f2fs \- relocate blocks in a given area to the specified region +.SH SYNOPSIS +.B defrag.f2fs +[ +.B \-s +.I start block address +] +[ +.B \-l +.I number of blocks +] +[ +.B \-t +.I target block address +] +[ +.B \-H +] +[ +.B \-i +.I direction +] +[ +.B \-d +.I debugging-level +] +.I device +.SH DESCRIPTION +.B defrag.f2fs +is used to move specified number of blocks starting from a given block address +to the target block address with a direction. +\fIdevice\fP is the special file corresponding to the device (e.g. +\fI/dev/sdXX\fP). + +For example, +# defrag.f2fs -s 0x4000 -l 0x100 -t 0x10000 -i /dev/sdb1 + +This moves blocks between 0x4000 and 0x4100 to the left-hand area of 0x10000. + +.PP +The exit code returned by +.B defrag.f2fs +is 0 on success and -1 on failure. +.SH OPTIONS +.TP +.BI \-s " start block address" +Specify the starting block address. +.TP +.BI \-l " number of blocks" +Specify the number of blocks to move. +.TP +.BI \-t " target block address" +Specify the destination block address. +.TP +.BI \-H +Specify support write hint. +.TP +.BI \-i " direction" +Set the direction to left. If it is not set, the direction becomes right +by default. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.SH AUTHOR +This version of +.B defrag.f2fs +has been written by Jaegeuk Kim . +.SH AVAILABILITY +.B defrag.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH SEE ALSO +.BR mkfs.f2fs(8), +.BR dump.f2fs(8), +.BR fsck.f2fs(8), +.BR resize.f2fs(8), +.BR sload.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/dump.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/dump.f2fs.8 new file mode 100644 index 00000000000..4035d57ad6e --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/dump.f2fs.8 @@ -0,0 +1,109 @@ +.\" Copyright (c) 2013 Samsung Electronics Co., Ltd. +.\" +.TH DUMP.F2FS 8 +.SH NAME +dump.f2fs \- retrieve directory and file entries from an F2FS-formated image +.SH SYNOPSIS +.B dump.f2fs +[ +.B \-i +.I inode number +] +[ +.B \-I +.I inode number +] +[ +.B \-n +.I NAT range +] +[ +.B \-M +.I Block map +] +[ +.B \-s +.I SIT range +] +[ +.B \-a +.I SSA range +] +[ +.B \-b +.I block address +] +[ +.B \-d +.I debugging-level +] +.I device +.SH DESCRIPTION +.B dump.f2fs +is used to retrieve f2fs metadata (usually in a disk partition). +\fIdevice\fP is the special file corresponding to the device (e.g. +\fI/dev/sdXX\fP). + +Currently, it can retrieve 1) a file or folder given its inode number +(folders are dumped recursively), 2) NAT +entries into a file, 3) SIT entries into a file, 4) SSA entries into +a file, 5) reverse information from the given block address. +.PP +The exit code returned by +.B dump.f2fs +is 0 on success and -1 on failure. +.SH OPTIONS +.TP +.BI \-i " inode number" +Specify an inode number to dump out. +.TP +.BI \-r +Dump out from the root inode. +.TP +.BI \-f +Do not prompt before dumping +.TP +.BI \-y +Alias for \-f +.TP +.BI \-o " path" +Dump inodes to the given path +.BI \-P +Preserve mode/owner/group for dumped inode +.TP +.BI \-L +Preserves symlinks. Otherwise symlinks are dumped as regular files. +.TP +.BI \-I " inode number" +Specify an inode number and scan full disk to dump out, include history inode block +.TP +.BI \-n " NAT range" +Specify a range presented by nids to dump NAT entries. +.TP +.BI \-M " Block map" +Show all the allocated block addresses given inode number. +.TP +.BI \-s " SIT range" +Specify a range presented by segment numbers to dump SIT entries. +.TP +.BI \-a " SSA range" +Specify a range presented by segment numbers to dump SSA entries. +.TP +.BI \-b " block address" +Specify a block address to retrieve its metadata information. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.SH AUTHOR +Initial checking code was written by Byoung Geun Kim . +.SH AVAILABILITY +.B dump.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH SEE ALSO +.BR mkfs.f2fs(8), +.BR fsck.f2fs(8), +.BR defrag.f2fs(8), +.BR resize.f2fs(8), +.BR sload.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fs_io.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fs_io.8 new file mode 100644 index 00000000000..e0f659e8986 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fs_io.8 @@ -0,0 +1,193 @@ +.\" Generated by help2man 1.47.12. +.TH f2fs_io "8" "March 2020" "f2fs-tools" "System Administration Utilities" +.SH NAME +f2fs_io \- f2fs ioctl utility +.SH DESCRIPTION +.B f2fs_io +is used to send various commands to the f2fs file system for +administrative purposes. +.SH "AVAILABLE COMMANDS" +.TP +\fBset_verity\fR \fI[file]\fR +Set the verity flags associated with the specified file. +.TP +\fBfsync\fR \fI[file]\fR +fsync given the file. +.TP +\fBfdatasync\fR \fI[file]\fR +fdatasync given the file. +.TP +\fBgetflags\fR \fI[file]\fR +Get the flags associated with the specified file. +.TP +\fBsetflags\fR \fI[flag] [file]\fR +Set an f2fs file on specified file. The flag can be casefold, +compression, nocompression, immutable, and nocow. +.TP +\fBclearflags\fR \fI[flag] [file]\fR +Clear the specified flag on the target file, which can be compression, + nocompression, immutable, and nocow. +.TP +\fBshutdown\fR \fIshutdown filesystem\fR +Freeze and stop all IOs for the file system mounted on +.IR dir. +The level parameter can be: +.RS 1.2i +.TP +0 +going down with full sync +.TP +1 +going down with checkpoint only +.TP +2 +going down with no sync +.TP +3 +going down with metadata flush +.TP +4 +going down with fsck mark +.RE +.TP +\fBpinfile\fR \fI[get|set|unset] [file]\fR +Get or set the pinning status on a file. +.TP +\fBfadvise\fR \fI[advice] [offset] [length] [file]\fR +Pass an advice to the specified file. The advice can be willneed, dontneed, +noreuse, sequential, random. +.TP +\fBfallocate\fR \fI[-c] [-i] [-p] [-z] [keep_size] [offset] [length] [file]\fR +Request that space be allocated on a file. The +.I keep_size +parameter can be either 1 or 0. +The +.I pattern +parameter can be: +.RS 1.2in +.TP +.B -c +collapse range +.TP +.B -i +insert range +.TP +.B -p +punch hole +.TP +.B -z +zero range +.RE +.TP +\fBwrite\fR \fI[chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path]\fR +Write a given pattern to +.IR file_path . +The +.I pattern +parameter can be: +.RS 1.2in +.TP +.B zero +zeros +.TP +.B inc_num +incrementing numbers +.TP +.B rand +random numbers +.RE +.IP +The +.I IO +parameter can be: +.RS 1.2in +.TP +.B buffered +buffered I/O +.TP +.B dio +direct I/O +.TP +.B dsync +direct I/O with O_DSYNC +.RE +.TP +\fBread\fR \fI[chunk_size in 4kb] [offset in chunk_size] [count] [IO] [print_nbytes] [file_path]\fR +Read data in +.I file_path +and print +.IR print_nbytes . +The +.I IO +options can be: +.RS 1.2in +.TP +.B buffered +buffered I/O +.TP +.B dio +direct I/O +.RE +.TP +\fBfiemap\fR \fI[offset in 4kb] [count] [file_path]\fR +get block address in file +.TP +\fBgc_urgent\fR \fIdev [start|end|run] [time in sec]\fR +Start, end, or run gc_urgent for a given time period +.TP +\fBdefrag_file\fR \fI[start] [length] [file_path]\fR +Defragment a file. +.TP +\fBcopy\fR \fI[-d] [-m] [-s] [src_path] [dst_path]\fR +Copy file from src_path to dst_path. +The +.I pattern +parameter can be: +.RS 1.2in +.TP +.B -d +use direct I/O +.TP +.B -m +use mmap for source file +.TP +.B -s +use sendfile to transfer data +.RE +.TP +\fBget_cblocks\fR \fI[file]\fR +Get the number of compressed blocks. +.TP +\fBrelease_cblocks\fR \fI[file]\fR +Release compressed blocks to get free space. +.TP +\fBreserve_cblocks\fR \fI[file]\fR +Reserve free blocks to prepare decompressing blocks in the file. +.TP +\fBgc\fR \fI[sync_mode] [file]\fR +Trigger filesystem GC +.TP +\fBcheckpoint\fR \fI[file]\fR +Trigger filesystem checkpoint +.TP +\fBprecache_extents\fR \fI[file]\fR +Trigger precache extents +.TP +\fBmove_range\fR \fI[src_path] [dst_path] [src_start] [dst_start] [length]\fR +Move a range of data blocks from source file to destination file +.TP +\fBgc_range\fR \fI[sync_mode] [start in 4kb] [length in 4kb] [file]\fR +Trigger gc to move data blocks from specified address range +.TP +\fBget_advise\fR \fI[file]\fR +Get i_advise value and info in file +.TP +\fBioprio\fR \fI[hint] [file]\fR +Set ioprio to the file. The ioprio can be ioprio_write. +.SH AUTHOR +This version of +.B f2fs_io +has been written by Jaegeuk Kim . +.SH AVAILABILITY +.B f2fs_io +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fslabel.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fslabel.8 new file mode 100644 index 00000000000..848ed3b2e2c --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/f2fslabel.8 @@ -0,0 +1,33 @@ +.\" Copyright (c) 2021 Samsung Electronics Co., Ltd. +.\" +.TH F2FSLABEL 8 +.SH NAME +f2fslabel \- Change the label on an f2fs volume +.SH SYNOPSIS +.B f2fslabel +.I device +[ +.I volume-label +] +.SH DESCRIPTION +.B f2fslabel +will display or change the volume label on the f2fs located on +.I device. +.PP +If the optional argument +.I volume-label +is present, then +.B f2fslabel +will set the volume label to be +.IR volume-label . +.PP +Otherwise, +.B f2fslabel +will simply show the current label. +.PP +.SH AUTHOR +.B f2fslabel +was written by Dongwoo Lee (dwoo08.lee@samsung.com). +.SH AVAILABILITY +.B f2fslabel +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/fsck.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/fsck.f2fs.8 new file mode 100644 index 00000000000..89cc455954b --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/fsck.f2fs.8 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2013 Samsung Electronics Co., Ltd. +.\" +.TH FSCK.F2FS 8 +.SH NAME +fsck.f2fs \- check a Linux F2FS file system +.SH SYNOPSIS +.B fsck.f2fs +[ +.B \-a +.I enable auto fix +] +[ +.B \-f +.I enable force fix +] +[ +.B \-H +] +[ +.B \-M +.I show file map +] +[ +.B \-p +.I enable preen mode +] +[ +.B \-t +.I show stored directory tree +] +[ +.B \-d +.I debugging-level +] +.I device +.SH DESCRIPTION +.B fsck.f2fs +is used to check an f2fs file system (usually in a disk partition). +\fIdevice\fP is the special file corresponding to the device (e.g. +\fI/dev/sdXX\fP). +.PP +The exit code returned by +.B fsck.f2fs +is 0 on success and -1 on failure. +.SH OPTIONS +.TP +.BI \-a " enable auto fix" +Enable to run file system check only if a bug was reported by the F2FS kernel +module. It is disabled by default. +.TP +.BI \-f " enable force fix" +Enable to fix all the inconsistency in the partition. +.TP +.BI \-H +Specify support write hint. +.TP +.BI \-M " show files map" +Enable to show all the filenames and inode numbers stored in the image +.TP +.BI \-p " enable preen mode" +Same as "-a" to support general fsck convention. +.TP +.BI \-t " show stored directory tree" +Enable to show every directory entries in the partition. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.BI \--nolinear-lookup +Tune linear lookup fallback, must specify an argument, 0: enable linear lookup, 1: disable linear lookup. +.TP +.BI \-\-fault_injection=%d " enable fault injection" +Enable fault injection in all supported types with specified injection rate. +.TP +.BI \-\-fault_type=%d " configure fault injection type" +Support configuring fault injection type, should be enabled with +fault_injection option, fault type value is shown below, it supports +single or combined type. +.br +=========================== =========== +.br +Type_Name Type_Value +.br +=========================== =========== +.br +FAULT_SEG_TYPE 0x00000001 +.br +FAULT_SUM_TYPE 0x00000002 +.br +FAULT_SUM_ENT 0x00000004 +.br +FAULT_NAT 0x00000008 +.br +FAULT_NODE 0x00000010 +.br +FAULT_XATTR_ENT 0x00000020 +.br +FAULT_COMPR 0x00000040 +.br +FAULT_INODE 0x00000080 +.br +FAULT_DENTRY 0x00000100 +.br +FAULT_DATA 0x00000200 +.br +FAULT_QUOTA 0x00000400 +.TP +.SH AUTHOR +Initial checking code was written by Byoung Geun Kim . +Jaegeuk Kim reworked most parts of the codes to support +fixing any corrupted images. +.SH AVAILABILITY +.B fsck.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH SEE ALSO +.BR mkfs.f2fs(8), +.BR dump.f2fs(8), +.BR defrag.f2fs(8), +.BR resize.f2fs(8), +.BR sload.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/inject.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/inject.f2fs.8 new file mode 100644 index 00000000000..01d58effbfe --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/inject.f2fs.8 @@ -0,0 +1,225 @@ +.\" Copyright (c) 2024 OPPO Mobile Comm Corp., Ltd. +.\" +.TH INJECT.F2FS 8 +.SH NAME +inject.f2fs \- inject a Linux F2FS file system +.SH SYNOPSIS +.B inject.f2fs +[ +.I options +] +.I device +.SH DESCRIPTION +.B inject.f2fs +is used to modify metadata or data (directory entry) of f2fs file system +image offline flexibly. +.SH OPTIONS +.TP +.BI \-d " debug level [default:0]" +Specify the level of debugging options. +.TP +.BI \-V +Print the version number and exit. +.TP +.BI \-\-mb " member name" +Specify the member name in a struct that is injected. +.TP +.BI \-\-val " new value" +New value to set if \fImb\fP is a number. +.TP +.BI \-\-str " new string" +New string to set if \fImb\fP is a string. +.TP +.BI \-\-idx " slot index" +Specify which slot is injected if \fImb\fP is an array. +.TP +.BI \-\-nid " nid" +Specify which nid is injected. +.TP +.BI \-\-blk " blkaddr" +Specify which blkaddr is injected. +.TP +.BI \-\-sb " 0 or 1 or 2" +Inject super block, its argument means which sb pack is injected, where 0 choses the current valid sb automatically. +The available \fImb\fP of \fIsb\fP are: +.RS 1.2i +.TP +.BI magic +magic numbe. +.TP +.BI s_stop_reason +s_stop_reason array. +.TP +.BI s_errors +s_errors array. +.TP +.BI devs.path +path in devs array. +.RE +.TP +.BI \-\-cp " 0 or 1 or 2" +Inject checkpoint, its argument means which cp pack is injected, where 0 choses the current valid cp automatically. +The available \fImb\fP of \fIcp\fP are: +.RS 1.2i +.TP +.BI checkpoint_ver +checkpoint version. +.TP +.BI ckpt_flags +checkpoint flags. +.TP +.BI cur_node_segno +cur_node_segno array. +.TP +.BI cur_node_blkoff +cur_node_blkoff array. +.TP +.BI cur_data_segno +cur_data_segno array. +.TP +.BI cur_data_blkoff +cur_data_blkoff array. +.RE +.TP +.BI \-\-nat " 0 or 1 or 2" +Inject nat entry specified by \fInid\fP, its argument means which nat pack is injected, where 0 choses the current valid nat automatically. +The available \fImb\fP of \fInat\fP are: +.RS 1.2i +.TP +.BI version +nat entry version. +.TP +.BI ino +nat entry ino. +.TP +.BI block_addr +nat entry block_addr. +.RE +.TP +.BI \-\-sit " 0 or 1 or 2" +Inject sit entry specified by \fIblk\fP, its argument means which sit pack is injected, where 0 choses the current valid sit automatically. +The available \fImb\fP of \fIsit\fP are: +.RS 1.2i +.TP +.BI vblocks +sit entry vblocks. +.TP +.BI valid_map +sit entry valid_map. +.TP +.BI mtime +sit entry mtime. +.RE +.TP +.BI \-\-ssa +Inject summary block or summary entry specified by \fIblk\fP. +The available \fImb\fP of \fIssa\fP are: +.RS 1.2i +.TP +.BI entry_type +summary block footer entry_type. +.TP +.BI check_sum +summary block footer check_sum. +.TP +.BI nid +summary entry nid. +.TP +.BI version +summary entry version. +.TP +.BI ofs_in_node +summary entry ofs_in_node. +.RE +.TP +.BI \-\-node +Inject node block specified by \fInid\P. +The available \fImb\fP of \fInode\fP are: +.RS 1.2i +.TP +.BI nid +node footer nid. +.TP +.BI ino +node footer ino. +.TP +.BI flag +node footer flag. +.TP +.BI cp_ver +node footer cp_ver. +.TP +.BI next_blkaddr +node footer next_blkaddr. +.TP +.BI i_mode +inode i_mode. +.TP +.BI i_advise +inode i_advise. +.TP +.BI i_inline +inode i_inline. +.TP +.BI i_links +inode i_links. +.TP +.BI i_size +inode i_size. +.TP +.BI i_blocks +inode i_blocks. +.TP +.BI i_extra_isize +inode i_extra_isize. +.TP +.BI i_inode_checksum +inode i_inode_checksum. +.TP +.BI i_addr +inode i_addr array specified by \fIidx\fP. +.TP +.BI i_nid +inode i_nid array specified by \fIidx\fP. +.TP +.BI addr +{in}direct node nid/addr array specified by \fIidx\fP. +.RE +.TP +.BI \-\-dent +Inject dentry block or dir entry specified \fInid\fP. +The available \fImb\fP of \fIdent\fP are: +.RS 1.2i +.TP +.BI d_bitmap +dentry block d_bitmap. +.TP +.BI d_hash +dentry hash. +.TP +.BI d_ino +dentry ino. +.TP +.BI d_ftype +dentry ftype. +.RE +.TP +.BI \-\-dry\-run +Do not really inject. + +.PP +.SH AUTHOR +This version of +.B inject.f2fs +has been written by Sheng Yong . +.SH AVAILABILITY +.B inject.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH "SEE ALSO" +.BR mkfs.f2fs(8), +.BR fsck.f2fs(8), +.BR dump.f2fs(8), +.BR defrag.f2fs(8), +.BR resize.f2fs(8), +.BR sload.f2fs(8), +.BR defrag.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/mkfs.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/mkfs.f2fs.8 new file mode 100644 index 00000000000..8b3b0cc22f7 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/mkfs.f2fs.8 @@ -0,0 +1,306 @@ +.\" Copyright (c) 2012 Samsung Electronics Co., Ltd. +.\" http://www.samsung.com/ +.\" Written by Jaegeuk Kim +.\" +.TH MKFS.F2FS 8 +.SH NAME +mkfs.f2fs \- create an F2FS file system +.SH SYNOPSIS +.B mkfs.f2fs +[ +.B \-c +.I device-list +] +[ +.B \-d +.I debug-level +] +[ +.B \-e +.I extension-list +] +[ +.B \-E +.I extension-list +] +[ +.B \-f +] +[ +.B \-g +.I default-options +] +[ +.B \-H +] +[ +.B \-i +] +[ +.B \-l +.I volume-label +] +[ +.B \-m +] +[ +.B \-o +.I overprovision-ratio-percentage +] +[ +.B \-O +.I feature-list +] +[ +.B \-C +.I encoding:flags +] +[ +.B \-q +] +[ +.B \-r +] +[ +.B \-R +.I root_owner +] +[ +.B \-s +.I #-of-segments-per-section +] +[ +.B \-S +] +[ +.B \-t +.I nodiscard/discard +] +[ +.B \-T +.I timestamp +] +[ +.B \-w +.I wanted-sector-size +] +[ +.B \-z +.I #-of-sections-per-zone +] +[ +.B \-V +] +[ +.B \-Z +.I #-of-reserved-sections +] +.I device +.I [sectors] +.SH DESCRIPTION +.B mkfs.f2fs +is used to create a f2fs file system (usually in a disk partition). +\fIdevice\fP is the special file corresponding to the device (e.g. +\fI/dev/sdXX\fP). +\fIsectors\fP is optionally given for specifying the filesystem size. +.PP +The exit code returned by +.B mkfs.f2fs +is 0 on success and 1 on failure. +.SH OPTIONS +.TP +.BI \-a " heap-based-allocation" (deprecated) +Specify 1 or 0 to enable/disable heap based block allocation policy. +If the value is equal to 1, each of active log areas are initially +assigned separately according to the whole volume size. +The default value is 1. +.TP +.BI \-b " block size" +Specify the block size in bytes. Valid blocksizes are powers of 2. +Currently, the kernel is only able to mount f2fs filesystems where the +block size matches the page size. +The default value is 4096. +.TP +.BI \-c " device-list" +Build f2fs with these additional devices, so that the user can +see all the devices as one big volume. +Supports up to 7 devices except meta device. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.BI \-e " extension-list" +Specify a list of file extensions that f2fs will treat as cold files. +The data of files with those extensions will be stored in the cold log. +The default list includes most of the multimedia file extensions such as +jpg, gif, mpeg, mkv, and so on. +.TP +.BI \-E " extension-list" +Specify a list of file extensions that f2fs will treat as hot files. +The data of files with those extensions will be stored in the hot log. +The default list includes database file extensions, such as db. +.TP +.BI \-f +Force overwrite when an existing filesystem is detected on the device. +By default, mkfs.f2fs will not write to the device if it suspects that +there is a filesystem or partition table on the device already. +.TP +.BI \-g " default-options" +Use a default set of options. +The following values are supported: +.RS 1.2i +.TP 1.2i +.B android +Use default options for Android having "-d1 -f -w 4096 -R 0:0 -O encrypt -O project_quota,extra_attr,{quota} -O verity". +.RE +.TP +.BI \-H +Specify support write hint. +.TP +.BI \-i +Enable extended node bitmap. +.TP +.BI \-l " volume-label" +Specify the volume label to the partition mounted as F2FS. +.TP +.BI \-m +Specify f2fs filesystem to supports the block zoned feature. +Without it, the filesystem doesn't support the feature. +.TP +.BI \-o " overprovision-ratio-percentage" +Specify the percentage of the volume that will be used as overprovision area. +This area is hidden to users, and utilized by F2FS cleaner. If not specified, the +best number will be assigned automatically according to the partition size. +.TP +.BI \-O " feature-list" +Set additional features for the filesystem. Features are comma separated, and +the flag can be repeated. The following features are supported: +.RS 1.2i +.TP 1.2i +.B encrypt +Enable support for filesystem level encryption. +.TP +.B extra_attr +Enable extra attr feature, required for some of the other features. +.TP +.B project_quota +Enable project ID tracking. This is used for projet quota accounting. Requires extra attr. +.TP +.B inode_checksum +Enable inode checksum. Requires extra attr. +.TP +.B flexible_inline_xattr +Enable flexible inline xattr. Requires extra attr. +.TP +.B quota +Enable quotas. +.TP +.B inode_crtime +Enable inode creation time feature. Requires extra attr. +.TP +.B lost_found +Enable lost+found feature. +.TP +.B verity +Enable support for verity protected files (a.k.a. fs-verity). +.TP +.B sb_checksum +Enable superblock checksum. +.TP +.B casefold +Enable casefolding support in the filesystem. Optional flags can be passed with +.B \-C +.TP +.B compression +Enable support for filesystem level compression. Requires extra attr. +.TP +.B ro +Enable readonly feature to eliminate OVP/SSA on-disk layout for small readonly partition. +.RE +.TP +.BI \-C " encoding:flags" +Support casefolding with a specific encoding, with optional comma separated flags. +.RS 1.2i +.TP 1.2i +.I encoding: +.RS 1.2i +.TP 1.2i +.B utf8 +Use UTF-8 for casefolding. +.RE +.I flags: +.RS 1.2i +.TP 1.2i +.B strict +This flag specifies that invalid strings should be rejected by the filesystem. +Default is disabled. +.RE +.RE +.TP +.BI \-q +Quiet mode. +With it, mkfs.f2fs does not show any messages, including the basic messages. +.TP +.BI \-r +Sets the checkpointing srand seed to 0. +.TP +.BI \-R +Give root_owner option for initial uid/gid assignment. +Default is set by getuid()/getgid(), and assigned by "-R $uid:$gid". +.TP +.BI \-s " #-of-segments-per-section" +Specify the number of segments per section. A section consists of +multiple consecutive segments, and is the unit of garbage collection. +The default number is 1, which means one segment is assigned to a section. +.TP +.BI \-S +Enable sparse mode. +.TP +.BI \-t " 1/0" +Specify 1 or 0 to enable or disable discard policy, respectively. +The default value is 1. +.TP +.BI \-T " timestamp" +Set inodes times to a given timestamp. By default, the current time will be used. +This behaviour corresponds to the value -1. +.TP +.BI \-w " wanted-sector-size" +Specify the sector size in bytes. +Without it, the sectors will be calculated by device sector size. +.TP +.BI \-z " #-of-sections-per-zone" +Specify the number of sections per zone. A zone consists of multiple sections. +F2FS allocates segments for active logs with separated zones as much as possible. +The default number is 1, which means a zone consists of one section. +.TP +.BI sectors +Number of sectors. Default is determined by device size. +.TP +.BI \-V +Print the version number and exit. +.TP +.BI \-Z " #-of-reserved-sections" +Specify the number of GC reserved sections for zoned device. If specified +to non-zero, reserved segments count is set to the larger size between 8 +sections and the input value. If specified to zero, the best number will be +assigned automatically according to the partition size. +If overprovision-ratio-percentage is not specified, it will set to default +3.0%. Without '-m' option, the filesystem doesn't support the feature. +.TP +.BI \-h,\ \-\-help +Print usage and exit. +.SH AUTHOR +This version of +.B mkfs.f2fs +has been written by Jaegeuk Kim . +.SH AVAILABILITY +.B mkfs.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH SEE ALSO +.BR mkfs (8), +.BR fsck.f2fs(8), +.BR dump.f2fs(8), +.BR defrag.f2fs(8), +.BR resize.f2fs(8), +.BR sload.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/resize.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/resize.f2fs.8 new file mode 100644 index 00000000000..5b6daf5dd24 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/resize.f2fs.8 @@ -0,0 +1,89 @@ +.\" Copyright (c) 2015 Jaegeuk Kim +.\" +.TH RESIZE.F2FS 8 +.SH NAME +resize.f2fs \- resize filesystem size +.SH SYNOPSIS +.B resize.f2fs +[ +.B \-t +.I target sectors +] +[ +.B \-d +.I debugging-level +] +[ +.B \-o +.I overprovision-ratio-percentage +] +[ +.B \-f +] +[ +.B \-F +] +[ +.B \-H +] +[ +.B \-s +] +[ +.B \-V +] +.I device +.SH DESCRIPTION +.B resize.f2fs +is used to resize an f2fs file system (usually in a disk partition). +\fIdevice\fP is the special file corresponding to the device (e.g. +\fI/dev/sdXX\fP). + +Current version only supports expanding the prebuilt filesystem. + +.PP +The exit code returned by +.B resize.f2fs +is 0 on success and -1 on failure. +.SH OPTIONS +.TP +.BI \-t " target sectors" +Specify the size in sectors. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.BI \-o " overprovision-ratio-percentage" +Specify the percentage of the volume that will be used as overprovision area. +This area is hidden to users, and utilized by F2FS cleaner. If not specified, the +best number will be assigned automatically according to the partition size. +.TP +.BI \-f +Force to fix any inconsistent data during resize. +.TP +.BI \-F +Skip caution dialogue and resize partition directly. +.TP +.BI \-H +Specify support write hint. +.TP +.BI \-s +Enable safe resize, it can only be used w/ shrink resize. +.TP +.BI \-V +Print the version number and exit. +.TP +.SH AUTHOR +This version of +.B resize.f2fs +has been written by Jaegeuk Kim . +.SH AVAILABILITY +.B resize.f2fs +is available from git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs-tools.git. +.SH SEE ALSO +.BR mkfs.f2fs(8), +.BR fsck.f2fs(8), +.BR dump.f2fs(8), +.BR defrag.f2fs(8), +.BR sload.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/sload.f2fs.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/sload.f2fs.8 new file mode 100644 index 00000000000..f213dea07b7 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/man/sload.f2fs.8 @@ -0,0 +1,137 @@ +.\" Copyright (C) 2015 Huawei Ltd. +.\" +.TH SLOAD.F2FS 8 +.SH NAME +sload.f2fs \- load directories and files into the device directly +.SH SYNOPSIS +.B sload.f2fs +[ +.B \-f +.I source-directory-path +] +[ +.B \-t +.I mount-point +] +[ +.B \-d +.I debugging-level +] +[ +.B \-P +] +[ +.B \-c +[ +.B \-L +.I log-of-blocks-per-cluster +] +[ +.B \-a +.I compression-algorithm +] +[ +.B \-x +.I file-extension-to-exclude-from-compression +| +.B \-i +.I file-extension-to-include-for-compression +] +[ +.B \-m +.I minimum-compressed-blocks-per-cluster +] +[ +.B \-r +] +] +.I device +.SH DESCRIPTION +.B sload.f2fs +is used to load directories and files into a disk partition, or an F2FS +image (file). +\fIdevice\fP could a special file corresponding to the device (e.g. +\fI/dev/sdXX\fP), or an F2FS image file. + +.PP +The exit code returned by +.B sload.f2fs +is 0 on success and -1 on failure. +.SH OPTIONS +.TP +.BI \-f " source-directory-path" +Specify the source directory path to be loaded. +.TP +.BI \-t " mount-point-path" +Specify the mount point path in the partition to load. +.TP +.BI \-d " debug-level" +Specify the level of debugging options. +The default number is 0, which shows basic debugging messages. +.TP +.BI \-P +Preserve owner: user and group. +The user and group of the source files will be taken into account. +.TP +.BI \-c +Enable a cluster-based file compression. +The file would be chopped into clusters, and each cluster is compressed +independently. +.TP +.BI \-L " log-of-blocks-per-cluster +Specify cluster size in power of two blocks. +The minimum value is 2 (4 blocks, default). +The maximum value is 8 (256 blocks). +Note that a block contains 4096 or 16384 bytes. +This option must be used with option \fB\-c\fR. +.TP +.BI \-a " compression-algorithm" +Choose the algorithm for compression. Available options are: +lzo, lz4 (default). +This option must be used with option \fB\-c\fR. +.TP +.BI \-i " file-extension-to-include-for-compression" +Specify a file extension to include for the compression. +To specify multiple file extensions, use multiple option \fB\-i\fR's. +Files having one of the listed extensions will be compressed. +This option must be used with option \fB\-c\fR. +.TP +.BI \-x " file-extension-to-exclude-from-compression" +Specify a file extension to exclude from compression. +To specify multiple file extensions, use multiple option \fB\-x\fR's. +Files having one of the listed extensions won't be compressed. +This option must be used with option \fB\-c\fR. +.TP +.BI \-m " minimum-compressed-blocks-per-cluster" +Specify a minimum block count saved (by compression) per cluster. +The minimum value is 1 (default). +Maximum value is the cluster size in blocks minus 1. +If compression of a cluster fails to save at least the minimum compressed +block count given by the option, the cluster will not be compressed. +This option must be used with option \fB\-c\fR. +.TP +.BI \-r +Specify read-only flag for the compressed files. +It allows filesystem to release compressed space to the users, since, without +this option, filesystem should keep the space for future file updates. +This option must be used with option \fB\-c\fR. + +.SH NOTES +If neither \fB\-i\fR nor \fB\-x\fR is used, all files will be compressed. +Obviously, option \fB\-i\fR and \fB-x\fR can not be used together. + +.SH AUTHOR +This version of +.B sload.f2fs +has been contributed by Hou Pengyang , +Liu Shuoran , Jaegeuk Kim , +Robin Hsu +.SH AVAILABILITY +.B sload.f2fs +is available from . +.SH SEE ALSO +.BR mkfs.f2fs(8), +.BR fsck.f2fs(8), +.BR dump.f2fs(8), +.BR defrag.f2fs(8), +.BR resize.f2fs(8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/Makefile.am new file mode 100644 index 00000000000..bfffd88de10 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/Makefile.am @@ -0,0 +1,30 @@ +## Makefile.am + +AM_CPPFLAGS = ${libuuid_CFLAGS} ${libblkid_CFLAGS} -I$(top_srcdir)/include +AM_CFLAGS = -Wall -DWITH_BLKDISCARD -D_FILE_OFFSET_BITS=64 +sbin_PROGRAMS = mkfs.f2fs +noinst_HEADERS = f2fs_format_utils.h +include_HEADERS = $(top_srcdir)/include/f2fs_fs.h +mkfs_f2fs_SOURCES = f2fs_format_main.c f2fs_format.c f2fs_format_utils.c +mkfs_f2fs_LDADD = ${libuuid_LIBS} ${libblkid_LIBS} $(top_builddir)/lib/libf2fs.la + +lib_LTLIBRARIES = libf2fs_format.la +libf2fs_format_la_SOURCES = f2fs_format_main.c f2fs_format.c f2fs_format_utils.c +libf2fs_format_la_CFLAGS = -DWITH_BLKDISCARD -D_FILE_OFFSET_BITS=64 +libf2fs_format_la_LDFLAGS = ${libblkid_LIBS} ${libuuid_LIBS} -L$(top_builddir)/lib -lf2fs \ + -version-info $(FMT_CURRENT):$(FMT_REVISION):$(FMT_AGE) + +install-exec-hook: + if test -n "$(root_libdir)" -a "$(libdir)" != "$(root_libdir)" -a \ + -f "$(DESTDIR)$(libdir)/libf2fs_format.so"; then \ + $(MKDIR_P) $(DESTDIR)$(root_libdir); \ + mv $(DESTDIR)$(libdir)/libf2fs_format.so.* $(DESTDIR)$(root_libdir); \ + so_img_name=$$(readlink $(DESTDIR)$(libdir)/libf2fs_format.so); \ + so_img_rel_target=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g'); \ + (cd $(DESTDIR)$(libdir) && \ + rm -f libf2fs_format.so && \ + $(LN_S) $$so_img_rel_target$(root_libdir)/$$so_img_name libf2fs_format.so); \ + fi + +uninstall-hook: + rm $(DESTDIR)$(root_libdir)/libf2fs_format.so* diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format.c new file mode 100644 index 00000000000..2680bd3a032 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format.c @@ -0,0 +1,1894 @@ +/** + * f2fs_format.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#include + +#ifdef HAVE_UUID_UUID_H +#include +#endif +#ifndef HAVE_LIBUUID +#define uuid_parse(a, b) -1 +#define uuid_generate(a) +#define uuid_unparse(a, b) -1 +#endif + +#include "quota.h" +#include "f2fs_format_utils.h" + +extern struct f2fs_configuration c; +struct f2fs_super_block raw_sb; +struct f2fs_super_block *sb = &raw_sb; +struct f2fs_checkpoint *cp; + +static inline bool device_is_aliased(unsigned int dev_num) +{ + if (dev_num >= c.ndevs) + return false; + return c.devices[dev_num].alias_filename != NULL; +} + +static inline unsigned int target_device_index(uint64_t blkaddr) +{ + int i; + + for (i = 0; i < c.ndevs; i++) + if (c.devices[i].start_blkaddr <= blkaddr && + c.devices[i].end_blkaddr >= blkaddr) + return i; + return 0; +} + +#define GET_SEGNO(blk_addr) ((blk_addr - get_sb(main_blkaddr)) / \ + c.blks_per_seg) +#define START_BLOCK(segno) (segno * c.blks_per_seg + get_sb(main_blkaddr)) + +/* Return first segment number of each area */ +static inline uint32_t next_zone(int seg_type) +{ + uint32_t next_seg = c.cur_seg[seg_type] + c.segs_per_zone; + uint64_t next_blkaddr = START_BLOCK(next_seg); + int dev_num; + + dev_num = target_device_index(next_blkaddr); + if (!device_is_aliased(dev_num)) + return GET_SEGNO(next_blkaddr); + + while (dev_num < c.ndevs && device_is_aliased(dev_num)) + dev_num++; + + return GET_SEGNO(c.devices[dev_num - 1].end_blkaddr + 1); +} + +static inline uint32_t last_zone(uint32_t total_zone) +{ + uint32_t last_seg = (total_zone - 1) * c.segs_per_zone; + uint64_t last_blkaddr = START_BLOCK(last_seg); + int dev_num; + + dev_num = target_device_index(last_blkaddr); + if (!device_is_aliased(dev_num)) + return GET_SEGNO(last_blkaddr); + + while (dev_num > 0 && device_is_aliased(dev_num)) + dev_num--; + + return GET_SEGNO(c.devices[dev_num + 1].start_blkaddr) - + c.segs_per_zone; +} + +#define last_section(cur) (cur + (c.secs_per_zone - 1) * c.segs_per_sec) + +/* Return time fixed by the user or current time by default */ +#define mkfs_time ((c.fixed_time == -1) ? time(NULL) : c.fixed_time) + +const char *media_ext_lists[] = { + /* common prefix */ + "mp", // Covers mp3, mp4, mpeg, mpg + "wm", // Covers wma, wmb, wmv + "og", // Covers oga, ogg, ogm, ogv + "jp", // Covers jpg, jpeg, jp2 + + /* video */ + "avi", + "m4v", + "m4p", + "mkv", + "mov", + "webm", + + /* audio */ + "wav", + "m4a", + "3gp", + "opus", + "flac", + + /* image */ + "gif", + "png", + "svg", + "webp", + + /* archives */ + "jar", + "deb", + "iso", + "gz", + "xz", + "zst", + + /* others */ + "pdf", + "pyc", // Python bytecode + "ttc", + "ttf", + "exe", + + /* android */ + "apk", + "cnt", // Image alias + "exo", // YouTube + "odex", // Android RunTime + "vdex", // Android RunTime + "so", + + NULL +}; + +const char *hot_ext_lists[] = { + "db", + +#ifndef WITH_ANDROID + /* Virtual machines */ + "vmdk", // VMware or VirtualBox + "vdi", // VirtualBox + "qcow2", // QEMU +#endif + NULL +}; + +const char **default_ext_list[] = { + media_ext_lists, + hot_ext_lists +}; + +static bool is_extension_exist(const char *name) +{ + int i; + + for (i = 0; i < F2FS_MAX_EXTENSION; i++) { + char *ext = (char *)sb->extension_list[i]; + if (!strcmp(ext, name)) + return 1; + } + + return 0; +} + +static void cure_extension_list(void) +{ + const char **extlist; + char *ext_str; + char *ue; + int name_len; + int i, pos = 0; + + set_sb(extension_count, 0); + memset(sb->extension_list, 0, sizeof(sb->extension_list)); + + for (i = 0; i < 2; i++) { + ext_str = c.extension_list[i]; + extlist = default_ext_list[i]; + + while (*extlist) { + name_len = strlen(*extlist); + memcpy(sb->extension_list[pos++], *extlist, name_len); + extlist++; + } + if (i == 0) + set_sb(extension_count, pos); + else + sb->hot_ext_count = pos - get_sb(extension_count);; + + if (!ext_str) + continue; + + /* add user ext list */ + ue = strtok(ext_str, ", "); + while (ue != NULL) { + name_len = strlen(ue); + if (name_len >= F2FS_EXTENSION_LEN) { + MSG(0, "\tWarn: Extension name (%s) is too long\n", ue); + goto next; + } + if (!is_extension_exist(ue)) + memcpy(sb->extension_list[pos++], ue, name_len); +next: + ue = strtok(NULL, ", "); + if (pos >= F2FS_MAX_EXTENSION) + break; + } + + if (i == 0) + set_sb(extension_count, pos); + else + sb->hot_ext_count = pos - get_sb(extension_count); + + free(c.extension_list[i]); + } +} + +static void verify_cur_segs(void) +{ + int i, j; + int reorder = 0; + + for (i = 0; i < NR_CURSEG_TYPE; i++) { + for (j = i + 1; j < NR_CURSEG_TYPE; j++) { + if (c.cur_seg[i] == c.cur_seg[j]) { + reorder = 1; + break; + } + } + } + + if (!reorder) + return; + + c.cur_seg[0] = 0; + for (i = 1; i < NR_CURSEG_TYPE; i++) + c.cur_seg[i] = next_zone(i - 1); +} + +static int f2fs_prepare_super_block(void) +{ + uint32_t blk_size_bytes; + uint32_t log_sectorsize, log_sectors_per_block; + uint32_t log_blocksize, log_blks_per_seg; + uint32_t segment_size_bytes, zone_size_bytes; + uint32_t alignment_bytes; + uint32_t sit_segments, nat_segments; + uint32_t blocks_for_sit, blocks_for_nat, blocks_for_ssa; + uint32_t total_valid_blks_available; + uint64_t zone_align_start_offset, diff; + uint64_t total_meta_zones, total_meta_segments; + uint32_t sit_bitmap_size, max_sit_bitmap_size; + uint32_t max_nat_bitmap_size, max_nat_segments; + uint32_t total_zones, avail_zones = 0; + enum quota_type qtype; + int i; + + set_sb(magic, F2FS_SUPER_MAGIC); + set_sb(major_ver, F2FS_MAJOR_VERSION); + set_sb(minor_ver, F2FS_MINOR_VERSION); + + log_sectorsize = log_base_2(c.sector_size); + log_sectors_per_block = log_base_2(c.sectors_per_blk); + log_blocksize = log_sectorsize + log_sectors_per_block; + log_blks_per_seg = log_base_2(c.blks_per_seg); + + set_sb(log_sectorsize, log_sectorsize); + set_sb(log_sectors_per_block, log_sectors_per_block); + + set_sb(log_blocksize, log_blocksize); + set_sb(log_blocks_per_seg, log_blks_per_seg); + + set_sb(segs_per_sec, c.segs_per_sec); + set_sb(secs_per_zone, c.secs_per_zone); + + blk_size_bytes = 1 << log_blocksize; + segment_size_bytes = blk_size_bytes * c.blks_per_seg; + zone_size_bytes = + blk_size_bytes * c.secs_per_zone * + c.segs_per_sec * c.blks_per_seg; + + set_sb(checksum_offset, 0); + + set_sb(block_count, c.total_sectors >> log_sectors_per_block); + + alignment_bytes = c.zoned_mode && c.ndevs > 1 ? segment_size_bytes : zone_size_bytes; + + zone_align_start_offset = + ((uint64_t) c.start_sector * DEFAULT_SECTOR_SIZE + + 2 * F2FS_BLKSIZE + alignment_bytes - 1) / + alignment_bytes * alignment_bytes - + (uint64_t) c.start_sector * DEFAULT_SECTOR_SIZE; + + if (c.feature & F2FS_FEATURE_RO) + zone_align_start_offset = 8192; + + if (c.start_sector % DEFAULT_SECTORS_PER_BLOCK) { + MSG(1, "\t%s: Align start sector number to the page unit\n", + c.zoned_mode ? "FAIL" : "WARN"); + MSG(1, "\ti.e., start sector: %d, ofs:%d (sects/page: %d)\n", + c.start_sector, + c.start_sector % DEFAULT_SECTORS_PER_BLOCK, + DEFAULT_SECTORS_PER_BLOCK); + if (c.zoned_mode) + return -1; + } + + if (c.zoned_mode && c.ndevs > 1) + zone_align_start_offset += + (c.devices[0].total_sectors * c.sector_size - + zone_align_start_offset) % zone_size_bytes; + + set_sb(segment0_blkaddr, zone_align_start_offset / blk_size_bytes); + sb->cp_blkaddr = sb->segment0_blkaddr; + + MSG(0, "Info: zone aligned segment0 blkaddr: %u\n", + get_sb(segment0_blkaddr)); + + if (c.zoned_mode && + ((c.ndevs == 1 && + (get_sb(segment0_blkaddr) + c.start_sector / + DEFAULT_SECTORS_PER_BLOCK) % c.zone_blocks) || + (c.ndevs > 1 && + c.devices[1].start_blkaddr % c.zone_blocks))) { + MSG(1, "\tError: Unaligned segment0 block address %u\n", + get_sb(segment0_blkaddr)); + return -1; + } + + for (i = 0; i < c.ndevs; i++) { + if (i == 0) { + c.devices[i].total_segments = + ((c.devices[i].total_sectors * + c.sector_size - zone_align_start_offset) / + segment_size_bytes) / c.segs_per_zone * + c.segs_per_zone; + c.devices[i].start_blkaddr = 0; + c.devices[i].end_blkaddr = c.devices[i].total_segments * + c.blks_per_seg - 1 + + sb->segment0_blkaddr; + } else { + c.devices[i].total_segments = + (c.devices[i].total_sectors / + (c.sectors_per_blk * c.blks_per_seg)) / + c.segs_per_zone * c.segs_per_zone; + c.devices[i].start_blkaddr = + c.devices[i - 1].end_blkaddr + 1; + c.devices[i].end_blkaddr = c.devices[i].start_blkaddr + + c.devices[i].total_segments * + c.blks_per_seg - 1; + if (device_is_aliased(i)) { + if (c.devices[i].zoned_model == + F2FS_ZONED_HM) { + MSG(1, "\tError: do not support " + "device aliasing for device[%d]\n", i); + return -1; + } + c.aliased_segments += + c.devices[i].total_segments; + } + } + if (c.ndevs > 1) { + strncpy((char *)sb->devs[i].path, c.devices[i].path, MAX_PATH_LEN); + sb->devs[i].total_segments = + cpu_to_le32(c.devices[i].total_segments); + } + + c.total_segments += c.devices[i].total_segments; + } + set_sb(segment_count, c.total_segments); + set_sb(segment_count_ckpt, F2FS_NUMBER_OF_CHECKPOINT_PACK); + + set_sb(sit_blkaddr, get_sb(segment0_blkaddr) + + get_sb(segment_count_ckpt) * c.blks_per_seg); + + blocks_for_sit = SIZE_ALIGN(get_sb(segment_count), SIT_ENTRY_PER_BLOCK); + + sit_segments = SEG_ALIGN(blocks_for_sit); + + set_sb(segment_count_sit, sit_segments * 2); + + set_sb(nat_blkaddr, get_sb(sit_blkaddr) + get_sb(segment_count_sit) * + c.blks_per_seg); + + total_valid_blks_available = (get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit))) * c.blks_per_seg; + + blocks_for_nat = SIZE_ALIGN(total_valid_blks_available, + NAT_ENTRY_PER_BLOCK); + + if (c.large_nat_bitmap) { + nat_segments = SEG_ALIGN(blocks_for_nat) * + DEFAULT_NAT_ENTRY_RATIO / 100; + set_sb(segment_count_nat, nat_segments ? nat_segments : 1); + max_nat_bitmap_size = (get_sb(segment_count_nat) << + log_blks_per_seg) / 8; + set_sb(segment_count_nat, get_sb(segment_count_nat) * 2); + } else { + set_sb(segment_count_nat, SEG_ALIGN(blocks_for_nat)); + max_nat_bitmap_size = 0; + } + + /* + * The number of node segments should not be exceeded a "Threshold". + * This number resizes NAT bitmap area in a CP page. + * So the threshold is determined not to overflow one CP page + */ + sit_bitmap_size = ((get_sb(segment_count_sit) / 2) << + log_blks_per_seg) / 8; + + if (sit_bitmap_size > MAX_SIT_BITMAP_SIZE) + max_sit_bitmap_size = MAX_SIT_BITMAP_SIZE; + else + max_sit_bitmap_size = sit_bitmap_size; + + if (c.large_nat_bitmap) { + /* use cp_payload if free space of f2fs_checkpoint is not enough */ + if (max_sit_bitmap_size + max_nat_bitmap_size > + MAX_BITMAP_SIZE_IN_CKPT) { + uint32_t diff = max_sit_bitmap_size + + max_nat_bitmap_size - + MAX_BITMAP_SIZE_IN_CKPT; + set_sb(cp_payload, F2FS_BLK_ALIGN(diff)); + } else { + set_sb(cp_payload, 0); + } + } else { + /* + * It should be reserved minimum 1 segment for nat. + * When sit is too large, we should expand cp area. + * It requires more pages for cp. + */ + if (max_sit_bitmap_size > MAX_SIT_BITMAP_SIZE_IN_CKPT) { + max_nat_bitmap_size = MAX_BITMAP_SIZE_IN_CKPT; + set_sb(cp_payload, F2FS_BLK_ALIGN(max_sit_bitmap_size)); + } else { + max_nat_bitmap_size = MAX_BITMAP_SIZE_IN_CKPT - + max_sit_bitmap_size; + set_sb(cp_payload, 0); + } + max_nat_segments = (max_nat_bitmap_size * 8) >> log_blks_per_seg; + + if (get_sb(segment_count_nat) > max_nat_segments) + set_sb(segment_count_nat, max_nat_segments); + + set_sb(segment_count_nat, get_sb(segment_count_nat) * 2); + } + + set_sb(ssa_blkaddr, get_sb(nat_blkaddr) + get_sb(segment_count_nat) * + c.blks_per_seg); + + total_valid_blks_available = (get_sb(segment_count) - + (get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat))) * + c.blks_per_seg; + + if (c.feature & F2FS_FEATURE_RO) + blocks_for_ssa = 0; + else + blocks_for_ssa = total_valid_blks_available / + c.blks_per_seg + 1; + + set_sb(segment_count_ssa, SEG_ALIGN(blocks_for_ssa)); + + total_meta_segments = get_sb(segment_count_ckpt) + + get_sb(segment_count_sit) + + get_sb(segment_count_nat) + + get_sb(segment_count_ssa); + diff = total_meta_segments % (c.segs_per_zone); + if (diff) + set_sb(segment_count_ssa, get_sb(segment_count_ssa) + + (c.segs_per_zone - diff)); + + total_meta_zones = ZONE_ALIGN(total_meta_segments * + c.blks_per_seg); + + set_sb(main_blkaddr, get_sb(segment0_blkaddr) + total_meta_zones * + c.segs_per_zone * c.blks_per_seg); + + if (c.zoned_mode) { + /* + * Make sure there is enough randomly writeable + * space at the beginning of the disk. + */ + unsigned long main_blkzone = get_sb(main_blkaddr) / c.zone_blocks; + + if (c.devices[0].zoned_model == F2FS_ZONED_HM && + c.devices[0].nr_rnd_zones < main_blkzone) { + MSG(0, "\tError: Device does not have enough random " + "write zones for F2FS volume (%lu needed)\n", + main_blkzone); + return -1; + } + /* + * Check if conventional device has enough space + * to accommodate all metadata, zoned device should + * not overlap to metadata area. + */ + for (i = 1; i < c.ndevs; i++) { + if (c.devices[i].zoned_model != F2FS_ZONED_NONE && + c.devices[i].start_blkaddr < get_sb(main_blkaddr)) { + MSG(0, "\tError: Conventional device %s is too small," + " (%"PRIu64" MiB needed).\n", c.devices[0].path, + (get_sb(main_blkaddr) - + c.devices[i].start_blkaddr) >> 8); + return -1; + } + } + } + + total_zones = get_sb(segment_count) / (c.segs_per_zone) - + total_meta_zones; + if (total_zones == 0) + goto too_small; + set_sb(section_count, total_zones * c.secs_per_zone); + + set_sb(segment_count_main, get_sb(section_count) * c.segs_per_sec); + + /* + * Let's determine the best reserved and overprovisioned space. + * For Zoned device, if zone capacity less than zone size, the segments + * starting after the zone capacity are unusable in each zone. So get + * overprovision ratio and reserved seg count based on avg usable + * segs_per_sec. + */ + if (c.overprovision == 0) + c.overprovision = get_best_overprovision(sb); + + c.reserved_segments = get_reserved(sb, c.overprovision); + + if (c.feature & F2FS_FEATURE_RO) { + c.overprovision = 0; + c.reserved_segments = 0; + } + if ((!(c.feature & F2FS_FEATURE_RO) && + c.overprovision == 0) || + c.total_segments < F2FS_MIN_SEGMENTS || + (c.devices[0].total_sectors * + c.sector_size < zone_align_start_offset) || + (get_sb(segment_count_main) - NR_CURSEG_TYPE) < + c.reserved_segments) { + goto too_small; + } + + if (c.vol_uuid) { + if (uuid_parse(c.vol_uuid, sb->uuid)) { + MSG(0, "\tError: supplied string is not a valid UUID\n"); + return -1; + } + } else { + uuid_generate(sb->uuid); + } + + /* precompute checksum seed for metadata */ + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) + c.chksum_seed = f2fs_cal_crc32(~0, sb->uuid, sizeof(sb->uuid)); + + utf8_to_utf16((char *)sb->volume_name, (const char *)c.vol_label, + MAX_VOLUME_NAME, strlen(c.vol_label)); + set_sb(node_ino, 1); + set_sb(meta_ino, 2); + set_sb(root_ino, 3); + c.next_free_nid = 4; + + for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { + if (!((1 << qtype) & c.quota_bits)) + continue; + sb->qf_ino[qtype] = cpu_to_le32(c.next_free_nid++); + MSG(0, "Info: add quota type = %u => %u\n", + qtype, c.next_free_nid - 1); + } + + if (c.feature & F2FS_FEATURE_LOST_FOUND) + c.lpf_ino = c.next_free_nid++; + + if (c.aliased_devices) { + c.first_alias_ino = c.next_free_nid; + c.next_free_nid += c.aliased_devices; + avail_zones += c.aliased_segments / c.segs_per_zone; + } + + if (c.feature & F2FS_FEATURE_RO) + avail_zones += 2; + else + avail_zones += 6; + + if (total_zones <= avail_zones) { + MSG(1, "\tError: %d zones: Need more zones " + "by shrinking zone size\n", total_zones); + return -1; + } + + if (c.feature & F2FS_FEATURE_RO) { + c.cur_seg[CURSEG_HOT_NODE] = last_section(last_zone(total_zones)); + c.cur_seg[CURSEG_WARM_NODE] = 0; + c.cur_seg[CURSEG_COLD_NODE] = 0; + c.cur_seg[CURSEG_HOT_DATA] = 0; + c.cur_seg[CURSEG_COLD_DATA] = 0; + c.cur_seg[CURSEG_WARM_DATA] = 0; + } else if (c.zoned_mode) { + c.cur_seg[CURSEG_HOT_NODE] = 0; + if (c.zoned_model == F2FS_ZONED_HM) { + uint32_t conv_zones = + c.devices[0].total_segments / c.segs_per_zone + - total_meta_zones; + + if (total_zones - conv_zones >= avail_zones) + c.cur_seg[CURSEG_HOT_NODE] = + (c.devices[1].start_blkaddr - + get_sb(main_blkaddr)) / c.blks_per_seg; + } + c.cur_seg[CURSEG_WARM_NODE] = next_zone(CURSEG_HOT_NODE); + c.cur_seg[CURSEG_COLD_NODE] = next_zone(CURSEG_WARM_NODE); + c.cur_seg[CURSEG_HOT_DATA] = next_zone(CURSEG_COLD_NODE); + c.cur_seg[CURSEG_WARM_DATA] = next_zone(CURSEG_HOT_DATA); + c.cur_seg[CURSEG_COLD_DATA] = next_zone(CURSEG_WARM_DATA); + } else { + c.cur_seg[CURSEG_HOT_NODE] = 0; + c.cur_seg[CURSEG_WARM_NODE] = next_zone(CURSEG_HOT_NODE); + c.cur_seg[CURSEG_COLD_NODE] = next_zone(CURSEG_WARM_NODE); + c.cur_seg[CURSEG_HOT_DATA] = next_zone(CURSEG_COLD_NODE); + c.cur_seg[CURSEG_COLD_DATA] = + max(last_zone((total_zones >> 2)), + next_zone(CURSEG_HOT_DATA)); + c.cur_seg[CURSEG_WARM_DATA] = + max(last_zone((total_zones >> 1)), + next_zone(CURSEG_COLD_DATA)); + } + + /* if there is redundancy, reassign it */ + if (!(c.feature & F2FS_FEATURE_RO)) + verify_cur_segs(); + + cure_extension_list(); + + /* get kernel version */ + if (c.kd >= 0) { + dev_read_version(c.version, 0, VERSION_LEN); + get_kernel_version(c.version); + } else { + get_kernel_uname_version(c.version); + } + MSG(0, "Info: format version with\n \"%s\"\n", c.version); + + memcpy(sb->version, c.version, VERSION_LEN); + memcpy(sb->init_version, c.version, VERSION_LEN); + + if (c.feature & F2FS_FEATURE_CASEFOLD) { + set_sb(s_encoding, c.s_encoding); + set_sb(s_encoding_flags, c.s_encoding_flags); + } + + sb->feature = cpu_to_le32(c.feature); + + if (c.feature & F2FS_FEATURE_SB_CHKSUM) { + set_sb(checksum_offset, SB_CHKSUM_OFFSET); + set_sb(crc, f2fs_cal_crc32(F2FS_SUPER_MAGIC, sb, + SB_CHKSUM_OFFSET)); + MSG(1, "Info: SB CRC is set: offset (%d), crc (0x%x)\n", + get_sb(checksum_offset), get_sb(crc)); + } + + return 0; + +too_small: + MSG(0, "\tError: Device size is not sufficient for F2FS volume\n"); + return -1; +} + +static int f2fs_init_sit_area(void) +{ + uint32_t blk_size, seg_size; + uint32_t index = 0; + uint64_t sit_seg_addr = 0; + uint8_t *zero_buf = NULL; + + blk_size = 1 << get_sb(log_blocksize); + seg_size = (1 << get_sb(log_blocks_per_seg)) * blk_size; + + zero_buf = calloc(sizeof(uint8_t), seg_size); + if(zero_buf == NULL) { + MSG(1, "\tError: Calloc Failed for sit_zero_buf!!!\n"); + return -1; + } + + sit_seg_addr = get_sb(sit_blkaddr); + sit_seg_addr *= blk_size; + + DBG(1, "\tFilling sit area at offset 0x%08"PRIx64"\n", sit_seg_addr); + for (index = 0; index < (get_sb(segment_count_sit) / 2); index++) { + if (dev_fill(zero_buf, sit_seg_addr, seg_size, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While zeroing out the sit area " + "on disk!!!\n"); + free(zero_buf); + return -1; + } + sit_seg_addr += seg_size; + } + + free(zero_buf); + return 0 ; +} + +static int f2fs_init_nat_area(void) +{ + uint32_t blk_size, seg_size; + uint32_t index = 0; + uint64_t nat_seg_addr = 0; + uint8_t *nat_buf = NULL; + + blk_size = 1 << get_sb(log_blocksize); + seg_size = (1 << get_sb(log_blocks_per_seg)) * blk_size; + + nat_buf = calloc(sizeof(uint8_t), seg_size); + if (nat_buf == NULL) { + MSG(1, "\tError: Calloc Failed for nat_zero_blk!!!\n"); + return -1; + } + + nat_seg_addr = get_sb(nat_blkaddr); + nat_seg_addr *= blk_size; + + DBG(1, "\tFilling nat area at offset 0x%08"PRIx64"\n", nat_seg_addr); + for (index = 0; index < get_sb(segment_count_nat) / 2; index++) { + if (dev_fill(nat_buf, nat_seg_addr, seg_size, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While zeroing out the nat area " + "on disk!!!\n"); + free(nat_buf); + return -1; + } + nat_seg_addr = nat_seg_addr + (2 * seg_size); + } + + free(nat_buf); + return 0 ; +} + +static int f2fs_write_check_point_pack(void) +{ + struct f2fs_summary_block *sum; + struct f2fs_journal *journal; + uint32_t blk_size_bytes; + uint32_t nat_bits_bytes, nat_bits_blocks; + unsigned char *nat_bits = NULL, *empty_nat_bits; + uint64_t cp_seg_blk = 0; + uint32_t crc = 0, flags; + unsigned int i; + char *cp_payload = NULL; + char *sum_compact, *sum_compact_p; + struct f2fs_summary *sum_entry; + unsigned short vblocks; + uint32_t used_segments = c.aliased_segments; + int ret = -1; + + cp = calloc(F2FS_BLKSIZE, 1); + if (cp == NULL) { + MSG(1, "\tError: Calloc failed for f2fs_checkpoint!!!\n"); + return ret; + } + + sum = calloc(F2FS_BLKSIZE, 1); + if (sum == NULL) { + MSG(1, "\tError: Calloc failed for summary_node!!!\n"); + goto free_cp; + } + + sum_compact = calloc(F2FS_BLKSIZE, 1); + if (sum_compact == NULL) { + MSG(1, "\tError: Calloc failed for summary buffer!!!\n"); + goto free_sum; + } + sum_compact_p = sum_compact; + + nat_bits_bytes = get_sb(segment_count_nat) << 5; + nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + + F2FS_BLKSIZE - 1); + nat_bits = calloc(F2FS_BLKSIZE, nat_bits_blocks); + if (nat_bits == NULL) { + MSG(1, "\tError: Calloc failed for nat bits buffer!!!\n"); + goto free_sum_compact; + } + + cp_payload = calloc(F2FS_BLKSIZE, 1); + if (cp_payload == NULL) { + MSG(1, "\tError: Calloc failed for cp_payload!!!\n"); + goto free_nat_bits; + } + + /* 1. cp page 1 of checkpoint pack 1 */ + srand((c.fake_seed) ? 0 : time(NULL)); + cp->checkpoint_ver = cpu_to_le64(rand() | 0x1); + set_cp(cur_node_segno[0], c.cur_seg[CURSEG_HOT_NODE]); + set_cp(cur_node_segno[1], c.cur_seg[CURSEG_WARM_NODE]); + set_cp(cur_node_segno[2], c.cur_seg[CURSEG_COLD_NODE]); + set_cp(cur_data_segno[0], c.cur_seg[CURSEG_HOT_DATA]); + set_cp(cur_data_segno[1], c.cur_seg[CURSEG_WARM_DATA]); + set_cp(cur_data_segno[2], c.cur_seg[CURSEG_COLD_DATA]); + for (i = 3; i < MAX_ACTIVE_NODE_LOGS; i++) { + set_cp(cur_node_segno[i], 0xffffffff); + set_cp(cur_data_segno[i], 0xffffffff); + } + + set_cp(cur_node_blkoff[0], c.curseg_offset[CURSEG_HOT_NODE]); + set_cp(cur_node_blkoff[2], c.curseg_offset[CURSEG_COLD_NODE]); + set_cp(cur_data_blkoff[0], c.curseg_offset[CURSEG_HOT_DATA]); + set_cp(cur_data_blkoff[2], c.curseg_offset[CURSEG_COLD_DATA]); + set_cp(valid_block_count, c.curseg_offset[CURSEG_HOT_NODE] + + c.curseg_offset[CURSEG_HOT_DATA] + + c.curseg_offset[CURSEG_COLD_NODE] + + c.curseg_offset[CURSEG_COLD_DATA] + + c.aliased_segments * c.blks_per_seg); + set_cp(rsvd_segment_count, c.reserved_segments); + + /* + * For zoned devices, if zone capacity less than zone size, get + * overprovision segment count based on usable segments in the device. + */ + set_cp(overprov_segment_count, (f2fs_get_usable_segments(sb) - + get_cp(rsvd_segment_count)) * + c.overprovision / 100); + + /* + * If conf_reserved_sections has a non zero value, overprov_segment_count + * is set to overprov_segment_count + rsvd_segment_count. + */ + if (c.conf_reserved_sections) { + /* + * Overprovision segments must be bigger than two sections. + * In non configurable reserved section case, overprovision + * segments are always bigger than two sections. + */ + if (get_cp(overprov_segment_count) < + overprovision_segment_buffer(sb)) { + MSG(0, "\tError: Not enough overprovision segments (%u)\n", + get_cp(overprov_segment_count)); + goto free_cp_payload; + } + set_cp(overprov_segment_count, get_cp(overprov_segment_count) + + get_cp(rsvd_segment_count)); + } else { + /* + * overprov_segment_count must bigger than rsvd_segment_count. + */ + set_cp(overprov_segment_count, max(get_cp(rsvd_segment_count), + get_cp(overprov_segment_count)) + overprovision_segment_buffer(sb)); + } + + if (f2fs_get_usable_segments(sb) <= get_cp(overprov_segment_count)) { + MSG(0, "\tError: Not enough segments to create F2FS Volume\n"); + goto free_cp_payload; + } + MSG(0, "Info: Overprovision ratio = %.3lf%%\n", c.overprovision); + MSG(0, "Info: Overprovision segments = %u (GC reserved = %u)\n", + get_cp(overprov_segment_count), + c.reserved_segments); + + /* main segments - reserved segments - (node + data segments) */ + if (c.feature & F2FS_FEATURE_RO) + used_segments += 2; + else + used_segments += 6; + + set_cp(user_block_count, (f2fs_get_usable_segments(sb) - + get_cp(overprov_segment_count)) * c.blks_per_seg); + set_cp(free_segment_count, f2fs_get_usable_segments(sb) - + used_segments); + + /* cp page (2), data summaries (1), node summaries (3) */ + set_cp(cp_pack_total_block_count, 6 + get_sb(cp_payload)); + flags = CP_UMOUNT_FLAG | CP_COMPACT_SUM_FLAG; + if (!(c.disabled_feature & F2FS_FEATURE_NAT_BITS) && + get_cp(cp_pack_total_block_count) <= + (1 << get_sb(log_blocks_per_seg)) - nat_bits_blocks) + flags |= CP_NAT_BITS_FLAG; + + if (c.trimmed) + flags |= CP_TRIMMED_FLAG; + + if (c.large_nat_bitmap) + flags |= CP_LARGE_NAT_BITMAP_FLAG; + + set_cp(ckpt_flags, flags); + set_cp(cp_pack_start_sum, 1 + get_sb(cp_payload)); + set_cp(valid_node_count, c.curseg_offset[CURSEG_HOT_NODE] + + c.curseg_offset[CURSEG_COLD_NODE]); + set_cp(valid_inode_count, c.curseg_offset[CURSEG_HOT_NODE] + + c.curseg_offset[CURSEG_COLD_NODE]); + set_cp(next_free_nid, c.next_free_nid); + set_cp(sit_ver_bitmap_bytesize, ((get_sb(segment_count_sit) / 2) << + get_sb(log_blocks_per_seg)) / 8); + + set_cp(nat_ver_bitmap_bytesize, ((get_sb(segment_count_nat) / 2) << + get_sb(log_blocks_per_seg)) / 8); + + if (c.large_nat_bitmap) + set_cp(checksum_offset, CP_MIN_CHKSUM_OFFSET); + else + set_cp(checksum_offset, CP_CHKSUM_OFFSET); + + crc = f2fs_checkpoint_chksum(cp); + *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + + blk_size_bytes = 1 << get_sb(log_blocksize); + + if (blk_size_bytes != F2FS_BLKSIZE) { + MSG(1, "\tError: Wrong block size %d / %d!!!\n", + blk_size_bytes, F2FS_BLKSIZE); + goto free_cp_payload; + } + + cp_seg_blk = get_sb(segment0_blkaddr); + + DBG(1, "\tWriting main segments, cp at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(cp, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the cp to disk!!!\n"); + goto free_cp_payload; + } + + for (i = 0; i < get_sb(cp_payload); i++) { + cp_seg_blk++; + if (dev_fill_block(cp_payload, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While zeroing out the sit bitmap area " + "on disk!!!\n"); + goto free_cp_payload; + } + } + + /* Prepare and write Segment summary for HOT/WARM/COLD DATA + * + * The structure of compact summary + * +-------------------+ + * | nat_journal | + * +-------------------+ + * | sit_journal | + * +-------------------+ + * | hot data summary | + * +-------------------+ + * | warm data summary | + * +-------------------+ + * | cold data summary | + * +-------------------+ + */ + + /* nat_sjournal */ + journal = &c.nat_jnl; + memcpy(sum_compact_p, &journal->n_nats, SUM_JOURNAL_SIZE); + sum_compact_p += SUM_JOURNAL_SIZE; + + /* sit_journal */ + journal = &c.sit_jnl; + + if (c.feature & F2FS_FEATURE_RO) { + i = CURSEG_RO_HOT_DATA; + vblocks = le16_to_cpu(journal->sit_j.entries[i].se.vblocks); + journal->sit_j.entries[i].segno = cp->cur_data_segno[0]; + journal->sit_j.entries[i].se.vblocks = + cpu_to_le16(vblocks | (CURSEG_HOT_DATA << 10)); + + i = CURSEG_RO_HOT_NODE; + vblocks = le16_to_cpu(journal->sit_j.entries[i].se.vblocks); + journal->sit_j.entries[i].segno = cp->cur_node_segno[0]; + journal->sit_j.entries[i].se.vblocks |= + cpu_to_le16(vblocks | (CURSEG_HOT_NODE << 10)); + + journal->n_sits = cpu_to_le16(2); + } else { + for (i = CURSEG_HOT_DATA; i < NR_CURSEG_TYPE; i++) { + if (i < NR_CURSEG_DATA_TYPE) + journal->sit_j.entries[i].segno = + cp->cur_data_segno[i]; + + else + journal->sit_j.entries[i].segno = + cp->cur_node_segno[i - NR_CURSEG_DATA_TYPE]; + + vblocks = + le16_to_cpu(journal->sit_j.entries[i].se.vblocks); + journal->sit_j.entries[i].se.vblocks = + cpu_to_le16(vblocks | (i << 10)); + } + + journal->n_sits = cpu_to_le16(6); + } + + memcpy(sum_compact_p, &journal->n_sits, SUM_JOURNAL_SIZE); + sum_compact_p += SUM_JOURNAL_SIZE; + + SET_SUM_TYPE((struct f2fs_summary_block *)sum_compact, SUM_TYPE_DATA); + + /* hot data summary */ + sum_entry = (struct f2fs_summary *)sum_compact_p; + memcpy(sum_entry, c.sum[CURSEG_HOT_DATA], + sizeof(struct f2fs_summary) * MAX_CACHE_SUMS); + + /* warm data summary, nothing to do */ + /* cold data summary, nothing to do */ + + cp_seg_blk++; + DBG(1, "\tWriting Segment summary for HOT/WARM/COLD_DATA, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(sum_compact, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); + goto free_cp_payload; + } + + /* Prepare and write Segment summary for HOT_NODE */ + memset(sum, 0, F2FS_BLKSIZE); + SET_SUM_TYPE(sum, SUM_TYPE_NODE); + memcpy(sum->entries, c.sum[CURSEG_HOT_NODE], + sizeof(struct f2fs_summary) * MAX_CACHE_SUMS); + + cp_seg_blk++; + DBG(1, "\tWriting Segment summary for HOT_NODE, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(sum, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); + goto free_cp_payload; + } + + /* Fill segment summary for WARM_NODE to zero. */ + memset(sum, 0, F2FS_BLKSIZE); + SET_SUM_TYPE(sum, SUM_TYPE_NODE); + + cp_seg_blk++; + DBG(1, "\tWriting Segment summary for WARM_NODE, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(sum, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); + goto free_cp_payload; + } + + /* Prepare and write Segment summary for COLD_NODE */ + memset(sum, 0, F2FS_BLKSIZE); + SET_SUM_TYPE(sum, SUM_TYPE_NODE); + memcpy(sum->entries, c.sum[CURSEG_COLD_NODE], + sizeof(struct f2fs_summary) * MAX_CACHE_SUMS); + + cp_seg_blk++; + DBG(1, "\tWriting Segment summary for COLD_NODE, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(sum, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the sum_blk to disk!!!\n"); + goto free_cp_payload; + } + + /* cp page2 */ + cp_seg_blk++; + DBG(1, "\tWriting cp page2, at offset 0x%08"PRIx64"\n", cp_seg_blk); + if (dev_write_block(cp, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the cp to disk!!!\n"); + goto free_cp_payload; + } + + /* write NAT bits, if possible */ + if (flags & CP_NAT_BITS_FLAG) { + uint32_t i; + + *(__le64 *)nat_bits = get_cp_crc(cp); + empty_nat_bits = nat_bits + 8 + nat_bits_bytes; + memset(empty_nat_bits, 0xff, nat_bits_bytes); + test_and_clear_bit_le(0, empty_nat_bits); + + /* write the last blocks in cp pack */ + cp_seg_blk = get_sb(segment0_blkaddr) + (1 << + get_sb(log_blocks_per_seg)) - nat_bits_blocks; + + DBG(1, "\tWriting NAT bits pages, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + + for (i = 0; i < nat_bits_blocks; i++) { + if (dev_write_block(nat_bits + i * + F2FS_BLKSIZE, cp_seg_blk + i, + WRITE_LIFE_NONE)) { + MSG(1, "\tError: write NAT bits to disk!!!\n"); + goto free_cp_payload; + } + } + } + + /* cp page 1 of check point pack 2 + * Initialize other checkpoint pack with version zero + */ + cp->checkpoint_ver = 0; + + crc = f2fs_checkpoint_chksum(cp); + *((__le32 *)((unsigned char *)cp + get_cp(checksum_offset))) = + cpu_to_le32(crc); + cp_seg_blk = get_sb(segment0_blkaddr) + c.blks_per_seg; + DBG(1, "\tWriting cp page 1 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(cp, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the cp to disk!!!\n"); + goto free_cp_payload; + } + + for (i = 0; i < get_sb(cp_payload); i++) { + cp_seg_blk++; + if (dev_fill_block(cp_payload, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While zeroing out the sit bitmap area " + "on disk!!!\n"); + goto free_cp_payload; + } + } + + /* cp page 2 of check point pack 2 */ + cp_seg_blk += (le32_to_cpu(cp->cp_pack_total_block_count) - + get_sb(cp_payload) - 1); + DBG(1, "\tWriting cp page 2 of checkpoint pack 2, at offset 0x%08"PRIx64"\n", + cp_seg_blk); + if (dev_write_block(cp, cp_seg_blk, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the cp to disk!!!\n"); + goto free_cp_payload; + } + + ret = 0; + +free_cp_payload: + free(cp_payload); +free_nat_bits: + free(nat_bits); +free_sum_compact: + free(sum_compact); +free_sum: + free(sum); +free_cp: + free(cp); + return ret; +} + +static int f2fs_write_super_block(void) +{ + int index; + uint8_t *zero_buff; + + zero_buff = calloc(F2FS_BLKSIZE, 1); + if (zero_buff == NULL) { + MSG(1, "\tError: Calloc Failed for super_blk_zero_buf!!!\n"); + return -1; + } + + memcpy(zero_buff + F2FS_SUPER_OFFSET, sb, sizeof(*sb)); + DBG(1, "\tWriting super block, at offset 0x%08x\n", 0); + for (index = 0; index < 2; index++) { + if (dev_write_block(zero_buff, index, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While while writing super_blk " + "on disk!!! index : %d\n", index); + free(zero_buff); + return -1; + } + } + + free(zero_buff); + return 0; +} + +#ifndef WITH_ANDROID +static int f2fs_discard_obsolete_dnode(void) +{ + struct f2fs_node *raw_node; + uint64_t next_blkaddr = 0, offset; + u64 end_blkaddr = (get_sb(segment_count_main) << + get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr); + uint64_t start_inode_pos = get_sb(main_blkaddr); + uint64_t last_inode_pos; + + if (c.zoned_mode || c.feature & F2FS_FEATURE_RO) + return 0; + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for discard_raw_node!!!\n"); + return -1; + } + + /* avoid power-off-recovery based on roll-forward policy */ + offset = get_sb(main_blkaddr); + offset += c.cur_seg[CURSEG_WARM_NODE] * c.blks_per_seg; + + last_inode_pos = start_inode_pos + + c.cur_seg[CURSEG_HOT_NODE] * c.blks_per_seg + + c.curseg_offset[CURSEG_COLD_NODE] - 1; + + do { + if (offset < get_sb(main_blkaddr) || offset >= end_blkaddr) + break; + + if (dev_read_block(raw_node, offset)) { + MSG(1, "\tError: While traversing direct node!!!\n"); + free(raw_node); + return -1; + } + + next_blkaddr = le32_to_cpu(F2FS_NODE_FOOTER(raw_node)->next_blkaddr); + memset(raw_node, 0, F2FS_BLKSIZE); + + DBG(1, "\tDiscard dnode, at offset 0x%08"PRIx64"\n", offset); + if (dev_write_block(raw_node, offset, + f2fs_io_type_to_rw_hint(CURSEG_WARM_NODE))) { + MSG(1, "\tError: While discarding direct node!!!\n"); + free(raw_node); + return -1; + } + offset = next_blkaddr; + /* should avoid recursive chain due to stale data */ + if (offset >= start_inode_pos || offset <= last_inode_pos) + break; + } while (1); + + free(raw_node); + return 0; +} +#endif + +static block_t alloc_next_free_block(int curseg_type) +{ + block_t blkaddr; + + blkaddr = get_sb(main_blkaddr) + + c.cur_seg[curseg_type] * c.blks_per_seg + + c.curseg_offset[curseg_type]; + + c.curseg_offset[curseg_type]++; + + return blkaddr; +} + +void update_sit_journal(int curseg_type) +{ + struct f2fs_journal *sit_jnl = &c.sit_jnl; + unsigned short vblocks; + int idx = curseg_type; + + if (c.feature & F2FS_FEATURE_RO) { + if (curseg_type < NR_CURSEG_DATA_TYPE) + idx = CURSEG_RO_HOT_DATA; + else + idx = CURSEG_RO_HOT_NODE; + } + + f2fs_set_bit(c.curseg_offset[curseg_type] - 1, + (char *)sit_jnl->sit_j.entries[idx].se.valid_map); + + vblocks = le16_to_cpu(sit_jnl->sit_j.entries[idx].se.vblocks); + sit_jnl->sit_j.entries[idx].se.vblocks = cpu_to_le16(vblocks + 1); +} + +void update_nat_journal(nid_t nid, block_t blkaddr) +{ + struct f2fs_journal *nat_jnl = &c.nat_jnl; + unsigned short n_nats = le16_to_cpu(nat_jnl->n_nats); + + nat_jnl->nat_j.entries[n_nats].nid = cpu_to_le32(nid); + nat_jnl->nat_j.entries[n_nats].ne.version = 0; + nat_jnl->nat_j.entries[n_nats].ne.ino = cpu_to_le32(nid); + nat_jnl->nat_j.entries[n_nats].ne.block_addr = cpu_to_le32(blkaddr); + nat_jnl->n_nats = cpu_to_le16(n_nats + 1); +} + +void update_summary_entry(int curseg_type, nid_t nid, + unsigned short ofs_in_node) +{ + struct f2fs_summary *sum; + unsigned int curofs = c.curseg_offset[curseg_type] - 1; + + assert(curofs < MAX_CACHE_SUMS); + + sum = c.sum[curseg_type] + curofs; + sum->nid = cpu_to_le32(nid); + sum->ofs_in_node = cpu_to_le16(ofs_in_node); +} + +static void add_dentry(struct f2fs_dentry_block *dent_blk, unsigned int *didx, + const char *name, uint32_t ino, u8 type) +{ + int len = strlen(name); + f2fs_hash_t hash; + + if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) + hash = 0; + else + hash = f2fs_dentry_hash(0, 0, (unsigned char *)name, len); + + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, *didx).hash_code = cpu_to_le32(hash); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, *didx).ino = cpu_to_le32(ino); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, *didx).name_len = cpu_to_le16(len); + F2FS_DENTRY_BLOCK_DENTRY(dent_blk, *didx).file_type = type; + + while (len > F2FS_SLOT_LEN) { + memcpy(F2FS_DENTRY_BLOCK_FILENAME(dent_blk, *didx), name, + F2FS_SLOT_LEN); + test_and_set_bit_le(*didx, dent_blk->dentry_bitmap); + len -= (int)F2FS_SLOT_LEN; + name += F2FS_SLOT_LEN; + (*didx)++; + } + memcpy(F2FS_DENTRY_BLOCK_FILENAME(dent_blk, *didx), name, len); + test_and_set_bit_le(*didx, dent_blk->dentry_bitmap); + (*didx)++; +} + +static block_t f2fs_add_default_dentry_root(void) +{ + struct f2fs_dentry_block *dent_blk = NULL; + block_t data_blkaddr; + unsigned int didx = 0; + + dent_blk = calloc(F2FS_BLKSIZE, 1); + if(dent_blk == NULL) { + MSG(1, "\tError: Calloc Failed for dent_blk!!!\n"); + return 0; + } + + add_dentry(dent_blk, &didx, ".", + le32_to_cpu(sb->root_ino), F2FS_FT_DIR); + add_dentry(dent_blk, &didx, "..", + le32_to_cpu(sb->root_ino), F2FS_FT_DIR); + + if (c.lpf_ino) + add_dentry(dent_blk, &didx, LPF, c.lpf_ino, F2FS_FT_DIR); + + if (c.aliased_devices) { + int i, dev_off = 0; + + for (i = 1; i < c.ndevs; i++) { + if (!device_is_aliased(i)) + continue; + + add_dentry(dent_blk, &didx, c.devices[i].alias_filename, + c.first_alias_ino + dev_off, + F2FS_FT_REG_FILE); + dev_off++; + } + } + + data_blkaddr = alloc_next_free_block(CURSEG_HOT_DATA); + + DBG(1, "\tWriting default dentry root, at offset 0x%x\n", data_blkaddr); + if (dev_write_block(dent_blk, data_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA))) { + MSG(1, "\tError: While writing the dentry_blk to disk!!!\n"); + free(dent_blk); + return 0; + } + + update_sit_journal(CURSEG_HOT_DATA); + update_summary_entry(CURSEG_HOT_DATA, le32_to_cpu(sb->root_ino), 0); + + free(dent_blk); + return data_blkaddr; +} + +static int f2fs_write_root_inode(void) +{ + struct f2fs_node *raw_node = NULL; + block_t data_blkaddr; + block_t node_blkaddr; + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); + return -1; + } + + f2fs_init_inode(sb, raw_node, le32_to_cpu(sb->root_ino), + mkfs_time, 0x41ed); + + if (c.lpf_ino) + raw_node->i.i_links = cpu_to_le32(3); + + data_blkaddr = f2fs_add_default_dentry_root(); + if (data_blkaddr == 0) { + MSG(1, "\tError: Failed to add default dentries for root!!!\n"); + free(raw_node); + return -1; + } + + raw_node->i.i_addr[get_extra_isize(raw_node)] = + cpu_to_le32(data_blkaddr); + + node_blkaddr = alloc_next_free_block(CURSEG_HOT_NODE); + F2FS_NODE_FOOTER(raw_node)->next_blkaddr = cpu_to_le32(node_blkaddr + 1); + + DBG(1, "\tWriting root inode (hot node), offset 0x%x\n", node_blkaddr); + if (write_inode(raw_node, node_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_NODE)) < 0) { + MSG(1, "\tError: While writing the raw_node to disk!!!\n"); + free(raw_node); + return -1; + } + + update_nat_journal(le32_to_cpu(sb->root_ino), node_blkaddr); + update_sit_journal(CURSEG_HOT_NODE); + update_summary_entry(CURSEG_HOT_NODE, le32_to_cpu(sb->root_ino), 0); + + free(raw_node); + return 0; +} + +static int f2fs_write_default_quota(int qtype, __le32 raw_id) +{ + char *filebuf = calloc(F2FS_BLKSIZE, 2); + int file_magics[] = INITQMAGICS; + struct v2_disk_dqheader ddqheader; + struct v2_disk_dqinfo ddqinfo; + struct v2r1_disk_dqblk dqblk; + block_t blkaddr; + uint64_t icnt = 1, bcnt = 1; + int i; + + if (filebuf == NULL) { + MSG(1, "\tError: Calloc Failed for filebuf!!!\n"); + return 0; + } + + /* Write basic quota header */ + ddqheader.dqh_magic = cpu_to_le32(file_magics[qtype]); + /* only support QF_VFSV1 */ + ddqheader.dqh_version = cpu_to_le32(1); + + memcpy(filebuf, &ddqheader, sizeof(ddqheader)); + + /* Fill Initial quota file content */ + ddqinfo.dqi_bgrace = cpu_to_le32(MAX_DQ_TIME); + ddqinfo.dqi_igrace = cpu_to_le32(MAX_IQ_TIME); + ddqinfo.dqi_flags = cpu_to_le32(0); + ddqinfo.dqi_blocks = cpu_to_le32(QT_TREEOFF + 5); + ddqinfo.dqi_free_blk = cpu_to_le32(0); + ddqinfo.dqi_free_entry = cpu_to_le32(5); + + memcpy(filebuf + V2_DQINFOOFF, &ddqinfo, sizeof(ddqinfo)); + + filebuf[1024] = 2; + filebuf[2048] = 3; + filebuf[3072] = 4; + filebuf[4096] = 5; + + filebuf[5120 + 8] = 1; + + dqblk.dqb_id = raw_id; + dqblk.dqb_pad = cpu_to_le32(0); + dqblk.dqb_ihardlimit = cpu_to_le64(0); + dqblk.dqb_isoftlimit = cpu_to_le64(0); + if (c.lpf_ino) { + icnt++; + bcnt++; + } + if (c.aliased_devices) { + icnt += c.aliased_devices; + bcnt += c.aliased_segments * c.blks_per_seg; + } + dqblk.dqb_curinodes = cpu_to_le64(icnt); + dqblk.dqb_bhardlimit = cpu_to_le64(0); + dqblk.dqb_bsoftlimit = cpu_to_le64(0); + dqblk.dqb_curspace = cpu_to_le64(F2FS_BLKSIZE * bcnt); + dqblk.dqb_btime = cpu_to_le64(0); + dqblk.dqb_itime = cpu_to_le64(0); + + memcpy(filebuf + 5136, &dqblk, sizeof(struct v2r1_disk_dqblk)); + + /* Write quota blocks */ + for (i = 0; i < QUOTA_DATA; i++) { + blkaddr = alloc_next_free_block(CURSEG_HOT_DATA); + + if (dev_write_block(filebuf + i * F2FS_BLKSIZE, blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA))) { + MSG(1, "\tError: While writing the quota_blk to disk!!!\n"); + free(filebuf); + return 0; + } + + update_sit_journal(CURSEG_HOT_DATA); + update_summary_entry(CURSEG_HOT_DATA, + le32_to_cpu(sb->qf_ino[qtype]), i); + DBG(1, "\tWriting quota data, at offset %08x (%d/%d)\n", + blkaddr, i + 1, QUOTA_DATA); + + } + + free(filebuf); + return blkaddr + 1 - QUOTA_DATA; +} + +static int f2fs_write_qf_inode(int qtype) +{ + struct f2fs_node *raw_node = NULL; + block_t data_blkaddr; + block_t node_blkaddr; + __le32 raw_id; + int i; + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); + return -1; + } + f2fs_init_inode(sb, raw_node, + le32_to_cpu(sb->qf_ino[qtype]), mkfs_time, 0x8180); + + raw_node->i.i_size = cpu_to_le64(1024 * 6); + raw_node->i.i_blocks = cpu_to_le64(1 + QUOTA_DATA); + raw_node->i.i_flags = cpu_to_le32(F2FS_NOATIME_FL | F2FS_IMMUTABLE_FL); + + node_blkaddr = alloc_next_free_block(CURSEG_HOT_NODE); + F2FS_NODE_FOOTER(raw_node)->next_blkaddr = cpu_to_le32(node_blkaddr + 1); + + if (qtype == 0) + raw_id = raw_node->i.i_uid; + else if (qtype == 1) + raw_id = raw_node->i.i_gid; + else if (qtype == 2) + raw_id = raw_node->i.i_projid; + else + ASSERT(0); + + /* write quota blocks */ + data_blkaddr = f2fs_write_default_quota(qtype, raw_id); + if (data_blkaddr == 0) { + free(raw_node); + return -1; + } + + for (i = 0; i < QUOTA_DATA; i++) + raw_node->i.i_addr[get_extra_isize(raw_node) + i] = + cpu_to_le32(data_blkaddr + i); + + DBG(1, "\tWriting quota inode (hot node), offset 0x%x\n", node_blkaddr); + if (write_inode(raw_node, node_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_NODE)) < 0) { + MSG(1, "\tError: While writing the raw_node to disk!!!\n"); + free(raw_node); + return -1; + } + + update_nat_journal(le32_to_cpu(sb->qf_ino[qtype]), node_blkaddr); + update_sit_journal(CURSEG_HOT_NODE); + update_summary_entry(CURSEG_HOT_NODE, le32_to_cpu(sb->qf_ino[qtype]), 0); + + free(raw_node); + return 0; +} + +static int f2fs_update_nat_default(void) +{ + struct f2fs_nat_block *nat_blk = NULL; + uint64_t nat_seg_blk_offset = 0; + + nat_blk = calloc(F2FS_BLKSIZE, 1); + if(nat_blk == NULL) { + MSG(1, "\tError: Calloc Failed for nat_blk!!!\n"); + return -1; + } + + /* update node nat */ + nat_blk->entries[get_sb(node_ino)].block_addr = cpu_to_le32(1); + nat_blk->entries[get_sb(node_ino)].ino = sb->node_ino; + + /* update meta nat */ + nat_blk->entries[get_sb(meta_ino)].block_addr = cpu_to_le32(1); + nat_blk->entries[get_sb(meta_ino)].ino = sb->meta_ino; + + nat_seg_blk_offset = get_sb(nat_blkaddr); + + DBG(1, "\tWriting nat root, at offset 0x%08"PRIx64"\n", + nat_seg_blk_offset); + if (dev_write_block(nat_blk, nat_seg_blk_offset, WRITE_LIFE_NONE)) { + MSG(1, "\tError: While writing the nat_blk set0 to disk!\n"); + free(nat_blk); + return -1; + } + + free(nat_blk); + return 0; +} + +static block_t f2fs_add_default_dentry_lpf(void) +{ + struct f2fs_dentry_block *dent_blk; + block_t data_blkaddr; + unsigned int didx = 0; + + dent_blk = calloc(F2FS_BLKSIZE, 1); + if (dent_blk == NULL) { + MSG(1, "\tError: Calloc Failed for dent_blk!!!\n"); + return 0; + } + + add_dentry(dent_blk, &didx, ".", c.lpf_ino, F2FS_FT_DIR); + add_dentry(dent_blk, &didx, "..", c.lpf_ino, F2FS_FT_DIR); + + data_blkaddr = alloc_next_free_block(CURSEG_HOT_DATA); + + DBG(1, "\tWriting default dentry lost+found, at offset 0x%x\n", + data_blkaddr); + if (dev_write_block(dent_blk, data_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_DATA))) { + MSG(1, "\tError While writing the dentry_blk to disk!!!\n"); + free(dent_blk); + return 0; + } + + update_sit_journal(CURSEG_HOT_DATA); + update_summary_entry(CURSEG_HOT_DATA, c.lpf_ino, 0); + + free(dent_blk); + return data_blkaddr; +} + +static int f2fs_write_lpf_inode(void) +{ + struct f2fs_node *raw_node; + block_t data_blkaddr; + block_t node_blkaddr; + int err = 0; + + ASSERT(c.lpf_ino); + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); + return -1; + } + + f2fs_init_inode(sb, raw_node, c.lpf_ino, mkfs_time, 0x41c0); + + raw_node->i.i_pino = sb->root_ino; + raw_node->i.i_namelen = cpu_to_le32(strlen(LPF)); + memcpy(raw_node->i.i_name, LPF, strlen(LPF)); + + node_blkaddr = alloc_next_free_block(CURSEG_HOT_NODE); + F2FS_NODE_FOOTER(raw_node)->next_blkaddr = cpu_to_le32(node_blkaddr + 1); + + data_blkaddr = f2fs_add_default_dentry_lpf(); + if (data_blkaddr == 0) { + MSG(1, "\tError: Failed to add default dentries for lost+found!!!\n"); + err = -1; + goto exit; + } + raw_node->i.i_addr[get_extra_isize(raw_node)] = cpu_to_le32(data_blkaddr); + + DBG(1, "\tWriting lost+found inode (hot node), offset 0x%x\n", + node_blkaddr); + if (write_inode(raw_node, node_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_HOT_NODE)) < 0) { + MSG(1, "\tError: While writing the raw_node to disk!!!\n"); + err = -1; + goto exit; + } + + update_nat_journal(c.lpf_ino, node_blkaddr); + update_sit_journal(CURSEG_HOT_NODE); + update_summary_entry(CURSEG_HOT_NODE, c.lpf_ino, 0); + +exit: + free(raw_node); + return err; +} + +static void allocate_blocks_for_aliased_device(struct f2fs_node *raw_node, + unsigned int dev_num) +{ + uint32_t start_segno = (c.devices[dev_num].start_blkaddr - + get_sb(main_blkaddr)) / c.blks_per_seg; + uint32_t end_segno = (c.devices[dev_num].end_blkaddr - + get_sb(main_blkaddr) + 1) / c.blks_per_seg; + uint32_t segno; + uint64_t blkcnt; + struct f2fs_sit_block *sit_blk = calloc(F2FS_BLKSIZE, 1); + + ASSERT(sit_blk); + + for (segno = start_segno; segno < end_segno; segno++) { + struct f2fs_sit_entry *sit; + uint64_t sit_blk_addr = get_sb(sit_blkaddr) + + (segno / SIT_ENTRY_PER_BLOCK); + + ASSERT(dev_read_block(sit_blk, sit_blk_addr) >= 0); + sit = &sit_blk->entries[segno % SIT_ENTRY_PER_BLOCK]; + memset(&sit->valid_map, 0xFF, SIT_VBLOCK_MAP_SIZE); + sit->vblocks = cpu_to_le16((CURSEG_COLD_DATA << + SIT_VBLOCKS_SHIFT) | c.blks_per_seg); + sit->mtime = cpu_to_le64(mkfs_time); + ASSERT(dev_write_block(sit_blk, sit_blk_addr, + f2fs_io_type_to_rw_hint(CURSEG_COLD_DATA)) >= 0); + } + + blkcnt = (end_segno - start_segno) * c.blks_per_seg; + raw_node->i.i_size = cpu_to_le64(blkcnt << get_sb(log_blocksize)); + raw_node->i.i_blocks = cpu_to_le64(blkcnt + 1); + + raw_node->i.i_ext.fofs = cpu_to_le32(0); + raw_node->i.i_ext.blk_addr = + cpu_to_le32(c.devices[dev_num].start_blkaddr); + raw_node->i.i_ext.len = cpu_to_le32(blkcnt); + + free(sit_blk); +} + +static int f2fs_write_alias_inodes(void) +{ + struct f2fs_node *raw_node; + block_t node_blkaddr; + int err = 0; + unsigned int i, dev_off = 0; + + ASSERT(c.aliased_devices); + + raw_node = calloc(F2FS_BLKSIZE, 1); + if (raw_node == NULL) { + MSG(1, "\tError: Calloc Failed for raw_node!!!\n"); + return -1; + } + + for (i = 1; i < c.ndevs; i++) { + const char *filename; + nid_t ino; + + if (!device_is_aliased(i)) + continue; + + ino = c.first_alias_ino + dev_off; + dev_off++; + f2fs_init_inode(sb, raw_node, ino, mkfs_time, 0x81c0); + + raw_node->i.i_flags = cpu_to_le32(F2FS_DEVICE_ALIAS_FL); + raw_node->i.i_inline = F2FS_PIN_FILE; + raw_node->i.i_pino = sb->root_ino; + filename = c.devices[i].alias_filename; + raw_node->i.i_namelen = cpu_to_le32(strlen(filename)); + memcpy(raw_node->i.i_name, filename, strlen(filename)); + + node_blkaddr = alloc_next_free_block(CURSEG_COLD_NODE); + F2FS_NODE_FOOTER(raw_node)->next_blkaddr = + cpu_to_le32(node_blkaddr + 1); + + allocate_blocks_for_aliased_device(raw_node, i); + + DBG(1, "\tWriting aliased device inode (cold node), " + "offset 0x%x\n", node_blkaddr); + if (write_inode(raw_node, node_blkaddr, + f2fs_io_type_to_rw_hint(CURSEG_COLD_NODE)) < 0) { + MSG(1, "\tError: While writing the raw_node to " + "disk!!!\n"); + err = -1; + goto exit; + } + + update_nat_journal(ino, node_blkaddr); + update_sit_journal(CURSEG_COLD_NODE); + update_summary_entry(CURSEG_COLD_NODE, ino, 0); + } + +exit: + free(raw_node); + return err; +} + +static int f2fs_create_root_dir(void) +{ + enum quota_type qtype; + int err = 0; + + err = f2fs_write_root_inode(); + if (err < 0) { + MSG(1, "\tError: Failed to write root inode!!!\n"); + goto exit; + } + + for (qtype = 0; qtype < F2FS_MAX_QUOTAS; qtype++) { + if (!((1 << qtype) & c.quota_bits)) + continue; + err = f2fs_write_qf_inode(qtype); + if (err < 0) { + MSG(1, "\tError: Failed to write quota inode!!!\n"); + goto exit; + } + } + + if (c.feature & F2FS_FEATURE_LOST_FOUND) { + err = f2fs_write_lpf_inode(); + if (err < 0) { + MSG(1, "\tError: Failed to write lost+found inode!!!\n"); + goto exit; + } + } + + if (c.aliased_devices) { + err = f2fs_write_alias_inodes(); + if (err < 0) { + MSG(1, "\tError: Failed to write aliased device " + "inodes!!!\n"); + goto exit; + } + } + +#ifndef WITH_ANDROID + err = f2fs_discard_obsolete_dnode(); + if (err < 0) { + MSG(1, "\tError: Failed to discard obsolete dnode!!!\n"); + goto exit; + } +#endif + + err = f2fs_update_nat_default(); + if (err < 0) { + MSG(1, "\tError: Failed to update NAT for root!!!\n"); + goto exit; + } +exit: + if (err) + MSG(1, "\tError: Could not create the root directory!!!\n"); + + return err; +} + +int f2fs_format_device(void) +{ + int err = 0; + + err= f2fs_prepare_super_block(); + if (err < 0) { + MSG(0, "\tError: Failed to prepare a super block!!!\n"); + goto exit; + } + + if (c.trim) { + err = f2fs_trim_devices(); + if (err < 0) { + MSG(0, "\tError: Failed to trim whole device!!!\n"); + goto exit; + } + } + + err = f2fs_init_sit_area(); + if (err < 0) { + MSG(0, "\tError: Failed to initialise the SIT AREA!!!\n"); + goto exit; + } + + err = f2fs_init_nat_area(); + if (err < 0) { + MSG(0, "\tError: Failed to initialise the NAT AREA!!!\n"); + goto exit; + } + + err = f2fs_create_root_dir(); + if (err < 0) { + MSG(0, "\tError: Failed to create the root directory!!!\n"); + goto exit; + } + + err = f2fs_write_check_point_pack(); + if (err < 0) { + MSG(0, "\tError: Failed to write the check point pack!!!\n"); + goto exit; + } + + err = f2fs_write_super_block(); + if (err < 0) { + MSG(0, "\tError: Failed to write the super block!!!\n"); + goto exit; + } +exit: + if (err) + MSG(0, "\tError: Could not format the device!!!\n"); + + return err; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_main.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_main.c new file mode 100644 index 00000000000..3a8fde02137 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_main.c @@ -0,0 +1,562 @@ +/** + * f2fs_format.c + * + * Copyright (c) 2012 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_MOUNT_H +#include +#endif +#include +#include +#include + +#include + +#ifdef HAVE_LIBBLKID +#include +#endif +#ifdef HAVE_UUID_UUID_H +#include +#endif + +#include "quota.h" +#include "f2fs_format_utils.h" + +#ifdef HAVE_SYS_UTSNAME_H +#include +#endif +#ifdef HAVE_SPARSE_SPARSE_H +#include +extern struct sparse_file *f2fs_sparse_file; +#endif + +extern struct f2fs_configuration c; +static int force_overwrite = 0; + +INIT_FEATURE_TABLE; + +static void mkfs_usage() +{ + MSG(0, "\nUsage: mkfs.f2fs [options] device [sectors]\n"); + MSG(0, "[options]:\n"); + MSG(0, " -b filesystem block size [default:4096]\n"); + MSG(0, " -c [device_name[@alias_filename]] up to 7 additional devices, except meta device\n"); + MSG(0, " -d debug level [default:0]\n"); + MSG(0, " -e [cold file ext list] e.g. \"mp3,gif,mov\"\n"); + MSG(0, " -E [hot file ext list] e.g. \"db\"\n"); + MSG(0, " -f force overwrite of the existing filesystem\n"); + MSG(0, " -g add default options\n"); + MSG(0, " -H support write hint\n"); + MSG(0, " -i extended node bitmap, node ratio is 20%% by default\n"); + MSG(0, " -l label\n"); + MSG(0, " -U uuid\n"); + MSG(0, " -m support zoned block device [default:0]\n"); + MSG(0, " -o overprovision percentage [default:auto]\n"); + MSG(0, " -O feature1[,feature2,...] e.g. \"encrypt\"\n"); + MSG(0, " -C [encoding[:flag1,...]] Support casefolding with optional flags\n"); + MSG(0, " -q quiet mode\n"); + MSG(0, " -r set checkpointing seed (srand()) to 0\n"); + MSG(0, " -R root_owner [default: 0:0]\n"); + MSG(0, " -s # of segments per section [default:1]\n"); + MSG(0, " -S sparse mode\n"); + MSG(0, " -t 0: nodiscard, 1: discard [default:1]\n"); + MSG(0, " -T timestamps\n"); + MSG(0, " -w wanted sector size\n"); + MSG(0, " -z # of sections per zone [default:1]\n"); + MSG(0, " -V print the version number and exit\n"); + MSG(0, " -Z # of reserved sections [default:auto]\n"); + MSG(0, "sectors: number of sectors [default: determined by device size]\n"); + exit(1); +} + +static void f2fs_show_info() +{ + MSG(0, "\n F2FS-tools: mkfs.f2fs Ver: %s (%s)\n\n", + F2FS_TOOLS_VERSION, + F2FS_TOOLS_DATE); + + MSG(0, "Info: Debug level = %d\n", c.dbg_lv); + if (c.extension_list[0]) + MSG(0, "Info: Add new cold file extension list\n"); + if (c.extension_list[1]) + MSG(0, "Info: Add new hot file extension list\n"); + + if (strlen(c.vol_label)) + MSG(0, "Info: Label = %s\n", c.vol_label); + MSG(0, "Info: Trim is %s\n", c.trim ? "enabled": "disabled"); + + if (c.defset == CONF_ANDROID) + MSG(0, "Info: Set conf for android\n"); + + if (c.feature & F2FS_FEATURE_CASEFOLD) + MSG(0, "Info: Enable %s with casefolding\n", + f2fs_encoding2str(c.s_encoding)); + if (c.feature & F2FS_FEATURE_PRJQUOTA) + MSG(0, "Info: Enable Project quota\n"); + + if (c.feature & F2FS_FEATURE_COMPRESSION) + MSG(0, "Info: Enable Compression\n"); + + if (c.feature & F2FS_FEATURE_DEVICE_ALIAS) + MSG(0, "Info: Enable device aliasing\n"); +} + +#if defined(ANDROID_TARGET) && defined(HAVE_SYS_UTSNAME_H) +static bool kernel_version_over(unsigned int min_major, unsigned int min_minor) +{ + unsigned int major, minor; + struct utsname uts; + + if ((uname(&uts) != 0) || + (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) + return false; + if (major > min_major) + return true; + if (major == min_major && minor >= min_minor) + return true; + return false; +} +#else +static bool kernel_version_over(unsigned int UNUSED(min_major), + unsigned int UNUSED(min_minor)) +{ + return false; +} +#endif + +static void add_default_options(void) +{ + switch (c.defset) { + case CONF_ANDROID: + /* -d1 -f -w 4096 -R 0:0 */ + c.dbg_lv = 1; + force_overwrite = 1; + c.wanted_sector_size = F2FS_BLKSIZE; + c.root_uid = c.root_gid = 0; + c.disabled_feature |= F2FS_FEATURE_NAT_BITS; + + /* RO doesn't need any other features */ + if (c.feature & F2FS_FEATURE_RO) + return; + + /* -O encrypt -O project_quota,extra_attr,{quota} -O verity */ + c.feature |= F2FS_FEATURE_ENCRYPT; + if (!kernel_version_over(4, 14)) + c.feature |= F2FS_FEATURE_QUOTA_INO; + c.feature |= F2FS_FEATURE_PRJQUOTA; + c.feature |= F2FS_FEATURE_EXTRA_ATTR; + c.feature |= F2FS_FEATURE_VERITY; + + /* enable write hitn by default */ + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + break; + } +#ifdef CONF_CASEFOLD + c.s_encoding = F2FS_ENC_UTF8_12_1; + c.feature |= F2FS_FEATURE_CASEFOLD; +#endif +#ifdef CONF_PROJID + c.feature |= F2FS_FEATURE_QUOTA_INO; + c.feature |= F2FS_FEATURE_PRJQUOTA; + c.feature |= F2FS_FEATURE_EXTRA_ATTR; +#endif + + if (c.feature & F2FS_FEATURE_QUOTA_INO) + c.quota_bits = QUOTA_USR_BIT | QUOTA_GRP_BIT; + if (c.feature & F2FS_FEATURE_PRJQUOTA) { + c.feature |= F2FS_FEATURE_QUOTA_INO; + c.quota_bits |= QUOTA_PRJ_BIT; + } +} + +static void f2fs_parse_options(int argc, char *argv[]) +{ + static const char *option_string = "qa:b:c:C:d:e:E:g:hHil:mo:O:rR:s:S:z:t:T:U:Vfw:Z:"; + static const struct option long_opts[] = { + { .name = "help", .has_arg = 0, .flag = NULL, .val = 'h' }, + { .name = NULL, .has_arg = 0, .flag = NULL, .val = 0 } + }; + int32_t option=0; + int val; + char *token; + int dev_num; + + while ((option = getopt_long(argc,argv,option_string,long_opts,NULL)) != EOF) { + switch (option) { + case 'q': + c.dbg_lv = -1; + break; + case 'a': + MSG(0, "Info: heap allocation is deprecated\n"); + break; + case 'b': + c.blksize = atoi(optarg); + c.blksize_bits = log_base_2(c.blksize); + c.sectors_per_blk = DEFAULT_SECTORS_PER_BLOCK; + if ((1 << c.blksize_bits) != c.blksize) { + MSG(0, "Error: Block size must be power of 2"); + mkfs_usage(); + } + break; + case 'c': + dev_num = c.ndevs; + + if (dev_num >= MAX_DEVICES) { + MSG(0, "Error: Too many devices\n"); + mkfs_usage(); + } + + token = strtok(optarg, "@"); + if (strlen(token) > MAX_PATH_LEN) { + MSG(0, "Error: device path should be equal or " + "less than %d characters\n", + MAX_PATH_LEN); + mkfs_usage(); + } + c.devices[dev_num].path = strdup(token); + token = strtok(NULL, ""); + if (token) { + if (strlen(token) > MAX_PATH_LEN) { + MSG(0, "Error: alias_filename should " + "be equal or less than %d " + "characters\n", MAX_PATH_LEN); + mkfs_usage(); + } + if (strchr(token, '/')) { + MSG(0, "Error: alias_filename has " + "invalid '/' character\n"); + mkfs_usage(); + } + c.devices[dev_num].alias_filename = + strdup(token); + if (!c.aliased_devices) + c.feature |= F2FS_FEATURE_DEVICE_ALIAS; + c.aliased_devices++; + } + c.ndevs++; + break; + case 'd': + c.dbg_lv = atoi(optarg); + break; + case 'e': + c.extension_list[0] = strdup(optarg); + break; + case 'E': + c.extension_list[1] = strdup(optarg); + break; + case 'g': + if (!strcmp(optarg, "android")) + c.defset = CONF_ANDROID; + break; + case 'h': + mkfs_usage(); + break; + case 'H': + c.need_whint = true; + c.whint = WRITE_LIFE_NOT_SET; + break; + case 'i': + c.large_nat_bitmap = 1; + break; + case 'l': /*v: volume label */ + if (strlen(optarg) > 512) { + MSG(0, "Error: Volume Label should be less than " + "512 characters\n"); + mkfs_usage(); + } + c.vol_label = optarg; + break; + case 'm': + c.zoned_mode = 1; + break; + case 'o': + c.overprovision = atof(optarg); + break; + case 'O': + if (parse_feature(feature_table, optarg)) + mkfs_usage(); + break; + case 'r': + c.fake_seed = 1; + break; + case 'R': + if (parse_root_owner(optarg, &c.root_uid, &c.root_gid)) + mkfs_usage(); + break; + case 's': + c.segs_per_sec = atoi(optarg); + break; + case 'S': + c.device_size = atoll(optarg); + c.device_size &= (~((uint64_t)(F2FS_BLKSIZE - 1))); + c.sparse_mode = 1; + break; + case 'z': + c.secs_per_zone = atoi(optarg); + break; + case 't': + c.trim = atoi(optarg); + break; + case 'T': + c.fixed_time = strtoul(optarg, NULL, 0); + break; + case 'U': + c.vol_uuid = strdup(optarg); + break; + case 'f': + force_overwrite = 1; + break; + case 'w': + c.wanted_sector_size = atoi(optarg); + break; + case 'V': + show_version("mkfs.f2fs"); + exit(0); + case 'C': + token = strtok(optarg, ":"); + val = f2fs_str2encoding(token); + if (val < 0) { + MSG(0, "\tError: Unknown encoding %s\n", token); + mkfs_usage(); + } + c.s_encoding = val; + token = strtok(NULL, ""); + val = f2fs_str2encoding_flags(&token, &c.s_encoding_flags); + if (val) { + MSG(0, "\tError: Unknown flag %s\n",token); + mkfs_usage(); + } + c.feature |= F2FS_FEATURE_CASEFOLD; + break; + case 'Z': + c.conf_reserved_sections = atoi(optarg); + break; + default: + MSG(0, "\tError: Unknown option %c\n",option); + mkfs_usage(); + break; + } + } + + add_default_options(); + + if (!(c.feature & F2FS_FEATURE_EXTRA_ATTR)) { + if (c.feature & F2FS_FEATURE_PRJQUOTA) { + MSG(0, "\tInfo: project quota feature should always be " + "enabled with extra attr feature\n"); + exit(1); + } + if (c.feature & F2FS_FEATURE_INODE_CHKSUM) { + MSG(0, "\tInfo: inode checksum feature should always be " + "enabled with extra attr feature\n"); + exit(1); + } + if (c.feature & F2FS_FEATURE_FLEXIBLE_INLINE_XATTR) { + MSG(0, "\tInfo: flexible inline xattr feature should always be " + "enabled with extra attr feature\n"); + exit(1); + } + if (c.feature & F2FS_FEATURE_INODE_CRTIME) { + MSG(0, "\tInfo: inode crtime feature should always be " + "enabled with extra attr feature\n"); + exit(1); + } + if (c.feature & F2FS_FEATURE_COMPRESSION) { + MSG(0, "\tInfo: compression feature should always be " + "enabled with extra attr feature\n"); + exit(1); + } + } + + if (optind >= argc) { + MSG(0, "\tError: Device not specified\n"); + mkfs_usage(); + } + + /* [0] : META, [1 to MAX_DEVICES - 1] : NODE/DATA */ + c.devices[0].path = strdup(argv[optind]); + + if ((optind + 1) < argc) { + if (c.ndevs > 1) { + MSG(0, "\tError: Not support custom size on multi-devs.\n"); + mkfs_usage(); + } + c.wanted_total_sectors = atoll(argv[optind+1]); + } + + if (c.sparse_mode) + c.trim = 0; + + if (c.zoned_mode) + c.feature |= F2FS_FEATURE_BLKZONED; + check_block_struct_sizes(); +} + +#ifdef HAVE_LIBBLKID +static int f2fs_dev_is_overwrite(const char *device) +{ + const char *type; + blkid_probe pr = NULL; + int ret = -1; + + if (!device || !*device) + return 0; + + pr = blkid_new_probe_from_filename(device); + if (!pr) + goto out; + + ret = blkid_probe_enable_partitions(pr, 1); + if (ret < 0) + goto out; + + ret = blkid_do_fullprobe(pr); + if (ret < 0) + goto out; + + /* + * Blkid returns 1 for nothing found and 0 when it finds a signature, + * but we want the exact opposite, so reverse the return value here. + * + * In addition print some useful diagnostics about what actually is + * on the device. + */ + if (ret) { + ret = 0; + goto out; + } + + if (!blkid_probe_lookup_value(pr, "TYPE", &type, NULL)) { + MSG(0, "\t%s appears to contain an existing filesystem (%s).\n", + device, type); + } else if (!blkid_probe_lookup_value(pr, "PTTYPE", &type, NULL)) { + MSG(0, "\t%s appears to contain a partition table (%s).\n", + device, type); + } else { + MSG(0, "\t%s appears to contain something weird according to blkid\n", + device); + } + ret = 1; +out: + if (pr) + blkid_free_probe(pr); + if (ret == -1) + MSG(0, "\tprobe of %s failed, cannot detect existing filesystem.\n", + device); + return ret; +} + +static int f2fs_check_overwrite(void) +{ + int i; + + for (i = 0; i < c.ndevs; i++) + if (f2fs_dev_is_overwrite((char *)c.devices[i].path)) + return -1; + return 0; +} + +#else + +static int f2fs_check_overwrite(void) +{ + return 0; +} + +#endif /* HAVE_LIBBLKID */ + +int main(int argc, char *argv[]) +{ + int ret; + + f2fs_init_configuration(); + + f2fs_parse_options(argc, argv); + + f2fs_show_info(); + + c.func = MKFS; + + ret = f2fs_devs_are_umounted(); + if (ret) { + if (ret != -EBUSY) + MSG(0, "\tError: Not available on mounted device!\n"); + goto err_format; + } + + if (f2fs_get_device_info() < 0) + return -1; + + if (f2fs_check_overwrite()) { + char *zero_buf = NULL; + int i; + + if (!force_overwrite) { + MSG(0, "\tUse the -f option to force overwrite.\n"); + goto err_format; + } + zero_buf = calloc(F2FS_BLKSIZE, 1); + if (!zero_buf) { + MSG(0, "\tError: Fail to allocate zero buffer.\n"); + goto err_format; + } + /* wipe out other FS magics mostly first 4MB space */ + for (i = 0; i < 1024; i++) + if (dev_fill_block(zero_buf, i, WRITE_LIFE_NONE)) + break; + free(zero_buf); + if (i != 1024) { + MSG(0, "\tError: Fail to fill zeros till %d.\n", i); + goto err_format; + } + if (f2fs_fsync_device()) + goto err_format; + } + + if (f2fs_get_f2fs_info() < 0) + goto err_format; + + /* + * Some options are mandatory for host-managed + * zoned block devices. + */ + if (c.zoned_model != F2FS_ZONED_NONE && !c.zoned_mode) { + MSG(0, "\tError: zoned block device feature is required\n"); + goto err_format; + } + + if (c.zoned_mode && !c.trim) { + MSG(0, "\tError: Trim is required for zoned block devices\n"); + goto err_format; + } + + if (c.conf_reserved_sections && !c.zoned_mode) { + MSG(0, "\tError: Reserved area can't be specified on non zoned device\n"); + goto err_format; + } + + if (f2fs_format_device() < 0) + goto err_format; + + if (f2fs_finalize_device() < 0) + goto err_format; + + MSG(0, "Info: format successful\n"); + + return 0; + +err_format: + f2fs_release_sparse_resource(); + return -1; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.c new file mode 100644 index 00000000000..1a9746a7718 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.c @@ -0,0 +1,181 @@ +/** + * f2fs_format_utils.c + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include +#include + +#ifdef HAVE_LINUX_FS_H +#include +#endif +#ifdef HAVE_LINUX_FALLOC_H +#include +#endif + +#ifdef __linux__ +#ifndef BLKDISCARD +#define BLKDISCARD _IO(0x12,119) +#endif +#ifndef BLKSECDISCARD +#define BLKSECDISCARD _IO(0x12,125) +#endif +#endif + +#if defined(FALLOC_FL_PUNCH_HOLE) || defined(BLKDISCARD) || \ + defined(BLKSECDISCARD) +static int trim_device(int i) +{ + unsigned long long range[2]; + struct stat *stat_buf; + struct device_info *dev = c.devices + i; + uint64_t bytes = dev->total_sectors * dev->sector_size; + int fd = dev->fd; + + if (dev->alias_filename) { + MSG(0, "Info: [%s] Skip Discarding as aliased\n", dev->path); + return 0; + } + + stat_buf = malloc(sizeof(struct stat)); + if (stat_buf == NULL) { + MSG(1, "\tError: Malloc Failed for trim_stat_buf!!!\n"); + return -1; + } + + if (fstat(fd, stat_buf) < 0 ) { + MSG(1, "\tError: Failed to get the device stat!!!\n"); + free(stat_buf); + return -1; + } + + range[0] = 0; + range[1] = bytes; + +#if defined(WITH_BLKDISCARD) && defined(BLKDISCARD) + MSG(0, "Info: [%s] Discarding device\n", dev->path); + if (S_ISREG(stat_buf->st_mode)) { +#if defined(HAVE_FALLOCATE) && defined(FALLOC_FL_PUNCH_HOLE) + if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + range[0], range[1]) < 0) { + MSG(0, "Info: fallocate(PUNCH_HOLE|KEEP_SIZE) is failed\n"); + } +#endif + free(stat_buf); + return 0; + } else if (S_ISBLK(stat_buf->st_mode)) { + if (dev->zoned_model != F2FS_ZONED_NONE) { + free(stat_buf); + return f2fs_reset_zones(i); + } +#ifdef BLKSECDISCARD + if (ioctl(fd, BLKSECDISCARD, &range) < 0) { + MSG(0, "Info: This device doesn't support BLKSECDISCARD\n"); + } else { + MSG(0, "Info: Secure Discarded %lu MB\n", + (unsigned long)stat_buf->st_size >> 20); + free(stat_buf); + return 0; + } +#endif + if (ioctl(fd, BLKDISCARD, &range) < 0) { + MSG(0, "Info: This device doesn't support BLKDISCARD\n"); + } else { + MSG(0, "Info: Discarded %llu MB\n", range[1] >> 20); + } + } else { + free(stat_buf); + return -1; + } +#endif + free(stat_buf); + return 0; +} +#else +static int trim_device(int UNUSED(i)) +{ + return 0; +} +#endif + +#ifdef WITH_ANDROID +static bool is_wiped_device(int i) +{ + struct device_info *dev = c.devices + i; + int fd = dev->fd; + char *buf, *zero_buf; + bool wiped = true; + int nblocks = (4096 * 4096) / F2FS_BLKSIZE; /* 16MB size */ + int j; + + /* let's trim the other devices except the first device */ + if (i > 0) + return false; + + buf = malloc(F2FS_BLKSIZE); + if (buf == NULL) { + MSG(1, "\tError: Malloc Failed for buf!!!\n"); + return false; + } + zero_buf = calloc(1, F2FS_BLKSIZE); + if (zero_buf == NULL) { + MSG(1, "\tError: Calloc Failed for zero buf!!!\n"); + free(buf); + return false; + } + + if (lseek(fd, 0, SEEK_SET) < 0) { + free(zero_buf); + free(buf); + return false; + } + + /* check first n blocks */ + for (j = 0; j < nblocks; j++) { + if (read(fd, buf, F2FS_BLKSIZE) != F2FS_BLKSIZE || + memcmp(buf, zero_buf, F2FS_BLKSIZE)) { + wiped = false; + break; + } + } + free(zero_buf); + free(buf); + + if (wiped) + MSG(0, "Info: Found all zeros in first %d blocks\n", nblocks); + return wiped; +} +#else +static bool is_wiped_device(int UNUSED(i)) +{ + return false; +} +#endif + +int f2fs_trim_devices(void) +{ + int i; + + for (i = 0; i < c.ndevs; i++) { + if (!is_wiped_device(i) && trim_device(i)) + return -1; + } + c.trimmed = 1; + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.h new file mode 100644 index 00000000000..6a7f6874a95 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/mkfs/f2fs_format_utils.h @@ -0,0 +1,15 @@ +/** + * f2fs_format_utils.c + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * Dual licensed under the GPL or LGPL version 2 licenses. + */ +#include "f2fs_fs.h" + +extern struct f2fs_configuration c; + +int f2fs_trim_device(int, uint64_t); +int f2fs_trim_devices(void); +int f2fs_format_device(void); diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/dumpf2fs.sh b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/dumpf2fs.sh new file mode 100755 index 00000000000..2c2a273ab73 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/dumpf2fs.sh @@ -0,0 +1,61 @@ +#!/system/bin/sh +DEV=/dev/block/mmcblk0p16 + +CMD=$1 +BASE=0x200000 +BASE_MAIN=0xac00000 + +case $CMD in +cp1) + echo dump cp1 + let addr=$BASE + echo $addr + hexdump -s $addr -n 4096 $DEV;; +cp2) + echo dump cp2 + let addr=$BASE+0x200000 + hexdump -s $addr -n 4096 $DEV;; +cp) + echo dump cp1 and cp2 + let addr=$BASE + hexdump -s $addr -n 409 $DEV + let addr=$BASE+0x200000 + hexdump -s $addr -n 4096 $DEV;; +cp1_all) + echo dump cp1 all + let addr=$BASE + hexdump -s $addr -n 20480 $DEV;; +cp2_all) + echo dump cp2 all + let addr=$BASE+0x200000 + hexdump -s $addr -n 20480 $DEV;; +cp_all) + echo dump cp1 and cp2 all + let addr=$BASE + hexdump -s $addr -n 20480 $DEV + let addr=$BASE+0x200000 + hexdump -s $addr -n 20480 $DEV;; +blk) + let addr=$BASE_MAIN+$2*0x200000+$3*0x1000 + hexdump -s $addr -n 4096 $DEV + echo ;; +inode) + let addr=$BASE_MAIN+$2*0x200000+$3*0x1000 + for i in `seq $3 511` + do + hexdump -s $addr -n 8 $DEV + let end=$addr+0x0ff0 + hexdump -s $end -n 16 $DEV + let addr=$addr+0x1000 + done + echo ;; +*) + let addr=$1*0x1000 + let segno=$addr-$BASE_MAIN + let segno=$segno/0x200000 + let off=$addr-$BASE_MAIN + let off=$off%0x200000/0x1000 + echo $segno, $off + hexdump -s $addr -n 4096 $DEV + echo ;; +esac diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/spo_test.sh b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/spo_test.sh new file mode 100755 index 00000000000..21912149989 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/spo_test.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +MNT=/mnt/f2fs +DEV=/dev/sdb1 +USER_DIR=/home/zeus +F2FS_DIR=$USER_DIR/f2fs_test + +check_stop() { + stop=`cat /tmp/stop` + if [ $stop -eq 1 ]; then + exit + fi +} + +case $1 in +start) + echo 0 > /tmp/stop + umount /mnt/* + echo 3 > /proc/sys/vm/drop_caches + echo 8 > /proc/sys/kernel/printk + + date >> $USER_DIR/por_result + sync + + insmod $F2FS_DIR/src/fs/f2fs/f2fs.ko || exit + + echo Start checking F2FS without fsync + check_stop + fsck.f2fs $DEV -d 0 || exit + mount -t f2fs -o disable_roll_forward $DEV $MNT || exit + umount $MNT + echo 3 > /proc/sys/vm/drop_caches + + echo Start checking F2FS with fsync + check_stop + fsck.f2fs $DEV -d 0 || exit + mount -t f2fs $DEV $MNT || exit + umount $MNT + + check_stop + fsck.f2fs $DEV -d 0 || exit + mount -t f2fs $DEV $MNT || exit + + count=`cat $USER_DIR/por_time` + if [ $count -eq 20 ]; then + echo Start rm all + time rm -rf $MNT/* || exit + echo 0 > $USER_DIR/por_time + sync + else + echo $((count+1)) > $USER_DIR/por_time + fi + echo 8 > /proc/sys/kernel/printk + echo Start fsstress + date + $F2FS_DIR/stress_test/fsstress/fsstress -z -f link=0 -f mkdir=3 -f mknod=3 -f rmdir=2 -f symlink=3 -f truncate=4 -f write=10 -f creat=10 -f unlink=5 -f rename=5 -f fsync=10 -p 10 -n 10000 -l 0 -d $MNT & + RANDOM=`date '+%s'` + rand=$[($RANDOM % 540) + 60] + echo Start sleep: $rand seconds + sleep $rand + + echo Reboot now + check_stop + echo b > /proc/sysrq-trigger + ;; +stop) + killall -9 fsstress + echo 1 > /tmp/stop + ;; +esac diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/tracepoint.sh b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/tracepoint.sh new file mode 100755 index 00000000000..15588d795cb --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/tracepoint.sh @@ -0,0 +1,71 @@ +#!/system/bin/sh + +TRACE=/sys/kernel/debug/tracing/ +dev=$(((8<<20) + 17)) # sdb1 (8,17) + +echo 1 > $TRACE/tracing_on + +# mmc tracepoints +echo 0 > $TRACE/events/mmc/enable + +# block tracepoints +#echo "dev == $dev" > $TRACE/events/block/block_rq_complete/filter +echo 0 > $TRACE/events/block/block_rq_complete/enable +echo 0 > $TRACE/events/block/block_bio_complete/enable + +# GC +G=0 +echo $G > $TRACE/events/f2fs/f2fs_get_victim/enable + +# block allocation +A=0 +echo $A > $TRACE/events/f2fs/f2fs_reserve_new_block/enable + +# block truncation +T=0 +echo $T > $TRACE/events/f2fs/f2fs_truncate/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_inode_blocks_enter/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_inode_blocks_exit/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_blocks_enter/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_blocks_exit/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_nodes_enter/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_nodes_exit/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_data_blocks_range/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_node/enable +echo $T > $TRACE/events/f2fs/f2fs_truncate_partial_nodes/enable + +# syscalls +S=0 +echo $S > $TRACE/events/f2fs/f2fs_unlink_enter/enable +echo $S > $TRACE/events/f2fs/f2fs_unlink_exit/enable +echo $S > $TRACE/events/f2fs/f2fs_fallocate/enable +echo $S > $TRACE/events/f2fs/f2fs_get_data_block/enable + +# IOs +R=0 +W=0 +echo $R > $TRACE/events/f2fs/f2fs_readpage/enable +echo $W > $TRACE/events/f2fs/f2fs_writepage/enable +echo $W > $TRACE/events/f2fs/f2fs_write_begin/enable +echo $W > $TRACE/events/f2fs/f2fs_write_end/enable + +echo 0 > $TRACE/events/f2fs/f2fs_submit_page_bio/enable +echo 0 > $TRACE/events/f2fs/f2fs_submit_page_mbio/enable +echo $R > $TRACE/events/f2fs/f2fs_submit_read_bio/enable +echo $W > $TRACE/events/f2fs/f2fs_submit_write_bio/enable + +echo 0 > $TRACE/events/f2fs/f2fs_issue_discard/enable +echo 0 > $TRACE/events/f2fs/f2fs_issue_flush/enable + +# VFS interfaces +V=0 +echo $V > $TRACE/events/f2fs/f2fs_iget/enable +echo $V > $TRACE/events/f2fs/f2fs_iget_exit/enable +echo $V > $TRACE/events/f2fs/f2fs_new_inode/enable +echo $V > $TRACE/events/f2fs/f2fs_evict_inode/enable +echo $V > $TRACE/events/f2fs/f2fs_sync_file_enter/enable +echo $V > $TRACE/events/f2fs/f2fs_sync_file_exit/enable +echo $V > $TRACE/events/f2fs/f2fs_write_checkpoint/enable +echo $V > $TRACE/events/f2fs/f2fs_sync_fs/enable + +cat $TRACE/trace_pipe diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/verify.sh b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/verify.sh new file mode 100755 index 00000000000..8a22a2d153b --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/scripts/verify.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +IMG=../test.img +TMP=/tmp/res +XFSTESTS=~/xfstests +TESTS="4 5 8 11 16 25 32 55 64" + +TARGET=./testdir +MNT=/mnt/resize + +mkdir $TARGET 2>/dev/null +mkdir $MNT 2>/dev/null + +umount $TARGET +umount $MNT + +_check_out() +{ + if [ $1 -ne 0 ]; then + grep ASSERT $TMP + echo FAIL RETURN $1 + exit + fi +} + +_get_sec() +{ + echo $(($1*1024*1024*1024/512)) +} + +_mkfs() +{ + echo "========== Initialize $1 GB ============" + mkfs.f2fs $IMG `_get_sec $1` | grep sectors +} + +_mount() +{ + echo "========== mount to $1 =================" + mount -t f2fs -o loop,discard,inline_data,inline_xattr $IMG $1 2>&1 + _check_out $? +} + +_fsck() +{ + echo "========== fsck.f2fs ===================" + fsck.f2fs $IMG -t 2>&1 >$TMP + _check_out $? + grep FSCK $TMP +} + +_fsstress() +{ + echo "========== fsstress $1 =================" + $XFSTESTS/ltp/fsstress -x "echo 3 > /proc/sys/vm/drop_caches && sleep 1" -X 1 -r -f fsync=8 -f sync=0 -f write=8 -f dwrite=2 -f truncate=6 -f allocsp=0 -f bulkstat=0 -f bulkstat1=0 -f freesp=0 -f zero=1 -f collapse=1 -f insert=1 -f resvsp=0 -f unresvsp=0 -S t -p 10 -n $2 -d $1 >/dev/null +} + +_resize() +{ + echo "========== resize.f2fs $1 GB ===========" + resize.f2fs -t `_get_sec $1` $IMG 2>&1 >$TMP + _check_out $? + _fsck +} + +_resize_tests() +{ + for i in $TESTS + do + if [ $i -ge $1 ]; then + _resize $i + fi + done +} + +_sload() +{ + echo "========== sload $1 ====================" + sload.f2fs -f $1 $IMG 2>&1 + _check_out $? +} + +from_mount() +{ + echo "" + echo " **** $1 GB to $2 GB with $3 *** " + _mkfs $1 + _mount $3 + _fsstress $3 10000 + umount $3 + _fsck + _resize_tests $2 +} + +from_sload() +{ + echo "" + echo " **** $1 GB to $2 GB with $3 *** " + + _mkfs $1 + _sload $3 + _fsck + + _mount $MNT + _fsstress $MNT 10000 + umount $MNT + _fsck + + _resize_tests $2 + + _mount $MNT + _fsstress $MNT 10000 + umount $MNT + _fsck +} + +test_all() +{ + for i in $TESTS + do + for j in $TESTS + do + if [ $i -lt $j ]; then + $1 $i $j $2 + fi + done + done +} + +test_all from_sload ~/grub + +rm -rf $TARGET/* +_fsstress $TARGET 5000 +test_all from_sload $TARGET +rm -rf $TARGET 2>/dev/null + +test_all from_mount $MNT diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/Makefile.am new file mode 100644 index 00000000000..7dfffb17a31 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/Makefile.am @@ -0,0 +1,19 @@ +## Makefile.am + +AM_CPPFLAGS = ${libuuid_CFLAGS} -I$(top_srcdir)/include +AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 +sbin_PROGRAMS = +if !WINDOWS +sbin_PROGRAMS += fibmap.f2fs parse.f2fs +endif +fibmap_f2fs_SOURCES = fibmap.c +parse_f2fs_SOURCES = f2fs_io_parse.c + +if LINUX +sbin_PROGRAMS += f2fscrypt +f2fscrypt_SOURCES = f2fscrypt.c sha512.c +f2fscrypt_LDFLAGS = ${libuuid_LIBS} +dist_man_MANS = f2fscrypt.8 +endif + +SUBDIRS = f2fs_io diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Android.bp b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Android.bp new file mode 100644 index 00000000000..2cc81eb859d --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Android.bp @@ -0,0 +1,15 @@ +cc_defaults { + name: "f2fs-io-defaults", + cflags: [ + "-Wno-unused-function" + ], +} + +cc_binary { + name: "f2fs_io", + defaults: [ "f2fs-io-defaults" ], + srcs: [ + "f2fs_io.c", + ], + product_specific: true, +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Makefile.am b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Makefile.am new file mode 100644 index 00000000000..f5227ce21b0 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/Makefile.am @@ -0,0 +1,8 @@ +## Makefile.am + +if LINUX +AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CFLAGS = -Wall -D_FILE_OFFSET_BITS=64 +sbin_PROGRAMS = f2fs_io +f2fs_io_SOURCES = f2fs_io.c +endif diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.c new file mode 100644 index 00000000000..292dcb350d1 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.c @@ -0,0 +1,2222 @@ +/* + * f2fs_io.c - f2fs ioctl utility + * + * Author: Jaegeuk Kim + * + * Copied portion of the code from ../f2fscrypt.c + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#ifndef __SANE_USERSPACE_TYPES__ +#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */ +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include +#endif +#include + +#include "f2fs_io.h" + +struct cmd_desc { + const char *cmd_name; + void (*cmd_func)(int, char **, const struct cmd_desc *); + const char *cmd_desc; + const char *cmd_help; + int cmd_flags; +}; + +static void __attribute__((noreturn)) +do_die(const char *format, va_list va, int err) +{ + vfprintf(stderr, format, va); + if (err) + fprintf(stderr, ": %s", strerror(err)); + putc('\n', stderr); + exit(1); +} + +static void __attribute__((noreturn, format(printf, 1, 2))) +die_errno(const char *format, ...) +{ + va_list va; + + va_start(va, format); + do_die(format, va, errno); + va_end(va); +} + +static void __attribute__((noreturn, format(printf, 1, 2))) +die(const char *format, ...) +{ + va_list va; + + va_start(va, format); + do_die(format, va, 0); + va_end(va); +} + +static void *xmalloc(size_t size) +{ + void *p = malloc(size); + + if (!p) + die("Memory alloc failed (requested %zu bytes)", size); + return p; +} + +static void *aligned_xalloc(size_t alignment, size_t size) +{ + void *p = aligned_alloc(alignment, size); + + if (!p) + die("Memory alloc failed (requested %zu bytes)", size); + return p; +} + +static int xopen(const char *pathname, int flags, mode_t mode) +{ + int fd = open(pathname, flags, mode); + + if (fd < 0) + die_errno("Failed to open %s", pathname); + return fd; +} + +static ssize_t xread(int fd, void *buf, size_t count) +{ + ssize_t ret = read(fd, buf, count); + + if (ret < 0) + die_errno("read failed"); + return ret; +} + +static void full_write(int fd, const void *buf, size_t count) +{ + while (count) { + ssize_t ret = write(fd, buf, count); + + if (ret < 0) + die_errno("write failed"); + buf = (char *)buf + ret; + count -= ret; + } +} + +#ifdef HAVE_MACH_TIME_H +static u64 get_current_us() +{ + return mach_absolute_time() / 1000; +} +#elif defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_BOOTTIME) +static u64 get_current_us() +{ + struct timespec t; + t.tv_sec = t.tv_nsec = 0; + clock_gettime(CLOCK_BOOTTIME, &t); + return (u64)t.tv_sec * 1000000LL + t.tv_nsec / 1000; +} +#else +static u64 get_current_us() +{ + return 0; +} +#endif + +#define fsync_desc "fsync" +#define fsync_help \ +"f2fs_io fsync [file]\n\n" \ +"fsync given the file\n" \ + +static void do_fsync(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + if (fsync(fd) != 0) + die_errno("fsync failed"); + + printf("fsync a file\n"); + exit(0); +} + +#define fdatasync_desc "fdatasync" +#define fdatasync_help \ +"f2fs_io fdatasync [file]\n\n" \ +"fdatasync given the file\n" \ + +static void do_fdatasync(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + if (fdatasync(fd) != 0) + die_errno("fdatasync failed"); + + printf("fdatasync a file\n"); + exit(0); +} + +#define set_verity_desc "Set fs-verity" +#define set_verity_help \ +"f2fs_io set_verity [file]\n\n" \ +"Set fsverity bit given a file\n" \ + +static void do_set_verity(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret, fd; + struct fsverity_enable_arg args = {.version = 1}; + + args.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + args.block_size = F2FS_DEFAULT_BLKSIZE; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + fd = open(argv[1], O_RDONLY); + + ret = ioctl(fd, FS_IOC_ENABLE_VERITY, &args); + if (ret < 0) { + perror("FS_IOC_ENABLE_VERITY"); + exit(1); + } + + printf("Set fsverity bit to %s\n", argv[1]); + exit(0); +} + +#define getflags_desc "getflags ioctl" +#define getflags_help \ +"f2fs_io getflags [file]\n\n" \ +"get a flag given the file\n" \ +"flag can show \n" \ +" encryption\n" \ +" nocow(pinned)\n" \ +" inline_data\n" \ +" verity\n" \ +" casefold\n" \ +" compression\n" \ +" nocompression\n" \ +" immutable\n" + +static void do_getflags(int argc, char **argv, const struct cmd_desc *cmd) +{ + long flag = 0; + int ret, fd; + int exist = 0; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag); + printf("get a flag on %s ret=%d, flags=", argv[1], ret); + if (flag & FS_CASEFOLD_FL) { + printf("casefold"); + exist = 1; + } + if (flag & FS_COMPR_FL) { + if (exist) + printf(","); + printf("compression"); + exist = 1; + } + if (flag & FS_NOCOMP_FL) { + if (exist) + printf(","); + printf("nocompression"); + exist = 1; + } + if (flag & FS_ENCRYPT_FL) { + if (exist) + printf(","); + printf("encrypt"); + exist = 1; + } + if (flag & FS_VERITY_FL) { + if (exist) + printf(","); + printf("verity"); + exist = 1; + } + if (flag & FS_INLINE_DATA_FL) { + if (exist) + printf(","); + printf("inline_data"); + exist = 1; + } + if (flag & FS_NOCOW_FL) { + if (exist) + printf(","); + printf("nocow(pinned)"); + exist = 1; + } + if (flag & FS_IMMUTABLE_FL) { + if (exist) + printf(","); + printf("immutable"); + exist = 1; + } + if (!exist) + printf("none"); + printf("\n"); + exit(0); +} + +#define setflags_desc "setflags ioctl" +#define setflags_help \ +"f2fs_io setflags [flag] [file]\n\n" \ +"set a flag given the file\n" \ +"flag can be\n" \ +" casefold\n" \ +" compression\n" \ +" nocompression\n" \ +" immutable\n" \ +" nocow\n" + +static void do_setflags(int argc, char **argv, const struct cmd_desc *cmd) +{ + long flag = 0; + int ret, fd; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[2], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag); + printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag); + if (ret) + die_errno("F2FS_IOC_GETFLAGS failed"); + + if (!strcmp(argv[1], "casefold")) + flag |= FS_CASEFOLD_FL; + else if (!strcmp(argv[1], "compression")) + flag |= FS_COMPR_FL; + else if (!strcmp(argv[1], "nocompression")) + flag |= FS_NOCOMP_FL; + else if (!strcmp(argv[1], "immutable")) + flag |= FS_IMMUTABLE_FL; + else if (!strcmp(argv[1], "nocow")) + flag |= FS_NOCOW_FL; + + ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag); + printf("set a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]); + exit(0); +} + +#define clearflags_desc "clearflags ioctl" +#define clearflags_help \ +"f2fs_io clearflags [flag] [file]\n\n" \ +"clear a flag given the file\n" \ +"flag can be\n" \ +" compression\n" \ +" nocompression\n" \ +" immutable\n" \ +" nocow\n" + +static void do_clearflags(int argc, char **argv, const struct cmd_desc *cmd) +{ + long flag = 0; + int ret, fd; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[2], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flag); + printf("get a flag on %s ret=%d, flags=%lx\n", argv[1], ret, flag); + if (ret) + die_errno("F2FS_IOC_GETFLAGS failed"); + + if (!strcmp(argv[1], "compression")) + flag &= ~FS_COMPR_FL; + else if (!strcmp(argv[1], "nocompression")) + flag &= ~FS_NOCOMP_FL; + else if (!strcmp(argv[1], "immutable")) + flag &= ~FS_IMMUTABLE_FL; + else if (!strcmp(argv[1], "nocow")) + flag &= ~FS_NOCOW_FL; + + ret = ioctl(fd, F2FS_IOC_SETFLAGS, &flag); + printf("clear a flag on %s ret=%d, flags=%s\n", argv[2], ret, argv[1]); + exit(0); +} + +#define shutdown_desc "shutdown filesystem" +#define shutdown_help \ +"f2fs_io shutdown [level] [dir]\n\n" \ +"Freeze and stop all IOs given mount point\n" \ +"level can be\n" \ +" 0 : going down with full sync\n" \ +" 1 : going down with checkpoint only\n" \ +" 2 : going down with no sync\n" \ +" 3 : going down with metadata flush\n" \ +" 4 : going down with fsck mark\n" + +static void do_shutdown(int argc, char **argv, const struct cmd_desc *cmd) +{ + u32 flag; + int ret, fd; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + flag = atoi(argv[1]); + if (flag >= F2FS_GOING_DOWN_MAX) { + fputs("Wrong level\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + fd = xopen(argv[2], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag); + if (ret < 0) + die_errno("F2FS_IOC_SHUTDOWN failed"); + + printf("Shutdown %s with level=%d\n", argv[2], flag); + exit(0); +} + +#define fadvise_desc "fadvise" +#define fadvise_help \ +"f2fs_io fadvise [advice] [offset] [length] [file]\n\n" \ +"fadvice given the file\n" \ +"advice can be\n" \ +" willneed\n" \ +" dontneed\n" \ +" noreuse\n" \ +" sequential\n" \ +" random\n" \ + +static void do_fadvise(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, advice; + off_t offset, length; + + if (argc != 5) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[4], O_RDWR, 0); + + if (!strcmp(argv[1], "willneed")) { + advice = POSIX_FADV_WILLNEED; + } else if (!strcmp(argv[1], "dontneed")) { + advice = POSIX_FADV_DONTNEED; + } else if (!strcmp(argv[1], "noreuse")) { + advice = POSIX_FADV_NOREUSE; + } else if (!strcmp(argv[1], "sequential")) { + advice = POSIX_FADV_SEQUENTIAL; + } else if (!strcmp(argv[1], "random")) { + advice = POSIX_FADV_RANDOM; + } else { + fputs("Wrong advice\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + offset = atoi(argv[2]); + length = atoll(argv[3]); + + if (posix_fadvise(fd, offset, length, advice) != 0) + die_errno("fadvise failed"); + + printf("fadvice %s to a file: %s\n", argv[1], argv[4]); + exit(0); +} + +#define ioprio_desc "ioprio" +#define ioprio_help \ +"f2fs_io ioprio [hint] [file]\n\n" \ +"ioprio given the file\n" \ +"hint can be\n" \ +" ioprio_write\n" \ + +static void do_ioprio(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, hint; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[2], O_RDWR, 0); + + if (!strcmp(argv[1], "ioprio_write")) { + hint = F2FS_IOPRIO_WRITE; + } else { + fputs("Not supported hint\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if (ioctl(fd, F2FS_IOC_IO_PRIO, &hint) != 0) + die_errno("ioprio failed"); + + printf("ioprio_hint %d to a file: %s\n", hint, argv[2]); + exit(0); +} + +#define pinfile_desc "pin file control" +#define pinfile_help \ +"f2fs_io pinfile [get|set|unset] [file] {size}\n\n" \ +"get/set/unset pinning given the file\n" \ +"{size} is fallocate length and optional only for set operations\n" + +static void do_pinfile(int argc, char **argv, const struct cmd_desc *cmd) +{ + u32 pin; + int ret, fd; + + if (argc < 3 || argc > 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[2], O_RDWR, 0); + + ret = -1; + if (!strcmp(argv[1], "set")) { + pin = 1; + ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin); + if (ret != 0) + die_errno("F2FS_IOC_SET_PIN_FILE failed"); + if (argc != 4) { + printf("%s pinfile: %u blocks moved in %s\n", + argv[1], ret, argv[2]); + exit(0); + } + + struct stat st; + if (fallocate(fd, 0, 0, atoll(argv[3])) != 0) + die_errno("fallocate failed"); + if (fstat(fd, &st) != 0) + die_errno("fstat failed"); + printf("%s pinfile: %u blocks moved and fallocate %"PRIu64" bytes in %s\n", + argv[1], ret, st.st_size, argv[2]); + } else if (!strcmp(argv[1], "unset")) { + pin = 0; + ret = ioctl(fd, F2FS_IOC_SET_PIN_FILE, &pin); + if (ret != 0) + die_errno("F2FS_IOC_SET_PIN_FILE failed"); + printf("%s pinfile in %s\n", argv[1], argv[2]); + } else if (!strcmp(argv[1], "get")) { + unsigned int flags; + + ret = ioctl(fd, F2FS_IOC_GET_PIN_FILE, &pin); + if (ret < 0) + die_errno("F2FS_IOC_GET_PIN_FILE failed"); + + ret = ioctl(fd, F2FS_IOC_GETFLAGS, &flags); + if (ret < 0) + die_errno("F2FS_IOC_GETFLAGS failed"); + + printf("get_pin_file: %s with %u blocks moved in %s\n", + (flags & F2FS_NOCOW_FL) ? "pinned" : "un-pinned", + pin, argv[2]); + } + exit(0); +} + +#define fallocate_desc "fallocate" +#define fallocate_help \ +"f2fs_io fallocate [-c] [-i] [-p] [-z] [keep_size] [offset] [length] [file]\n\n" \ +"fallocate given the file\n" \ +" [keep_size] : 1 or 0\n" \ +" -c : collapse range\n" \ +" -i : insert range\n" \ +" -p : punch hole\n" \ +" -z : zero range\n" \ + +static void do_fallocate(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd; + off_t offset, length; + struct stat sb; + int mode = 0; + int c; + + while ((c = getopt(argc, argv, "cipz")) != -1) { + switch (c) { + case 'c': + mode |= FALLOC_FL_COLLAPSE_RANGE; + break; + case 'i': + mode |= FALLOC_FL_INSERT_RANGE; + break; + case 'p': + mode |= FALLOC_FL_PUNCH_HOLE; + break; + case 'z': + mode |= FALLOC_FL_ZERO_RANGE; + break; + default: + fputs(cmd->cmd_help, stderr); + exit(2); + } + } + argc -= optind; + argv += optind; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if (!strcmp(argv[0], "1")) + mode |= FALLOC_FL_KEEP_SIZE; + + offset = atoll(argv[1]); + length = atoll(argv[2]); + + fd = xopen(argv[3], O_RDWR, 0); + + if (fallocate(fd, mode, offset, length) != 0) + die_errno("fallocate failed"); + + if (fstat(fd, &sb) != 0) + die_errno("fstat failed"); + + printf("fallocated a file: i_size=%"PRIu64", i_blocks=%"PRIu64"\n", sb.st_size, sb.st_blocks); + exit(0); +} + +#define erase_desc "erase a block device" +#define erase_help \ +"f2fs_io erase [block_device_path]\n\n" \ +"Send DISCARD | BLKSECDISCARD comamnd to" \ +"block device in block_device_path\n" \ + +static void do_erase(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, ret; + struct stat st; + u64 range[2]; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if (stat(argv[1], &st) != 0) { + fputs("stat error\n", stderr); + exit(1); + } + + if (!S_ISBLK(st.st_mode)) { + fputs(argv[1], stderr); + fputs(" is not a block device\n", stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + range[0] = 0; + ret = ioctl(fd, BLKGETSIZE64, &range[1]); + if (ret < 0) { + fputs("get size failed\n", stderr); + exit(1); + } + + ret = ioctl(fd, BLKSECDISCARD, &range); + if (ret < 0) { + ret = ioctl(fd, BLKDISCARD, &range); + if (ret < 0) { + fputs("Discard failed\n", stderr); + exit(1); + } + } + + exit(0); +} + +static void do_write_with_advice(int argc, char **argv, + const struct cmd_desc *cmd, bool with_advice) +{ + u64 buf_size = 0, inc_num = 0, written = 0; + u64 offset; + char *buf = NULL; + unsigned bs, count, i; + int flags = 0; + int fd; + u64 total_time = 0, max_time = 0, max_time_t = 0; + bool atomic_commit = false, atomic_abort = false, replace = false; + int useconds = 0; + + srand(time(0)); + + bs = atoi(argv[1]); + if (bs > 1024) + die("Too big chunk size - limit: 4MB"); + + buf_size = bs * F2FS_DEFAULT_BLKSIZE; + + offset = atoi(argv[2]) * buf_size; + + buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size); + count = atoi(argv[3]); + + if (!strcmp(argv[4], "zero")) + memset(buf, 0, buf_size); + else if (strcmp(argv[4], "inc_num") && strcmp(argv[4], "rand")) + die("Wrong pattern type"); + + if (!strcmp(argv[5], "dio")) { + flags |= O_DIRECT; + } else if (!strcmp(argv[5], "dsync")) { + flags |= O_DIRECT | O_DSYNC; + } else if (!strcmp(argv[5], "osync")) { + flags |= O_SYNC; + } else if (!strcmp(argv[5], "atomic_commit")) { + atomic_commit = true; + } else if (!strcmp(argv[5], "atomic_abort")) { + atomic_abort = true; + } else if (!strcmp(argv[5], "atomic_rcommit")) { + atomic_commit = true; + replace = true; + } else if (!strcmp(argv[5], "atomic_rabort")) { + atomic_abort = true; + replace = true; + } else if (strcmp(argv[5], "buffered")) { + die("Wrong IO type"); + } + + if (!with_advice) { + fd = xopen(argv[6], O_CREAT | O_WRONLY | flags, 0755); + } else { + unsigned char advice; + int ret; + + if (!strcmp(argv[6], "hot")) + advice = FADVISE_HOT_BIT; + else if (!strcmp(argv[6], "cold")) + advice = FADVISE_COLD_BIT; + else + die("Wrong Advise type"); + + fd = xopen(argv[7], O_CREAT | O_WRONLY | flags, 0755); + + ret = fsetxattr(fd, F2FS_SYSTEM_ADVISE_NAME, + (char *)&advice, 1, XATTR_CREATE); + if (ret) { + fputs("fsetxattr advice failed\n", stderr); + exit(1); + } + } + + total_time = get_current_us(); + if (atomic_commit || atomic_abort) { + int ret; + + if (argc == 8) + useconds = atoi(argv[7]) * 1000 / (count + 2); + + if (useconds) + usleep(useconds); + + if (replace) + ret = ioctl(fd, F2FS_IOC_START_ATOMIC_REPLACE); + else + ret = ioctl(fd, F2FS_IOC_START_ATOMIC_WRITE); + + if (useconds) + usleep(useconds); + + if (ret < 0) { + fputs("setting atomic file mode failed\n", stderr); + exit(1); + } + } + + for (i = 0; i < count; i++) { + uint64_t ret; + + if (!strcmp(argv[4], "inc_num")) + *(int *)buf = inc_num++; + else if (!strcmp(argv[4], "rand")) + *(int *)buf = rand(); + + /* write data */ + max_time_t = get_current_us(); + ret = pwrite(fd, buf, buf_size, offset + buf_size * i); + max_time_t = get_current_us() - max_time_t; + if (max_time < max_time_t) + max_time = max_time_t; + if (ret != buf_size) + break; + written += ret; + + if (useconds) + usleep(useconds); + } + + if (atomic_commit) { + int ret; + + ret = ioctl(fd, F2FS_IOC_COMMIT_ATOMIC_WRITE); + if (ret < 0) { + fputs("committing atomic write failed\n", stderr); + exit(1); + } + } else if (atomic_abort) { + int ret; + + ret = ioctl(fd, F2FS_IOC_ABORT_VOLATILE_WRITE); + if (ret < 0) { + fputs("aborting atomic write failed\n", stderr); + exit(1); + } + } + + printf("Written %"PRIu64" bytes with pattern=%s, total_time=%"PRIu64" us, max_latency=%"PRIu64" us\n", + written, argv[4], + get_current_us() - total_time, + max_time); + exit(0); +} + +#define write_desc "write data into file" +#define write_help \ +"f2fs_io write [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [file_path] {delay}\n\n" \ +"Write given patten data in file_path\n" \ +"pattern can be\n" \ +" zero : zeros\n" \ +" inc_num : incrementing numbers\n" \ +" rand : random numbers\n" \ +"IO can be\n" \ +" buffered : buffered IO\n" \ +" dio : O_DIRECT\n" \ +" dsync : O_DIRECT | O_DSYNC\n" \ +" osync : O_SYNC\n" \ +" atomic_commit : atomic write & commit\n" \ +" atomic_abort : atomic write & abort\n" \ +" atomic_rcommit: atomic replace & commit\n" \ +" atomic_rabort : atomic replace & abort\n" \ +"{delay} is in ms unit and optional only for atomic operations\n" + +static void do_write(int argc, char **argv, const struct cmd_desc *cmd) +{ + if (argc < 7 || argc > 8) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + do_write_with_advice(argc, argv, cmd, false); +} + +#define write_advice_desc "write data into file with a hint" +#define write_advice_help \ +"f2fs_io write_advice [chunk_size in 4kb] [offset in chunk_size] [count] [pattern] [IO] [advise] [file_path] {delay}\n\n" \ +"Write given patten data in file_path\n" \ +"pattern can be\n" \ +" zero : zeros\n" \ +" inc_num : incrementing numbers\n" \ +" rand : random numbers\n" \ +"IO can be\n" \ +" buffered : buffered IO\n" \ +" dio : O_DIRECT\n" \ +" dsync : O_DIRECT | O_DSYNC\n" \ +" osync : O_SYNC\n" \ +" atomic_commit : atomic write & commit\n" \ +" atomic_abort : atomic write & abort\n" \ +" atomic_rcommit: atomic replace & commit\n" \ +" atomic_rabort : atomic replace & abort\n" \ +"advise can be\n" \ +" cold : indicate a cold file\n" \ +" hot : indicate a hot file\n" \ +"{delay} is in ms unit and optional only for atomic operations\n" + +static void do_write_advice(int argc, char **argv, const struct cmd_desc *cmd) +{ + if (argc < 8 || argc > 9) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + do_write_with_advice(argc, argv, cmd, true); +} + +#define read_desc "read data from file" +#define read_help \ +"f2fs_io read [chunk_size in 4kb] [offset in chunk_size] [count] [IO] [advice] [print_nbytes] [file_path]\n\n" \ +"Read data in file_path and print nbytes\n" \ +"IO can be\n" \ +" buffered : buffered IO\n" \ +" dio : direct IO\n" \ +" mmap : mmap IO\n" \ +"advice can be\n" \ +" 1 : set sequential|willneed\n" \ +" 0 : none\n" \ + +static void do_read(int argc, char **argv, const struct cmd_desc *cmd) +{ + u64 buf_size = 0, ret = 0, read_cnt = 0; + u64 offset; + char *buf = NULL; + char *data; + char *print_buf = NULL; + unsigned bs, count, i, print_bytes; + u64 total_time = 0; + int flags = 0; + int do_mmap = 0; + int fd, advice; + + if (argc != 8) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + bs = atoi(argv[1]); + if (bs > 256 * 1024) + die("Too big chunk size - limit: 1GB"); + buf_size = bs * F2FS_DEFAULT_BLKSIZE; + + offset = atoi(argv[2]) * buf_size; + + buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size); + + count = atoi(argv[3]); + if (!strcmp(argv[4], "dio")) + flags |= O_DIRECT; + else if (!strcmp(argv[4], "mmap")) + do_mmap = 1; + else if (strcmp(argv[4], "buffered")) + die("Wrong IO type"); + + print_bytes = atoi(argv[6]); + if (print_bytes > buf_size) + die("Print_nbytes should be less then chunk_size in kb"); + + print_buf = xmalloc(print_bytes); + + fd = xopen(argv[7], O_RDONLY | flags, 0); + + advice = atoi(argv[5]); + if (advice) { + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, + POSIX_FADV_SEQUENTIAL) != 0) + die_errno("fadvise failed"); + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, + POSIX_FADV_WILLNEED) != 0) + die_errno("fadvise failed"); + printf("fadvise SEQUENTIAL|WILLNEED to a file: %s\n", argv[7]); + } + + total_time = get_current_us(); + if (do_mmap) { + data = mmap(NULL, count * buf_size, PROT_READ, + MAP_SHARED | MAP_POPULATE, fd, offset); + if (data == MAP_FAILED) + die("Mmap failed"); + } + if (!do_mmap) { + for (i = 0; i < count; i++) { + ret = pread(fd, buf, buf_size, offset + buf_size * i); + if (ret != buf_size) { + printf("pread expected: %"PRIu64", readed: %"PRIu64"\n", + buf_size, ret); + if (ret > 0) { + read_cnt += ret; + memcpy(print_buf, buf, print_bytes); + } + break; + } + + read_cnt += ret; + if (i == 0) + memcpy(print_buf, buf, print_bytes); + } + } else { + read_cnt = count * buf_size; + memcpy(print_buf, data, print_bytes); + } + printf("Read %"PRIu64" bytes total_time = %"PRIu64" us, BW = %.Lf MB/s print %u bytes:\n", + read_cnt, get_current_us() - total_time, + ((long double)read_cnt / (get_current_us() - total_time)), print_bytes); + printf("%08"PRIx64" : ", offset); + for (i = 1; i <= print_bytes; i++) { + printf("%02x", print_buf[i - 1]); + if (i % 16 == 0) + printf("\n%08"PRIx64" : ", offset + 16 * i); + else if (i % 2 == 0) + printf(" "); + } + printf("\n"); + exit(0); +} + +#define fragread_desc "read data with a fragmented buffer from file" +#define fragread_help \ +"f2fs_io fragread [chunk_size in 4kb] [offset in chunk_size] [count] [advice] [file_path]\n\n" \ +"Read data in file_path and print nbytes\n" \ +"advice can be\n" \ +" 1 : set sequential|willneed\n" \ +" 0 : none\n" \ + +#ifndef PAGE_SIZE +#define PAGE_SIZE sysconf(_SC_PAGESIZE) +#endif +#define ALLOC_SIZE (2 * 1024 * 1024 - 4 * 1024) // 2MB - 4KB + +static void do_fragread(int argc, char **argv, const struct cmd_desc *cmd) +{ + u64 buf_size = 0, ret = 0, read_cnt = 0; + u64 offset; + char *buf = NULL; + uintptr_t idx, ptr; + unsigned bs, count, i; + u64 total_time = 0; + int flags = 0, alloc_count = 0; + void *mem_hole, **mem_holes; + int fd, advice; + + if (argc != 6) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + bs = atoi(argv[1]); + if (bs > 256 * 1024) + die("Too big chunk size - limit: 1GB"); + buf_size = bs * F2FS_DEFAULT_BLKSIZE; + + offset = atoi(argv[2]) * buf_size; + count = atoi(argv[3]); + advice = atoi(argv[4]); + mem_holes = xmalloc(sizeof(void *) * (buf_size / PAGE_SIZE)); + + /* 1. Allocate the buffer using mmap. */ + buf = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + + /* 2. Loop and touch each page. */ + for (idx = (uintptr_t)buf; idx < (uintptr_t)buf + buf_size; + idx += PAGE_SIZE) + { + /* Touch the current page. */ + volatile char *page = (volatile char *)idx; + *page; + + /* 3. Allocate (2M - 4K) memory using mmap and touch all of it. */ + mem_hole = mmap(NULL, ALLOC_SIZE, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (mem_hole == MAP_FAILED) + die_errno("map failed"); + + /* Store the allocated memory pointer. */ + mem_holes[alloc_count++] = mem_hole; + + /* Touch all allocated memory. */ + for (ptr = (uintptr_t)mem_hole; + ptr < (uintptr_t)mem_hole + ALLOC_SIZE; + ptr += PAGE_SIZE) { + volatile char *alloc_page = (volatile char *)ptr; + *alloc_page; + } + } + printf("Touched allocated memory: count = %u\n", alloc_count); + printf(" - allocated memory: = "); + for (idx = 0; idx < 5; idx++) + printf(" %p", mem_holes[idx]); + printf("\n"); + + /* Pin the pages. */ + if (mlock(buf, buf_size)) + die_errno("mlock failed"); + + fd = xopen(argv[5], O_RDONLY | flags, 0); + + if (advice) { + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, + POSIX_FADV_SEQUENTIAL) != 0) + die_errno("fadvise failed"); + if (posix_fadvise(fd, 0, F2FS_DEFAULT_BLKSIZE, + POSIX_FADV_WILLNEED) != 0) + die_errno("fadvise failed"); + printf("fadvise SEQUENTIAL|WILLNEED to a file: %s\n", argv[5]); + } + + total_time = get_current_us(); + + for (i = 0; i < count; i++) { + ret = pread(fd, buf, buf_size, offset + buf_size * i); + if (ret != buf_size) { + printf("pread expected: %"PRIu64", readed: %"PRIu64"\n", + buf_size, ret); + if (ret > 0) + read_cnt += ret; + break; + } + + read_cnt += ret; + } + printf("Fragmented_Read %"PRIu64" bytes total_time = %"PRIu64" us, BW = %.Lf MB/s\n", + read_cnt, get_current_us() - total_time, + ((long double)read_cnt / (get_current_us() - total_time))); + printf("\n"); + exit(0); +} + +#define randread_desc "random read data from file" +#define randread_help \ +"f2fs_io randread [chunk_size in 4kb] [count] [IO] [advise] [file_path]\n\n" \ +"Do random read data in file_path\n" \ +"IO can be\n" \ +" buffered : buffered IO\n" \ +" dio : direct IO\n" \ +" mmap : mmap IO\n" \ +"advice can be\n" \ +" 1 : set random|willneed\n" \ +" 0 : none\n" \ + +static void do_randread(int argc, char **argv, const struct cmd_desc *cmd) +{ + u64 buf_size = 0, ret = 0, read_cnt = 0; + u64 idx, end_idx, aligned_size; + char *buf = NULL; + char *data; + unsigned bs, count, i, j; + u64 total_time = 0, elapsed_time = 0; + int flags = 0; + int do_mmap = 0; + int fd, advice; + time_t t; + struct stat stbuf; + + if (argc != 6) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + bs = atoi(argv[1]); + if (bs > 1024) + die("Too big chunk size - limit: 4MB"); + buf_size = bs * F2FS_DEFAULT_BLKSIZE; + + buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, buf_size); + + count = atoi(argv[2]); + if (!strcmp(argv[3], "dio")) + flags |= O_DIRECT; + else if (!strcmp(argv[3], "mmap")) + do_mmap = 1; + else if (strcmp(argv[3], "buffered")) + die("Wrong IO type"); + + fd = xopen(argv[5], O_RDONLY | flags, 0); + + advice = atoi(argv[4]); + if (advice) { + if (posix_fadvise(fd, 0, stbuf.st_size, POSIX_FADV_RANDOM) != 0) + die_errno("fadvise failed"); + if (posix_fadvise(fd, 0, 4096, POSIX_FADV_WILLNEED) != 0) + die_errno("fadvise failed"); + printf("fadvise RANDOM|WILLNEED to a file: %s\n", argv[5]); + } + + if (fstat(fd, &stbuf) != 0) + die_errno("fstat of source file failed"); + + aligned_size = (u64)stbuf.st_size & ~((u64)(F2FS_DEFAULT_BLKSIZE - 1)); + if (aligned_size < buf_size) + die("File is too small to random read"); + end_idx = (u64)(aligned_size - buf_size) / (u64)F2FS_DEFAULT_BLKSIZE + 1; + + if (do_mmap) { + data = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + die("Mmap failed"); + if (madvise((void *)data, stbuf.st_size, MADV_RANDOM) != 0) + die_errno("madvise failed"); + } + + srand((unsigned) time(&t)); + + total_time = get_current_us(); + + for (i = 0; i < count; i++) { + idx = rand() % end_idx; + + if (!do_mmap) { + ret = pread(fd, buf, buf_size, 4096 * idx); + if (ret != buf_size) + break; + } else { + for (j = 0; j < bs; j++) + *buf = data[4096 * (idx + j)]; + } + read_cnt += buf_size; + } + elapsed_time = get_current_us() - total_time; + + printf("Read %"PRIu64" bytes total_time = %"PRIu64" us, avg. latency = %.Lf us, IOPs= %.Lf, BW = %.Lf MB/s\n", + read_cnt, elapsed_time, + (long double)elapsed_time / count, + (long double)count * 1000 * 1000 / elapsed_time, + (long double)read_cnt / elapsed_time); + exit(0); +} + +#define fiemap_desc "get block address in file" +#define fiemap_help \ +"f2fs_io fiemap [offset in 4kb] [count in 4kb] [file_path]\n\n"\ + +#if defined(HAVE_LINUX_FIEMAP_H) && defined(HAVE_LINUX_FS_H) +static void do_fiemap(int argc, char **argv, const struct cmd_desc *cmd) +{ + unsigned int i; + int fd, extents_mem_size; + u64 start, length; + u32 mapped_extents; + struct fiemap *fm = xmalloc(sizeof(struct fiemap)); + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + memset(fm, 0, sizeof(struct fiemap)); + start = (u64)atoi(argv[1]) * F2FS_DEFAULT_BLKSIZE; + length = (u64)atoi(argv[2]) * F2FS_DEFAULT_BLKSIZE; + fm->fm_start = start; + fm->fm_length = length; + + fd = xopen(argv[3], O_RDONLY | O_LARGEFILE, 0); + + printf("Fiemap: offset = %"PRIu64" len = %"PRIu64"\n", + start / F2FS_DEFAULT_BLKSIZE, + length / F2FS_DEFAULT_BLKSIZE); + if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0) + die_errno("FIEMAP failed"); + + mapped_extents = fm->fm_mapped_extents; + extents_mem_size = sizeof(struct fiemap_extent) * mapped_extents; + free(fm); + fm = xmalloc(sizeof(struct fiemap) + extents_mem_size); + + memset(fm, 0, sizeof(struct fiemap) + extents_mem_size); + fm->fm_start = start; + fm->fm_length = length; + fm->fm_extent_count = mapped_extents; + + if (ioctl(fd, FS_IOC_FIEMAP, fm) < 0) + die_errno("FIEMAP failed"); + + printf("\t%-17s%-17s%-17s%s\n", "logical addr.", "physical addr.", "length", "flags"); + for (i = 0; i < fm->fm_mapped_extents; i++) { + printf("%d\t%.16llx %.16llx %.16llx %.8x\n", i, + fm->fm_extents[i].fe_logical, fm->fm_extents[i].fe_physical, + fm->fm_extents[i].fe_length, fm->fm_extents[i].fe_flags); + + if (fm->fm_extents[i].fe_flags & FIEMAP_EXTENT_LAST) + break; + } + printf("\n"); + free(fm); + exit(0); +} +#else +static void do_fiemap(int UNUSED(argc), char **UNUSED(argv), + const struct cmd_desc *UNUSED(cmd)) +{ + die("Not support for this platform"); +} +#endif + +#define gc_urgent_desc "start/end/run gc_urgent for given time period" +#define gc_urgent_help \ +"f2fs_io gc_urgent $dev [start/end/run] [time in sec]\n\n"\ +" - f2fs_io gc_urgent sda21 start\n" \ +" - f2fs_io gc_urgent sda21 end\n" \ +" - f2fs_io gc_urgent sda21 run 10\n" \ + +static void do_gc_urgent(int argc, char **argv, const struct cmd_desc *cmd) +{ + char command[255]; + + if (argc == 3 && !strcmp(argv[2], "start")) { + printf("gc_urgent: start on %s\n", argv[1]); + sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]); + if (system(command)) + exit(1); + } else if (argc == 3 && !strcmp(argv[2], "end")) { + printf("gc_urgent: end on %s\n", argv[1]); + sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]); + if (system(command)) + exit(1); + } else if (argc == 4 && !strcmp(argv[2], "run")) { + printf("gc_urgent: start on %s for %d secs\n", argv[1], atoi(argv[3])); + sprintf(command, "echo %d > %s/%s/gc_urgent", 1, "/sys/fs/f2fs/", argv[1]); + if (system(command)) + exit(1); + sleep(atoi(argv[3])); + printf("gc_urgent: end on %s for %d secs\n", argv[1], atoi(argv[3])); + sprintf(command, "echo %d > %s/%s/gc_urgent", 0, "/sys/fs/f2fs/", argv[1]); + if (system(command)) + exit(1); + } else { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } +} + +#define defrag_file_desc "do defragment on file" +#define defrag_file_help \ +"f2fs_io defrag_file [start] [length] [file_path]\n\n" \ +" start : start offset of defragment region, unit: bytes\n" \ +" length : bytes number of defragment region\n" \ + +static void do_defrag_file(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_defragment df; + u64 len; + int ret, fd; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + df.start = atoll(argv[1]); + df.len = len = atoll(argv[2]); + + fd = xopen(argv[3], O_RDWR, 0); + + ret = ioctl(fd, F2FS_IOC_DEFRAGMENT, &df); + if (ret < 0) + die_errno("F2FS_IOC_DEFRAGMENT failed"); + + printf("defrag %s in region[%"PRIu64", %"PRIu64"]\n", + argv[3], df.start, df.start + len); + exit(0); +} + +#define copy_desc "copy a file" +#define copy_help \ +"f2fs_io copy [-d] [-m] [-s] src_path dst_path\n\n" \ +" src_path : path to source file\n" \ +" dst_path : path to destination file\n" \ +" -d : use direct I/O\n" \ +" -m : mmap the source file\n" \ +" -s : use sendfile\n" \ + +static void do_copy(int argc, char **argv, const struct cmd_desc *cmd) +{ + int c; + int src_fd; + int dst_fd; + int open_flags = 0; + bool mmap_source_file = false; + bool use_sendfile = false; + ssize_t ret; + + while ((c = getopt(argc, argv, "dms")) != -1) { + switch (c) { + case 'd': + open_flags |= O_DIRECT; + break; + case 'm': + mmap_source_file = true; + break; + case 's': + use_sendfile = true; + break; + default: + fputs(cmd->cmd_help, stderr); + exit(2); + } + } + argc -= optind; + argv += optind; + if (argc != 2) { + fputs("Wrong number of arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(2); + } + if (mmap_source_file && use_sendfile) + die("-m and -s are mutually exclusive"); + + src_fd = xopen(argv[0], O_RDONLY | open_flags, 0); + dst_fd = xopen(argv[1], O_WRONLY | O_CREAT | O_TRUNC | open_flags, 0644); + + if (mmap_source_file) { + struct stat stbuf; + void *src_addr; + + if (fstat(src_fd, &stbuf) != 0) + die_errno("fstat of source file failed"); + + if ((size_t)stbuf.st_size != stbuf.st_size) + die("Source file is too large"); + + src_addr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_SHARED, + src_fd, 0); + if (src_addr == MAP_FAILED) + die("mmap of source file failed"); + + full_write(dst_fd, src_addr, stbuf.st_size); + + munmap(src_addr, stbuf.st_size); + } else if (use_sendfile) { + while ((ret = sendfile(dst_fd, src_fd, NULL, INT_MAX)) > 0) + ; + if (ret < 0) + die_errno("sendfile failed"); + } else { + char *buf = aligned_xalloc(F2FS_DEFAULT_BLKSIZE, F2FS_DEFAULT_BLKSIZE); + + while ((ret = xread(src_fd, buf, F2FS_DEFAULT_BLKSIZE)) > 0) + full_write(dst_fd, buf, ret); + free(buf); + } + close(src_fd); + close(dst_fd); +} + +#define get_cblocks_desc "get number of reserved blocks on compress inode" +#define get_cblocks_help "f2fs_io get_cblocks [file]\n\n" + +static void do_get_cblocks(int argc, char **argv, const struct cmd_desc *cmd) +{ + unsigned long long blkcnt; + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_BLOCKS, &blkcnt); + if (ret < 0) + die_errno("F2FS_IOC_GET_COMPRESS_BLOCKS failed"); + + printf("%llu\n", blkcnt); + + exit(0); +} + +#define release_cblocks_desc "release reserved blocks on compress inode" +#define release_cblocks_help "f2fs_io release_cblocks [file]\n\n" + +static void do_release_cblocks(int argc, char **argv, const struct cmd_desc *cmd) +{ + unsigned long long blkcnt; + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_RELEASE_COMPRESS_BLOCKS, &blkcnt); + if (ret < 0) + die_errno("F2FS_IOC_RELEASE_COMPRESS_BLOCKS failed"); + + printf("%llu\n", blkcnt); + + exit(0); +} + +#define reserve_cblocks_desc "reserve blocks on compress inode" +#define reserve_cblocks_help "f2fs_io reserve_cblocks [file]\n\n" + +static void do_reserve_cblocks(int argc, char **argv, const struct cmd_desc *cmd) +{ + unsigned long long blkcnt; + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_RESERVE_COMPRESS_BLOCKS, &blkcnt); + if (ret < 0) + die_errno("F2FS_IOC_RESERVE_COMPRESS_BLOCKS failed"); + + printf("%llu\n", blkcnt); + + exit(0); +} + +#define get_coption_desc "get compression option of a compressed file" +#define get_coption_help \ +"f2fs_io get_coption [file]\n\n" \ +" algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \ +" log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n" + +static void do_get_coption(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_comp_option option; + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GET_COMPRESS_OPTION, &option); + if (ret < 0) + die_errno("F2FS_IOC_GET_COMPRESS_OPTION failed"); + + printf("compression algorithm:%u\n", option.algorithm); + printf("compression cluster log size:%u\n", option.log_cluster_size); + + exit(0); +} + +#define set_coption_desc "set compression option of a compressed file" +#define set_coption_help \ +"f2fs_io set_coption [algorithm] [log_cluster_size] [file_path]\n\n" \ +" algorithm : compression algorithm (0:lzo, 1: lz4, 2:zstd, 3:lzorle)\n" \ +" log_cluster_size : compression cluster log size (2 <= log_size <= 8)\n" + +static void do_set_coption(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_comp_option option; + int fd, ret; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + option.algorithm = atoi(argv[1]); + option.log_cluster_size = atoi(argv[2]); + + fd = xopen(argv[3], O_WRONLY, 0); + + ret = ioctl(fd, F2FS_IOC_SET_COMPRESS_OPTION, &option); + if (ret < 0) + die_errno("F2FS_IOC_SET_COMPRESS_OPTION failed"); + + printf("set compression option: algorithm=%u, log_cluster_size=%u\n", + option.algorithm, option.log_cluster_size); + exit(0); +} + +#define decompress_desc "decompress an already compressed file" +#define decompress_help "f2fs_io decompress [file_path]\n\n" + +static void do_decompress(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, ret; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + ret = ioctl(fd, F2FS_IOC_DECOMPRESS_FILE); + if (ret < 0) + die_errno("F2FS_IOC_DECOMPRESS_FILE failed"); + + exit(0); +} + +#define compress_desc "compress a compression enabled file" +#define compress_help "f2fs_io compress [file_path]\n\n" + +static void do_compress(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, ret; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + ret = ioctl(fd, F2FS_IOC_COMPRESS_FILE); + if (ret < 0) + die_errno("F2FS_IOC_COMPRESS_FILE failed"); + + exit(0); +} + +#define get_filename_encrypt_mode_desc "get file name encrypt mode" +#define get_filename_encrypt_mode_help \ +"f2fs_io filename_encrypt_mode [file or directory path]\n\n" \ +"Get the file name encription mode of the given file/directory.\n" \ + +static void do_get_filename_encrypt_mode (int argc, char **argv, + const struct cmd_desc *cmd) +{ + static const char *enc_name[] = { + "invalid", /* FSCRYPT_MODE_INVALID (0) */ + "aes-256-xts", /* FSCRYPT_MODE_AES_256_XTS (1) */ + "aes-256-gcm", /* FSCRYPT_MODE_AES_256_GCM (2) */ + "aes-256-cbc", /* FSCRYPT_MODE_AES_256_CBC (3) */ + "aes-256-cts", /* FSCRYPT_MODE_AES_256_CTS (4) */ + "aes-128-cbc", /* FSCRYPT_MODE_AES_128_CBC (5) */ + "aes-128-cts", /* FSCRYPT_MODE_AES_128_CTS (6) */ + "speck128-256-xts", /* FSCRYPT_MODE_SPECK128_256_XTS (7) */ + "speck128-256-cts", /* FSCRYPT_MODE_SPECK128_256_CTS (8) */ + "adiantum", /* FSCRYPT_MODE_ADIANTUM (9) */ + "aes-256-hctr2", /* FSCRYPT_MODE_AES_256_HCTR2 (10) */ + }; + int fd, mode, ret; + struct fscrypt_get_policy_ex_arg arg; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDONLY, 0); + arg.policy_size = sizeof(arg.policy); + ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY_EX, &arg); + if (ret != 0 && errno == ENOTTY) + ret = ioctl(fd, FS_IOC_GET_ENCRYPTION_POLICY, arg.policy.v1); + close(fd); + + if (ret) { + perror("FS_IOC_GET_ENCRYPTION_POLICY|_EX"); + exit(1); + } + + switch (arg.policy.version) { + case FSCRYPT_POLICY_V1: + mode = arg.policy.v1.filenames_encryption_mode; + break; + case FSCRYPT_POLICY_V2: + mode = arg.policy.v2.filenames_encryption_mode; + break; + default: + printf("Do not support policy version: %d\n", + arg.policy.version); + exit(1); + } + + if (mode >= sizeof(enc_name)/sizeof(enc_name[0])) { + printf("Do not support algorithm: %d\n", mode); + exit(1); + } + printf ("%s\n", enc_name[mode]); + exit(0); +} + +#define rename_desc "rename source to target file with fsync option" +#define rename_help \ +"f2fs_io rename [src_path] [target_path] [fsync_after_rename]\n\n" \ +"e.g., f2fs_io rename source dest 1\n" \ +" 1. open(source)\n" \ +" 2. rename(source, dest)\n" \ +" 3. fsync(source)\n" \ +" 4. close(source)\n" + +static void do_rename(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd = -1; + int ret; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if (atoi(argv[3])) + fd = xopen(argv[1], O_WRONLY, 0); + + ret = rename(argv[1], argv[2]); + if (ret < 0) + die_errno("rename failed"); + + if (fd >= 0) { + if (fsync(fd) != 0) + die_errno("fsync failed: %s", argv[1]); + close(fd); + } + exit(0); +} + +#define gc_desc "trigger filesystem GC" +#define gc_help "f2fs_io gc sync_mode [file_path]\n\n" + +static void do_gc(int argc, char **argv, const struct cmd_desc *cmd) +{ + u32 sync; + int ret, fd; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + sync = atoi(argv[1]); + + fd = xopen(argv[2], O_RDONLY, 0); + + ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT, &sync); + if (ret < 0) + die_errno("F2FS_IOC_GARBAGE_COLLECT failed"); + + printf("trigger %s gc ret=%d\n", + sync ? "synchronous" : "asynchronous", ret); + exit(0); +} + +#define checkpoint_desc "trigger filesystem checkpoint" +#define checkpoint_help "f2fs_io checkpoint [file_path]\n\n" + +static void do_checkpoint(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + ret = ioctl(fd, F2FS_IOC_WRITE_CHECKPOINT); + if (ret < 0) + die_errno("F2FS_IOC_WRITE_CHECKPOINT failed"); + + printf("trigger filesystem checkpoint ret=%d\n", ret); + exit(0); +} + +#define precache_extents_desc "trigger precache extents" +#define precache_extents_help "f2fs_io precache_extents [file_path]\n\n" + +static void do_precache_extents(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret, fd; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_WRONLY, 0); + + ret = ioctl(fd, F2FS_IOC_PRECACHE_EXTENTS); + if (ret < 0) + die_errno("F2FS_IOC_PRECACHE_EXTENTS failed"); + + printf("trigger precache extents ret=%d\n", ret); + exit(0); +} + +#define move_range_desc "moving a range of data blocks from source file to destination file" +#define move_range_help \ +"f2fs_io move_range [src_path] [dst_path] [src_start] [dst_start] " \ +"[length]\n\n" \ +" src_path : path to source file\n" \ +" dst_path : path to destination file\n" \ +" src_start : start offset of src file move region, unit: bytes\n" \ +" dst_start : start offset of dst file move region, unit: bytes\n" \ +" length : size to move\n" \ + +static void do_move_range(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_move_range range; + int ret, fd; + + if (argc != 6) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + fd = xopen(argv[1], O_RDWR, 0); + range.dst_fd = xopen(argv[2], O_RDWR | O_CREAT, 0644); + range.pos_in = atoll(argv[3]); + range.pos_out = atoll(argv[4]); + range.len = atoll(argv[5]); + + ret = ioctl(fd, F2FS_IOC_MOVE_RANGE, &range); + if (ret < 0) + die_errno("F2FS_IOC_MOVE_RANGE failed"); + + printf("move range ret=%d\n", ret); + exit(0); +} + +#define gc_range_desc "trigger filesystem gc_range" +#define gc_range_help "f2fs_io gc_range [sync_mode] [start] [length] [file_path]\n\n"\ +" sync_mode : 0: asynchronous, 1: synchronous\n" \ +" start : start offset of defragment region, unit: 4kb\n" \ +" length : bytes number of defragment region, unit: 4kb\n" \ + +static void do_gc_range(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_gc_range range; + int ret, fd; + + if (argc != 5) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + range.sync = atoi(argv[1]); + range.start = (u64)atoi(argv[2]); + range.len = (u64)atoi(argv[3]); + + fd = xopen(argv[4], O_RDWR, 0); + + ret = ioctl(fd, F2FS_IOC_GARBAGE_COLLECT_RANGE, &range); + if (ret < 0) { + die_errno("F2FS_IOC_GARBAGE_COLLECT_RANGE failed"); + } + + printf("trigger %s gc_range [%"PRIu64", %"PRIu64"] ret=%d\n", + range.sync ? "synchronous" : "asynchronous", + range.start, range.len, ret); + exit(0); +} + +#define listxattr_desc "listxattr" +#define listxattr_help "f2fs_io listxattr [file_path]\n\n" + +static void do_listxattr(int argc, char **argv, const struct cmd_desc *cmd) +{ + char *buf, *key, *val; + ssize_t buflen, vallen, keylen; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + buflen = listxattr(argv[1], NULL, 0); + if (buflen == -1) { + perror("listxattr"); + exit(1); + } + if (buflen == 0) { + printf("%s has no attributes.\n", argv[1]); + exit(0); + } + buf = xmalloc(buflen); + buflen = listxattr(argv[1], buf, buflen); + if (buflen == -1) { + perror("listxattr"); + exit(1); + } + + key = buf; + while (buflen > 0) { + printf("%s: ", key); + vallen = getxattr(argv[1], key, NULL, 0); + if (vallen == -1) { + perror("getxattr"); + exit(1); + } + if (vallen == 0) { + printf(""); + } else { + val = xmalloc(vallen + 1); + vallen = getxattr(argv[1], key, val, vallen); + if (vallen == -1) { + perror("getxattr"); + exit(1); + } + val[vallen] = 0; + printf("%s", val); + free(val); + } + printf("\n"); + keylen = strlen(key) + 1; + buflen -= keylen; + key += keylen; + } + exit(0); +} + +#define setxattr_desc "setxattr" +#define setxattr_help "f2fs_io setxattr [name] [value] [file_path]\n\n" + +static void do_setxattr(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret; + char *value; + unsigned char tmp; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if (!strcmp(argv[1], F2FS_SYSTEM_ADVISE_NAME)) { + tmp = strtoul(argv[2], NULL, 0); + value = (char *)&tmp; + } else { + value = argv[2]; + } + + ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_CREATE); + printf("setxattr %s CREATE: name: %s, value: %s: ret=%d\n", + argv[3], argv[1], argv[2], ret); + if (ret < 0 && errno == EEXIST) { + ret = setxattr(argv[3], argv[1], value, strlen(argv[2]), XATTR_REPLACE); + printf("setxattr %s REPLACE: name: %s, value: %s: ret=%d\n", + argv[3], argv[1], argv[2], ret); + } + if (ret < 0) + perror("setxattr"); + exit(0); +} + +#define removexattr_desc "removexattr" +#define removexattr_help "f2fs_io removexattr [name] [file_path]\n\n" + +static void do_removexattr(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + ret = removexattr(argv[2], argv[1]); + printf("removexattr %s REMOVE: name: %s: ret=%d\n", argv[1], argv[2], ret); + exit(0); +} + +#define lseek_desc "do lseek for a file" +#define lseek_help \ +"f2fs_io lseek [whence] [offset] [file_path]\n\n" \ +"Do lseek file data in file_path and return the adjusted file offset\n" \ +"whence can be\n" \ +" set : SEEK_SET, The file offset is set to offset bytes\n" \ +" cur : SEEK_CUR, The file offset is set to its current location plus offset bytes\n" \ +" end : SEEK_END, The file offset is set to the size of the file plus offset bytes\n" \ +" data : SEEK_DATA, set the file offset to the next data location from offset\n" \ +" hole : SEEK_HOLE, set the file offset to the next hole from offset\n" + +static void do_lseek(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, whence; + off_t offset, ret; + + if (argc != 4) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + offset = atoll(argv[2]); + + if (!strcmp(argv[1], "set")) + whence = SEEK_SET; + else if (!strcmp(argv[1], "cur")) + whence = SEEK_CUR; + else if (!strcmp(argv[1], "end")) + whence = SEEK_END; + else if (!strcmp(argv[1], "data")) + whence = SEEK_DATA; + else if (!strcmp(argv[1], "hole")) + whence = SEEK_HOLE; + else + die("Wrong whence type"); + + fd = xopen(argv[3], O_RDONLY, 0); + + ret = lseek(fd, offset, whence); + if (ret < 0) + die_errno("lseek failed"); + printf("returned offset=%lld\n", (long long)ret); + exit(0); +} + +#define get_advise_desc "get_advise" +#define get_advise_help "f2fs_io get_advise [file_path]\n\n" + +static void do_get_advise(int argc, char **argv, const struct cmd_desc *cmd) +{ + int ret; + unsigned char value; + + if (argc != 2) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + ret = getxattr(argv[1], F2FS_SYSTEM_ADVISE_NAME, &value, sizeof(value)); + if (ret != sizeof(value)) { + perror("getxattr"); + exit(1); + } + + printf("i_advise=0x%x, advise_type: ", value); + if (value & FADVISE_COLD_BIT) + printf("cold "); + if (value & FADVISE_LOST_PINO_BIT) + printf("lost_pino "); + if (value & FADVISE_ENCRYPT_BIT) + printf("encrypt "); + if (value & FADVISE_ENC_NAME_BIT) + printf("enc_name "); + if (value & FADVISE_KEEP_SIZE_BIT) + printf("keep_size "); + if (value & FADVISE_HOT_BIT) + printf("hot "); + if (value & FADVISE_VERITY_BIT) + printf("verity "); + if (value & FADVISE_TRUNC_BIT) + printf("trunc "); + printf("\n"); +} + +#define ftruncate_desc "ftruncate a file" +#define ftruncate_help \ +"f2fs_io ftruncate [length] [file_path]\n\n" \ +"Do ftruncate a file in file_path with the length\n" \ + +static void do_ftruncate(int argc, char **argv, const struct cmd_desc *cmd) +{ + int fd, ret; + off_t length; + + if (argc != 3) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + length = atoll(argv[1]); + fd = xopen(argv[2], O_WRONLY, 0); + + ret = ftruncate(fd, length); + if (ret < 0) + die_errno("ftruncate failed"); + exit(0); +} + +#define CMD_HIDDEN 0x0001 +#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 } +#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN } + +static void do_help(int argc, char **argv, const struct cmd_desc *cmd); +const struct cmd_desc cmd_list[] = { + _CMD(help), + CMD(fsync), + CMD(fdatasync), + CMD(set_verity), + CMD(getflags), + CMD(setflags), + CMD(clearflags), + CMD(shutdown), + CMD(pinfile), + CMD(fadvise), + CMD(fallocate), + CMD(erase), + CMD(write), + CMD(write_advice), + CMD(read), + CMD(randread), + CMD(fragread), + CMD(fiemap), + CMD(gc_urgent), + CMD(defrag_file), + CMD(copy), + CMD(get_cblocks), + CMD(release_cblocks), + CMD(reserve_cblocks), + CMD(get_coption), + CMD(set_coption), + CMD(decompress), + CMD(compress), + CMD(get_filename_encrypt_mode), + CMD(rename), + CMD(gc), + CMD(checkpoint), + CMD(precache_extents), + CMD(move_range), + CMD(gc_range), + CMD(listxattr), + CMD(setxattr), + CMD(removexattr), + CMD(lseek), + CMD(get_advise), + CMD(ioprio), + CMD(ftruncate), + { NULL, NULL, NULL, NULL, 0 } +}; + +static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd)) +{ + const struct cmd_desc *p; + + if (argc > 1) { + for (p = cmd_list; p->cmd_name; p++) { + if (p->cmd_flags & CMD_HIDDEN) + continue; + if (strcmp(p->cmd_name, argv[1]) == 0) { + putc('\n', stdout); + fputs("USAGE:\n ", stdout); + fputs(p->cmd_help, stdout); + exit(0); + } + } + printf("Unknown command: %s\n\n", argv[1]); + } + + fputs("Available commands:\n", stdout); + for (p = cmd_list; p->cmd_name; p++) { + if (p->cmd_flags & CMD_HIDDEN) + continue; + printf(" %-20s %s\n", p->cmd_name, p->cmd_desc); + } + printf("\nTo get more information on a command, " + "type 'f2fs_io help cmd'\n"); + exit(0); +} + +static void die_signal_handler(int UNUSED(signum), siginfo_t *UNUSED(siginfo), + void *UNUSED(context)) +{ + exit(-1); +} + +static void sigcatcher_setup(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_sigaction = die_signal_handler; + sa.sa_flags = SA_SIGINFO; + + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGFPE, &sa, 0); + sigaction(SIGILL, &sa, 0); + sigaction(SIGBUS, &sa, 0); + sigaction(SIGSEGV, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + sigaction(SIGALRM, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGUSR2, &sa, 0); + sigaction(SIGPOLL, &sa, 0); + sigaction(SIGPROF, &sa, 0); + sigaction(SIGSYS, &sa, 0); + sigaction(SIGTRAP, &sa, 0); + sigaction(SIGVTALRM, &sa, 0); + sigaction(SIGXCPU, &sa, 0); + sigaction(SIGXFSZ, &sa, 0); +} + +int main(int argc, char **argv) +{ + const struct cmd_desc *cmd; + + if (argc < 2) + do_help(argc, argv, cmd_list); + + sigcatcher_setup(); + for (cmd = cmd_list; cmd->cmd_name; cmd++) { + if (strcmp(cmd->cmd_name, argv[1]) == 0) { + cmd->cmd_func(argc - 1, argv + 1, cmd); + exit(0); + } + } + printf("Unknown command: %s\n\n", argv[1]); + do_help(1, argv, cmd_list); + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.h b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.h new file mode 100644 index 00000000000..21fd3864a20 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io/f2fs_io.h @@ -0,0 +1,255 @@ +/* + * ioctl.h - f2fs ioctl header + * + * Authors: Jaegeuk Kim + */ + +#include +#include + +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#ifdef HAVE_LINUX_FIEMAP_H +#include +#endif +#ifdef HAVE_LINUX_FS_H +#include +#endif +#ifdef HAVE_LINUX_VERITY_H +#include +#endif + +#include + +#ifdef UNUSED +#elif defined(__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__((unused)) +#elif defined(__LCLINT__) +# define UNUSED(x) x +#elif defined(__cplusplus) +# define UNUSED(x) +#else +# define UNUSED(x) x +#endif + +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; + +#ifndef HAVE_LINUX_TYPES_H +typedef u8 __u8; +typedef u16 __u16; +typedef u32 __u32; +typedef u16 __le16; +typedef u32 __le32; +typedef u16 __be16; +typedef u32 __be32; +#endif + +#define F2FS_DEFAULT_BLKSIZE 4096 +#define NEW_ADDR 0xFFFFFFFF + +#ifndef FS_IOC_GETFLAGS +#define FS_IOC_GETFLAGS _IOR('f', 1, long) +#endif +#ifndef FS_IOC_SETFLAGS +#define FS_IOC_SETFLAGS _IOW('f', 2, long) +#endif + +#define F2FS_IOCTL_MAGIC 0xf5 +#define F2FS_IOC_GETFLAGS FS_IOC_GETFLAGS +#define F2FS_IOC_SETFLAGS FS_IOC_SETFLAGS + +#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1) +#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2) +#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3) +#define F2FS_IOC_RELEASE_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 4) +#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5) +#define F2FS_IOC_GARBAGE_COLLECT _IOW(F2FS_IOCTL_MAGIC, 6, __u32) +#define F2FS_IOC_WRITE_CHECKPOINT _IO(F2FS_IOCTL_MAGIC, 7) +#define F2FS_IOC_DEFRAGMENT _IOWR(F2FS_IOCTL_MAGIC, 8, \ + struct f2fs_defragment) +#define F2FS_IOC_MOVE_RANGE _IOWR(F2FS_IOCTL_MAGIC, 9, \ + struct f2fs_move_range) +#define F2FS_IOC_FLUSH_DEVICE _IOW(F2FS_IOCTL_MAGIC, 10, \ + struct f2fs_flush_device) +#define F2FS_IOC_GARBAGE_COLLECT_RANGE _IOW(F2FS_IOCTL_MAGIC, 11, \ + struct f2fs_gc_range) +#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, __u32) +#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32) +#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32) +#define F2FS_IOC_PRECACHE_EXTENTS _IO(F2FS_IOCTL_MAGIC, 15) +#define F2FS_IOC_RESIZE_FS _IOW(F2FS_IOCTL_MAGIC, 16, __u64) +#define F2FS_IOC_GET_COMPRESS_BLOCKS _IOR(F2FS_IOCTL_MAGIC, 17, __u64) +#define F2FS_IOC_RELEASE_COMPRESS_BLOCKS \ + _IOR(F2FS_IOCTL_MAGIC, 18, __u64) +#define F2FS_IOC_RESERVE_COMPRESS_BLOCKS \ + _IOR(F2FS_IOCTL_MAGIC, 19, __u64) +#define F2FS_IOC_GET_COMPRESS_OPTION _IOR(F2FS_IOCTL_MAGIC, 21, \ + struct f2fs_comp_option) +#define F2FS_IOC_SET_COMPRESS_OPTION _IOW(F2FS_IOCTL_MAGIC, 22, \ + struct f2fs_comp_option) +#define F2FS_IOC_DECOMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 23) +#define F2FS_IOC_COMPRESS_FILE _IO(F2FS_IOCTL_MAGIC, 24) +#define F2FS_IOC_START_ATOMIC_REPLACE _IO(F2FS_IOCTL_MAGIC, 25) +#define F2FS_IOC_GET_DEV_ALIAS_FILE _IOR(F2FS_IOCTL_MAGIC, 26, __u32) +#define F2FS_IOC_IO_PRIO _IOW(F2FS_IOCTL_MAGIC, 27, __u32) + +#ifndef FSCRYPT_POLICY_V1 +#define FSCRYPT_POLICY_V1 0 +#define FSCRYPT_KEY_DESCRIPTOR_SIZE 8 +struct fscrypt_policy_v1 { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE]; +}; +#endif +#ifndef FS_IOC_GET_ENCRYPTION_POLICY +#define FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct fscrypt_policy_v1) +#endif + +#ifndef FSCRYPT_POLICY_V2 +#define FSCRYPT_POLICY_V2 2 +#define FSCRYPT_KEY_IDENTIFIER_SIZE 16 +struct fscrypt_policy_v2 { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 __reserved[4]; + __u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]; +}; +/* Struct passed to FS_IOC_GET_ENCRYPTION_POLICY_EX */ +struct fscrypt_get_policy_ex_arg { + __u64 policy_size; /* input/output */ + union { + __u8 version; + struct fscrypt_policy_v1 v1; + struct fscrypt_policy_v2 v2; + } policy; /* output */ +}; +#endif +#ifndef FS_IOC_GET_ENCRYPTION_POLICY_EX +#define FS_IOC_GET_ENCRYPTION_POLICY_EX _IOWR('f', 22, __u8[9]) /* size + version */ +#endif + +#define F2FS_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY +#define F2FS_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY +#define F2FS_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT + +#ifndef FS_IOC_ENABLE_VERITY +#define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) +#define FS_VERITY_HASH_ALG_SHA256 1 +struct fsverity_enable_arg { + __u32 version; + __u32 hash_algorithm; + __u32 block_size; + __u32 salt_size; + __u64 salt_ptr; + __u32 sig_size; + __u32 __reserved1; + __u64 sig_ptr; + __u64 __reserved2[11]; +}; +#endif +/* + * Inode flags + */ +#define F2FS_NOCOW_FL 0x00800000 /* Do not cow file */ + +/* + * should be same as XFS_IOC_GOINGDOWN. + * Flags for going down operation used by FS_IOC_GOINGDOWN + */ +#define F2FS_IOC_SHUTDOWN _IOR('X', 125, __u32) /* Shutdown */ +#define F2FS_GOING_DOWN_FULLSYNC 0x0 /* going down with full sync */ +#define F2FS_GOING_DOWN_METASYNC 0x1 /* going down with metadata */ +#define F2FS_GOING_DOWN_NOSYNC 0x2 /* going down */ +#define F2FS_GOING_DOWN_METAFLUSH 0x3 /* going down with meta flush */ +#define F2FS_GOING_DOWN_NEED_FSCK 0x4 /* going down to trigger fsck */ +#define F2FS_GOING_DOWN_MAX 0x5 + +#if defined(__KERNEL__) && defined(CONFIG_COMPAT) +/* + * ioctl commands in 32 bit emulation + */ +#define F2FS_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define F2FS_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define F2FS_IOC32_GETVERSION FS_IOC32_GETVERSION +#endif + +#define F2FS_IOC_FSGETXATTR FS_IOC_FSGETXATTR +#define F2FS_IOC_FSSETXATTR FS_IOC_FSSETXATTR + +#define F2FS_SYSTEM_ADVISE_NAME "system.advise" +#define FADVISE_COLD_BIT 0x01 +#define FADVISE_LOST_PINO_BIT 0x02 +#define FADVISE_ENCRYPT_BIT 0x04 +#define FADVISE_ENC_NAME_BIT 0x08 +#define FADVISE_KEEP_SIZE_BIT 0x10 +#define FADVISE_HOT_BIT 0x20 +#define FADVISE_VERITY_BIT 0x40 +#define FADVISE_TRUNC_BIT 0x80 + +/* used for F2FS_IOC_IO_PRIO */ +enum { + F2FS_IOPRIO_WRITE = 1, /* high write priority */ +}; + +#ifndef FS_IMMUTABLE_FL +#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#endif + +#ifndef FS_ENCRYPT_FL +#define FS_ENCRYPT_FL 0x00000800 /* Encrypted file */ +#endif +#ifndef FS_VERITY_FL +#define FS_VERITY_FL 0x00100000 /* Verity protected inode */ +#endif +#ifndef FS_INLINE_DATA_FL +#define FS_INLINE_DATA_FL 0x10000000 /* Inline data for regular/symlink files */ +#endif +#ifndef FS_NOCOW_FL +#define FS_NOCOW_FL 0x00800000 /* Do not cow file */ +#endif +#ifndef FS_NOCOMP_FL +#define FS_NOCOMP_FL 0x00000400 /* Don't compress */ +#endif +#ifndef FS_COMPR_FL +#define FS_COMPR_FL 0x00000004 /* Compress file */ +#endif +#ifndef FS_CASEFOLD_FL +#define FS_CASEFOLD_FL 0x40000000 /* Folder is case insensitive */ +#endif + +struct f2fs_gc_range { + u32 sync; + u64 start; + u64 len; +}; + +struct f2fs_defragment { + u64 start; + u64 len; +}; + +struct f2fs_move_range { + u32 dst_fd; /* destination fd */ + u64 pos_in; /* start position in src_fd */ + u64 pos_out; /* start position in dst_fd */ + u64 len; /* size to move */ +}; + +struct f2fs_flush_device { + u32 dev_num; /* device number to flush */ + u32 segments; /* # of segments to flush */ +}; + +struct f2fs_comp_option { + u8 algorithm; + u8 log_cluster_size; +}; diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io_parse.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io_parse.c new file mode 100644 index 00000000000..c3c1005ac27 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fs_io_parse.c @@ -0,0 +1,323 @@ +/* + * f2fs IO tracer + * + * Copyright (c) 2014 Motorola Mobility + * Copyright (c) 2014 Jaegeuk Kim + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include + +#define P_NAMELEN 16 + +/* For global trace methods */ +enum show_type { + SHOW_PID, + SHOW_FTYPE, + SHOW_ALL, +}; + +enum trace_types { + TP_PID, + TP_IOS, + TP_MAX, +}; + +struct tps { + enum trace_types type; + const char *name; +}; + +struct tps trace_points[] = { + { TP_PID, "f2fs_trace_pid" }, + { TP_IOS, "f2fs_trace_ios" }, +}; + +/* For f2fs_trace_pid and f2fs_trace_ios */ +enum rw_type { + READ, + WRITE, + MAX_RW, +}; + +enum file_type { + __NORMAL_FILE, + __DIR_FILE, + __NODE_FILE, + __META_FILE, + __ATOMIC_FILE, + __VOLATILE_FILE, + __MISC_FILE, + __NR_FILES, +}; + +char *file_type_string[] = { + "User ", + "Dir ", + "Node ", + "Meta ", + "Atomic ", + "Voltile ", + "Misc ", +}; + +struct pid_ent { + int pid; + char name[P_NAMELEN]; + unsigned long long io[__NR_FILES][MAX_RW]; + unsigned long long total_io[MAX_RW]; + LIST_ENTRY(pid_ent) ptr; +}; + +/* global variables */ +int major = 0, minor = 0; +int show_option = SHOW_ALL; +unsigned long long total_io[__NR_FILES][MAX_RW]; + +LIST_HEAD(plist, pid_ent) pid_info; + +/* Functions */ +static inline int atoh(char *str) +{ + int val; + sscanf(str, "%x", &val); + return val; +} + +static void do_init() +{ + struct pid_ent *misc; + + misc = calloc(1, sizeof(struct pid_ent)); + assert(misc); + + LIST_INIT(&pid_info); + LIST_INSERT_HEAD(&pid_info, misc, ptr); +} + +void show_usage() +{ + printf("\nUsage: parse.f2fs [options] log_file\n"); + printf("[options]:\n"); + printf(" -a RW sorted by pid & file types\n"); + printf(" -f RW sorted by file types\n"); + printf(" -p RW sorted by pid\n"); + printf(" -m major number\n"); + printf(" -n minor number\n"); + exit(1); +} + +static int parse_options(int argc, char *argv[]) +{ + const char *option_string = "fm:n:p"; + int option = 0; + + while ((option = getopt(argc, argv, option_string)) != EOF) { + switch (option) { + case 'f': + show_option = SHOW_FTYPE; + break; + case 'm': + major = atoh(optarg); + break; + case 'n': + minor = atoh(optarg); + break; + case 'p': + show_option = SHOW_PID; + break; + default: + printf("\tError: Unknown option %c\n", option); + show_usage(); + break; + } + } + if ((optind + 1) != argc) { + printf("\tError: Log file is not specified.\n"); + show_usage(); + } + return optind; +} + +struct pid_ent *get_pid_entry(int pid) +{ + struct pid_ent *entry; + + LIST_FOREACH(entry, &pid_info, ptr) { + if (entry->pid == pid) + return entry; + } + return LIST_FIRST(&pid_info); +} + +static void handle_tp_pid(char *ptr) +{ + struct pid_ent *pent; + + pent = calloc(1, sizeof(struct pid_ent)); + assert(pent); + + ptr = strtok(NULL, " "); + pent->pid = atoh(ptr); + + ptr = strtok(NULL, " "); + strcpy(pent->name, ptr); + + LIST_INSERT_HEAD(&pid_info, pent, ptr); +} + +static void handle_tp_ios(char *ptr) +{ + int pid, type, rw, len; + struct pid_ent *p; + + ptr = strtok(NULL, " "); + pid = atoh(ptr); + + ptr = strtok(NULL, " "); + ptr = strtok(NULL, " "); + type = atoh(ptr); + + ptr = strtok(NULL, " "); + rw = atoh(ptr); + + ptr = strtok(NULL, " "); + /* int op_flags = atoh(ptr) */ + ptr = strtok(NULL, " "); + /* unsigned long long blkaddr = atoh(ptr); */ + + ptr = strtok(NULL, " "); + len = atoh(ptr); + + /* update per-pid stat */ + p = get_pid_entry(pid); + p->io[type][rw & 0x1] += len; + p->total_io[rw & 0x1] += len; + + /* update total stat */ + total_io[type][rw & 0x1] += len; +} + +static void do_parse(FILE *file) +{ + char line[300]; + char *ptr; + int i; + + while (fgets(line, sizeof(line), file) != NULL) { + ptr = strtok(line, ":"); + + ptr = strtok(NULL, " :"); + + for (i = 0; i < TP_MAX; i++) { + if (!strcmp(ptr, trace_points[i].name)) + break; + } + if (i == TP_MAX) + continue; + ptr = strtok(NULL, " :"); + if (major && major != atoh(ptr)) + continue; + ptr = strtok(NULL, " :"); + if (minor && minor != atoh(ptr)) + continue; + + switch (i) { + case TP_PID: + handle_tp_pid(ptr); + break; + case TP_IOS: + handle_tp_ios(ptr); + break; + } + } +} + +static void __print_pid() +{ + struct pid_ent *entry; + int i; + + setlocale(LC_ALL, ""); + printf("%8s %16s %17s ||", "PID", "NAME", "R/W in 4KB"); + for (i = 0; i < __NR_FILES; i++) + printf(" %17s |", file_type_string[i]); + printf("\n"); + + LIST_FOREACH(entry, &pid_info, ptr) { + printf("%8x %16s %'8lld %'8lld ||", + entry->pid, entry->name, + entry->total_io[READ], + entry->total_io[WRITE]); + for (i = 0; i < __NR_FILES; i++) + printf(" %'8lld %'8lld |", + entry->io[i][READ], + entry->io[i][WRITE]); + printf("\n"); + } +} + +static void __print_ftype() +{ + int i; + + setlocale(LC_ALL, ""); + printf("\n===== Data R/W in 4KB according to File types =====\n"); + for (i = 0; i < __NR_FILES; i++) + printf(" %17s |", file_type_string[i]); + printf("\n"); + + for (i = 0; i < __NR_FILES; i++) + printf(" %'8lld %'8lld |", + total_io[i][READ], + total_io[i][WRITE]); + printf("\n"); +} + +static void do_print() +{ + switch (show_option) { + case SHOW_PID: + __print_pid(); + break; + case SHOW_FTYPE: + __print_ftype(); + break; + case SHOW_ALL: + __print_pid(); + printf("\n\n"); + __print_ftype(); + break; + } +} + +int main(int argc, char **argv) +{ + FILE *file; + int opt; + + opt = parse_options(argc, argv); + + file = fopen(argv[opt], "r"); + if (!file) { + perror("open log file"); + exit(EXIT_FAILURE); + } + + do_init(); + + do_parse(file); + + do_print(); + + fclose(file); + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.8 b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.8 new file mode 100644 index 00000000000..5e2258adde6 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.8 @@ -0,0 +1,102 @@ +.TH F2FSCRYPT 8 +.SH NAME +f2fscrypt \- f2fs filesystem encryption utility +.SH SYNOPSIS +.B f2fscrypt add_key -S \fR[\fB -k \fIkeyring\fR ] [\fB-v\fR] [\fB-q\fR] [ \fI path\fR ... ] +.br +.B f2fscrypt new_session +.br +.B f2fscrypt get_policy \fIpath\fR ... +.br +.B f2fscrypt set_policy \fIpolicy path\fR ... +.SH DESCRIPTION +.B f2fscrypt +performs encryption management for f2fs file systems. +.SH COMMANDS +.TP +.B f2fscrypt add_key -S \fR[\fB -k \fIkeyring\fR ] [\fB-v\fR] [\fB-q\fR] [ \fI path\fR ... ] +Prompts the user for a passphrase and inserts it into the specified +keyring. If no keyring is specified, f2fscrypt will use the session +keyring if it exists or the user session keyring if it does not. +.IP +If one or more directory paths are specified, f2fscrypt will try to +set the policy of those directories to use the key just entered by +the user. +.TP +.B f2fscrypt get_policy \fIpath\fR ... +Print the policy for the directories specified on the command line. +.TP +.B f2fscrypt new_session +Give the invoking process (typically a shell) a new session keyring, +discarding its old session keyring. +.TP +.B f2fscrypt set_policy \fIpolicy path\fR ... +Sets the policy for the directories specified on the command line. +All directories must be empty to set the policy; if the directory +already has a policy established, f2fscrypt will validate that the +policy matches what was specified. A policy is an encryption key +identifier consisting of 16 hexadecimal characters. +.SH NOTES +The target directory must be empty. +.SH EXAMPLE +.nf +Formats a f2fs filesystem that supports encrypt. + +.ft R +# mkfs.f2fs -O encrypt /dev/sdxx +# mount /dev/sdxx /encrypted/ +# mkdir /encrypted/dir + +.nf +First create the key in the keyring use an simple salt +(or generate a random salt). +Then use it to set the policy for the directory to be encrypted. + +.ft R +# f2fscrypt add_key -S 0x1234 + Enter passphrase (echo disabled): + Added key with descriptor [28e21cc0c4393da1] + +# f2fscrypt set_policy 28e21cc0c4393da1 /encrypted/dir + Key with descriptor [28e21cc0c4393da1] applied to /encrypted/dir. + +# touch /encrypted/dir/test.txt +# ls -l /encrypted/dir/ + -rw-r--r--. 1 root root 0 Mar 5 21:41 test.txt + +.nf +After each reboot, the same command can be used set the key for +decryption of the directory and its descendants. + +.ft R +# ls -l /encrypted/dir/ + -rw-r--r--. 1 root root 0 Mar 5 21:41 zbx7tsUEMLzh+AUVMkQcnB + +# f2fscrypt get_policy /encrypted/dir/ + /encrypted/dir/: 28e21cc0c4393da1 + +# f2fscrypt add_key -S 0x1234 + Enter passphrase (echo disabled): + Added key with descriptor [28e21cc0c4393da1] + +# ls -l /encrypted/dir/ + -rw-r--r--. 1 root root 0 Mar 5 21:41 test.txt + +.nf +Show process keyrings. + +.ft R +# keyctl show + Session Keyring + 84022412 --alswrv 0 0 keyring: _ses + 204615789 --alswrv 0 65534 \\_ keyring: _uid.0 + 529474961 --alsw-v 0 0 \\_ logon: f2fs:28e21cc0c4393da1 + +.SH AUTHOR +Written by Kinglong Mee , +Migrated from e4crypt that Written by Michael Halcrow , +Ildar Muslukhov , and Theodore Ts'o +.SH SEE ALSO +.BR keyctl (1), +.BR mkfs.f2fs (8), +.BR mount (8). diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.c new file mode 100644 index 00000000000..d5222fb4121 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/f2fscrypt.c @@ -0,0 +1,928 @@ +/* + * f2fscrypt.c - f2fs encryption management utility + * + * Authors: Kinglong Mee + * + * Copied from e4crypt that for ext4 filesystem. + * Authors: Michael Halcrow , + * Ildar Muslukhov + */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_MNTENT_H +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#ifdef __KERNEL__ +#include +#endif + +#ifdef HAVE_UUID_UUID_H +#include +#else +typedef unsigned char uuid_t[16]; +#endif + +#if !defined(HAVE_ADD_KEY) || !defined(HAVE_KEYCTL) +#include +#endif +#ifdef HAVE_SYS_KEY_H +#include +#endif + +#define F2FS_MAX_KEY_SIZE 64 +#define F2FS_MAX_PASSPHRASE_SIZE 1024 +#define F2FS_MAX_SALT_SIZE 256 + +/* Encryption algorithms, key size and key reference len */ +#define F2FS_ENCRYPTION_MODE_INVALID 0 +#define F2FS_ENCRYPTION_MODE_AES_256_XTS 1 +#define F2FS_ENCRYPTION_MODE_AES_256_GCM 2 +#define F2FS_ENCRYPTION_MODE_AES_256_CBC 3 +#define F2FS_ENCRYPTION_MODE_AES_256_CTS 4 + +#define F2FS_AES_256_XTS_KEY_SIZE 64 +#define F2FS_AES_256_GCM_KEY_SIZE 32 +#define F2FS_AES_256_CBC_KEY_SIZE 32 +#define F2FS_AES_256_CTS_KEY_SIZE 32 +#define F2FS_MAX_KEY_SIZE 64 + +/* Password derivation constants */ +#define F2FS_MAX_PASSPHRASE_SIZE 1024 +#define F2FS_MAX_SALT_SIZE 256 +#define F2FS_PBKDF2_ITERATIONS 0xFFFF + +/* special process keyring shortcut IDs */ +#define KEY_SPEC_THREAD_KEYRING -1 +#define KEY_SPEC_PROCESS_KEYRING -2 +#define KEY_SPEC_SESSION_KEYRING -3 +#define KEY_SPEC_USER_KEYRING -4 +#define KEY_SPEC_USER_SESSION_KEYRING -5 +#define KEY_SPEC_GROUP_KEYRING -6 + +#define KEYCTL_GET_KEYRING_ID 0 +#define KEYCTL_JOIN_SESSION_KEYRING 1 +#define KEYCTL_DESCRIBE 6 +#define KEYCTL_SEARCH 10 +#define KEYCTL_SESSION_TO_PARENT 18 + +/* + * File system encryption support + */ +/* Policy provided via an ioctl on the topmost directory */ +#define F2FS_KEY_DESCRIPTOR_SIZE 8 +#define F2FS_KEY_REF_STR_BUF_SIZE ((F2FS_KEY_DESCRIPTOR_SIZE * 2) + 1) + +struct f2fs_fscrypt_policy { + __u8 version; + __u8 contents_encryption_mode; + __u8 filenames_encryption_mode; + __u8 flags; + __u8 master_key_descriptor[F2FS_KEY_DESCRIPTOR_SIZE]; +}; + +static_assert(sizeof(struct f2fs_fscrypt_policy) == 12, ""); + +#define F2FS_IOC_SET_ENCRYPTION_POLICY _IOR('f', 19, struct f2fs_fscrypt_policy) +#define F2FS_IOC_GET_ENCRYPTION_PWSALT _IOW('f', 20, __u8[16]) +#define F2FS_IOC_GET_ENCRYPTION_POLICY _IOW('f', 21, struct f2fs_fscrypt_policy) + +typedef int32_t key_serial_t; + + + +#define OPT_VERBOSE 0x0001 +#define OPT_QUIET 0x0002 + +struct f2fs_encryption_key { + __u32 mode; + char raw[F2FS_MAX_KEY_SIZE]; + __u32 size; +}; + +static_assert(sizeof(struct f2fs_encryption_key) == 72, ""); + +int options; + +extern void f2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char *out); + +#if !defined(HAVE_KEYCTL) +static long keyctl(int cmd, ...) +{ + va_list va; + unsigned long arg2, arg3, arg4, arg5; + + va_start(va, cmd); + arg2 = va_arg(va, unsigned long); + arg3 = va_arg(va, unsigned long); + arg4 = va_arg(va, unsigned long); + arg5 = va_arg(va, unsigned long); + va_end(va); + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +} +#endif + +#if !defined(HAVE_ADD_KEY) +static key_serial_t add_key(const char *type, const char *description, + const void *payload, size_t plen, + key_serial_t keyring) +{ + return syscall(__NR_add_key, type, description, payload, + plen, keyring); +} +#endif + +static const unsigned char *hexchars = (const unsigned char *) "0123456789abcdef"; +static const size_t hexchars_size = 16; + +#define SHA512_LENGTH 64 +#define F2FS_KEY_TYPE_LOGON "logon" +#define F2FS_KEY_DESC_PREFIX "f2fs:" +#define F2FS_KEY_DESC_PREFIX_SIZE 5 + +static int int_log2(int arg) +{ + int l = 0; + + arg >>= 1; + while (arg) { + l++; + arg >>= 1; + } + return l; +} + +static void validate_paths(int argc, char *argv[], int path_start_index) +{ + int x; + int valid = 1; + struct stat st; + + for (x = path_start_index; x < argc; x++) { + int ret = access(argv[x], W_OK); + if (ret) { + invalid: + perror(argv[x]); + valid = 0; + continue; + } + ret = stat(argv[x], &st); + if (ret < 0) + goto invalid; + if (!S_ISDIR(st.st_mode)) { + fprintf(stderr, "%s is not a directory\n", argv[x]); + goto invalid; + } + } + if (!valid) + exit(1); +} + +static int hex2byte(const char *hex, size_t hex_size, unsigned char *bytes, + size_t bytes_size) +{ + size_t x; + unsigned char *h, *l; + + if (hex_size % 2) + return -EINVAL; + for (x = 0; x < hex_size; x += 2) { + h = memchr(hexchars, hex[x], hexchars_size); + if (!h) + return -EINVAL; + l = memchr(hexchars, hex[x + 1], hexchars_size); + if (!l) + return -EINVAL; + if ((x >> 1) >= bytes_size) + return -EINVAL; + bytes[x >> 1] = (((unsigned char)(h - hexchars) << 4) + + (unsigned char)(l - hexchars)); + } + return 0; +} + +/* + * Salt handling + */ +struct salt { + unsigned char *salt; + char key_ref_str[F2FS_KEY_REF_STR_BUF_SIZE]; + unsigned char key_desc[F2FS_KEY_DESCRIPTOR_SIZE]; + unsigned char key[F2FS_MAX_KEY_SIZE]; + size_t salt_len; +}; +struct salt *salt_list; +unsigned num_salt; +unsigned max_salt; +char in_passphrase[F2FS_MAX_PASSPHRASE_SIZE]; + +static struct salt *find_by_salt(unsigned char *salt, size_t salt_len) +{ + unsigned int i; + struct salt *p; + + for (i = 0, p = salt_list; i < num_salt; i++, p++) + if ((p->salt_len == salt_len) && + !memcmp(p->salt, salt, salt_len)) + return p; + return NULL; +} + +static void add_salt(unsigned char *salt, size_t salt_len) +{ + if (find_by_salt(salt, salt_len)) + return; + if (num_salt >= max_salt) { + max_salt = num_salt + 10; + salt_list = realloc(salt_list, max_salt * sizeof(struct salt)); + if (!salt_list) { + fprintf(stderr, "Couldn't allocate salt list\n"); + exit(1); + } + } + salt_list[num_salt].salt = salt; + salt_list[num_salt].salt_len = salt_len; + num_salt++; +} + +static void clear_secrets(void) +{ + if (salt_list) { + memset(salt_list, 0, sizeof(struct salt) * max_salt); + free(salt_list); + salt_list = NULL; + } + memset(in_passphrase, 0, sizeof(in_passphrase)); +} + +static void die_signal_handler(int UNUSED(signum), + siginfo_t *UNUSED(siginfo), void *UNUSED(context)) +{ + clear_secrets(); + exit(-1); +} + +static void sigcatcher_setup(void) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_sigaction = die_signal_handler; + sa.sa_flags = SA_SIGINFO; + + sigaction(SIGHUP, &sa, 0); + sigaction(SIGINT, &sa, 0); + sigaction(SIGQUIT, &sa, 0); + sigaction(SIGFPE, &sa, 0); + sigaction(SIGILL, &sa, 0); + sigaction(SIGBUS, &sa, 0); + sigaction(SIGSEGV, &sa, 0); + sigaction(SIGABRT, &sa, 0); + sigaction(SIGPIPE, &sa, 0); + sigaction(SIGALRM, &sa, 0); + sigaction(SIGTERM, &sa, 0); + sigaction(SIGUSR1, &sa, 0); + sigaction(SIGUSR2, &sa, 0); + sigaction(SIGPOLL, &sa, 0); + sigaction(SIGPROF, &sa, 0); + sigaction(SIGSYS, &sa, 0); + sigaction(SIGTRAP, &sa, 0); + sigaction(SIGVTALRM, &sa, 0); + sigaction(SIGXCPU, &sa, 0); + sigaction(SIGXFSZ, &sa, 0); +} + + +#define PARSE_FLAGS_NOTSUPP_OK 0x0001 +#define PARSE_FLAGS_FORCE_FN 0x0002 + +static void parse_salt(char *salt_str, int flags) +{ + unsigned char buf[F2FS_MAX_SALT_SIZE]; + char *cp = salt_str; + unsigned char *salt_buf; + int fd, ret, salt_len = 0; + + if (flags & PARSE_FLAGS_FORCE_FN) + goto salt_from_filename; + if (strncmp(cp, "s:", 2) == 0) { + cp += 2; + salt_len = strlen(cp); + if (salt_len >= F2FS_MAX_SALT_SIZE) + goto invalid_salt; + strncpy((char *) buf, cp, sizeof(buf)); + } else if (cp[0] == '/') { + salt_from_filename: + fd = open(cp, O_RDONLY | O_DIRECTORY); + if (fd == -1 && errno == ENOTDIR) + fd = open(cp, O_RDONLY); + if (fd == -1) { + perror(cp); + exit(1); + } + ret = ioctl(fd, F2FS_IOC_GET_ENCRYPTION_PWSALT, &buf); + close(fd); + if (ret < 0) { + if (flags & PARSE_FLAGS_NOTSUPP_OK) + return; + perror("F2FS_IOC_GET_ENCRYPTION_PWSALT"); + exit(1); + } +#ifdef HAVE_LIBUUID + if (options & OPT_VERBOSE) { + char tmp[80]; + uuid_unparse(buf, tmp); + printf("%s has pw salt %s\n", cp, tmp); + } +#endif + salt_len = 16; + } else if (strncmp(cp, "f:", 2) == 0) { + cp += 2; + goto salt_from_filename; + } else if (strncmp(cp, "0x", 2) == 0) { + unsigned char *h, *l; + + cp += 2; + if (strlen(cp) & 1) + goto invalid_salt; + while (*cp) { + if (salt_len >= F2FS_MAX_SALT_SIZE) + goto invalid_salt; + h = memchr(hexchars, *cp++, hexchars_size); + l = memchr(hexchars, *cp++, hexchars_size); + if (!h || !l) + goto invalid_salt; + buf[salt_len++] = + (((unsigned char)(h - hexchars) << 4) + + (unsigned char)(l - hexchars)); + } +#ifdef HAVE_LIBUUID + } else if (uuid_parse(cp, buf) == 0) { + salt_len = 16; +#endif + } else { + invalid_salt: + fprintf(stderr, "Invalid salt: %s\n", salt_str); + exit(1); + } + salt_buf = malloc(salt_len); + if (!salt_buf) { + fprintf(stderr, "Couldn't allocate salt\n"); + exit(1); + } + memcpy(salt_buf, buf, salt_len); + add_salt(salt_buf, salt_len); +} + +static void set_policy(struct salt *set_salt, int pad, + int argc, char *argv[], int path_start_index) +{ + struct salt *salt; + struct f2fs_fscrypt_policy policy; + uuid_t uu; + int fd; + int x; + int rc; + + if ((pad != 4) && (pad != 8) && + (pad != 16) && (pad != 32)) { + fprintf(stderr, "Invalid padding %d\n", pad); + exit(1); + } + + for (x = path_start_index; x < argc; x++) { + fd = open(argv[x], O_DIRECTORY); + if (fd == -1) { + perror(argv[x]); + exit(1); + } + if (set_salt) + salt = set_salt; + else { + if (ioctl(fd, F2FS_IOC_GET_ENCRYPTION_PWSALT, + &uu) < 0) { + perror("F2FS_IOC_GET_ENCRYPTION_PWSALT"); + exit(1); + } + salt = find_by_salt(uu, sizeof(uu)); + if (!salt) { + fprintf(stderr, "Couldn't find salt!?!\n"); + exit(1); + } + } + policy.version = 0; + policy.contents_encryption_mode = + F2FS_ENCRYPTION_MODE_AES_256_XTS; + policy.filenames_encryption_mode = + F2FS_ENCRYPTION_MODE_AES_256_CTS; + policy.flags = int_log2(pad >> 2); + memcpy(policy.master_key_descriptor, salt->key_desc, + F2FS_KEY_DESCRIPTOR_SIZE); + rc = ioctl(fd, F2FS_IOC_SET_ENCRYPTION_POLICY, &policy); + close(fd); + if (rc) { + printf("Error [%s] setting policy.\nThe key descriptor " + "[%s] may not match the existing encryption " + "context for directory [%s].\n", + strerror(errno), salt->key_ref_str, argv[x]); + continue; + } + printf("Key with descriptor [%s] applied to %s.\n", + salt->key_ref_str, argv[x]); + } +} + +static void pbkdf2_sha512(const char *passphrase, struct salt *salt, + unsigned int count, + unsigned char derived_key[F2FS_MAX_KEY_SIZE]) +{ + size_t passphrase_size = strlen(passphrase); + unsigned char buf[SHA512_LENGTH + F2FS_MAX_PASSPHRASE_SIZE] = {0}; + unsigned char tempbuf[SHA512_LENGTH] = {0}; + char final[SHA512_LENGTH] = {0}; + unsigned char saltbuf[F2FS_MAX_SALT_SIZE + F2FS_MAX_PASSPHRASE_SIZE] = {0}; + int actual_buf_len = SHA512_LENGTH + passphrase_size; + int actual_saltbuf_len = F2FS_MAX_SALT_SIZE + passphrase_size; + unsigned int x, y; + __u32 *final_u32 = (__u32 *)final; + __u32 *temp_u32 = (__u32 *)tempbuf; + + if (passphrase_size > F2FS_MAX_PASSPHRASE_SIZE) { + printf("Passphrase size is %zd; max is %d.\n", passphrase_size, + F2FS_MAX_PASSPHRASE_SIZE); + exit(1); + } + if (salt->salt_len > F2FS_MAX_SALT_SIZE) { + printf("Salt size is %zd; max is %d.\n", salt->salt_len, + F2FS_MAX_SALT_SIZE); + exit(1); + } + assert(F2FS_MAX_KEY_SIZE <= SHA512_LENGTH); + + memcpy(saltbuf, salt->salt, salt->salt_len); + memcpy(&saltbuf[F2FS_MAX_SALT_SIZE], passphrase, passphrase_size); + + memcpy(&buf[SHA512_LENGTH], passphrase, passphrase_size); + + for (x = 0; x < count; ++x) { + if (x == 0) { + f2fs_sha512(saltbuf, actual_saltbuf_len, tempbuf); + } else { + /* + * buf: [previous hash || passphrase] + */ + memcpy(buf, tempbuf, SHA512_LENGTH); + f2fs_sha512(buf, actual_buf_len, tempbuf); + } + for (y = 0; y < (sizeof(final) / sizeof(*final_u32)); ++y) + final_u32[y] = final_u32[y] ^ temp_u32[y]; + } + memcpy(derived_key, final, F2FS_MAX_KEY_SIZE); +} + +static int disable_echo(struct termios *saved_settings) +{ + struct termios current_settings; + int rc = 0; + + rc = tcgetattr(0, ¤t_settings); + if (rc) + return rc; + *saved_settings = current_settings; + current_settings.c_lflag &= ~ECHO; + rc = tcsetattr(0, TCSANOW, ¤t_settings); + + return rc; +} + +static void get_passphrase(char *passphrase, int len) +{ + char *p; + struct termios current_settings; + + assert(len > 0); + disable_echo(¤t_settings); + p = fgets(passphrase, len, stdin); + tcsetattr(0, TCSANOW, ¤t_settings); + printf("\n"); + if (!p) { + printf("Aborting.\n"); + exit(1); + } + p = strrchr(passphrase, '\n'); + if (!p) + p = passphrase + len - 1; + *p = '\0'; +} + +struct keyring_map { + char name[4]; + size_t name_len; + int code; +}; + +static const struct keyring_map keyrings[] = { + {"@us", 3, KEY_SPEC_USER_SESSION_KEYRING}, + {"@u", 2, KEY_SPEC_USER_KEYRING}, + {"@s", 2, KEY_SPEC_SESSION_KEYRING}, + {"@g", 2, KEY_SPEC_GROUP_KEYRING}, + {"@p", 2, KEY_SPEC_PROCESS_KEYRING}, + {"@t", 2, KEY_SPEC_THREAD_KEYRING}, +}; + +static int get_keyring_id(const char *keyring) +{ + unsigned int x; + char *end; + + /* + * If no keyring is specified, by default use either the user + * session key ring or the session keyring. Fetching the + * session keyring will return the user session keyring if no + * session keyring has been set. + * + * We need to do this instead of simply adding the key to + * KEY_SPEC_SESSION_KEYRING since trying to add a key to a + * session keyring that does not yet exist will cause the + * kernel to create a session keyring --- which wil then get + * garbage collected as soon as f2fscrypt exits. + * + * The fact that the keyctl system call and the add_key system + * call treats KEY_SPEC_SESSION_KEYRING differently when a + * session keyring does not exist is very unfortunate and + * confusing, but so it goes... + */ + if (keyring == NULL) + return keyctl(KEYCTL_GET_KEYRING_ID, + KEY_SPEC_SESSION_KEYRING, 0); + for (x = 0; x < (sizeof(keyrings) / sizeof(keyrings[0])); ++x) { + if (strcmp(keyring, keyrings[x].name) == 0) { + return keyrings[x].code; + } + } + x = strtoul(keyring, &end, 10); + if (*end == '\0') { + if (keyctl(KEYCTL_DESCRIBE, x, NULL, 0) < 0) + return 0; + return x; + } + return 0; +} + +static void generate_key_ref_str(struct salt *salt) +{ + unsigned char key_ref1[SHA512_LENGTH]; + unsigned char key_ref2[SHA512_LENGTH]; + int x; + + f2fs_sha512(salt->key, F2FS_MAX_KEY_SIZE, key_ref1); + f2fs_sha512(key_ref1, SHA512_LENGTH, key_ref2); + memcpy(salt->key_desc, key_ref2, F2FS_KEY_DESCRIPTOR_SIZE); + for (x = 0; x < F2FS_KEY_DESCRIPTOR_SIZE; ++x) { + sprintf(&salt->key_ref_str[x * 2], "%02x", + salt->key_desc[x]); + } + salt->key_ref_str[F2FS_KEY_REF_STR_BUF_SIZE - 1] = '\0'; +} + +static void insert_key_into_keyring(const char *keyring, struct salt *salt) +{ + int keyring_id = get_keyring_id(keyring); + struct f2fs_encryption_key key; + char key_ref_full[F2FS_KEY_DESC_PREFIX_SIZE + + F2FS_KEY_REF_STR_BUF_SIZE]; + int rc; + + if (keyring_id == 0) { + printf("Invalid keyring [%s].\n", keyring); + exit(1); + } + sprintf(key_ref_full, "%s%s", F2FS_KEY_DESC_PREFIX, + salt->key_ref_str); + rc = keyctl(KEYCTL_SEARCH, keyring_id, F2FS_KEY_TYPE_LOGON, + key_ref_full, 0); + if (rc != -1) { + if ((options & OPT_QUIET) == 0) + printf("Key with descriptor [%s] already exists\n", + salt->key_ref_str); + return; + } else if ((rc == -1) && (errno != ENOKEY)) { + printf("keyctl_search failed: %s\n", strerror(errno)); + if (errno == -EINVAL) + printf("Keyring [%s] is not available.\n", keyring); + exit(1); + } + key.mode = F2FS_ENCRYPTION_MODE_AES_256_XTS; + memcpy(key.raw, salt->key, F2FS_MAX_KEY_SIZE); + key.size = F2FS_MAX_KEY_SIZE; + rc = add_key(F2FS_KEY_TYPE_LOGON, key_ref_full, (void *)&key, + sizeof(key), keyring_id); + if (rc == -1) { + if (errno == EDQUOT) { + printf("Error adding key to keyring; quota exceeded\n"); + } else { + printf("Error adding key with key descriptor [%s]: " + "%s\n", salt->key_ref_str, strerror(errno)); + } + exit(1); + } else { + if ((options & OPT_QUIET) == 0) + printf("Added key with descriptor [%s]\n", + salt->key_ref_str); + } +} + +static void get_default_salts(void) +{ + FILE *f = setmntent("/etc/mtab", "r"); + struct mntent *mnt; + + while (f && ((mnt = getmntent(f)) != NULL)) { + if (strcmp(mnt->mnt_type, "f2fs") || + access(mnt->mnt_dir, R_OK)) + continue; + parse_salt(mnt->mnt_dir, PARSE_FLAGS_NOTSUPP_OK); + } + endmntent(f); +} + +/* Functions which implement user commands */ + +struct cmd_desc { + const char *cmd_name; + void (*cmd_func)(int, char **, const struct cmd_desc *); + const char *cmd_desc; + const char *cmd_help; + int cmd_flags; +}; + +#define CMD_HIDDEN 0x0001 + +static void do_help(int argc, char **argv, const struct cmd_desc *cmd); + +#define add_key_desc "adds a key to the user's keyring" +#define add_key_help \ +"f2fscrypt add_key -S salt [ -k keyring ] [-v] [-q] [ path ... ]\n\n" \ +"Prompts the user for a passphrase and inserts it into the specified\n" \ +"keyring. If no keyring is specified, f2fscrypt will use the session\n" \ +"keyring if it exists or the user session keyring if it does not.\n\n" \ +"If one or more directory paths are specified, f2fscrypt will try to\n" \ +"set the policy of those directories to use the key just entered by\n" \ +"the user.\n" + +static void do_add_key(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct salt *salt; + char *keyring = NULL; + int i, opt, pad = 4; + unsigned j; + + while ((opt = getopt(argc, argv, "k:S:p:vq")) != -1) { + switch (opt) { + case 'k': + /* Specify a keyring. */ + keyring = optarg; + break; + case 'p': + pad = atoi(optarg); + break; + case 'S': + /* Salt value for passphrase. */ + parse_salt(optarg, 0); + break; + case 'v': + options |= OPT_VERBOSE; + break; + case 'q': + options |= OPT_QUIET; + break; + default: + fprintf(stderr, "Unrecognized option: %c\n", opt); + fallthrough; + case '?': + fputs("USAGE:\n ", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + } + if (num_salt == 0) + get_default_salts(); + if (num_salt == 0) { + fprintf(stderr, "No salt values available\n"); + exit(1); + } + validate_paths(argc, argv, optind); + for (i = optind; i < argc; i++) + parse_salt(argv[i], PARSE_FLAGS_FORCE_FN); + printf("Enter passphrase (echo disabled): "); + get_passphrase(in_passphrase, sizeof(in_passphrase)); + for (j = 0, salt = salt_list; j < num_salt; j++, salt++) { + pbkdf2_sha512(in_passphrase, salt, + F2FS_PBKDF2_ITERATIONS, salt->key); + generate_key_ref_str(salt); + insert_key_into_keyring(keyring, salt); + } + if (optind != argc) + set_policy(NULL, pad, argc, argv, optind); + clear_secrets(); + exit(0); +} + +#define set_policy_desc "sets a policy for directories" +#define set_policy_help \ +"f2fscrypt set_policy policy path ... \n\n" \ +"Sets the policy for the directories specified on the command line.\n" \ +"All directories must be empty to set the policy; if the directory\n" \ +"already has a policy established, f2fscrypt will validate that it the\n" \ +"policy matches what was specified. A policy is an encryption key\n" \ +"identifier consisting of 16 hexadecimal characters.\n" + +static void do_set_policy(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct salt saltbuf; + int c, pad = 4; + + while ((c = getopt (argc, argv, "p:")) != EOF) { + switch (c) { + case 'p': + pad = atoi(optarg); + break; + } + } + + if (argc < optind + 2) { + fprintf(stderr, "Missing required argument(s).\n\n"); + fputs("USAGE:\n ", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + if ((strlen(argv[optind]) != (F2FS_KEY_DESCRIPTOR_SIZE * 2)) || + hex2byte(argv[optind], (F2FS_KEY_DESCRIPTOR_SIZE * 2), + saltbuf.key_desc, F2FS_KEY_DESCRIPTOR_SIZE)) { + printf("Invalid key descriptor [%s]. Valid characters " + "are 0-9 and a-f, lower case. " + "Length must be %d.\n", + argv[optind], (F2FS_KEY_DESCRIPTOR_SIZE * 2)); + exit(1); + } + validate_paths(argc, argv, optind+1); + strcpy(saltbuf.key_ref_str, argv[optind]); + set_policy(&saltbuf, pad, argc, argv, optind+1); + exit(0); +} + +#define get_policy_desc "get the encryption for directories" +#define get_policy_help \ +"f2fscrypt get_policy path ... \n\n" \ +"Gets the policy for the directories specified on the command line.\n" + +static void do_get_policy(int argc, char **argv, const struct cmd_desc *cmd) +{ + struct f2fs_fscrypt_policy policy; + struct stat st; + int i, j, fd, rc; + + if (argc < 2) { + fprintf(stderr, "Missing required argument(s).\n\n"); + fputs("USAGE:\n ", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + + for (i = 1; i < argc; i++) { + if (stat(argv[i], &st) < 0) { + perror(argv[i]); + continue; + } + fd = open(argv[i], + S_ISDIR(st.st_mode) ? O_DIRECTORY : O_RDONLY); + if (fd == -1) { + perror(argv[i]); + exit(1); + } + rc = ioctl(fd, F2FS_IOC_GET_ENCRYPTION_POLICY, &policy); + close(fd); + if (rc) { + printf("Error getting policy for %s: %s\n", + argv[i], strerror(errno)); + continue; + } + printf("%s: ", argv[i]); + for (j = 0; j < F2FS_KEY_DESCRIPTOR_SIZE; j++) { + printf("%02x", (unsigned char) policy.master_key_descriptor[j]); + } + fputc('\n', stdout); + } + exit(0); +} + +#define new_session_desc "give the invoking process a new session keyring" +#define new_session_help \ +"f2fscrypt new_session\n\n" \ +"Give the invoking process (typically a shell) a new session keyring,\n" \ +"discarding its old session keyring.\n" + +static void do_new_session(int argc, char **UNUSED(argv), + const struct cmd_desc *cmd) +{ + long keyid, ret; + + if (argc > 1) { + fputs("Excess arguments\n\n", stderr); + fputs(cmd->cmd_help, stderr); + exit(1); + } + keyid = keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL); + if (keyid < 0) { + perror("KEYCTL_JOIN_SESSION_KEYRING"); + exit(1); + } + ret = keyctl(KEYCTL_SESSION_TO_PARENT, NULL); + if (ret < 0) { + perror("KEYCTL_SESSION_TO_PARENT"); + exit(1); + } + printf("Switched invoking process to new session keyring %ld\n", keyid); + exit(0); +} + +#define CMD(name) { #name, do_##name, name##_desc, name##_help, 0 } +#define _CMD(name) { #name, do_##name, NULL, NULL, CMD_HIDDEN } + +const struct cmd_desc cmd_list[] = { + _CMD(help), + CMD(add_key), + CMD(get_policy), + CMD(new_session), + CMD(set_policy), + { NULL, NULL, NULL, NULL, 0 } +}; + +static void do_help(int argc, char **argv, const struct cmd_desc *UNUSED(cmd)) +{ + const struct cmd_desc *p; + + if (argc > 1) { + for (p = cmd_list; p->cmd_name; p++) { + if (p->cmd_flags & CMD_HIDDEN) + continue; + if (strcmp(p->cmd_name, argv[1]) == 0) { + putc('\n', stdout); + fputs("USAGE:\n ", stdout); + fputs(p->cmd_help, stdout); + exit(0); + } + } + printf("Unknown command: %s\n\n", argv[1]); + } + + fputs("Available commands:\n", stdout); + for (p = cmd_list; p->cmd_name; p++) { + if (p->cmd_flags & CMD_HIDDEN) + continue; + printf(" %-20s %s\n", p->cmd_name, p->cmd_desc); + } + printf("\nTo get more information on a command, " + "type 'f2fscrypt help cmd'\n"); + exit(0); +} + +int main(int argc, char *argv[]) +{ + const struct cmd_desc *cmd; + + if (argc < 2) + do_help(argc, argv, cmd_list); + + sigcatcher_setup(); + for (cmd = cmd_list; cmd->cmd_name; cmd++) { + if (strcmp(cmd->cmd_name, argv[1]) == 0) { + cmd->cmd_func(argc-1, argv+1, cmd); + exit(0); + } + } + printf("Unknown command: %s\n\n", argv[1]); + do_help(1, argv, cmd_list); + return 0; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/fibmap.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/fibmap.c new file mode 100644 index 00000000000..3acc77ba1f6 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/fibmap.c @@ -0,0 +1,216 @@ +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) +#define _XOPEN_SOURCE 600 +#define _DARWIN_C_SOURCE +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#endif +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#include +#ifdef HAVE_SYS_SYSMACROS_H +#include +#endif +#include +#ifdef HAVE_LINUX_HDREG_H +#include +#endif +#ifdef HAVE_LINUX_TYPES_H +#include +#endif +#ifdef __KERNEL__ +#include +#endif +#include + +#ifndef FIBMAP +#define FIBMAP _IO(0x00, 1) /* bmap access */ +#endif + +struct file_ext { + __u64 f_pos; + __u32 start_blk; + __u32 end_blk; + __u32 blk_count; +}; + +void print_ext(struct file_ext *ext) +{ + if (ext->end_blk == 0) + printf("%8llu %8d %8d %8d\n", ext->f_pos, 0, 0, ext->blk_count); + else + printf("%8llu %8d %8d %8d\n", ext->f_pos, ext->start_blk, + ext->end_blk, ext->blk_count); +} + +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +void print_stat(struct stat64 *st) +#else +void print_stat(struct stat *st) +#endif +{ + printf("--------------------------------------------\n"); + printf("dev [%d:%d]\n", major(st->st_dev), minor(st->st_dev)); + printf("ino [0x%8"PRIx64" : %"PRIu64"]\n", + st->st_ino, st->st_ino); + printf("mode [0x%8x : %d]\n", st->st_mode, st->st_mode); + printf("nlink [0x%8lx : %ld]\n", + (unsigned long)st->st_nlink, + (long)st->st_nlink); + printf("uid [0x%8x : %d]\n", st->st_uid, st->st_uid); + printf("gid [0x%8x : %d]\n", st->st_gid, st->st_gid); + printf("size [0x%8"PRIx64" : %"PRIu64"]\n", + (u64)st->st_size, (u64)st->st_size); + printf("blksize [0x%8lx : %ld]\n", + (unsigned long)st->st_blksize, + (long)st->st_blksize); + printf("blocks [0x%8"PRIx64" : %"PRIu64"]\n", + (u64)st->st_blocks, (u64)st->st_blocks); + printf("--------------------------------------------\n\n"); +} + +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +static void stat_bdev(struct stat64 *st, unsigned int *start_lba) +#else +static void stat_bdev(struct stat *st, unsigned int *start_lba) +#endif +{ + struct stat bdev_stat; +#ifdef HDIO_GETGIO + struct hd_geometry geom; +#endif + char devname[32] = { 0, }; + char linkname[32] = { 0, }; + int fd; + + sprintf(devname, "/sys/dev/block/%d:%d", major(st->st_dev), minor(st->st_dev)); + + fd = open(devname, O_RDONLY); + if (fd < 0) + return; + + if (fstat(fd, &bdev_stat) < 0) + goto out; + + if (S_ISBLK(bdev_stat.st_mode)) { +#ifdef HDIO_GETGIO + if (ioctl(fd, HDIO_GETGEO, &geom) < 0) + *start_lba = 0; + else + *start_lba = geom.start; +#else + *start_lba = 0; +#endif + } + + if (readlink(devname, linkname, sizeof(linkname)) < 0) + goto out; + + printf("----------------bdev info-------------------\n"); + printf("devname = %s\n", basename(linkname)); + printf("start_lba = %u\n", *start_lba); + +out: + close(fd); + +} + +int main(int argc, char *argv[]) +{ + int fd; + int ret = 0; + char *filename; +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + struct stat64 st; +#else + struct stat st; +#endif + int total_blks; + unsigned int i; + struct file_ext ext; + __u32 start_lba; + __u32 blknum; + + if (argc != 2) { + fprintf(stderr, "No filename\n"); + exit(-1); + } + filename = argv[1]; + + fd = open(filename, O_RDONLY|O_LARGEFILE); + if (fd < 0) { + ret = errno; + perror(filename); + exit(-1); + } + + fsync(fd); + +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) + if (fstat64(fd, &st) < 0) { +#else + if (fstat(fd, &st) < 0) { +#endif + ret = errno; + perror(filename); + goto out; + } + + stat_bdev(&st, &start_lba); + + total_blks = (st.st_size + st.st_blksize - 1) / st.st_blksize; + + printf("\n----------------file info-------------------\n"); + printf("%s :\n", filename); + print_stat(&st); + printf("file_pos start_blk end_blk blks\n"); + + blknum = 0; + if (ioctl(fd, FIBMAP, &blknum) < 0) { + ret = errno; + perror("ioctl(FIBMAP)"); + goto out; + } + ext.f_pos = 0; + ext.start_blk = blknum; + ext.end_blk = blknum; + ext.blk_count = 1; + + for (i = 1; i < total_blks; i++) { + blknum = i; + + if (ioctl(fd, FIBMAP, &blknum) < 0) { + ret = errno; + perror("ioctl(FIBMAP)"); + goto out; + } + + if ((blknum == 0 && blknum == ext.end_blk) || (ext.end_blk + 1) == blknum) { + ext.end_blk = blknum; + ext.blk_count++; + } else { + print_ext(&ext); + ext.f_pos = (__u64)i * st.st_blksize; + ext.start_blk = blknum; + ext.end_blk = blknum; + ext.blk_count = 1; + } + } + + print_ext(&ext); +out: + close(fd); + return ret; +} diff --git a/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/sha512.c b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/sha512.c new file mode 100644 index 00000000000..c6d35afa7e2 --- /dev/null +++ b/base/cvd/vendor_src/+_repo_rules3+f2fs_tools/tools/sha512.c @@ -0,0 +1,322 @@ +/* + * sha512.c --- The sha512 algorithm + * + * Copyright (C) 2004 Sam Hocevar + * (copied from libtomcrypt and then relicensed under GPLv2) + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_SYS_TYPES_H +#include +#endif + +#define F2FS_SHA512_LENGTH 64 + +/* the K array */ +#define CONST64(n) n +static const __u64 K[80] = { + CONST64(0x428a2f98d728ae22), CONST64(0x7137449123ef65cd), + CONST64(0xb5c0fbcfec4d3b2f), CONST64(0xe9b5dba58189dbbc), + CONST64(0x3956c25bf348b538), CONST64(0x59f111f1b605d019), + CONST64(0x923f82a4af194f9b), CONST64(0xab1c5ed5da6d8118), + CONST64(0xd807aa98a3030242), CONST64(0x12835b0145706fbe), + CONST64(0x243185be4ee4b28c), CONST64(0x550c7dc3d5ffb4e2), + CONST64(0x72be5d74f27b896f), CONST64(0x80deb1fe3b1696b1), + CONST64(0x9bdc06a725c71235), CONST64(0xc19bf174cf692694), + CONST64(0xe49b69c19ef14ad2), CONST64(0xefbe4786384f25e3), + CONST64(0x0fc19dc68b8cd5b5), CONST64(0x240ca1cc77ac9c65), + CONST64(0x2de92c6f592b0275), CONST64(0x4a7484aa6ea6e483), + CONST64(0x5cb0a9dcbd41fbd4), CONST64(0x76f988da831153b5), + CONST64(0x983e5152ee66dfab), CONST64(0xa831c66d2db43210), + CONST64(0xb00327c898fb213f), CONST64(0xbf597fc7beef0ee4), + CONST64(0xc6e00bf33da88fc2), CONST64(0xd5a79147930aa725), + CONST64(0x06ca6351e003826f), CONST64(0x142929670a0e6e70), + CONST64(0x27b70a8546d22ffc), CONST64(0x2e1b21385c26c926), + CONST64(0x4d2c6dfc5ac42aed), CONST64(0x53380d139d95b3df), + CONST64(0x650a73548baf63de), CONST64(0x766a0abb3c77b2a8), + CONST64(0x81c2c92e47edaee6), CONST64(0x92722c851482353b), + CONST64(0xa2bfe8a14cf10364), CONST64(0xa81a664bbc423001), + CONST64(0xc24b8b70d0f89791), CONST64(0xc76c51a30654be30), + CONST64(0xd192e819d6ef5218), CONST64(0xd69906245565a910), + CONST64(0xf40e35855771202a), CONST64(0x106aa07032bbd1b8), + CONST64(0x19a4c116b8d2d0c8), CONST64(0x1e376c085141ab53), + CONST64(0x2748774cdf8eeb99), CONST64(0x34b0bcb5e19b48a8), + CONST64(0x391c0cb3c5c95a63), CONST64(0x4ed8aa4ae3418acb), + CONST64(0x5b9cca4f7763e373), CONST64(0x682e6ff3d6b2b8a3), + CONST64(0x748f82ee5defb2fc), CONST64(0x78a5636f43172f60), + CONST64(0x84c87814a1f0ab72), CONST64(0x8cc702081a6439ec), + CONST64(0x90befffa23631e28), CONST64(0xa4506cebde82bde9), + CONST64(0xbef9a3f7b2c67915), CONST64(0xc67178f2e372532b), + CONST64(0xca273eceea26619c), CONST64(0xd186b8c721c0c207), + CONST64(0xeada7dd6cde0eb1e), CONST64(0xf57d4f7fee6ed178), + CONST64(0x06f067aa72176fba), CONST64(0x0a637dc5a2c898a6), + CONST64(0x113f9804bef90dae), CONST64(0x1b710b35131c471b), + CONST64(0x28db77f523047d84), CONST64(0x32caab7b40c72493), + CONST64(0x3c9ebe0a15c9bebc), CONST64(0x431d67c49c100d4c), + CONST64(0x4cc5d4becb3e42b6), CONST64(0x597f299cfc657e2a), + CONST64(0x5fcb6fab3ad6faec), CONST64(0x6c44198c4a475817) +}; +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) +#define RND(a,b,c,d,e,f,g,h,i)\ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];\ + t1 = Sigma0(a) + Maj(a, b, c);\ + d += t0;\ + h = t0 + t1; +#define STORE64H(x, y) \ + do { \ + (y)[0] = (unsigned char)(((x)>>56)&255);\ + (y)[1] = (unsigned char)(((x)>>48)&255);\ + (y)[2] = (unsigned char)(((x)>>40)&255);\ + (y)[3] = (unsigned char)(((x)>>32)&255);\ + (y)[4] = (unsigned char)(((x)>>24)&255);\ + (y)[5] = (unsigned char)(((x)>>16)&255);\ + (y)[6] = (unsigned char)(((x)>>8)&255);\ + (y)[7] = (unsigned char)((x)&255); } while(0) + +#define LOAD64H(x, y)\ + do {x = \ + (((__u64)((y)[0] & 255)) << 56) |\ + (((__u64)((y)[1] & 255)) << 48) |\ + (((__u64)((y)[2] & 255)) << 40) |\ + (((__u64)((y)[3] & 255)) << 32) |\ + (((__u64)((y)[4] & 255)) << 24) |\ + (((__u64)((y)[5] & 255)) << 16) |\ + (((__u64)((y)[6] & 255)) << 8) |\ + (((__u64)((y)[7] & 255)));\ + } while(0) + +#define ROR64c(x, y) \ + ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((__u64)(y)&CONST64(63))) | \ + ((x)<<((__u64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF)) + +struct sha512_state { + __u64 length, state[8]; + unsigned long curlen; + unsigned char buf[128]; +}; + +/* This is a highly simplified version from libtomcrypt */ +struct hash_state { + struct sha512_state sha512; +}; + +static void sha512_compress(struct hash_state * md, const unsigned char *buf) +{ + __u64 S[8], W[80], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->sha512.state[i]; + } + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD64H(W[i], buf + (8*i)); + } + + /* fill W[16..79] */ + for (i = 16; i < 80; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + + Gamma0(W[i - 15]) + W[i - 16]; + } + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + /* feedback */ + for (i = 0; i < 8; i++) { + md->sha512.state[i] = md->sha512.state[i] + S[i]; + } +} + +static void sha512_init(struct hash_state * md) +{ + md->sha512.curlen = 0; + md->sha512.length = 0; + md->sha512.state[0] = CONST64(0x6a09e667f3bcc908); + md->sha512.state[1] = CONST64(0xbb67ae8584caa73b); + md->sha512.state[2] = CONST64(0x3c6ef372fe94f82b); + md->sha512.state[3] = CONST64(0xa54ff53a5f1d36f1); + md->sha512.state[4] = CONST64(0x510e527fade682d1); + md->sha512.state[5] = CONST64(0x9b05688c2b3e6c1f); + md->sha512.state[6] = CONST64(0x1f83d9abfb41bd6b); + md->sha512.state[7] = CONST64(0x5be0cd19137e2179); +} + +static void sha512_done(struct hash_state * md, unsigned char *out) +{ + int i; + + /* increase the length of the message */ + md->sha512.length += md->sha512.curlen * CONST64(8); + + /* append the '1' bit */ + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0x80; + + /* if the length is currently above 112 bytes we append zeros then + * compress. Then we can fall back to padding zeros and length encoding + * like normal. */ + if (md->sha512.curlen > 112) { + while (md->sha512.curlen < 128) { + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + } + sha512_compress(md, md->sha512.buf); + md->sha512.curlen = 0; + } + + /* pad upto 120 bytes of zeroes note: that from 112 to 120 is the 64 MSB + * of the length. We assume that you won't hash > 2^64 bits of data. */ + while (md->sha512.curlen < 120) { + md->sha512.buf[md->sha512.curlen++] = (unsigned char)0; + } + + /* store length */ + STORE64H(md->sha512.length, md->sha512.buf + 120); + sha512_compress(md, md->sha512.buf); + + /* copy output */ + for (i = 0; i < 8; i++) { + STORE64H(md->sha512.state[i], out+(8 * i)); + } +} + +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#define SHA512_BLOCKSIZE 128 +static void sha512_process(struct hash_state * md, + const unsigned char *in, + unsigned long inlen) +{ + unsigned long n; + + while (inlen > 0) { + if (md->sha512.curlen == 0 && inlen >= SHA512_BLOCKSIZE) { + sha512_compress(md, in); + md->sha512.length += SHA512_BLOCKSIZE * 8; + in += SHA512_BLOCKSIZE; + inlen -= SHA512_BLOCKSIZE; + } else { + n = MIN(inlen, (SHA512_BLOCKSIZE - md->sha512.curlen)); + memcpy(md->sha512.buf + md->sha512.curlen, + in, (size_t)n); + md->sha512.curlen += n; + in += n; + inlen -= n; + if (md->sha512.curlen == SHA512_BLOCKSIZE) { + sha512_compress(md, md->sha512.buf); + md->sha512.length += SHA512_BLOCKSIZE * 8; + md->sha512.curlen = 0; + } + } + } +} + +void f2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char out[F2FS_SHA512_LENGTH]) +{ + struct hash_state md; + + sha512_init(&md); + sha512_process(&md, in, in_size); + sha512_done(&md, out); +} + +#ifdef UNITTEST +static const struct { + char *msg; + unsigned char hash[64]; +} tests[] = { + { "", + { 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e } + }, + { "abc", + { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, + 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, + 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, + 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8, + 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, + 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f } + }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + { 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda, + 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f, + 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1, + 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18, + 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4, + 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a, + 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54, + 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 } + }, +}; + +int main(int argc, char **argv) +{ + int i; + int errors = 0; + unsigned char tmp[64]; + struct hash_state md; + + for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) { + unsigned char *msg = (unsigned char *) tests[i].msg; + int len = strlen(tests[i].msg); + + f2fs_sha512(msg, len, tmp); + printf("SHA512 test message %d: ", i); + if (memcmp(tmp, tests[i].hash, 64) != 0) { + printf("FAILED\n"); + errors++; + } else + printf("OK\n"); + } + return errors; +} + +#endif /* UNITTEST */ diff --git a/base/cvd/vendor_src/.gitignore b/base/cvd/vendor_src/.gitignore new file mode 100644 index 00000000000..d6caee2f7a4 --- /dev/null +++ b/base/cvd/vendor_src/.gitignore @@ -0,0 +1 @@ +bazel-external diff --git a/base/cvd/vendor_src/@+_repo_rules3+f2fs_tools.marker b/base/cvd/vendor_src/@+_repo_rules3+f2fs_tools.marker new file mode 100644 index 00000000000..f268516c4cf --- /dev/null +++ b/base/cvd/vendor_src/@+_repo_rules3+f2fs_tools.marker @@ -0,0 +1,2 @@ +656ca3e01bf6dd098b60cfe275fb5709011ee7bf088b960b32cae0ed42483a41 +FILE:@@//BUILD.f2fs_tools.bazel 17d359291bdd635578e179fca87e0a6aae5225c87b5dc6edaa6814b6a57361dc diff --git a/base/cvd/vendor_src/VENDOR.bazel b/base/cvd/vendor_src/VENDOR.bazel new file mode 100644 index 00000000000..a3a497e1d97 --- /dev/null +++ b/base/cvd/vendor_src/VENDOR.bazel @@ -0,0 +1,12 @@ +############################################################################### +# This file is used to configure how external repositories are handled in vendor mode. +# ONLY the two following functions can be used: +# +# ignore('@@', ...) is used to completely ignore this repo from vendoring. +# Bazel will use the normal external cache and fetch process for this repo. +# +# pin('@@', ...) is used to pin the contents of this repo under the vendor +# directory as if there is a --override_repository flag for this repo. +# Note that Bazel will NOT update the vendored source for this repo while running vendor command +# unless it's unpinned. The user can modify and maintain the vendored source for this repo manually. +###############################################################################