diff --git a/.vs/bled.vcxproj b/.vs/bled.vcxproj index 97fd5bdd..21801bb5 100644 --- a/.vs/bled.vcxproj +++ b/.vs/bled.vcxproj @@ -155,7 +155,6 @@ Level3 ProgramDatabase - true Disabled _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;_FILE_OFFSET_BITS=64;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug @@ -175,7 +174,6 @@ Level3 ProgramDatabase - true Disabled _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;_FILE_OFFSET_BITS=64;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug @@ -194,7 +192,6 @@ Level3 ProgramDatabase - true Disabled _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;_FILE_OFFSET_BITS=64;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug diff --git a/.vs/ext2fs.vcxproj b/.vs/ext2fs.vcxproj new file mode 100644 index 00000000..67148a4d --- /dev/null +++ b/.vs/ext2fs.vcxproj @@ -0,0 +1,328 @@ + + + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ext2fs + {B01F5886-2B39-4B66-B65C-6427135B6A02} + ext2fs + 10.0.17763.0 + + + + StaticLibrary + Unicode + v141 + + + StaticLibrary + Unicode + v141 + true + + + StaticLibrary + Unicode + v141 + true + + + StaticLibrary + Unicode + v141 + + + StaticLibrary + Unicode + v141 + + + StaticLibrary + Unicode + v141 + true + + + StaticLibrary + Unicode + v141 + true + + + StaticLibrary + Unicode + v141 + + + + <_ProjectFileVersion>10.0.30319.1 + $(SolutionDir)arm\$(Configuration)\ + $(SolutionDir)arm\$(Configuration)\$(ProjectName)\ + $(SolutionDir)arm\$(Configuration)\ + $(SolutionDir)arm\$(Configuration)\$(ProjectName)\ + $(SolutionDir)arm64\$(Configuration)\ + $(SolutionDir)arm64\$(Configuration)\$(ProjectName)\ + $(SolutionDir)arm64\$(Configuration)\ + $(SolutionDir)arm64\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x86\$(Configuration)\ + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x86\$(Configuration)\ + $(SolutionDir)x86\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x64\$(Configuration)\ + $(SolutionDir)x64\$(Configuration)\$(ProjectName)\ + $(SolutionDir)x64\$(Configuration)\ + $(SolutionDir)x64\$(Configuration)\$(ProjectName)\ + false + false + false + false + false + false + false + false + + + + Level3 + ProgramDatabase + Disabled + _CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\src;..\src\msvc-missing + CompileAsC + 4018;4146;4244;4267 + + + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + ProgramDatabase + Disabled + _CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\src;..\src\msvc-missing + 4018;4146;4244;4267 + + + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + ProgramDatabase + Disabled + _CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\src;..\src\msvc-missing + 4018;4146;4244;4267 + + + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + ProgramDatabase + EnableFastChecks + Disabled + _CRT_SECURE_NO_WARNINGS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) + MultiThreadedDebug + ..\src;..\src\msvc-missing + CompileAsC + 4018;4146;4244;4267 + + + true + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\src;..\src\msvc-missing + CompileAsC + 4018;4146;4244;4267 + + + true + true + $(OutDir)$(TargetName)$(TargetExt) + odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\src;..\src\msvc-missing + 4018;4146;4244;4267 + + + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + true + + + + + Level3 + true + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\src;..\src\msvc-missing + 4018;4146;4244;4267 + + + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + true + + + + + Level3 + _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + ..\src;..\src\msvc-missing + CompileAsC + 4018;4146;4244;4267 + + + true + true + $(OutDir)$(TargetName)$(TargetExt) + + + true + + + + \ No newline at end of file diff --git a/.vs/ext2fs.vcxproj.filters b/.vs/ext2fs.vcxproj.filters new file mode 100644 index 00000000..e7004006 --- /dev/null +++ b/.vs/ext2fs.vcxproj.filters @@ -0,0 +1,204 @@ + + + + + {396df203-84ec-49b8-ae11-074c50a020f0} + + + {0147b833-dc8f-4666-be99-77dfae5e6679} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/.vs/getopt.vcxproj b/.vs/getopt.vcxproj index 0db9725c..91b184f4 100644 --- a/.vs/getopt.vcxproj +++ b/.vs/getopt.vcxproj @@ -119,7 +119,6 @@ HAVE_STRING_H;%(PreprocessorDefinitions) - true MultiThreadedDebug Level3 ProgramDatabase @@ -135,7 +134,6 @@ HAVE_STRING_H;%(PreprocessorDefinitions) - true MultiThreadedDebug Level3 ProgramDatabase @@ -149,7 +147,6 @@ HAVE_STRING_H;%(PreprocessorDefinitions) - true MultiThreadedDebug Level3 ProgramDatabase diff --git a/.vs/rufus.vcxproj b/.vs/rufus.vcxproj index b23e7d23..94b57769 100644 --- a/.vs/rufus.vcxproj +++ b/.vs/rufus.vcxproj @@ -124,7 +124,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -149,7 +149,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -175,7 +175,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -201,7 +201,7 @@ X64 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;_CRTDBG_MAP_ALLOC;%(PreprocessorDefinitions) MultiThreadedDebug Level3 @@ -230,7 +230,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -255,7 +255,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -282,7 +282,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -312,7 +312,7 @@ _OFF_T_DEFINED;_off_t=__int64;off_t=_off_t;COBJMACROS;%(PreprocessorDefinitions) MultiThreaded Level3 - ..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) + ..\src;..\src\msvc-missing;..\src\ms-sys\inc;..\src\syslinux\libinstaller;..\src\syslinux\libfat;..\src\syslinux\win;..\src\libcdio;..\src\getopt;%(AdditionalIncludeDirectories) CompileAsC true false @@ -421,6 +421,9 @@ {7d2e9784-ddf7-4988-a887-cf099bc3b340} + + {b01f5886-2b39-4b66-b65c-6427135b6a02} + diff --git a/configure b/configure index d29e699e..9cd3e70e 100755 --- a/configure +++ b/configure @@ -3907,6 +3907,8 @@ ac_config_files="$ac_config_files src/Makefile" ac_config_files="$ac_config_files src/bled/Makefile" +ac_config_files="$ac_config_files src/ext2fs/Makefile" + ac_config_files="$ac_config_files src/libcdio/iso9660/Makefile" ac_config_files="$ac_config_files src/libcdio/udf/Makefile" @@ -4651,6 +4653,7 @@ do "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/bled/Makefile") CONFIG_FILES="$CONFIG_FILES src/bled/Makefile" ;; + "src/ext2fs/Makefile") CONFIG_FILES="$CONFIG_FILES src/ext2fs/Makefile" ;; "src/libcdio/iso9660/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcdio/iso9660/Makefile" ;; "src/libcdio/udf/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcdio/udf/Makefile" ;; "src/libcdio/driver/Makefile") CONFIG_FILES="$CONFIG_FILES src/libcdio/driver/Makefile" ;; diff --git a/configure.ac b/configure.ac index 03430bd1..a2e31162 100644 --- a/configure.ac +++ b/configure.ac @@ -72,6 +72,7 @@ AC_SUBST([SUFFIX]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([src/Makefile]) AC_CONFIG_FILES([src/bled/Makefile]) +AC_CONFIG_FILES([src/ext2fs/Makefile]) AC_CONFIG_FILES([src/libcdio/iso9660/Makefile]) AC_CONFIG_FILES([src/libcdio/udf/Makefile]) AC_CONFIG_FILES([src/libcdio/driver/Makefile]) diff --git a/rufus.sln b/rufus.sln index cdd7caa6..37264f40 100644 --- a/rufus.sln +++ b/rufus.sln @@ -22,178 +22,196 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt", ".vs\getopt.vcxpro EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bled", ".vs\bled.vcxproj", "{FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ext2fs", ".vs\ext2fs.vcxproj", "{B01F5886-2B39-4B66-B65C-6427135B6A02}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|arm = Debug|arm Debug|arm64 = Debug|arm64 - Debug|x86 = Debug|x86 Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|arm = Release|arm Release|arm64 = Release|arm64 - Release|x86 = Release|x86 Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {731858A7-0303-4988-877B-9C0DD6471864}.Debug|arm.ActiveCfg = Debug|ARM {731858A7-0303-4988-877B-9C0DD6471864}.Debug|arm.Build.0 = Debug|ARM {731858A7-0303-4988-877B-9C0DD6471864}.Debug|arm64.ActiveCfg = Debug|ARM64 {731858A7-0303-4988-877B-9C0DD6471864}.Debug|arm64.Build.0 = Debug|ARM64 - {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x86.ActiveCfg = Debug|Win32 - {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x86.Build.0 = Debug|Win32 {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x64.ActiveCfg = Debug|x64 {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x64.Build.0 = Debug|x64 + {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x86.ActiveCfg = Debug|Win32 + {731858A7-0303-4988-877B-9C0DD6471864}.Debug|x86.Build.0 = Debug|Win32 {731858A7-0303-4988-877B-9C0DD6471864}.Release|arm.ActiveCfg = Release|ARM {731858A7-0303-4988-877B-9C0DD6471864}.Release|arm.Build.0 = Release|ARM {731858A7-0303-4988-877B-9C0DD6471864}.Release|arm64.ActiveCfg = Release|ARM64 {731858A7-0303-4988-877B-9C0DD6471864}.Release|arm64.Build.0 = Release|ARM64 - {731858A7-0303-4988-877B-9C0DD6471864}.Release|x86.ActiveCfg = Release|Win32 - {731858A7-0303-4988-877B-9C0DD6471864}.Release|x86.Build.0 = Release|Win32 {731858A7-0303-4988-877B-9C0DD6471864}.Release|x64.ActiveCfg = Release|x64 {731858A7-0303-4988-877B-9C0DD6471864}.Release|x64.Build.0 = Release|x64 + {731858A7-0303-4988-877B-9C0DD6471864}.Release|x86.ActiveCfg = Release|Win32 + {731858A7-0303-4988-877B-9C0DD6471864}.Release|x86.Build.0 = Release|Win32 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|arm.ActiveCfg = Debug|ARM {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|arm.Build.0 = Debug|ARM {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|arm64.ActiveCfg = Debug|ARM64 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|arm64.Build.0 = Debug|ARM64 - {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x86.ActiveCfg = Debug|Win32 - {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x86.Build.0 = Debug|Win32 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x64.ActiveCfg = Debug|x64 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x64.Build.0 = Debug|x64 + {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x86.ActiveCfg = Debug|Win32 + {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Debug|x86.Build.0 = Debug|Win32 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|arm.ActiveCfg = Release|ARM {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|arm.Build.0 = Release|ARM {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|arm64.ActiveCfg = Release|ARM64 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|arm64.Build.0 = Release|ARM64 - {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x86.ActiveCfg = Release|Win32 - {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x86.Build.0 = Release|Win32 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x64.ActiveCfg = Release|x64 {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x64.Build.0 = Release|x64 + {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x86.ActiveCfg = Release|Win32 + {2B1D078D-8EB4-4398-9CA4-23457265A7F6}.Release|x86.Build.0 = Release|Win32 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|arm.ActiveCfg = Debug|ARM {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|arm.Build.0 = Debug|ARM {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|arm64.ActiveCfg = Debug|ARM64 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|arm64.Build.0 = Debug|ARM64 - {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x86.ActiveCfg = Debug|Win32 - {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x86.Build.0 = Debug|Win32 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x64.ActiveCfg = Debug|x64 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x64.Build.0 = Debug|x64 + {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x86.ActiveCfg = Debug|Win32 + {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Debug|x86.Build.0 = Debug|Win32 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|arm.ActiveCfg = Release|ARM {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|arm.Build.0 = Release|ARM {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|arm64.ActiveCfg = Release|ARM64 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|arm64.Build.0 = Release|ARM64 - {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x86.ActiveCfg = Release|Win32 - {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x86.Build.0 = Release|Win32 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x64.ActiveCfg = Release|x64 {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x64.Build.0 = Release|x64 + {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x86.ActiveCfg = Release|Win32 + {8390DCE0-859D-4F57-AD9C-AAEAC4D77EEF}.Release|x86.Build.0 = Release|Win32 {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|arm.ActiveCfg = Debug|ARM {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|arm.Build.0 = Debug|ARM {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|arm64.ActiveCfg = Debug|ARM64 {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|arm64.Build.0 = Debug|ARM64 - {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x86.ActiveCfg = Debug|Win32 - {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x86.Build.0 = Debug|Win32 {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x64.ActiveCfg = Debug|x64 {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x64.Build.0 = Debug|x64 + {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x86.ActiveCfg = Debug|Win32 + {266502AC-CD74-4581-B707-938A7D05AD7A}.Debug|x86.Build.0 = Debug|Win32 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|arm.ActiveCfg = Release|ARM {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|arm.Build.0 = Release|ARM {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|arm64.ActiveCfg = Release|ARM64 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|arm64.Build.0 = Release|ARM64 - {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86.ActiveCfg = Release|Win32 - {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86.Build.0 = Release|Win32 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x64.ActiveCfg = Release|x64 {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x64.Build.0 = Release|x64 + {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86.ActiveCfg = Release|Win32 + {266502AC-CD74-4581-B707-938A7D05AD7A}.Release|x86.Build.0 = Release|Win32 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|arm.ActiveCfg = Debug|ARM {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|arm.Build.0 = Debug|ARM {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|arm64.ActiveCfg = Debug|ARM64 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|arm64.Build.0 = Debug|ARM64 - {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86.ActiveCfg = Debug|Win32 - {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86.Build.0 = Debug|Win32 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x64.ActiveCfg = Debug|x64 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x64.Build.0 = Debug|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86.ActiveCfg = Debug|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Debug|x86.Build.0 = Debug|Win32 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|arm.ActiveCfg = Release|ARM {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|arm.Build.0 = Release|ARM {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|arm64.ActiveCfg = Release|ARM64 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|arm64.Build.0 = Release|ARM64 - {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86.ActiveCfg = Release|Win32 - {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86.Build.0 = Release|Win32 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x64.ActiveCfg = Release|x64 {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x64.Build.0 = Release|x64 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86.ActiveCfg = Release|Win32 + {7D2E9784-DDF7-4988-A887-CF099BC3B340}.Release|x86.Build.0 = Release|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|arm.ActiveCfg = Debug|ARM {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|arm.Build.0 = Debug|ARM {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|arm64.ActiveCfg = Debug|ARM64 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|arm64.Build.0 = Debug|ARM64 - {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86.ActiveCfg = Debug|Win32 - {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86.Build.0 = Debug|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x64.ActiveCfg = Debug|x64 {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x64.Build.0 = Debug|x64 + {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86.ActiveCfg = Debug|Win32 + {D4E80F35-2604-40AC-B436-97B052ECB572}.Debug|x86.Build.0 = Debug|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|arm.ActiveCfg = Release|ARM {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|arm.Build.0 = Release|ARM {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|arm64.ActiveCfg = Release|ARM64 {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|arm64.Build.0 = Release|ARM64 - {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x86.ActiveCfg = Release|Win32 - {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x86.Build.0 = Release|Win32 {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x64.ActiveCfg = Release|x64 {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x64.Build.0 = Release|x64 + {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x86.ActiveCfg = Release|Win32 + {D4E80F35-2604-40AC-B436-97B052ECB572}.Release|x86.Build.0 = Release|Win32 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|arm.ActiveCfg = Debug|ARM {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|arm.Build.0 = Debug|ARM {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|arm64.ActiveCfg = Debug|ARM64 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|arm64.Build.0 = Debug|ARM64 - {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x86.ActiveCfg = Debug|Win32 - {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x86.Build.0 = Debug|Win32 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x64.ActiveCfg = Debug|x64 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x64.Build.0 = Debug|x64 + {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x86.ActiveCfg = Debug|Win32 + {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Debug|x86.Build.0 = Debug|Win32 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|arm.ActiveCfg = Release|ARM {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|arm.Build.0 = Release|ARM {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|arm64.ActiveCfg = Release|ARM64 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|arm64.Build.0 = Release|ARM64 - {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x86.ActiveCfg = Release|Win32 - {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x86.Build.0 = Release|Win32 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x64.ActiveCfg = Release|x64 {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x64.Build.0 = Release|x64 + {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x86.ActiveCfg = Release|Win32 + {0CEC40A6-A195-4BE5-A88B-0AB00EB142EC}.Release|x86.Build.0 = Release|Win32 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|arm.ActiveCfg = Debug|ARM {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|arm.Build.0 = Debug|ARM {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|arm64.ActiveCfg = Debug|ARM64 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|arm64.Build.0 = Debug|ARM64 - {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x86.ActiveCfg = Debug|Win32 - {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x86.Build.0 = Debug|Win32 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x64.ActiveCfg = Debug|x64 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x64.Build.0 = Debug|x64 + {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x86.ActiveCfg = Debug|Win32 + {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Debug|x86.Build.0 = Debug|Win32 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|arm.ActiveCfg = Release|ARM {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|arm.Build.0 = Release|ARM {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|arm64.ActiveCfg = Release|ARM64 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|arm64.Build.0 = Release|ARM64 - {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x86.ActiveCfg = Release|Win32 - {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x86.Build.0 = Release|Win32 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x64.ActiveCfg = Release|x64 {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x64.Build.0 = Release|x64 + {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x86.ActiveCfg = Release|Win32 + {FA1B1093-BA86-410A-B7A0-7A54C605F812}.Release|x86.Build.0 = Release|Win32 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|arm.ActiveCfg = Debug|ARM {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|arm.Build.0 = Debug|ARM {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|arm64.ActiveCfg = Debug|ARM64 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|arm64.Build.0 = Debug|ARM64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x86.ActiveCfg = Debug|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x86.Build.0 = Debug|Win32 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x86.ActiveCfg = Debug|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x86.Build.0 = Debug|Win32 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|arm.ActiveCfg = Release|ARM {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|arm.Build.0 = Release|ARM {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|arm64.ActiveCfg = Release|ARM64 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|arm64.Build.0 = Release|ARM64 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x86.ActiveCfg = Release|Win32 - {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x86.Build.0 = Release|Win32 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64 {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x86.ActiveCfg = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x86.Build.0 = Release|Win32 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|arm.ActiveCfg = Debug|ARM {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|arm.Build.0 = Debug|ARM {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|arm64.ActiveCfg = Debug|ARM64 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|arm64.Build.0 = Debug|ARM64 - {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86.ActiveCfg = Debug|Win32 - {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86.Build.0 = Debug|Win32 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x64.ActiveCfg = Debug|x64 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x64.Build.0 = Debug|x64 + {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86.ActiveCfg = Debug|Win32 + {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Debug|x86.Build.0 = Debug|Win32 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|arm.ActiveCfg = Release|ARM {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|arm.Build.0 = Release|ARM {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|arm64.ActiveCfg = Release|ARM64 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|arm64.Build.0 = Release|ARM64 - {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86.ActiveCfg = Release|Win32 - {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86.Build.0 = Release|Win32 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x64.ActiveCfg = Release|x64 {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x64.Build.0 = Release|x64 + {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86.ActiveCfg = Release|Win32 + {FB6D52D4-A2F8-C358-DB85-BBCAECFDDD7D}.Release|x86.Build.0 = Release|Win32 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|arm.ActiveCfg = Debug|ARM + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|arm.Build.0 = Debug|ARM + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|arm64.ActiveCfg = Debug|ARM64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|arm64.Build.0 = Debug|ARM64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|x64.ActiveCfg = Debug|x64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|x64.Build.0 = Debug|x64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|x86.ActiveCfg = Debug|Win32 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Debug|x86.Build.0 = Debug|Win32 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|arm.ActiveCfg = Release|ARM + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|arm.Build.0 = Release|ARM + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|arm64.ActiveCfg = Release|ARM64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|arm64.Build.0 = Release|ARM64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|x64.ActiveCfg = Release|x64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|x64.Build.0 = Release|x64 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|x86.ActiveCfg = Release|Win32 + {B01F5886-2B39-4B66-B65C-6427135B6A02}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Makefile.am b/src/Makefile.am index 030743a5..8cbdf4fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc +SUBDIRS = bled ext2fs ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc noinst_PROGRAMS = rufus @@ -12,7 +12,7 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V)) rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \ net.c parser.c pki.c process.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c ui.c vhd.c -rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) +rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) -Wno-shadow rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows -rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ +rufus_LDADD = rufus_rc.o bled/libbled.a ext2fs/libext2fs.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -lcomctl32 -luuid -lpsapi diff --git a/src/Makefile.in b/src/Makefile.in index 0174fec6..d0764301 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -99,10 +99,11 @@ am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \ rufus-syslinux.$(OBJEXT) rufus-ui.$(OBJEXT) \ rufus-vhd.$(OBJEXT) rufus_OBJECTS = $(am_rufus_OBJECTS) -rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ms-sys/libmssys.a \ - syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ - syslinux/win/libwin.a libcdio/iso9660/libiso9660.a \ - libcdio/udf/libudf.a libcdio/driver/libdriver.a +rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ext2fs/libext2fs.a \ + ms-sys/libmssys.a syslinux/libfat/libfat.a \ + syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ + libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a \ + libcdio/driver/libdriver.a rufus_LINK = $(CCLD) $(rufus_CFLAGS) $(CFLAGS) $(rufus_LDFLAGS) \ $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) @@ -266,7 +267,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -SUBDIRS = bled ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc +SUBDIRS = bled ext2fs ms-sys syslinux/libfat syslinux/libinstaller syslinux/win libcdio/iso9660 libcdio/udf libcdio/driver ../res/loc AM_V_WINDRES_0 = @echo " RC $@";$(WINDRES) AM_V_WINDRES_1 = $(WINDRES) AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY)) @@ -274,9 +275,9 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V)) rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \ net.c parser.c pki.c process.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c ui.c vhd.c -rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) +rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS) -Wno-shadow rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows -rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ +rufus_LDADD = rufus_rc.o bled/libbled.a ext2fs/libext2fs.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -lcomctl32 -luuid -lpsapi all: all-recursive diff --git a/src/badblocks.c b/src/badblocks.c index 268cdabd..f88aae47 100644 --- a/src/badblocks.c +++ b/src/badblocks.c @@ -1,36 +1,19 @@ /* - * badblocks.c - Bad blocks checker + * badblocks.c - Bad blocks checker * - * Copyright (C) 1992, 1993, 1994 Remy Card - * Laboratoire MASI, Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * Copyright 1995, 1996, 1997, 1998, 1999 by Theodore Ts'o - * Copyright 1999 by David Beattie - * Copyright 2011-2018 by Pete Batard + * Copyright 1992-1994 Remy Card + * Copyright 1995-1999 Theodore Ts'o + * Copyright 1999 David Beattie + * Copyright 2011-2019 Pete Batard * * This file is based on the minix file system programs fsck and mkfs * written and copyrighted by Linus Torvalds * * %Begin-Header% - * This file may be redistributed under the terms of the GNU Public - * License. + * This file may be redistributed under the terms of the GNU Public License. * %End-Header% */ -/* - * History: - * 93/05/26 - Creation from e2fsck - * 94/02/27 - Made a separate bad blocks checker - * 99/06/30...99/07/26 - Added non-destructive write-testing, - * configurable blocks-at-once parameter, - * loading of badblocks list to avoid testing - * blocks known to be bad, multiple passes to - * make sure that no new blocks are added to the - * list. (Work done by David Beattie) - * 11/12/04 - Windows/Rufus integration (Pete Batard) - */ - #include #include #include @@ -84,16 +67,16 @@ static errcode_t make_u64_list(int size, int num, uint64_t *list, bb_u64_list *r bb->magic = BB_ET_MAGIC_BADBLOCKS_LIST; bb->size = size ? size : 10; bb->num = num; - bb->list = malloc(sizeof(blk_t) * bb->size); + bb->list = malloc(sizeof(blk64_t) * bb->size); if (bb->list == NULL) { free(bb); bb = NULL; return BB_ET_NO_MEMORY; } if (list) - memcpy(bb->list, list, bb->size * sizeof(blk_t)); + memcpy(bb->list, list, bb->size * sizeof(blk64_t)); else - memset(bb->list, 0, bb->size * sizeof(blk_t)); + memset(bb->list, 0, bb->size * sizeof(blk64_t)); *ret = bb; return 0; } @@ -155,7 +138,7 @@ static errcode_t bb_u64_list_add(bb_u64_list bb, uint64_t blk) return 0; } -static errcode_t bb_badblocks_list_add(bb_badblocks_list bb, blk_t blk) +static errcode_t bb_badblocks_list_add(bb_badblocks_list bb, blk64_t blk) { return bb_u64_list_add((bb_u64_list) bb, blk); } @@ -164,7 +147,7 @@ static errcode_t bb_badblocks_list_add(bb_badblocks_list bb, blk_t blk) * This procedure finds a particular block is on a badblocks * list. */ -static int bb_u64_list_find(bb_u64_list bb, uint64_t blk) +static int bb_u64_list_find(bb_u64_list bb, blk64_t blk) { int low, high, mid; @@ -199,7 +182,7 @@ static int bb_u64_list_find(bb_u64_list bb, uint64_t blk) * This procedure tests to see if a particular block is on a badblocks * list. */ -static int bb_u64_list_test(bb_u64_list bb, uint64_t blk) +static int bb_u64_list_test(bb_u64_list bb, blk64_t blk) { if (bb_u64_list_find(bb, blk) < 0) return 0; @@ -207,12 +190,12 @@ static int bb_u64_list_test(bb_u64_list bb, uint64_t blk) return 1; } -static int bb_badblocks_list_test(bb_badblocks_list bb, blk_t blk) +static int bb_badblocks_list_test(bb_badblocks_list bb, blk64_t blk) { return bb_u64_list_test((bb_u64_list) bb, blk); } -static int bb_u64_list_iterate(bb_u64_iterate iter, uint64_t *blk) +static int bb_u64_list_iterate(bb_u64_iterate iter, blk64_t *blk) { bb_u64_list bb; @@ -232,7 +215,7 @@ static int bb_u64_list_iterate(bb_u64_iterate iter, uint64_t *blk) return 0; } -static int bb_badblocks_list_iterate(bb_badblocks_iterate iter, blk_t *blk) +static int bb_badblocks_list_iterate(bb_badblocks_iterate iter, blk64_t *blk) { return bb_u64_list_iterate((bb_u64_iterate) iter, blk); } @@ -247,13 +230,13 @@ static int cur_pattern, nr_pattern; static int cur_op; /* Abort test if more than this number of bad blocks has been encountered */ static unsigned int max_bb = BB_BAD_BLOCKS_THRESHOLD; -static blk_t currently_testing = 0; -static blk_t num_blocks = 0; +static blk64_t currently_testing = 0; +static blk64_t num_blocks = 0; static uint32_t num_read_errors = 0; static uint32_t num_write_errors = 0; static uint32_t num_corruption_errors = 0; static bb_badblocks_list bb_list = NULL; -static blk_t next_bad = 0; +static blk64_t next_bad = 0; static bb_badblocks_iterate bb_iter = NULL; static __inline void *allocate_buffer(size_t size) { @@ -268,7 +251,7 @@ static __inline void free_buffer(void* p) { * This routine reports a new bad block. If the bad block has already * been seen before, then it returns 0; otherwise it returns 1. */ -static int bb_output (blk_t bad, enum error_types error_type) +static int bb_output (blk64_t bad, enum error_types error_type) { errcode_t error_code; @@ -381,8 +364,8 @@ static void pattern_fill(unsigned char *buffer, unsigned int pattern, * Perform a read of a sequence of blocks; return the number of blocks * successfully sequentially read. */ -static int64_t do_read (HANDLE hDrive, unsigned char * buffer, uint64_t tryout, uint64_t block_size, - blk_t current_block) +static int64_t do_read (HANDLE hDrive, unsigned char * buffer, uint64_t tryout, + uint64_t block_size, blk64_t current_block) { int64_t got; @@ -403,8 +386,8 @@ static int64_t do_read (HANDLE hDrive, unsigned char * buffer, uint64_t tryout, * Perform a write of a sequence of blocks; return the number of blocks * successfully sequentially written. */ -static int64_t do_write(HANDLE hDrive, unsigned char * buffer, uint64_t tryout, uint64_t block_size, - blk_t current_block) +static int64_t do_write(HANDLE hDrive, unsigned char * buffer, uint64_t tryout, + uint64_t block_size, blk64_t current_block) { int64_t got; @@ -421,15 +404,15 @@ static int64_t do_write(HANDLE hDrive, unsigned char * buffer, uint64_t tryout, return got; } -static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, blk_t first_block, - size_t blocks_at_once, int pattern_type, int nb_passes) +static unsigned int test_rw(HANDLE hDrive, blk64_t last_block, size_t block_size, blk64_t first_block, + size_t blocks_at_once, int pattern_type, int nb_passes) { const unsigned int pattern[BADLOCKS_PATTERN_TYPES][BADBLOCK_PATTERN_COUNT] = { BADBLOCK_PATTERN_SLC, BADCLOCK_PATTERN_MLC, BADBLOCK_PATTERN_TLC }; unsigned char *buffer = NULL, *read_buffer; int i, pat_idx; unsigned int bb_count = 0; - blk_t got, tryout, recover_block = ~0, *blk_id; + blk64_t got, tryout, recover_block = ~0, *blk_id; size_t id_offset = 0; if ((pattern_type < 0) || (pattern_type >= BADLOCKS_PATTERN_TYPES)) { @@ -463,7 +446,7 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, goto out; if (detect_fakes && (pat_idx == 0)) { srand((unsigned int)GetTickCount64()); - id_offset = rand() * (block_size - sizeof(blk_t)) / RAND_MAX; + id_offset = rand() * (block_size - sizeof(blk64_t)) / RAND_MAX; uprintf("%sUsing offset %d for fake device check\n", bb_prefix, id_offset); } // coverity[dont_call] @@ -492,8 +475,8 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, /* Add the block number at a fixed (random) offset during each pass to allow for the detection of 'fake' media (eg. 2GB USB masquerading as 16GB) */ for (i=0; i<(int)blocks_at_once; i++) { - blk_id = (blk_t*)(intptr_t)(buffer + id_offset+ i*block_size); - *blk_id = (blk_t)(currently_testing + i); + blk_id = (blk64_t*)(intptr_t)(buffer + id_offset+ i*block_size); + *blk_id = (blk64_t)(currently_testing + i); } } got = do_write(hDrive, buffer, tryout, block_size, currently_testing); @@ -538,8 +521,8 @@ static unsigned int test_rw(HANDLE hDrive, blk_t last_block, size_t block_size, tryout = last_block - currently_testing; if (detect_fakes && (pat_idx == 0)) { for (i=0; i<(int)blocks_at_once; i++) { - blk_id = (blk_t*)(intptr_t)(buffer + id_offset+ i*block_size); - *blk_id = (blk_t)(currently_testing + i); + blk_id = (blk64_t*)(intptr_t)(buffer + id_offset+ i*block_size); + *blk_id = (blk64_t)(currently_testing + i); } } got = do_read(hDrive, read_buffer, tryout, block_size, @@ -575,10 +558,10 @@ out: } BOOL BadBlocks(HANDLE hPhysicalDrive, ULONGLONG disk_size, int nb_passes, - int flash_type, badblocks_report *report, FILE* fd) + int flash_type, badblocks_report *report, FILE* fd) { errcode_t error_code; - blk_t last_block = disk_size / BADBLOCK_BLOCK_SIZE; + blk64_t last_block = disk_size / BADBLOCK_BLOCK_SIZE; if (report == NULL) return FALSE; num_read_errors = 0; diff --git a/src/badblocks.h b/src/badblocks.h index 45f6a303..809a95ef 100644 --- a/src/badblocks.h +++ b/src/badblocks.h @@ -21,8 +21,7 @@ #include #include -typedef uint64_t blk_t; -typedef DWORD errcode_t; +#include "ext2fs/ext2fs.h" typedef struct bb_struct_u64_list *bb_badblocks_list; typedef struct bb_struct_u64_iterate *bb_badblocks_iterate; diff --git a/src/drive.c b/src/drive.c index 474bb022..f723fda6 100644 --- a/src/drive.c +++ b/src/drive.c @@ -228,6 +228,22 @@ out: return (success)?safe_strdup(physical_name):NULL; } +/* + * Return an NT path to access the physical drive, or NULL on error. + * The string is allocated and must be freed (to ensure concurrent access) + */ +char* GetNtPhysicalName(DWORD DriveIndex) +{ + BOOL success = FALSE; + char physical_name[32]; + + CheckDriveIndex(DriveIndex); + static_sprintf(physical_name, "\\??\\PHYSICALDRIVE%lu", DriveIndex); + success = TRUE; +out: + return (success) ? safe_strdup(physical_name) : NULL; +} + /* * Return a handle to the physical drive identified by DriveIndex */ diff --git a/src/drive.h b/src/drive.h index 30c870d2..335aa91a 100644 --- a/src/drive.h +++ b/src/drive.h @@ -258,6 +258,7 @@ extern RUFUS_DRIVE_INFO SelectedDrive; BOOL SetAutoMount(BOOL enable); BOOL GetAutoMount(BOOL* enabled); char* GetPhysicalName(DWORD DriveIndex); +char* GetNtPhysicalName(DWORD DriveIndex); BOOL DeletePartitions(DWORD DriveIndex); HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWriteShare); char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent); diff --git a/src/ext2fs/.editorconfig b/src/ext2fs/.editorconfig new file mode 100644 index 00000000..817bf043 --- /dev/null +++ b/src/ext2fs/.editorconfig @@ -0,0 +1,2 @@ +[*] +tab_width = 8 diff --git a/src/ext2fs/Makefile.am b/src/ext2fs/Makefile.am new file mode 100644 index 00000000..1f4bb618 --- /dev/null +++ b/src/ext2fs/Makefile.am @@ -0,0 +1,9 @@ +noinst_LIBRARIES = libext2fs.a + +libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c bitmaps.c \ + bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c crc32c.c csum.c \ + dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c gen_bitmap.c gen_bitmap64.c \ + get_num_dirs.c i_block.c ind_block.c initialize.c inline.c inline_data.c inode.c io_manager.c link.c \ + lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c symlink.c valid_blk.c + +libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow diff --git a/src/ext2fs/Makefile.in b/src/ext2fs/Makefile.in new file mode 100644 index 00000000..688ef4b9 --- /dev/null +++ b/src/ext2fs/Makefile.in @@ -0,0 +1,779 @@ +# Makefile.in generated by automake 1.14.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2013 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = src/ext2fs +DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libext2fs_a_AR = $(AR) $(ARFLAGS) +libext2fs_a_LIBADD = +am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \ + libext2fs_a-alloc_sb.$(OBJEXT) \ + libext2fs_a-alloc_stats.$(OBJEXT) \ + libext2fs_a-alloc_tables.$(OBJEXT) \ + libext2fs_a-badblocks.$(OBJEXT) libext2fs_a-bb_inode.$(OBJEXT) \ + libext2fs_a-bitmaps.$(OBJEXT) libext2fs_a-bitops.$(OBJEXT) \ + libext2fs_a-blkmap64_ba.$(OBJEXT) \ + libext2fs_a-blkmap64_rb.$(OBJEXT) libext2fs_a-blknum.$(OBJEXT) \ + libext2fs_a-block.$(OBJEXT) libext2fs_a-bmap.$(OBJEXT) \ + libext2fs_a-closefs.$(OBJEXT) libext2fs_a-crc16.$(OBJEXT) \ + libext2fs_a-crc32c.$(OBJEXT) libext2fs_a-csum.$(OBJEXT) \ + libext2fs_a-dirblock.$(OBJEXT) \ + libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ + libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ + libext2fs_a-fileio.$(OBJEXT) libext2fs_a-freefs.$(OBJEXT) \ + libext2fs_a-gen_bitmap.$(OBJEXT) \ + libext2fs_a-gen_bitmap64.$(OBJEXT) \ + libext2fs_a-get_num_dirs.$(OBJEXT) \ + libext2fs_a-i_block.$(OBJEXT) libext2fs_a-ind_block.$(OBJEXT) \ + libext2fs_a-initialize.$(OBJEXT) libext2fs_a-inline.$(OBJEXT) \ + libext2fs_a-inline_data.$(OBJEXT) libext2fs_a-inode.$(OBJEXT) \ + libext2fs_a-io_manager.$(OBJEXT) libext2fs_a-link.$(OBJEXT) \ + libext2fs_a-lookup.$(OBJEXT) libext2fs_a-missing.$(OBJEXT) \ + libext2fs_a-mkdir.$(OBJEXT) libext2fs_a-mmp.$(OBJEXT) \ + libext2fs_a-newdir.$(OBJEXT) libext2fs_a-nt_io.$(OBJEXT) \ + libext2fs_a-punch.$(OBJEXT) libext2fs_a-rbtree.$(OBJEXT) \ + libext2fs_a-read_bb.$(OBJEXT) libext2fs_a-rw_bitmaps.$(OBJEXT) \ + libext2fs_a-symlink.$(OBJEXT) libext2fs_a-valid_blk.$(OBJEXT) +libext2fs_a_OBJECTS = $(am_libext2fs_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = +am__depfiles_maybe = +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libext2fs_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SUFFIX = @SUFFIX@ +VERSION = @VERSION@ +VISIBILITY_CFLAGS = @VISIBILITY_CFLAGS@ +WINDRES = @WINDRES@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +am__leading_dot = @am__leading_dot@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = libext2fs.a +libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c bitmaps.c \ + bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c crc32c.c csum.c \ + dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fileio.c freefs.c gen_bitmap.c gen_bitmap64.c \ + get_num_dirs.c i_block.c ind_block.c initialize.c inline.c inline_data.c inode.c io_manager.c link.c \ + lookup.c missing.c mkdir.c mmp.c newdir.c nt_io.c punch.c rbtree.c read_bb.c rw_bitmaps.c symlink.c valid_blk.c + +libext2fs_a_CFLAGS = $(AM_CFLAGS) -DEXT2_FLAT_INCLUDES -DHAVE_CONFIG_H -I. -I.. -Wno-undef -Wno-strict-aliasing -Wno-shadow +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps src/ext2fs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign --ignore-deps src/ext2fs/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libext2fs.a: $(libext2fs_a_OBJECTS) $(libext2fs_a_DEPENDENCIES) $(EXTRA_libext2fs_a_DEPENDENCIES) + $(AM_V_at)-rm -f libext2fs.a + $(AM_V_AR)$(libext2fs_a_AR) libext2fs.a $(libext2fs_a_OBJECTS) $(libext2fs_a_LIBADD) + $(AM_V_at)$(RANLIB) libext2fs.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +.c.o: + $(AM_V_CC)$(COMPILE) -c -o $@ $< + +.c.obj: + $(AM_V_CC)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +libext2fs_a-alloc.o: alloc.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc.o `test -f 'alloc.c' || echo '$(srcdir)/'`alloc.c + +libext2fs_a-alloc.obj: alloc.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc.obj `if test -f 'alloc.c'; then $(CYGPATH_W) 'alloc.c'; else $(CYGPATH_W) '$(srcdir)/alloc.c'; fi` + +libext2fs_a-alloc_sb.o: alloc_sb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_sb.o `test -f 'alloc_sb.c' || echo '$(srcdir)/'`alloc_sb.c + +libext2fs_a-alloc_sb.obj: alloc_sb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_sb.obj `if test -f 'alloc_sb.c'; then $(CYGPATH_W) 'alloc_sb.c'; else $(CYGPATH_W) '$(srcdir)/alloc_sb.c'; fi` + +libext2fs_a-alloc_stats.o: alloc_stats.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_stats.o `test -f 'alloc_stats.c' || echo '$(srcdir)/'`alloc_stats.c + +libext2fs_a-alloc_stats.obj: alloc_stats.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_stats.obj `if test -f 'alloc_stats.c'; then $(CYGPATH_W) 'alloc_stats.c'; else $(CYGPATH_W) '$(srcdir)/alloc_stats.c'; fi` + +libext2fs_a-alloc_tables.o: alloc_tables.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_tables.o `test -f 'alloc_tables.c' || echo '$(srcdir)/'`alloc_tables.c + +libext2fs_a-alloc_tables.obj: alloc_tables.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-alloc_tables.obj `if test -f 'alloc_tables.c'; then $(CYGPATH_W) 'alloc_tables.c'; else $(CYGPATH_W) '$(srcdir)/alloc_tables.c'; fi` + +libext2fs_a-badblocks.o: badblocks.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-badblocks.o `test -f 'badblocks.c' || echo '$(srcdir)/'`badblocks.c + +libext2fs_a-badblocks.obj: badblocks.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-badblocks.obj `if test -f 'badblocks.c'; then $(CYGPATH_W) 'badblocks.c'; else $(CYGPATH_W) '$(srcdir)/badblocks.c'; fi` + +libext2fs_a-bb_inode.o: bb_inode.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bb_inode.o `test -f 'bb_inode.c' || echo '$(srcdir)/'`bb_inode.c + +libext2fs_a-bb_inode.obj: bb_inode.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bb_inode.obj `if test -f 'bb_inode.c'; then $(CYGPATH_W) 'bb_inode.c'; else $(CYGPATH_W) '$(srcdir)/bb_inode.c'; fi` + +libext2fs_a-bitmaps.o: bitmaps.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bitmaps.o `test -f 'bitmaps.c' || echo '$(srcdir)/'`bitmaps.c + +libext2fs_a-bitmaps.obj: bitmaps.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bitmaps.obj `if test -f 'bitmaps.c'; then $(CYGPATH_W) 'bitmaps.c'; else $(CYGPATH_W) '$(srcdir)/bitmaps.c'; fi` + +libext2fs_a-bitops.o: bitops.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bitops.o `test -f 'bitops.c' || echo '$(srcdir)/'`bitops.c + +libext2fs_a-bitops.obj: bitops.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bitops.obj `if test -f 'bitops.c'; then $(CYGPATH_W) 'bitops.c'; else $(CYGPATH_W) '$(srcdir)/bitops.c'; fi` + +libext2fs_a-blkmap64_ba.o: blkmap64_ba.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blkmap64_ba.o `test -f 'blkmap64_ba.c' || echo '$(srcdir)/'`blkmap64_ba.c + +libext2fs_a-blkmap64_ba.obj: blkmap64_ba.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blkmap64_ba.obj `if test -f 'blkmap64_ba.c'; then $(CYGPATH_W) 'blkmap64_ba.c'; else $(CYGPATH_W) '$(srcdir)/blkmap64_ba.c'; fi` + +libext2fs_a-blkmap64_rb.o: blkmap64_rb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blkmap64_rb.o `test -f 'blkmap64_rb.c' || echo '$(srcdir)/'`blkmap64_rb.c + +libext2fs_a-blkmap64_rb.obj: blkmap64_rb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blkmap64_rb.obj `if test -f 'blkmap64_rb.c'; then $(CYGPATH_W) 'blkmap64_rb.c'; else $(CYGPATH_W) '$(srcdir)/blkmap64_rb.c'; fi` + +libext2fs_a-blknum.o: blknum.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blknum.o `test -f 'blknum.c' || echo '$(srcdir)/'`blknum.c + +libext2fs_a-blknum.obj: blknum.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-blknum.obj `if test -f 'blknum.c'; then $(CYGPATH_W) 'blknum.c'; else $(CYGPATH_W) '$(srcdir)/blknum.c'; fi` + +libext2fs_a-block.o: block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-block.o `test -f 'block.c' || echo '$(srcdir)/'`block.c + +libext2fs_a-block.obj: block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-block.obj `if test -f 'block.c'; then $(CYGPATH_W) 'block.c'; else $(CYGPATH_W) '$(srcdir)/block.c'; fi` + +libext2fs_a-bmap.o: bmap.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bmap.o `test -f 'bmap.c' || echo '$(srcdir)/'`bmap.c + +libext2fs_a-bmap.obj: bmap.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-bmap.obj `if test -f 'bmap.c'; then $(CYGPATH_W) 'bmap.c'; else $(CYGPATH_W) '$(srcdir)/bmap.c'; fi` + +libext2fs_a-closefs.o: closefs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-closefs.o `test -f 'closefs.c' || echo '$(srcdir)/'`closefs.c + +libext2fs_a-closefs.obj: closefs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-closefs.obj `if test -f 'closefs.c'; then $(CYGPATH_W) 'closefs.c'; else $(CYGPATH_W) '$(srcdir)/closefs.c'; fi` + +libext2fs_a-crc16.o: crc16.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-crc16.o `test -f 'crc16.c' || echo '$(srcdir)/'`crc16.c + +libext2fs_a-crc16.obj: crc16.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-crc16.obj `if test -f 'crc16.c'; then $(CYGPATH_W) 'crc16.c'; else $(CYGPATH_W) '$(srcdir)/crc16.c'; fi` + +libext2fs_a-crc32c.o: crc32c.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-crc32c.o `test -f 'crc32c.c' || echo '$(srcdir)/'`crc32c.c + +libext2fs_a-crc32c.obj: crc32c.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-crc32c.obj `if test -f 'crc32c.c'; then $(CYGPATH_W) 'crc32c.c'; else $(CYGPATH_W) '$(srcdir)/crc32c.c'; fi` + +libext2fs_a-csum.o: csum.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-csum.o `test -f 'csum.c' || echo '$(srcdir)/'`csum.c + +libext2fs_a-csum.obj: csum.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-csum.obj `if test -f 'csum.c'; then $(CYGPATH_W) 'csum.c'; else $(CYGPATH_W) '$(srcdir)/csum.c'; fi` + +libext2fs_a-dirblock.o: dirblock.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dirblock.o `test -f 'dirblock.c' || echo '$(srcdir)/'`dirblock.c + +libext2fs_a-dirblock.obj: dirblock.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dirblock.obj `if test -f 'dirblock.c'; then $(CYGPATH_W) 'dirblock.c'; else $(CYGPATH_W) '$(srcdir)/dirblock.c'; fi` + +libext2fs_a-dir_iterate.o: dir_iterate.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dir_iterate.o `test -f 'dir_iterate.c' || echo '$(srcdir)/'`dir_iterate.c + +libext2fs_a-dir_iterate.obj: dir_iterate.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dir_iterate.obj `if test -f 'dir_iterate.c'; then $(CYGPATH_W) 'dir_iterate.c'; else $(CYGPATH_W) '$(srcdir)/dir_iterate.c'; fi` + +libext2fs_a-extent.o: extent.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-extent.o `test -f 'extent.c' || echo '$(srcdir)/'`extent.c + +libext2fs_a-extent.obj: extent.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-extent.obj `if test -f 'extent.c'; then $(CYGPATH_W) 'extent.c'; else $(CYGPATH_W) '$(srcdir)/extent.c'; fi` + +libext2fs_a-ext_attr.o: ext_attr.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ext_attr.o `test -f 'ext_attr.c' || echo '$(srcdir)/'`ext_attr.c + +libext2fs_a-ext_attr.obj: ext_attr.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ext_attr.obj `if test -f 'ext_attr.c'; then $(CYGPATH_W) 'ext_attr.c'; else $(CYGPATH_W) '$(srcdir)/ext_attr.c'; fi` + +libext2fs_a-fileio.o: fileio.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fileio.o `test -f 'fileio.c' || echo '$(srcdir)/'`fileio.c + +libext2fs_a-fileio.obj: fileio.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-fileio.obj `if test -f 'fileio.c'; then $(CYGPATH_W) 'fileio.c'; else $(CYGPATH_W) '$(srcdir)/fileio.c'; fi` + +libext2fs_a-freefs.o: freefs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-freefs.o `test -f 'freefs.c' || echo '$(srcdir)/'`freefs.c + +libext2fs_a-freefs.obj: freefs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-freefs.obj `if test -f 'freefs.c'; then $(CYGPATH_W) 'freefs.c'; else $(CYGPATH_W) '$(srcdir)/freefs.c'; fi` + +libext2fs_a-gen_bitmap.o: gen_bitmap.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-gen_bitmap.o `test -f 'gen_bitmap.c' || echo '$(srcdir)/'`gen_bitmap.c + +libext2fs_a-gen_bitmap.obj: gen_bitmap.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-gen_bitmap.obj `if test -f 'gen_bitmap.c'; then $(CYGPATH_W) 'gen_bitmap.c'; else $(CYGPATH_W) '$(srcdir)/gen_bitmap.c'; fi` + +libext2fs_a-gen_bitmap64.o: gen_bitmap64.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-gen_bitmap64.o `test -f 'gen_bitmap64.c' || echo '$(srcdir)/'`gen_bitmap64.c + +libext2fs_a-gen_bitmap64.obj: gen_bitmap64.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-gen_bitmap64.obj `if test -f 'gen_bitmap64.c'; then $(CYGPATH_W) 'gen_bitmap64.c'; else $(CYGPATH_W) '$(srcdir)/gen_bitmap64.c'; fi` + +libext2fs_a-get_num_dirs.o: get_num_dirs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-get_num_dirs.o `test -f 'get_num_dirs.c' || echo '$(srcdir)/'`get_num_dirs.c + +libext2fs_a-get_num_dirs.obj: get_num_dirs.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-get_num_dirs.obj `if test -f 'get_num_dirs.c'; then $(CYGPATH_W) 'get_num_dirs.c'; else $(CYGPATH_W) '$(srcdir)/get_num_dirs.c'; fi` + +libext2fs_a-i_block.o: i_block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-i_block.o `test -f 'i_block.c' || echo '$(srcdir)/'`i_block.c + +libext2fs_a-i_block.obj: i_block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-i_block.obj `if test -f 'i_block.c'; then $(CYGPATH_W) 'i_block.c'; else $(CYGPATH_W) '$(srcdir)/i_block.c'; fi` + +libext2fs_a-ind_block.o: ind_block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ind_block.o `test -f 'ind_block.c' || echo '$(srcdir)/'`ind_block.c + +libext2fs_a-ind_block.obj: ind_block.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-ind_block.obj `if test -f 'ind_block.c'; then $(CYGPATH_W) 'ind_block.c'; else $(CYGPATH_W) '$(srcdir)/ind_block.c'; fi` + +libext2fs_a-initialize.o: initialize.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-initialize.o `test -f 'initialize.c' || echo '$(srcdir)/'`initialize.c + +libext2fs_a-initialize.obj: initialize.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-initialize.obj `if test -f 'initialize.c'; then $(CYGPATH_W) 'initialize.c'; else $(CYGPATH_W) '$(srcdir)/initialize.c'; fi` + +libext2fs_a-inline.o: inline.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inline.o `test -f 'inline.c' || echo '$(srcdir)/'`inline.c + +libext2fs_a-inline.obj: inline.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inline.obj `if test -f 'inline.c'; then $(CYGPATH_W) 'inline.c'; else $(CYGPATH_W) '$(srcdir)/inline.c'; fi` + +libext2fs_a-inline_data.o: inline_data.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inline_data.o `test -f 'inline_data.c' || echo '$(srcdir)/'`inline_data.c + +libext2fs_a-inline_data.obj: inline_data.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inline_data.obj `if test -f 'inline_data.c'; then $(CYGPATH_W) 'inline_data.c'; else $(CYGPATH_W) '$(srcdir)/inline_data.c'; fi` + +libext2fs_a-inode.o: inode.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inode.o `test -f 'inode.c' || echo '$(srcdir)/'`inode.c + +libext2fs_a-inode.obj: inode.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-inode.obj `if test -f 'inode.c'; then $(CYGPATH_W) 'inode.c'; else $(CYGPATH_W) '$(srcdir)/inode.c'; fi` + +libext2fs_a-io_manager.o: io_manager.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-io_manager.o `test -f 'io_manager.c' || echo '$(srcdir)/'`io_manager.c + +libext2fs_a-io_manager.obj: io_manager.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-io_manager.obj `if test -f 'io_manager.c'; then $(CYGPATH_W) 'io_manager.c'; else $(CYGPATH_W) '$(srcdir)/io_manager.c'; fi` + +libext2fs_a-link.o: link.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-link.o `test -f 'link.c' || echo '$(srcdir)/'`link.c + +libext2fs_a-link.obj: link.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-link.obj `if test -f 'link.c'; then $(CYGPATH_W) 'link.c'; else $(CYGPATH_W) '$(srcdir)/link.c'; fi` + +libext2fs_a-lookup.o: lookup.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-lookup.o `test -f 'lookup.c' || echo '$(srcdir)/'`lookup.c + +libext2fs_a-lookup.obj: lookup.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-lookup.obj `if test -f 'lookup.c'; then $(CYGPATH_W) 'lookup.c'; else $(CYGPATH_W) '$(srcdir)/lookup.c'; fi` + +libext2fs_a-missing.o: missing.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.o `test -f 'missing.c' || echo '$(srcdir)/'`missing.c + +libext2fs_a-missing.obj: missing.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-missing.obj `if test -f 'missing.c'; then $(CYGPATH_W) 'missing.c'; else $(CYGPATH_W) '$(srcdir)/missing.c'; fi` + +libext2fs_a-mkdir.o: mkdir.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.o `test -f 'mkdir.c' || echo '$(srcdir)/'`mkdir.c + +libext2fs_a-mkdir.obj: mkdir.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mkdir.obj `if test -f 'mkdir.c'; then $(CYGPATH_W) 'mkdir.c'; else $(CYGPATH_W) '$(srcdir)/mkdir.c'; fi` + +libext2fs_a-mmp.o: mmp.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mmp.o `test -f 'mmp.c' || echo '$(srcdir)/'`mmp.c + +libext2fs_a-mmp.obj: mmp.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-mmp.obj `if test -f 'mmp.c'; then $(CYGPATH_W) 'mmp.c'; else $(CYGPATH_W) '$(srcdir)/mmp.c'; fi` + +libext2fs_a-newdir.o: newdir.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-newdir.o `test -f 'newdir.c' || echo '$(srcdir)/'`newdir.c + +libext2fs_a-newdir.obj: newdir.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-newdir.obj `if test -f 'newdir.c'; then $(CYGPATH_W) 'newdir.c'; else $(CYGPATH_W) '$(srcdir)/newdir.c'; fi` + +libext2fs_a-nt_io.o: nt_io.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-nt_io.o `test -f 'nt_io.c' || echo '$(srcdir)/'`nt_io.c + +libext2fs_a-nt_io.obj: nt_io.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-nt_io.obj `if test -f 'nt_io.c'; then $(CYGPATH_W) 'nt_io.c'; else $(CYGPATH_W) '$(srcdir)/nt_io.c'; fi` + +libext2fs_a-punch.o: punch.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-punch.o `test -f 'punch.c' || echo '$(srcdir)/'`punch.c + +libext2fs_a-punch.obj: punch.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-punch.obj `if test -f 'punch.c'; then $(CYGPATH_W) 'punch.c'; else $(CYGPATH_W) '$(srcdir)/punch.c'; fi` + +libext2fs_a-rbtree.o: rbtree.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-rbtree.o `test -f 'rbtree.c' || echo '$(srcdir)/'`rbtree.c + +libext2fs_a-rbtree.obj: rbtree.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-rbtree.obj `if test -f 'rbtree.c'; then $(CYGPATH_W) 'rbtree.c'; else $(CYGPATH_W) '$(srcdir)/rbtree.c'; fi` + +libext2fs_a-read_bb.o: read_bb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-read_bb.o `test -f 'read_bb.c' || echo '$(srcdir)/'`read_bb.c + +libext2fs_a-read_bb.obj: read_bb.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-read_bb.obj `if test -f 'read_bb.c'; then $(CYGPATH_W) 'read_bb.c'; else $(CYGPATH_W) '$(srcdir)/read_bb.c'; fi` + +libext2fs_a-rw_bitmaps.o: rw_bitmaps.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-rw_bitmaps.o `test -f 'rw_bitmaps.c' || echo '$(srcdir)/'`rw_bitmaps.c + +libext2fs_a-rw_bitmaps.obj: rw_bitmaps.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-rw_bitmaps.obj `if test -f 'rw_bitmaps.c'; then $(CYGPATH_W) 'rw_bitmaps.c'; else $(CYGPATH_W) '$(srcdir)/rw_bitmaps.c'; fi` + +libext2fs_a-symlink.o: symlink.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-symlink.o `test -f 'symlink.c' || echo '$(srcdir)/'`symlink.c + +libext2fs_a-symlink.obj: symlink.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-symlink.obj `if test -f 'symlink.c'; then $(CYGPATH_W) 'symlink.c'; else $(CYGPATH_W) '$(srcdir)/symlink.c'; fi` + +libext2fs_a-valid_blk.o: valid_blk.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-valid_blk.o `test -f 'valid_blk.c' || echo '$(srcdir)/'`valid_blk.c + +libext2fs_a-valid_blk.obj: valid_blk.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-valid_blk.obj `if test -f 'valid_blk.c'; then $(CYGPATH_W) 'valid_blk.c'; else $(CYGPATH_W) '$(srcdir)/valid_blk.c'; fi` + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-tags dvi dvi-am \ + html html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/ext2fs/alloc.c b/src/ext2fs/alloc.c new file mode 100644 index 00000000..ea573efb --- /dev/null +++ b/src/ext2fs/alloc.c @@ -0,0 +1,556 @@ +/* + * alloc.c --- allocate new inodes, blocks for ext2fs + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#undef DEBUG + +#ifdef DEBUG +# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0) +#else +# define dbg_printf(f, ...) +#endif + +/* + * Clear the uninit block bitmap flag if necessary + */ +void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group) +{ + if (group >= fs->group_desc_count || + !ext2fs_has_group_desc_csum(fs) || + !(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))) + return; + + /* uninit block bitmaps are now initialized in read_bitmaps() */ + + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); +} + +/* + * Check for uninit inode bitmaps and deal with them appropriately + */ +static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map, + dgrp_t group) +{ + ext2_ino_t i, ino; + + if (group >= fs->group_desc_count || + !ext2fs_has_group_desc_csum(fs) || + !(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) + return; + + ino = (group * fs->super->s_inodes_per_group) + 1; + for (i=0; i < fs->super->s_inodes_per_group; i++, ino++) + ext2fs_fast_unmark_inode_bitmap2(map, ino); + + ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); + /* Mimics what the kernel does */ + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_mark_ib_dirty(fs); + ext2fs_mark_super_dirty(fs); +} + +/* + * Right now, just search forward from the parent directory's block + * group to find the next free inode. + * + * Should have a special policy for directories. + */ +errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, + int mode EXT2FS_ATTR((unused)), + ext2fs_inode_bitmap map, ext2_ino_t *ret) +{ + ext2_ino_t start_inode = 0; + ext2_ino_t i, ino_in_group, upto, first_zero; + errcode_t retval; + dgrp_t group; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) + map = fs->inode_map; + if (!map) + return EXT2_ET_NO_INODE_BITMAP; + + if (dir > 0) { + group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super); + start_inode = (group * EXT2_INODES_PER_GROUP(fs->super)) + 1; + } + if (start_inode < EXT2_FIRST_INODE(fs->super)) + start_inode = EXT2_FIRST_INODE(fs->super); + if (start_inode > fs->super->s_inodes_count) + return EXT2_ET_INODE_ALLOC_FAIL; + i = start_inode; + do { + ino_in_group = (i - 1) % EXT2_INODES_PER_GROUP(fs->super); + group = (i - 1) / EXT2_INODES_PER_GROUP(fs->super); + + check_inode_uninit(fs, map, group); + upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group); + if (i < start_inode && upto >= start_inode) + upto = start_inode - 1; + if (upto > fs->super->s_inodes_count) + upto = fs->super->s_inodes_count; + + retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto, + &first_zero); + if (retval == 0) { + i = first_zero; + break; + } + if (retval != ENOENT) + return EXT2_ET_INODE_ALLOC_FAIL; + i = upto + 1; + if (i > fs->super->s_inodes_count) + i = EXT2_FIRST_INODE(fs->super); + } while (i != start_inode); + + if (ext2fs_test_inode_bitmap2(map, i)) + return EXT2_ET_INODE_ALLOC_FAIL; + *ret = i; + return 0; +} + +/* + * Stupid algorithm --- we now just search forward starting from the + * goal. Should put in a smarter one someday.... + */ +errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret, + struct blk_alloc_ctx *ctx) +{ + errcode_t retval; + blk64_t b = 0; + errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret); + errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *, + struct blk_alloc_ctx *); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) { + /* + * In case there are clients out there whose get_alloc_block + * handlers call ext2fs_new_block2 with a NULL block map, + * temporarily swap out the function pointer so that we don't + * end up in an infinite loop. + */ + if (fs->get_alloc_block2) { + gab2 = fs->get_alloc_block2; + fs->get_alloc_block2 = NULL; + retval = gab2(fs, goal, &b, ctx); + fs->get_alloc_block2 = gab2; + goto allocated; + } else if (fs->get_alloc_block) { + gab = fs->get_alloc_block; + fs->get_alloc_block = NULL; + retval = gab(fs, goal, &b); + fs->get_alloc_block = gab; + goto allocated; + } + } + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!goal || (goal >= ext2fs_blocks_count(fs->super))) + goal = fs->super->s_first_data_block; + goal &= ~EXT2FS_CLUSTER_MASK(fs); + + retval = ext2fs_find_first_zero_block_bitmap2(map, + goal, ext2fs_blocks_count(fs->super) - 1, &b); + if ((retval == ENOENT) && (goal != fs->super->s_first_data_block)) + retval = ext2fs_find_first_zero_block_bitmap2(map, + fs->super->s_first_data_block, goal - 1, &b); +allocated: + if (retval == ENOENT) + return EXT2_ET_BLOCK_ALLOC_FAIL; + if (retval) + return retval; + + ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b)); + *ret = b; + return 0; +} + +errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret) +{ + return ext2fs_new_block3(fs, goal, map, ret, NULL); +} + +errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, + ext2fs_block_bitmap map, blk_t *ret) +{ + errcode_t retval; + blk64_t val; + retval = ext2fs_new_block2(fs, goal, map, &val); + if (!retval) + *ret = (blk_t) val; + return retval; +} + +/* + * This function zeros out the allocated block, and updates all of the + * appropriate filesystem records. + */ +errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf, + blk64_t *ret, struct blk_alloc_ctx *ctx) +{ + errcode_t retval; + blk64_t block; + + if (fs->get_alloc_block2) { + retval = (fs->get_alloc_block2)(fs, goal, &block, ctx); + if (retval) + goto fail; + } else if (fs->get_alloc_block) { + retval = (fs->get_alloc_block)(fs, goal, &block); + if (retval) + goto fail; + } else { + if (!fs->block_map) { + retval = ext2fs_read_block_bitmap(fs); + if (retval) + goto fail; + } + + retval = ext2fs_new_block3(fs, goal, 0, &block, ctx); + if (retval) + goto fail; + } + + if (block_buf) { + memset(block_buf, 0, fs->blocksize); + retval = io_channel_write_blk64(fs->io, block, 1, block_buf); + } else + retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL); + if (retval) + goto fail; + + ext2fs_block_alloc_stats2(fs, block, +1); + *ret = block; + +fail: + return retval; +} + +errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret) +{ + return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL); +} + +errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, + char *block_buf, blk_t *ret) +{ + errcode_t retval; + blk64_t ret64, goal64 = goal; + retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL); + if (!retval) + *ret = (blk_t)ret64; + return retval; +} + +errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish, + int num, ext2fs_block_bitmap map, blk64_t *ret) +{ + blk64_t b = start; + int c_ratio; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!b) + b = fs->super->s_first_data_block; + if (!finish) + finish = start; + if (!num) + num = 1; + c_ratio = 1 << ext2fs_get_bitmap_granularity(map); + b &= ~(c_ratio - 1); + finish &= ~(c_ratio -1); + do { + if (b + num - 1 >= ext2fs_blocks_count(fs->super)) { + if (finish > start) + return EXT2_ET_BLOCK_ALLOC_FAIL; + b = fs->super->s_first_data_block; + } + if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) { + *ret = b; + return 0; + } + b += c_ratio; + } while (b != finish); + return EXT2_ET_BLOCK_ALLOC_FAIL; +} + +errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, + int num, ext2fs_block_bitmap map, blk_t *ret) +{ + errcode_t retval; + blk64_t val; + retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val); + if(!retval) + *ret = (blk_t) val; + return retval; +} + +void ext2fs_set_alloc_block_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret), + errcode_t (**old)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + + if (old) + *old = fs->get_alloc_block; + + fs->get_alloc_block = func; +} + +blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk) +{ + dgrp_t group; + __u8 log_flex; + struct ext2fs_extent extent; + ext2_extent_handle_t handle = NULL; + errcode_t err; + + /* Make sure data stored in inode->i_block is neither fast symlink nor + * inline data. + */ + if (inode == NULL || ext2fs_is_fast_symlink(inode) || + inode->i_flags & EXT4_INLINE_DATA_FL) + goto no_blocks; + + if (inode->i_flags & EXT4_EXTENTS_FL) { + err = ext2fs_extent_open2(fs, ino, inode, &handle); + if (err) + goto no_blocks; + err = ext2fs_extent_goto2(handle, 0, lblk); + if (err) + goto no_blocks; + err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (err) + goto no_blocks; + ext2fs_extent_free(handle); + return extent.e_pblk + (lblk - extent.e_lblk); + } + + /* block mapped file; see if block zero is mapped? */ + if (inode->i_block[0]) + return inode->i_block[0]; + +no_blocks: + ext2fs_extent_free(handle); + log_flex = fs->super->s_log_groups_per_flex; + group = ext2fs_group_of_ino(fs, ino); + if (log_flex) + group = group & ~((1 << (log_flex)) - 1); + return ext2fs_group_first_block2(fs, group); +} + +/* + * Starting at _goal_, scan around the filesystem to find a run of free blocks + * that's at least _len_ blocks long. Possible flags: + * - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_. + * - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_. + * - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning. + * + * The starting block is returned in _pblk_ and the length is returned via + * _plen_. The blocks are not marked in the bitmap; the caller must mark + * however much of the returned run they actually use, hopefully via + * ext2fs_block_alloc_stats_range(). + * + * This function can return a range that is longer than what was requested. + */ +errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, + blk64_t *plen) +{ + errcode_t retval; + blk64_t start, end, b; + int looped = 0; + blk64_t max_blocks = ext2fs_blocks_count(fs->super); + errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen); + + dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags, + goal, len); + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS)) + return EXT2_ET_INVALID_ARGUMENT; + + if (!map && fs->new_range) { + /* + * In case there are clients out there whose new_range + * handlers call ext2fs_new_range with a NULL block map, + * temporarily swap out the function pointer so that we don't + * end up in an infinite loop. + */ + nrf = fs->new_range; + fs->new_range = NULL; + retval = nrf(fs, flags, goal, len, pblk, plen); + fs->new_range = nrf; + if (retval) + return retval; + start = *pblk; + end = *pblk + *plen; + goto allocated; + } + if (!map) + map = fs->block_map; + if (!map) + return EXT2_ET_NO_BLOCK_BITMAP; + if (!goal || goal >= ext2fs_blocks_count(fs->super)) + goal = fs->super->s_first_data_block; + + start = goal; + while (!looped || start <= goal) { + retval = ext2fs_find_first_zero_block_bitmap2(map, start, + max_blocks - 1, + &start); + if (retval == ENOENT) { + /* + * If there are no free blocks beyond the starting + * point, try scanning the whole filesystem, unless the + * user told us only to allocate from _goal_, or if + * we're already scanning the whole filesystem. + */ + if (flags & EXT2_NEWRANGE_FIXED_GOAL || + start == fs->super->s_first_data_block) + goto fail; + start = fs->super->s_first_data_block; + continue; + } else if (retval) + goto errout; + + if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal) + goto fail; + + b = min(start + len - 1, max_blocks - 1); + retval = ext2fs_find_first_set_block_bitmap2(map, start, b, + &end); + if (retval == ENOENT) + end = b + 1; + else if (retval) + goto errout; + + if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) || + (end - start) >= len) { + /* Success! */ + *pblk = start; + *plen = end - start; + dbg_printf("%s: new_range goal=%llu--%llu " + "blk=%llu--%llu %llu\n", + __func__, goal, goal + len - 1, + *pblk, *pblk + *plen - 1, *plen); +allocated: + for (b = start; b < end; + b += fs->super->s_blocks_per_group) + ext2fs_clear_block_uninit(fs, + ext2fs_group_of_blk2(fs, b)); + return 0; + } + + if (flags & EXT2_NEWRANGE_FIXED_GOAL) + goto fail; + start = end; + if (start >= max_blocks) { + if (looped) + goto fail; + looped = 1; + start = fs->super->s_first_data_block; + } + } + +fail: + retval = EXT2_ET_BLOCK_ALLOC_FAIL; +errout: + return retval; +} + +void ext2fs_set_new_range_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen), + errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + + if (old) + *old = fs->new_range; + + fs->new_range = func; +} + +errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, + blk_t len, blk64_t *ret) +{ + int newr_flags = EXT2_NEWRANGE_MIN_LENGTH; + errcode_t retval; + blk64_t plen; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS)) + return EXT2_ET_INVALID_ARGUMENT; + + if (flags & EXT2_ALLOCRANGE_FIXED_GOAL) + newr_flags |= EXT2_NEWRANGE_FIXED_GOAL; + + retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen); + if (retval) + return retval; + + if (plen < len) + return EXT2_ET_BLOCK_ALLOC_FAIL; + + if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) { + retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL); + if (retval) + return retval; + } + + ext2fs_block_alloc_stats_range(fs, *ret, len, +1); + return retval; +} diff --git a/src/ext2fs/alloc_sb.c b/src/ext2fs/alloc_sb.c new file mode 100644 index 00000000..8530b40f --- /dev/null +++ b/src/ext2fs/alloc_sb.c @@ -0,0 +1,81 @@ +/* + * alloc_sb.c --- Allocate the superblock and block group descriptors for a + * newly initialized filesystem. Used by mke2fs when initializing a filesystem + * + * Copyright (C) 1994, 1995, 1996, 2003 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * This function reserves the superblock and block group descriptors + * for a given block group. It currently returns the number of free + * blocks assuming that inode table and allocation bitmaps will be in + * the group. This is not necessarily the case when the flex_bg + * feature is enabled, so callers should take care! It was only + * really intended for use by mke2fs, and even there it's not that + * useful. In the future, when we redo this function for 64-bit block + * numbers, we should probably return the number of blocks used by the + * super block and group descriptors instead. + * + * See also the comment for ext2fs_super_and_bgd_loc() + */ +int ext2fs_reserve_super_and_bgd(ext2_filsys fs, + dgrp_t group, + ext2fs_block_bitmap bmap) +{ + blk64_t super_blk, old_desc_blk, new_desc_blk; + blk_t used_blks; + int old_desc_blocks, num_blocks; + + ext2fs_super_and_bgd_loc2(fs, group, &super_blk, + &old_desc_blk, &new_desc_blk, &used_blks); + + if (ext2fs_has_feature_meta_bg(fs->super)) + old_desc_blocks = fs->super->s_first_meta_bg; + else + old_desc_blocks = + fs->desc_blocks + fs->super->s_reserved_gdt_blocks; + + if (super_blk || (group == 0)) + ext2fs_mark_block_bitmap2(bmap, super_blk); + if ((group == 0) && (fs->blocksize == 1024) && + EXT2FS_CLUSTER_RATIO(fs) > 1) + ext2fs_mark_block_bitmap2(bmap, 0); + + if (old_desc_blk) { + num_blocks = old_desc_blocks; + if (old_desc_blk + num_blocks >= ext2fs_blocks_count(fs->super)) + num_blocks = ext2fs_blocks_count(fs->super) - + old_desc_blk; + ext2fs_mark_block_bitmap_range2(bmap, old_desc_blk, num_blocks); + } + if (new_desc_blk) + ext2fs_mark_block_bitmap2(bmap, new_desc_blk); + + num_blocks = ext2fs_group_blocks_count(fs, group); + num_blocks -= 2 + fs->inode_blocks_per_group + used_blks; + + return num_blocks ; +} diff --git a/src/ext2fs/alloc_stats.c b/src/ext2fs/alloc_stats.c new file mode 100644 index 00000000..3949f618 --- /dev/null +++ b/src/ext2fs/alloc_stats.c @@ -0,0 +1,164 @@ +/* + * alloc_stats.c --- Update allocation statistics for ext2fs + * + * Copyright (C) 2001 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, + int inuse, int isdir) +{ + int group = ext2fs_group_of_ino(fs, ino); + + if (ino > fs->super->s_inodes_count) { +#ifndef OMIT_COM_ERR + com_err("ext2fs_inode_alloc_stats2", 0, + "Illegal inode number: %lu", (unsigned long) ino); +#endif + return; + } + if (inuse > 0) + ext2fs_mark_inode_bitmap2(fs->inode_map, ino); + else + ext2fs_unmark_inode_bitmap2(fs->inode_map, ino); + ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) - inuse); + if (isdir) + ext2fs_bg_used_dirs_count_set(fs, group, ext2fs_bg_used_dirs_count(fs, group) + inuse); + + /* We don't strictly need to be clearing the uninit flag if inuse < 0 + * (i.e. freeing inodes) but it also means something is bad. */ + ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); + if (ext2fs_has_group_desc_csum(fs)) { + ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group - + ext2fs_bg_itable_unused(fs, group) + + group * fs->super->s_inodes_per_group + 1; + + if (ino >= first_unused_inode) + ext2fs_bg_itable_unused_set(fs, group, group * fs->super->s_inodes_per_group + fs->super->s_inodes_per_group - ino); + ext2fs_group_desc_csum_set(fs, group); + } + + fs->super->s_free_inodes_count -= inuse; + ext2fs_mark_super_dirty(fs); + ext2fs_mark_ib_dirty(fs); +} + +void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse) +{ + ext2fs_inode_alloc_stats2(fs, ino, inuse, 0); +} + +void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse) +{ + int group = ext2fs_group_of_blk2(fs, blk); + + if (blk >= ext2fs_blocks_count(fs->super)) { +#ifndef OMIT_COM_ERR + com_err("ext2fs_block_alloc_stats", 0, + "Illegal block number: %lu", (unsigned long) blk); +#endif + return; + } + if (inuse > 0) + ext2fs_mark_block_bitmap2(fs->block_map, blk); + else + ext2fs_unmark_block_bitmap2(fs->block_map, blk); + ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) - inuse); + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + + ext2fs_free_blocks_count_add(fs->super, + -inuse * (blk64_t) EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + if (fs->block_alloc_stats) + (fs->block_alloc_stats)(fs, (blk64_t) blk, inuse); +} + +void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse) +{ + ext2fs_block_alloc_stats2(fs, blk, inuse); +} + +void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, + blk64_t blk, + int inuse), + void (**old)(ext2_filsys fs, + blk64_t blk, + int inuse)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + if (old) + *old = fs->block_alloc_stats; + + fs->block_alloc_stats = func; +} + +void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse) +{ +#ifndef OMIT_COM_ERR + if (blk + num > ext2fs_blocks_count(fs->super)) { + com_err("ext2fs_block_alloc_stats_range", 0, + "Illegal block range: %llu (%u) ", + (unsigned long long) blk, num); + return; + } +#endif + if (inuse == 0) + return; + if (inuse > 0) { + ext2fs_mark_block_bitmap_range2(fs->block_map, blk, num); + inuse = 1; + } else { + ext2fs_unmark_block_bitmap_range2(fs->block_map, blk, num); + inuse = -1; + } + while (num) { + int group = ext2fs_group_of_blk2(fs, blk); + blk64_t last_blk = ext2fs_group_last_block2(fs, group); + blk64_t n = num; + + if (blk + num > last_blk) + n = last_blk - blk + 1; + + ext2fs_bg_free_blocks_count_set(fs, group, + ext2fs_bg_free_blocks_count(fs, group) - + inuse*n/EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, group); + ext2fs_free_blocks_count_add(fs->super, -inuse * (blk64_t) n); + blk += n; + num -= n; + } + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + if (fs->block_alloc_stats_range) + (fs->block_alloc_stats_range)(fs, blk, num, inuse); +} + +void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse), + void (**old)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse)) +{ + if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS) + return; + if (old) + *old = fs->block_alloc_stats_range; + + fs->block_alloc_stats_range = func; +} diff --git a/src/ext2fs/alloc_tables.c b/src/ext2fs/alloc_tables.c new file mode 100644 index 00000000..971a6ceb --- /dev/null +++ b/src/ext2fs/alloc_tables.c @@ -0,0 +1,278 @@ +/* + * alloc_tables.c --- Allocate tables for a newly initialized + * filesystem. Used by mke2fs when initializing a filesystem + * + * Copyright (C) 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +/* + * This routine searches for free blocks that can allocate a full + * group of bitmaps or inode tables for a flexbg group. Returns the + * block number with a correct offset were the bitmaps and inode + * tables can be allocated continuously and in order. + */ +static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk, + ext2fs_block_bitmap bmap, int rem_grp, + int elem_size) +{ + int flexbg, flexbg_size, size; + blk64_t last_blk, first_free = 0; + dgrp_t last_grp; + + flexbg_size = 1 << fs->super->s_log_groups_per_flex; + flexbg = group / flexbg_size; + size = rem_grp * elem_size; + + if (size > (int) (fs->super->s_blocks_per_group / 4)) + size = (int) fs->super->s_blocks_per_group / 4; + + /* + * Don't do a long search if the previous block search is still valid, + * but skip minor obstructions such as group descriptor backups. + */ + if (start_blk && start_blk < ext2fs_blocks_count(fs->super) && + ext2fs_get_free_blocks2(fs, start_blk, start_blk + size, elem_size, + bmap, &first_free) == 0) + return first_free; + + start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg); + last_grp = group | (flexbg_size - 1); + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; + last_blk = ext2fs_group_last_block2(fs, last_grp); + + /* Find the first available block */ + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size, + bmap, &first_free) == 0) + return first_free; + + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size, + bmap, &first_free) == 0) + return first_free; + + if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap, + &first_free) == 0) + return first_free; + + return first_free; +} + +errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, + ext2fs_block_bitmap bmap) +{ + errcode_t retval; + blk64_t group_blk, start_blk, last_blk, new_blk; + dgrp_t last_grp = 0; + int rem_grps = 0, flexbg_size = 0, table_offset = 0; + + group_blk = ext2fs_group_first_block2(fs, group); + last_blk = ext2fs_group_last_block2(fs, group); + + if (!bmap) + bmap = fs->block_map; + + if (ext2fs_has_feature_flex_bg(fs->super) && + fs->super->s_log_groups_per_flex) { + flexbg_size = 1 << fs->super->s_log_groups_per_flex; + last_grp = group | (flexbg_size - 1); + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; + rem_grps = last_grp - group + 1; + } + + /* + * Allocate the block and inode bitmaps, if necessary + */ + if (fs->stride && !flexbg_size) { + retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, + 1, bmap, &start_blk); + if (retval) + return retval; + start_blk += fs->inode_blocks_per_group; + start_blk += ((fs->stride * group) % + (last_blk - start_blk + 1)); + if (start_blk >= last_blk) + start_blk = group_blk; + } else + start_blk = group_blk; + + if (flexbg_size) { + blk64_t prev_block = 0; + + table_offset = flexbg_size; + if (group % flexbg_size) + prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1; + else if (last_grp == fs->group_desc_count-1) { + /* + * If we are allocating for the last flex_bg + * keep the metadata tables contiguous + */ + table_offset = last_grp & (flexbg_size - 1); + if (table_offset == 0) + table_offset = flexbg_size; + else + table_offset++; + } + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + start_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, 1); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_block_bitmap_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, + 1, bmap, &new_blk); + if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) + retval = ext2fs_get_free_blocks2(fs, group_blk, + last_blk, 1, bmap, &new_blk); + if (retval) + return retval; + ext2fs_mark_block_bitmap2(bmap, new_blk); + ext2fs_block_bitmap_loc_set(fs, group, new_blk); + if (flexbg_size) { + dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); + ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); + ext2fs_free_blocks_count_add(fs->super, -1); + ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + } + } + + if (flexbg_size) { + blk64_t prev_block = 0; + if (group % flexbg_size) + prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1; + else + prev_block = ext2fs_block_bitmap_loc(fs, group) + + table_offset; + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + start_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, 1); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_inode_bitmap_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk, + 1, bmap, &new_blk); + if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) + retval = ext2fs_get_free_blocks2(fs, group_blk, + last_blk, 1, bmap, &new_blk); + if (retval) + return retval; + ext2fs_mark_block_bitmap2(bmap, new_blk); + ext2fs_inode_bitmap_loc_set(fs, group, new_blk); + if (flexbg_size) { + dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk); + ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1); + ext2fs_free_blocks_count_add(fs->super, -1); + ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + } + } + + /* + * Allocate the inode table + */ + if (flexbg_size) { + blk64_t prev_block = 0; + + if (group % flexbg_size) + prev_block = ext2fs_inode_table_loc(fs, group - 1) + + fs->inode_blocks_per_group; + else + prev_block = ext2fs_inode_bitmap_loc(fs, group) + + table_offset; + + /* FIXME: Take backup group descriptor blocks into account + * if the flexbg allocations will grow to overlap them... */ + group_blk = flexbg_offset(fs, group, prev_block, bmap, + rem_grps, fs->inode_blocks_per_group); + last_blk = ext2fs_group_last_block2(fs, last_grp); + } + + if (!ext2fs_inode_table_loc(fs, group)) { + retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk, + fs->inode_blocks_per_group, + bmap, &new_blk); + if (retval) + return retval; + + ext2fs_mark_block_bitmap_range2(bmap, + new_blk, fs->inode_blocks_per_group); + if (flexbg_size) { + blk64_t num, blk; + num = fs->inode_blocks_per_group; + blk = new_blk; + while (num) { + int gr = ext2fs_group_of_blk2(fs, blk); + last_blk = ext2fs_group_last_block2(fs, gr); + blk64_t n = num; + + if (blk + num > last_blk) + n = last_blk - blk + 1; + + ext2fs_bg_free_blocks_count_set(fs, gr, + ext2fs_bg_free_blocks_count(fs, gr) - + n/EXT2FS_CLUSTER_RATIO(fs)); + ext2fs_bg_flags_clear(fs, gr, + EXT2_BG_BLOCK_UNINIT); + ext2fs_group_desc_csum_set(fs, gr); + ext2fs_free_blocks_count_add(fs->super, -n); + blk += n; + num -= n; + } + } + ext2fs_inode_table_loc_set(fs, group, new_blk); + } + ext2fs_group_desc_csum_set(fs, group); + return 0; +} + +errcode_t ext2fs_allocate_tables(ext2_filsys fs) +{ + errcode_t retval; + dgrp_t i; + struct ext2fs_numeric_progress_struct progress; + + if (fs->progress_ops && fs->progress_ops->init) + (fs->progress_ops->init)(fs, &progress, NULL, + fs->group_desc_count); + + for (i = 0; i < fs->group_desc_count; i++) { + if (fs->progress_ops && fs->progress_ops->update) + (fs->progress_ops->update)(fs, &progress, i); + retval = ext2fs_allocate_group_table(fs, i, fs->block_map); + if (retval) + return retval; + } + if (fs->progress_ops && fs->progress_ops->close) + (fs->progress_ops->close)(fs, &progress, NULL); + return 0; +} + diff --git a/src/ext2fs/badblocks.c b/src/ext2fs/badblocks.c new file mode 100644 index 00000000..0f23983b --- /dev/null +++ b/src/ext2fs/badblocks.c @@ -0,0 +1,328 @@ +/* + * badblocks.c --- routines to manipulate the bad block structure + * + * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +/* + * Helper function for making a badblocks list + */ +static errcode_t make_u32_list(int size, int num, __u32 *list, + ext2_u32_list *ret) +{ + ext2_u32_list bb; + errcode_t retval; + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb); + if (retval) + return retval; + memset(bb, 0, sizeof(struct ext2_struct_u32_list)); + bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST; + bb->size = size ? size : 10; + bb->num = num; + retval = ext2fs_get_array(bb->size, sizeof(blk_t), &bb->list); + if (retval) { + ext2fs_free_mem(&bb); + return retval; + } + if (list) + memcpy(bb->list, list, bb->size * sizeof(blk_t)); + else + memset(bb->list, 0, bb->size * sizeof(blk_t)); + *ret = bb; + return 0; +} + + +/* + * This procedure creates an empty u32 list. + */ +errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size) +{ + return make_u32_list(size, 0, 0, ret); +} + +/* + * This procedure creates an empty badblocks list. + */ +errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size) +{ + return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret); +} + + +/* + * This procedure copies a badblocks list + */ +errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest) +{ + errcode_t retval; + + retval = make_u32_list(src->size, src->num, src->list, dest); + if (retval) + return retval; + (*dest)->badblocks_flags = src->badblocks_flags; + return 0; +} + +errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, + ext2_badblocks_list *dest) +{ + return ext2fs_u32_copy((ext2_u32_list) src, + (ext2_u32_list *) dest); +} + +/* + * This procedure frees a badblocks list. + * + * (note: moved to closefs.c) + */ + + +/* + * This procedure adds a block to a badblocks list. + */ +errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk) +{ + errcode_t retval; + int i, j; + unsigned long old_size; + + EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + if (bb->num >= bb->size) { + old_size = bb->size * sizeof(__u32); + bb->size += 100; + retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32), + &bb->list); + if (retval) { + bb->size -= 100; + return retval; + } + } + + /* + * Add special case code for appending to the end of the list + */ + i = bb->num-1; + if ((bb->num != 0) && (bb->list[i] == blk)) + return 0; + if ((bb->num == 0) || (bb->list[i] < blk)) { + bb->list[bb->num++] = blk; + return 0; + } + + j = bb->num; + for (i=0; i < bb->num; i++) { + if (bb->list[i] == blk) + return 0; + if (bb->list[i] > blk) { + j = i; + break; + } + } + for (i=bb->num; i > j; i--) + bb->list[i] = bb->list[i-1]; + bb->list[j] = blk; + bb->num++; + return 0; +} + +errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk) +{ + return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk); +} + +/* + * This procedure finds a particular block is on a badblocks + * list. + */ +int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk) +{ + int low, high, mid; + + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return -1; + + if (bb->num == 0) + return -1; + + low = 0; + high = bb->num-1; + if (blk == bb->list[low]) + return low; + if (blk == bb->list[high]) + return high; + + while (low < high) { + mid = ((unsigned)low + (unsigned)high)/2; + if (mid == low || mid == high) + break; + if (blk == bb->list[mid]) + return mid; + if (blk < bb->list[mid]) + high = mid; + else + low = mid; + } + return -1; +} + +/* + * This procedure tests to see if a particular block is on a badblocks + * list. + */ +int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk) +{ + if (ext2fs_u32_list_find(bb, blk) < 0) + return 0; + else + return 1; +} + +int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk) +{ + return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk); +} + + +/* + * Remove a block from the badblock list + */ +int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk) +{ + int remloc, i; + + if (bb->num == 0) + return -1; + + remloc = ext2fs_u32_list_find(bb, blk); + if (remloc < 0) + return -1; + + for (i = remloc ; i < bb->num-1; i++) + bb->list[i] = bb->list[i+1]; + bb->num--; + return 0; +} + +void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk) +{ + ext2fs_u32_list_del(bb, blk); +} + +errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, + ext2_u32_iterate *ret) +{ + ext2_u32_iterate iter; + errcode_t retval; + + EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter); + if (retval) + return retval; + + iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE; + iter->bb = bb; + iter->ptr = 0; + *ret = iter; + return 0; +} + +errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, + ext2_badblocks_iterate *ret) +{ + return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb, + (ext2_u32_iterate *) ret); +} + + +int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk) +{ + ext2_u32_list bb; + + if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE) + return 0; + + bb = iter->bb; + + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return 0; + + if (iter->ptr < bb->num) { + *blk = bb->list[iter->ptr++]; + return 1; + } + *blk = 0; + return 0; +} + +int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk) +{ + return ext2fs_u32_list_iterate((ext2_u32_iterate) iter, + (__u32 *) blk); +} + + +void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter) +{ + if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)) + return; + + iter->bb = 0; + ext2fs_free_mem(&iter); +} + +void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter) +{ + ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter); +} + + +int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2) +{ + EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST); + EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST); + + if (bb1->num != bb2->num) + return 0; + + if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0) + return 0; + return 1; +} + +int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2) +{ + return ext2fs_u32_list_equal((ext2_u32_list) bb1, + (ext2_u32_list) bb2); +} + +int ext2fs_u32_list_count(ext2_u32_list bb) +{ + return bb->num; +} diff --git a/src/ext2fs/bb_inode.c b/src/ext2fs/bb_inode.c new file mode 100644 index 00000000..11f10ebc --- /dev/null +++ b/src/ext2fs/bb_inode.c @@ -0,0 +1,270 @@ +/* + * bb_inode.c --- routines to update the bad block inode. + * + * WARNING: This routine modifies a lot of state in the filesystem; if + * this routine returns an error, the bad block inode may be in an + * inconsistent state. + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct set_badblock_record { + ext2_badblocks_iterate bb_iter; + int bad_block_count; + blk_t *ind_blocks; + int max_ind_blocks; + int ind_blocks_size; + int ind_blocks_ptr; + char *block_buf; + errcode_t err; +}; + +static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block, int ref_offset, + void *priv_data); +static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block, int ref_offset, + void *priv_data); + +/* + * Given a bad blocks bitmap, update the bad blocks inode to reflect + * the map. + */ +errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list) +{ + errcode_t retval; + struct set_badblock_record rec; + struct ext2_inode inode; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!fs->block_map) + return EXT2_ET_NO_BLOCK_BITMAP; + + memset(&rec, 0, sizeof(rec)); + rec.max_ind_blocks = 10; + retval = ext2fs_get_array(rec.max_ind_blocks, sizeof(blk_t), + &rec.ind_blocks); + if (retval) + return retval; + memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t)); + retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf); + if (retval) + goto cleanup; + memset(rec.block_buf, 0, fs->blocksize); + rec.err = 0; + + /* + * First clear the old bad blocks (while saving the indirect blocks) + */ + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, + BLOCK_FLAG_DEPTH_TRAVERSE, 0, + clear_bad_block_proc, &rec); + if (retval) + goto cleanup; + if (rec.err) { + retval = rec.err; + goto cleanup; + } + + /* + * Now set the bad blocks! + * + * First, mark the bad blocks as used. This prevents a bad + * block from being used as an indirect block for the bad + * block inode (!). + */ + if (bb_list) { + retval = ext2fs_badblocks_list_iterate_begin(bb_list, + &rec.bb_iter); + if (retval) + goto cleanup; + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, + BLOCK_FLAG_APPEND, 0, + set_bad_block_proc, &rec); + ext2fs_badblocks_list_iterate_end(rec.bb_iter); + if (retval) + goto cleanup; + if (rec.err) { + retval = rec.err; + goto cleanup; + } + } + + /* + * Update the bad block inode's mod time and block count + * field. + */ + retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + goto cleanup; + + inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0); + if (!inode.i_ctime) + inode.i_ctime = fs->now ? fs->now : time(0); + ext2fs_iblk_set(fs, &inode, rec.bad_block_count); + retval = ext2fs_inode_size_set(fs, &inode, + rec.bad_block_count * fs->blocksize); + if (retval) + goto cleanup; + + retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + goto cleanup; + +cleanup: + ext2fs_free_mem(&rec.ind_blocks); + ext2fs_free_mem(&rec.block_buf); + return retval; +} + +/* + * Helper function for update_bb_inode() + * + * Clear the bad blocks in the bad block inode, while saving the + * indirect blocks. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct set_badblock_record *rec = (struct set_badblock_record *) + priv_data; + errcode_t retval; + unsigned long old_size; + + if (!*block_nr) + return 0; + + /* + * If the block number is outrageous, clear it and ignore it. + */ + if (*block_nr >= ext2fs_blocks_count(fs->super) || + *block_nr < fs->super->s_first_data_block) { + *block_nr = 0; + return BLOCK_CHANGED; + } + + if (blockcnt < 0) { + if (rec->ind_blocks_size >= rec->max_ind_blocks) { + old_size = rec->max_ind_blocks * sizeof(blk_t); + rec->max_ind_blocks += 10; + retval = ext2fs_resize_mem(old_size, + rec->max_ind_blocks * sizeof(blk_t), + &rec->ind_blocks); + if (retval) { + rec->max_ind_blocks -= 10; + rec->err = retval; + return BLOCK_ABORT; + } + } + rec->ind_blocks[rec->ind_blocks_size++] = *block_nr; + } + + /* + * Mark the block as unused, and update accounting information + */ + ext2fs_block_alloc_stats2(fs, *block_nr, -1); + + *block_nr = 0; + return BLOCK_CHANGED; +} + + +/* + * Helper function for update_bb_inode() + * + * Set the block list in the bad block inode, using the supplied bitmap. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct set_badblock_record *rec = (struct set_badblock_record *) + priv_data; + errcode_t retval; + blk_t blk; + + if (blockcnt >= 0) { + /* + * Get the next bad block. + */ + if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk)) + return BLOCK_ABORT; + rec->bad_block_count++; + } else { + /* + * An indirect block; fetch a block from the + * previously used indirect block list. The block + * most be not marked as used; if so, get another one. + * If we run out of reserved indirect blocks, allocate + * a new one. + */ + retry: + if (rec->ind_blocks_ptr < rec->ind_blocks_size) { + blk = rec->ind_blocks[rec->ind_blocks_ptr++]; + if (ext2fs_test_block_bitmap2(fs->block_map, blk)) + goto retry; + } else { + retval = ext2fs_new_block(fs, 0, 0, &blk); + if (retval) { + rec->err = retval; + return BLOCK_ABORT; + } + } + retval = io_channel_write_blk64(fs->io, blk, 1, rec->block_buf); + if (retval) { + rec->err = retval; + return BLOCK_ABORT; + } + } + + /* + * Update block counts + */ + ext2fs_block_alloc_stats2(fs, blk, +1); + + *block_nr = blk; + return BLOCK_CHANGED; +} + + + + + + diff --git a/src/ext2fs/bitmaps.c b/src/ext2fs/bitmaps.c new file mode 100644 index 00000000..84021917 --- /dev/null +++ b/src/ext2fs/bitmaps.c @@ -0,0 +1,308 @@ +/* + * bitmaps.c --- routines to read, write, and manipulate the inode and + * block bitmaps. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap) +{ + ext2fs_free_generic_bmap(bitmap); +} + +void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap) +{ + ext2fs_free_generic_bmap(bitmap); +} + +errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + return (ext2fs_copy_generic_bmap(src, dest)); +} +void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map) +{ + ext2fs_set_generic_bmap_padding(map); +} + +errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_inode_bitmap *ret) +{ + __u64 start, end, real_end; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + start = 1; + end = fs->super->s_inodes_count; + real_end = (EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count); + + /* Are we permitted to use new-style bitmaps? */ + if (fs->flags & EXT2_FLAG_64BITS) + return (ext2fs_alloc_generic_bmap(fs, + EXT2_ET_MAGIC_INODE_BITMAP64, + fs->default_bitmap_type, + start, end, real_end, descr, ret)); + + /* Otherwise, check to see if the file system is small enough + * to use old-style 32-bit bitmaps */ + if ((end > ~0U) || (real_end > ~0U)) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, fs, + start, end, real_end, + descr, 0, + (ext2fs_generic_bitmap *) ret)); +} + +errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + start = EXT2FS_B2C(fs, fs->super->s_first_data_block); + end = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1); + real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + if (fs->flags & EXT2_FLAG_64BITS) + return (ext2fs_alloc_generic_bmap(fs, + EXT2_ET_MAGIC_BLOCK_BITMAP64, + fs->default_bitmap_type, + start, end, real_end, descr, ret)); + + if ((end > ~0U) || (real_end > ~0U)) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs, + start, end, real_end, + descr, 0, + (ext2fs_generic_bitmap *) ret)); +} + +/* + * ext2fs_allocate_block_bitmap() really allocates a per-cluster + * bitmap for backwards compatibility. This function allocates a + * block bitmap which is truly per-block, even if clusters/bigalloc + * are enabled. mke2fs and e2fsck need this for tracking the + * allocation of the file system metadata blocks. + */ +errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + ext2fs_generic_bitmap bmap; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs->write_bitmaps = ext2fs_write_bitmaps; + + if (!fs->cluster_ratio_bits) + return ext2fs_allocate_block_bitmap(fs, descr, ret); + + if ((fs->flags & EXT2_FLAG_64BITS) == 0) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + start = fs->super->s_first_data_block; + end = ext2fs_blocks_count(fs->super)-1; + real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64, + fs->default_bitmap_type, start, + end, real_end, descr, &bmap); + if (retval) + return retval; + bmap->cluster_bits = 0; + *ret = bmap; + return 0; +} + +int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap) +{ + ext2fs_generic_bitmap bmap = bitmap; + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return 0; + + return bmap->cluster_bits; +} + +errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, + ext2_ino_t end, ext2_ino_t *oend) +{ + __u64 tmp_oend; + int retval; + + retval = ext2fs_fudge_generic_bmap_end((ext2fs_generic_bitmap) bitmap, + EXT2_ET_FUDGE_INODE_BITMAP_END, + end, &tmp_oend); + if (oend) + *oend = tmp_oend; + return retval; +} + +errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, + blk_t end, blk_t *oend) +{ + return (ext2fs_fudge_generic_bitmap_end(bitmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + EXT2_ET_FUDGE_BLOCK_BITMAP_END, + end, oend)); +} + +errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap, + blk64_t end, blk64_t *oend) +{ + return (ext2fs_fudge_generic_bmap_end(bitmap, + EXT2_ET_FUDGE_BLOCK_BITMAP_END, + end, oend)); +} + +void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap) +{ + ext2fs_clear_generic_bmap(bitmap); +} + +void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap) +{ + ext2fs_clear_generic_bmap(bitmap); +} + +errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_inode_bitmap bmap) +{ + return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, + new_end, new_real_end, bmap)); +} + +errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, __u64 new_real_end, + ext2fs_inode_bitmap bmap) +{ + return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end)); +} + +errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_block_bitmap bmap) +{ + return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, + new_end, new_real_end, bmap)); +} + +errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, __u64 new_real_end, + ext2fs_block_bitmap bmap) +{ + return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end)); +} + +errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, + ext2fs_block_bitmap bm2) +{ + return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_BLOCK_BITMAP, + bm1, bm2)); +} + +errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, + ext2fs_inode_bitmap bm2) +{ + return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_INODE_BITMAP, + bm1, bm2)); +} + +errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *in) +{ + return (ext2fs_set_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_INODE_BITMAP, + start, num, in)); +} + +errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *in) +{ + return (ext2fs_set_generic_bmap_range(bmap, start, num, in)); +} + +errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *out) +{ + return (ext2fs_get_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_INODE_BITMAP, + start, num, out)); +} + +errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *out) +{ + return (ext2fs_get_generic_bmap_range(bmap, start, num, out)); +} + +errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *in) +{ + return (ext2fs_set_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + start, num, in)); +} + +errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *in) +{ + return (ext2fs_set_generic_bmap_range(bmap, start, num, in)); +} + +errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *out) +{ + return (ext2fs_get_generic_bitmap_range(bmap, + EXT2_ET_MAGIC_BLOCK_BITMAP, + start, num, out)); +} + +errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *out) +{ + return (ext2fs_get_generic_bmap_range(bmap, start, num, out)); +} diff --git a/src/ext2fs/bitops.c b/src/ext2fs/bitops.c new file mode 100644 index 00000000..c4a1d4e0 --- /dev/null +++ b/src/ext2fs/bitops.c @@ -0,0 +1,158 @@ +/* + * bitops.c --- Bitmap frobbing code. See bitops.h for the inlined + * routines. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef _EXT2_HAVE_ASM_BITOPS_ + +/* + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. You should + * recode these in the native assembly language, if at all possible. + * + * C language equivalents written by Theodore Ts'o, 9/26/92. + * Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian + * systems, as well as non-32 bit systems. + */ + +int ext2fs_set_bit(unsigned int nr,void * addr) +{ + int mask, retval; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR |= mask; + return retval; +} + +int ext2fs_clear_bit(unsigned int nr, void * addr) +{ + int mask, retval; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR &= ~mask; + return retval; +} + +int ext2fs_test_bit(unsigned int nr, const void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +#endif /* !_EXT2_HAVE_ASM_BITOPS_ */ + +void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, + const char *description) +{ +#ifndef OMIT_COM_ERR + if (description) + com_err(0, errcode, "#%lu for %s", arg, description); + else + com_err(0, errcode, "#%lu", arg); +#endif +} + +/* + * C-only 64 bit ops. + */ + +int ext2fs_set_bit64(__u64 nr, void * addr) +{ + int mask, retval; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR |= mask; + return retval; +} + +int ext2fs_clear_bit64(__u64 nr, void * addr) +{ + int mask, retval; + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + retval = mask & *ADDR; + *ADDR &= ~mask; + return retval; +} + +int ext2fs_test_bit64(__u64 nr, const void * addr) +{ + int mask; + const unsigned char *ADDR = (const unsigned char *) addr; + + ADDR += nr >> 3; + mask = 1 << (nr & 0x07); + return (mask & *ADDR); +} + +static unsigned int popcount8(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res + (res >> 4)) & 0x0F; +} + +static unsigned int popcount32(unsigned int w) +{ + unsigned int res = w - ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res + (res >> 4)) & 0x0F0F0F0F; + res = res + (res >> 8); + return (res + (res >> 16)) & 0x000000FF; +} + +unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes) +{ + const unsigned char *cp = addr; + const __u32 *p; + unsigned int res = 0; + + while (((((uintptr_t) cp) & 3) != 0) && (nbytes > 0)) { + res += popcount8(*cp++); + nbytes--; + } + p = (const __u32 *) cp; + + while (nbytes > 4) { + res += popcount32(*p++); + nbytes -= 4; + } + cp = (const unsigned char *) p; + + while (nbytes > 0) { + res += popcount8(*cp++); + nbytes--; + } + return res; +} diff --git a/src/ext2fs/bitops.h b/src/ext2fs/bitops.h new file mode 100644 index 00000000..505b3c9c --- /dev/null +++ b/src/ext2fs/bitops.h @@ -0,0 +1,703 @@ +/* + * bitops.h --- Bitmap frobbing code. The byte swapping routines are + * also included here. + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifdef WORDS_BIGENDIAN +#define ext2fs_cpu_to_le64(x) ((__force __le64)ext2fs_swab64((__u64)(x))) +#define ext2fs_le64_to_cpu(x) ext2fs_swab64((__force __u64)(__le64)(x)) +#define ext2fs_cpu_to_le32(x) ((__force __le32)ext2fs_swab32((__u32)(x))) +#define ext2fs_le32_to_cpu(x) ext2fs_swab32((__force __u32)(__le32)(x)) +#define ext2fs_cpu_to_le16(x) ((__force __le16)ext2fs_swab16((__u16)(x))) +#define ext2fs_le16_to_cpu(x) ext2fs_swab16((__force __u16)(__le16)(x)) + +#define ext2fs_cpu_to_be64(x) ((__force __be64)(__u64)(x)) +#define ext2fs_be64_to_cpu(x) ((__force __u64)(__be64)(x)) +#define ext2fs_cpu_to_be32(x) ((__force __be32)(__u32)(x)) +#define ext2fs_be32_to_cpu(x) ((__force __u32)(__be32)(x)) +#define ext2fs_cpu_to_be16(x) ((__force __be16)(__u16)(x)) +#define ext2fs_be16_to_cpu(x) ((__force __u16)(__be16)(x)) +#else +#define ext2fs_cpu_to_le64(x) ((__force __le64)(__u64)(x)) +#define ext2fs_le64_to_cpu(x) ((__force __u64)(__le64)(x)) +#define ext2fs_cpu_to_le32(x) ((__force __le32)(__u32)(x)) +#define ext2fs_le32_to_cpu(x) ((__force __u32)(__le32)(x)) +#define ext2fs_cpu_to_le16(x) ((__force __le16)(__u16)(x)) +#define ext2fs_le16_to_cpu(x) ((__force __u16)(__le16)(x)) + +#define ext2fs_cpu_to_be64(x) ((__force __be64)ext2fs_swab64((__u64)(x))) +#define ext2fs_be64_to_cpu(x) ext2fs_swab64((__force __u64)(__be64)(x)) +#define ext2fs_cpu_to_be32(x) ((__force __be32)ext2fs_swab32((__u32)(x))) +#define ext2fs_be32_to_cpu(x) ext2fs_swab32((__force __u32)(__be32)(x)) +#define ext2fs_cpu_to_be16(x) ((__force __be16)ext2fs_swab16((__u16)(x))) +#define ext2fs_be16_to_cpu(x) ext2fs_swab16((__force __u16)(__be16)(x)) +#endif + +/* + * EXT2FS bitmap manipulation routines. + */ + +/* Support for sending warning messages from the inline subroutines */ +extern const char *ext2fs_block_string; +extern const char *ext2fs_inode_string; +extern const char *ext2fs_mark_string; +extern const char *ext2fs_unmark_string; +extern const char *ext2fs_test_string; +extern void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, + const char *description); +extern void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, + int code, unsigned long arg); + +#ifdef NO_INLINE_FUNCS +extern void ext2fs_fast_set_bit(unsigned int nr,void * addr); +extern void ext2fs_fast_clear_bit(unsigned int nr, void * addr); +extern void ext2fs_fast_set_bit64(__u64 nr,void * addr); +extern void ext2fs_fast_clear_bit64(__u64 nr, void * addr); +extern __u16 ext2fs_swab16(__u16 val); +extern __u32 ext2fs_swab32(__u32 val); +extern __u64 ext2fs_swab64(__u64 val); + +extern int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); +extern int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, blk_t block); + +extern int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); +extern int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, ext2_ino_t inode); + +extern void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); +extern int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block); + +extern void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap); +extern blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap); + +extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +#endif + +/* These functions routines moved to gen_bitmap.c */ +extern void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode, int num); +extern int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 bitno); +extern int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno); +extern int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno); +extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); +extern void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map); +extern __u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap); +extern __u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap); + +/* 64-bit versions */ + +#ifdef NO_INLINE_FUNCS +extern int ext2fs_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); + +extern int ext2fs_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); + +extern void ext2fs_fast_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern void ext2fs_fast_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); +extern int ext2fs_fast_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block); + +extern void ext2fs_fast_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern void ext2fs_fast_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode); +extern errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out); +extern errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out); +extern errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out); +extern errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out); +extern blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_start2(ext2fs_inode_bitmap bitmap); +extern blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap); +extern ext2_ino_t ext2fs_get_inode_bitmap_end2(ext2fs_inode_bitmap bitmap); + +extern int ext2fs_fast_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +extern void ext2fs_fast_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +extern void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num); +#endif + +/* These routines moved to gen_bitmap64.c */ +extern void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap); +extern errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +extern void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap); +extern int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + blk64_t bitno); +extern int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap); +extern __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap); +extern int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, unsigned int num); +extern errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, + __u64 *out); +extern errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, + __u64 *out); + +/* + * The inline routines themselves... + * + * If NO_INLINE_FUNCS is defined, then we won't try to do inline + * functions at all; they will be included as normal functions in + * inline.c + */ +#ifdef NO_INLINE_FUNCS +#if (defined(__GNUC__) && (defined(__i386__) || defined(__i486__) || \ + defined(__i586__))) + /* This prevents bitops.c from trying to include the C */ + /* function version of these functions */ +#define _EXT2_HAVE_ASM_BITOPS_ +#endif +#endif /* NO_INLINE_FUNCS */ + +#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +#ifdef INCLUDE_INLINE_FUNCS +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ extern inline +#else +#define _INLINE_ inline +#endif +#else /* !INCLUDE_INLINE FUNCS */ +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ inline +#else /* not C99 */ +#ifdef __GNUC__ +#define _INLINE_ extern __inline__ +#else /* For Watcom C */ +#define _INLINE_ extern inline +#endif /* __GNUC__ */ +#endif /* __STDC_VERSION__ >= 199901L */ +#endif /* INCLUDE_INLINE_FUNCS */ + +/* + * Fast bit set/clear functions that doesn't need to return the + * previous bit value. + */ + +_INLINE_ void ext2fs_fast_set_bit(unsigned int nr,void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR |= (unsigned char) (1 << (nr & 0x07)); +} + +_INLINE_ void ext2fs_fast_clear_bit(unsigned int nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR &= (unsigned char) ~(1 << (nr & 0x07)); +} + + +_INLINE_ void ext2fs_fast_set_bit64(__u64 nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR |= (unsigned char) (1 << (nr & 0x07)); +} + +_INLINE_ void ext2fs_fast_clear_bit64(__u64 nr, void * addr) +{ + unsigned char *ADDR = (unsigned char *) addr; + + ADDR += nr >> 3; + *ADDR &= (unsigned char) ~(1 << (nr & 0x07)); +} + + +#if ((defined __GNUC__) && !defined(_EXT2_USE_C_VERSIONS_) && \ + (defined(__i386__) || defined(__i486__) || defined(__i586__))) + +#define _EXT2_HAVE_ASM_BITOPS_ +#define _EXT2_HAVE_ASM_SWAB_ + +/* + * These are done by inline assembly for speed reasons..... + * + * All bitoperations return 0 if the bit was cleared before the + * operation and != 0 if it was not. Bit 0 is the LSB of addr; bit 32 + * is the LSB of (addr+1). + */ + +/* + * Some hacks to defeat gcc over-optimizations.. + */ +struct __dummy_h { unsigned long a[100]; }; +#define EXT2FS_ADDR (*(struct __dummy_h *) addr) +#define EXT2FS_CONST_ADDR (*(const struct __dummy_h *) addr) + +_INLINE_ int ext2fs_set_bit(unsigned int nr, void * addr) +{ + int oldbit; + + addr = (void *) (((unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (EXT2FS_ADDR) + :"r" (nr & 7)); + return oldbit; +} + +_INLINE_ int ext2fs_clear_bit(unsigned int nr, void * addr) +{ + int oldbit; + + addr = (void *) (((unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (EXT2FS_ADDR) + :"r" (nr & 7)); + return oldbit; +} + +_INLINE_ int ext2fs_test_bit(unsigned int nr, const void * addr) +{ + int oldbit; + + addr = (const void *) (((const unsigned char *) addr) + (nr >> 3)); + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit) + :"m" (EXT2FS_CONST_ADDR),"r" (nr & 7)); + return oldbit; +} + +_INLINE_ __u32 ext2fs_swab32(__u32 val) +{ +#ifdef EXT2FS_REQUIRE_486 + __asm__("bswap %0" : "=r" (val) : "0" (val)); +#else + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (val) + : "0" (val)); +#endif + return val; +} + +_INLINE_ __u16 ext2fs_swab16(__u16 val) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ \ + : "=q" (val) \ + : "0" (val)); \ + return val; +} + +#undef EXT2FS_ADDR + +#endif /* i386 */ + + +#if !defined(_EXT2_HAVE_ASM_SWAB_) + +_INLINE_ __u16 ext2fs_swab16(__u16 val) +{ + return (val >> 8) | (__u16) (val << 8); +} + +_INLINE_ __u32 ext2fs_swab32(__u32 val) +{ + return ((val>>24) | ((val>>8)&0xFF00) | + ((val<<8)&0xFF0000) | (val<<24)); +} + +#endif /* !_EXT2_HAVE_ASM_SWAB */ + +_INLINE_ __u64 ext2fs_swab64(__u64 val) +{ + return (ext2fs_swab32((__u32) (val >> 32)) | + (((__u64)ext2fs_swab32(val & 0xFFFFFFFFUL)) << 32)); +} + +_INLINE_ int ext2fs_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap(ext2fs_block_bitmap bitmap, + blk_t block) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ void ext2fs_fast_mark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_mark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ void ext2fs_fast_unmark_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_unmark_generic_bitmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ int ext2fs_fast_test_inode_bitmap(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bitmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ blk_t ext2fs_get_block_bitmap_start(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start(ext2fs_inode_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ blk_t ext2fs_get_block_bitmap_end(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end(ext2fs_inode_bitmap bitmap) +{ + return ext2fs_get_generic_bitmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + return ext2fs_test_block_bitmap_range(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + ext2fs_mark_block_bitmap_range(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + ext2fs_unmark_block_bitmap_range(bitmap, block, num); +} + +/* 64-bit versions */ + +_INLINE_ int ext2fs_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ int ext2fs_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ int ext2fs_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, block); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t block) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + block); +} + +_INLINE_ void ext2fs_fast_mark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_mark_generic_bmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ void ext2fs_fast_unmark_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + ext2fs_unmark_generic_bmap((ext2fs_generic_bitmap) bitmap, inode); +} + +_INLINE_ int ext2fs_fast_test_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode) +{ + return ext2fs_test_generic_bmap((ext2fs_generic_bitmap) bitmap, + inode); +} + +_INLINE_ errcode_t ext2fs_find_first_zero_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_zero_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_zero_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_zero_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = (ext2_ino_t) o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_set_block_bitmap2(ext2fs_block_bitmap bitmap, + blk64_t start, + blk64_t end, + blk64_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = o; + return rv; +} + +_INLINE_ errcode_t ext2fs_find_first_set_inode_bitmap2(ext2fs_inode_bitmap bitmap, + ext2_ino_t start, + ext2_ino_t end, + ext2_ino_t *out) +{ + __u64 o; + errcode_t rv; + + rv = ext2fs_find_first_set_generic_bmap((ext2fs_generic_bitmap) bitmap, + start, end, &o); + if (!rv) + *out = (ext2_ino_t) o; + return rv; +} + +_INLINE_ blk64_t ext2fs_get_block_bitmap_start2(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_start2(ext2fs_inode_bitmap bitmap) +{ + return (ext2_ino_t) ext2fs_get_generic_bmap_start((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ blk64_t ext2fs_get_block_bitmap_end2(ext2fs_block_bitmap bitmap) +{ + return ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ ext2_ino_t ext2fs_get_inode_bitmap_end2(ext2fs_inode_bitmap bitmap) +{ + return (ext2_ino_t) ext2fs_get_generic_bmap_end((ext2fs_generic_bitmap) bitmap); +} + +_INLINE_ int ext2fs_fast_test_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + return ext2fs_test_block_bitmap_range2(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_mark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + ext2fs_mark_block_bitmap_range2(bitmap, block, num); +} + +_INLINE_ void ext2fs_fast_unmark_block_bitmap_range2(ext2fs_block_bitmap bitmap, + blk64_t block, + unsigned int num) +{ + ext2fs_unmark_block_bitmap_range2(bitmap, block, num); +} + +#undef _INLINE_ +#endif + +#ifndef _EXT2_HAVE_ASM_BITOPS_ +extern int ext2fs_set_bit(unsigned int nr,void * addr); +extern int ext2fs_clear_bit(unsigned int nr, void * addr); +extern int ext2fs_test_bit(unsigned int nr, const void * addr); +#endif + +extern int ext2fs_set_bit64(__u64 nr,void * addr); +extern int ext2fs_clear_bit64(__u64 nr, void * addr); +extern int ext2fs_test_bit64(__u64 nr, const void * addr); +extern unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes); diff --git a/src/ext2fs/blkmap64_ba.c b/src/ext2fs/blkmap64_ba.c new file mode 100644 index 00000000..3707a61e --- /dev/null +++ b/src/ext2fs/blkmap64_ba.c @@ -0,0 +1,492 @@ +/* + * blkmap64_ba.c --- Simple bitarray implementation for bitmaps + * + * Copyright (C) 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +/* + * Private data for bit array implementation of bitmap ops. + * Currently, this is just a pointer to our big flat hunk of memory, + * exactly equivalent to the old-skool char * bitmap member. + */ + +struct ext2fs_ba_private_struct { + char *bitarray; +}; + +typedef struct ext2fs_ba_private_struct *ext2fs_ba_private; + +static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp; + errcode_t retval; + size_t size; + + /* + * Since we only have the one pointer, we could just shove our + * private data in the void *private field itself, but then + * we'd have to do a fair bit of rewriting if we ever added a + * field. I'm agnostic. + */ + retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp); + if (retval) + return retval; + + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + + retval = ext2fs_get_mem(size, &bp->bitarray); + if (retval) { + ext2fs_free_mem(&bp); + bp = 0; + return retval; + } + bitmap->private = (void *) bp; + return 0; +} + +static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), + ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp; + errcode_t retval; + size_t size; + + retval = ba_alloc_private_data (bitmap); + if (retval) + return retval; + + bp = (ext2fs_ba_private) bitmap->private; + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + memset(bp->bitarray, 0, size); + + return 0; +} + +static void ba_free_bmap(ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + if (!bp) + return; + + if (bp->bitarray) { + ext2fs_free_mem (&bp->bitarray); + bp->bitarray = 0; + } + ext2fs_free_mem (&bp); + bp = 0; +} + +static errcode_t ba_copy_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest) +{ + ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private; + ext2fs_ba_private dest_bp; + errcode_t retval; + size_t size; + + retval = ba_alloc_private_data (dest); + if (retval) + return retval; + + dest_bp = (ext2fs_ba_private) dest->private; + + size = (size_t) (((src->real_end - src->start) / 8) + 1); + memcpy (dest_bp->bitarray, src_bp->bitarray, size); + + return 0; +} + +static errcode_t ba_resize_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, __u64 new_real_end) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private; + errcode_t retval; + size_t size, new_size; + __u64 bitno; + + /* + * If we're expanding the bitmap, make sure all of the new + * parts of the bitmap are zero. + */ + if (new_end > bmap->end) { + bitno = bmap->real_end; + if (bitno > new_end) + bitno = new_end; + for (; bitno > bmap->end; bitno--) + ext2fs_clear_bit64(bitno - bmap->start, bp->bitarray); + } + if (new_real_end == bmap->real_end) { + bmap->end = new_end; + return 0; + } + + size = ((bmap->real_end - bmap->start) / 8) + 1; + new_size = ((new_real_end - bmap->start) / 8) + 1; + + if (size != new_size) { + retval = ext2fs_resize_mem(size, new_size, &bp->bitarray); + if (retval) + return retval; + } + if (new_size > size) + memset(bp->bitarray + size, 0, new_size - size); + + bmap->end = new_end; + bmap->real_end = new_real_end; + return 0; + +} + +static int ba_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray); +} + +static int ba_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray); +} + +static int ba_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + + return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray); +} + +static void ba_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + unsigned int i; + + for (i = 0; i < num; i++) + ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray); +} + +static void ba_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + blk64_t bitno = (blk64_t) arg; + unsigned int i; + + for (i = 0; i < num; i++) + ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray); +} + +static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int len) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + __u64 start_byte, len_byte = len >> 3; + unsigned int start_bit, len_bit = len % 8; + unsigned int first_bit = 0; + unsigned int last_bit = 0; + int mark_count = 0; + int mark_bit = 0; + int i; + const char *ADDR; + + ADDR = bp->bitarray; + start -= bitmap->start; + start_byte = start >> 3; + start_bit = start % 8; + + if (start_bit != 0) { + /* + * The compared start block number or start inode number + * is not the first bit in a byte. + */ + mark_count = 8 - start_bit; + if (len < 8 - start_bit) { + mark_count = (int)len; + mark_bit = len + start_bit - 1; + } else + mark_bit = 7; + + for (i = mark_count; i > 0; i--, mark_bit--) + first_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the first byte. + * If there is any marked bit, this function returns 0. + */ + if (first_bit & ADDR[start_byte]) + return 0; + else if (len <= 8 - start_bit) + return 1; + + start_byte++; + len_bit = (len - mark_count) % 8; + len_byte = (len - mark_count) >> 3; + } + + /* + * The compared start block number or start inode number is + * the first bit in a byte. + */ + if (len_bit != 0) { + /* + * The compared end block number or end inode number is + * not the last bit in a byte. + */ + for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--) + last_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the last byte. + * If there is any marked bit, this function returns 0. + */ + if (last_bit & ADDR[start_byte + len_byte]) + return 0; + else if (len_byte == 0) + return 1; + } + + /* Check whether all bytes are 0 */ + return ext2fs_mem_is_zero(ADDR + start_byte, len_byte); +} + + +static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3); + + return 0; +} + +static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3); + + return 0; +} + +static void ba_clear_bmap(ext2fs_generic_bitmap bitmap) +{ + ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private; + + memset(bp->bitarray, 0, + (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); +} + +#ifdef ENABLE_BMAP_STATS +static void ba_print_stats(ext2fs_generic_bitmap bitmap) +{ + fprintf(stderr, "%16llu Bytes used by bitarray\n", + ((bitmap->real_end - bitmap->start) >> 3) + 1 + + sizeof(struct ext2fs_ba_private_struct)); +} +#else +static void ba_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused))) +{ +} +#endif + +/* Find the first zero bit between start and end, inclusive. */ +static errcode_t ba_find_first_zero(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private; + unsigned long bitpos = start - bitmap->start; + unsigned long count = end - start + 1; + int byte_found = 0; /* whether a != 0xff byte has been found */ + const unsigned char *pos; + unsigned long max_loop_count, i; + + /* scan bits until we hit a byte boundary */ + while ((bitpos & 0x7) != 0 && count > 0) { + if (!ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + count--; + } + + if (!count) + return ENOENT; + + pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3); + /* scan bytes until 8-byte (64-bit) aligned */ + while (count >= 8 && (((uintptr_t)pos) & 0x07)) { + if (*pos != 0xff) { + byte_found = 1; + break; + } + pos++; + count -= 8; + bitpos += 8; + } + + if (!byte_found) { + max_loop_count = count >> 6; /* 8-byte blocks */ + i = max_loop_count; + while (i) { + if (*((const __u64 *)pos) != ((__u64)-1)) + break; + pos += 8; + i--; + } + count -= 64 * (max_loop_count - i); + bitpos += 64 * (max_loop_count - i); + + max_loop_count = count >> 3; + i = max_loop_count; + while (i) { + if (*pos != 0xff) { + byte_found = 1; + break; + } + pos++; + i--; + } + count -= 8 * (max_loop_count - i); + bitpos += 8 * (max_loop_count - i); + } + + /* Here either count < 8 or byte_found == 1. */ + while (count-- > 0) { + if (!ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + } + + return ENOENT; +} + +/* Find the first one bit between start and end, inclusive. */ +static errcode_t ba_find_first_set(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private; + unsigned long bitpos = start - bitmap->start; + unsigned long count = end - start + 1; + int byte_found = 0; /* whether a != 0xff byte has been found */ + const unsigned char *pos; + unsigned long max_loop_count, i; + + /* scan bits until we hit a byte boundary */ + while ((bitpos & 0x7) != 0 && count > 0) { + if (ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + count--; + } + + if (!count) + return ENOENT; + + pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3); + /* scan bytes until 8-byte (64-bit) aligned */ + while (count >= 8 && (((uintptr_t)pos) & 0x07)) { + if (*pos != 0) { + byte_found = 1; + break; + } + pos++; + count -= 8; + bitpos += 8; + } + + if (!byte_found) { + max_loop_count = count >> 6; /* 8-byte blocks */ + i = max_loop_count; + while (i) { + if (*((const __u64 *)pos) != 0) + break; + pos += 8; + i--; + } + count -= 64 * (max_loop_count - i); + bitpos += 64 * (max_loop_count - i); + + max_loop_count = count >> 3; + i = max_loop_count; + while (i) { + if (*pos != 0) { + byte_found = 1; + break; + } + pos++; + i--; + } + count -= 8 * (max_loop_count - i); + bitpos += 8 * (max_loop_count - i); + } + + /* Here either count < 8 or byte_found == 1. */ + while (count-- > 0) { + if (ext2fs_test_bit64(bitpos, bp->bitarray)) { + *out = bitpos + bitmap->start; + return 0; + } + bitpos++; + } + + return ENOENT; +} + +struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = { + .type = EXT2FS_BMAP64_BITARRAY, + .new_bmap = ba_new_bmap, + .free_bmap = ba_free_bmap, + .copy_bmap = ba_copy_bmap, + .resize_bmap = ba_resize_bmap, + .mark_bmap = ba_mark_bmap, + .unmark_bmap = ba_unmark_bmap, + .test_bmap = ba_test_bmap, + .test_clear_bmap_extent = ba_test_clear_bmap_extent, + .mark_bmap_extent = ba_mark_bmap_extent, + .unmark_bmap_extent = ba_unmark_bmap_extent, + .set_bmap_range = ba_set_bmap_range, + .get_bmap_range = ba_get_bmap_range, + .clear_bmap = ba_clear_bmap, + .print_stats = ba_print_stats, + .find_first_zero = ba_find_first_zero, + .find_first_set = ba_find_first_set +}; diff --git a/src/ext2fs/blkmap64_rb.c b/src/ext2fs/blkmap64_rb.c new file mode 100644 index 00000000..55704774 --- /dev/null +++ b/src/ext2fs/blkmap64_rb.c @@ -0,0 +1,980 @@ +/* + * blkmap64_rb.c --- Simple rb-tree implementation for bitmaps + * + * (C)2010 Red Hat, Inc., Lukas Czerner + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_LINUX_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" +#include "rbtree.h" + +#include + +struct bmap_rb_extent { + struct rb_node node; + __u64 start; + __u64 count; +}; + +struct ext2fs_rb_private { + struct rb_root root; + struct bmap_rb_extent *wcursor; + struct bmap_rb_extent *rcursor; + struct bmap_rb_extent *rcursor_next; +#ifdef ENABLE_BMAP_STATS_OPS + __u64 mark_hit; + __u64 test_hit; +#endif +}; + +inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node) +{ + /* + * This depends on the fact the struct rb_node is at the + * beginning of the bmap_rb_extent structure. We use this + * instead of the ext2fs_rb_entry macro because it causes gcc + * -Wall to generate a huge amount of noise. + */ + return (struct bmap_rb_extent *) node; +} + +static int rb_insert_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *); +static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64); + +/* #define DEBUG_RB */ + +#ifdef DEBUG_RB +static void print_tree(struct rb_root *root) +{ + struct rb_node *node = NULL; + struct bmap_rb_extent *ext; + + printf("\t\t\t=================================\n"); + node = ext2fs_rb_first(root); + for (node = ext2fs_rb_first(root); node != NULL; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + printf("\t\t\t--> (%llu -> %llu)\n", + ext->start, ext->start + ext->count); + } + printf("\t\t\t=================================\n"); +} + +static void check_tree(struct rb_root *root, const char *msg) +{ + struct rb_node *node; + struct bmap_rb_extent *ext, *old = NULL; + + for (node = ext2fs_rb_first(root); node; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + if (ext->count == 0) { + printf("Tree Error: count is zero\n"); + printf("extent: %llu -> %llu (%llu)\n", ext->start, + ext->start + ext->count, ext->count); + goto err_out; + } + if (ext->start + ext->count < ext->start) { + printf("Tree Error: start or count is crazy\n"); + printf("extent: %llu -> %llu (%llu)\n", ext->start, + ext->start + ext->count, ext->count); + goto err_out; + } + + if (old) { + if (old->start > ext->start) { + printf("Tree Error: start is crazy\n"); + printf("extent: %llu -> %llu (%llu)\n", + old->start, old->start + old->count, + old->count); + printf("extent next: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + if ((old->start + old->count) >= ext->start) { + printf("Tree Error: extent is crazy\n"); + printf("extent: %llu -> %llu (%llu)\n", + old->start, old->start + old->count, + old->count); + printf("extent next: %llu -> %llu (%llu)\n", + ext->start, ext->start + ext->count, + ext->count); + goto err_out; + } + } + old = ext; + } + return; + +err_out: + printf("%s\n", msg); + print_tree(root); + exit(1); +} +#else +#define check_tree(root, msg) do {} while (0) +#define print_tree(root) do {} while (0) +#endif + +static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start, + __u64 count) +{ + struct bmap_rb_extent *new_ext; + int retval; + + retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), + &new_ext); + if (retval) + abort(); + + new_ext->start = start; + new_ext->count = count; + *ext = new_ext; +} + +inline +static void rb_free_extent(struct ext2fs_rb_private *bp, + struct bmap_rb_extent *ext) +{ + if (bp->wcursor == ext) + bp->wcursor = NULL; + if (bp->rcursor == ext) + bp->rcursor = NULL; + if (bp->rcursor_next == ext) + bp->rcursor_next = NULL; + ext2fs_free_mem(&ext); +} + +static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + errcode_t retval; + + retval = ext2fs_get_mem(sizeof (struct ext2fs_rb_private), &bp); + if (retval) + return retval; + + bp->root = RB_ROOT; + bp->rcursor = NULL; + bp->rcursor_next = NULL; + bp->wcursor = NULL; + +#ifdef ENABLE_BMAP_STATS_OPS + bp->test_hit = 0; + bp->mark_hit = 0; +#endif + + bitmap->private = (void *) bp; + return 0; +} + +static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), + ext2fs_generic_bitmap bitmap) +{ + errcode_t retval; + + retval = rb_alloc_private_data (bitmap); + if (retval) + return retval; + + return 0; +} + +static void rb_free_tree(struct rb_root *root) +{ + struct bmap_rb_extent *ext; + struct rb_node *node, *next; + + for (node = ext2fs_rb_first(root); node; node = next) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + ext2fs_rb_erase(node, root); + ext2fs_free_mem(&ext); + } +} + +static void rb_free_bmap(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + rb_free_tree(&bp->root); + ext2fs_free_mem(&bp); + bp = 0; +} + +static errcode_t rb_copy_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest) +{ + struct ext2fs_rb_private *src_bp, *dest_bp; + struct bmap_rb_extent *src_ext, *dest_ext; + struct rb_node *dest_node, *src_node, *dest_last, **n; + errcode_t retval = 0; + + retval = rb_alloc_private_data (dest); + if (retval) + return retval; + + src_bp = (struct ext2fs_rb_private *) src->private; + dest_bp = (struct ext2fs_rb_private *) dest->private; + src_bp->rcursor = NULL; + dest_bp->rcursor = NULL; + + src_node = ext2fs_rb_first(&src_bp->root); + while (src_node) { + src_ext = node_to_extent(src_node); + retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), + &dest_ext); + if (retval) + break; + + memcpy(dest_ext, src_ext, sizeof(struct bmap_rb_extent)); + + dest_node = &dest_ext->node; + n = &dest_bp->root.rb_node; + + dest_last = NULL; + if (*n) { + dest_last = ext2fs_rb_last(&dest_bp->root); + n = &(dest_last)->rb_right; + } + + ext2fs_rb_link_node(dest_node, dest_last, n); + ext2fs_rb_insert_color(dest_node, &dest_bp->root); + + src_node = ext2fs_rb_next(src_node); + } + + return retval; +} + +static void rb_truncate(__u64 new_max, struct rb_root *root) +{ + struct bmap_rb_extent *ext; + struct rb_node *node; + + node = ext2fs_rb_last(root); + while (node) { + ext = node_to_extent(node); + + if ((ext->start + ext->count - 1) <= new_max) + break; + else if (ext->start > new_max) { + ext2fs_rb_erase(node, root); + ext2fs_free_mem(&ext); + node = ext2fs_rb_last(root); + continue; + } else + ext->count = new_max - ext->start + 1; + } +} + +static errcode_t rb_resize_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, __u64 new_real_end) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bmap->private; + bp->rcursor = NULL; + bp->wcursor = NULL; + + rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start, + &bp->root); + + bmap->end = new_end; + bmap->real_end = new_real_end; + + if (bmap->end < bmap->real_end) + rb_insert_extent(bmap->end + 1 - bmap->start, + bmap->real_end - bmap->end, bp); + return 0; + +} + +inline static int +rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit) +{ + struct bmap_rb_extent *rcursor, *next_ext = NULL; + struct rb_node *parent = NULL, *next; + struct rb_node **n = &bp->root.rb_node; + struct bmap_rb_extent *ext; + + rcursor = bp->rcursor; + if (!rcursor) + goto search_tree; + + if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) { +#ifdef ENABLE_BMAP_STATS_OPS + bp->test_hit++; +#endif + return 1; + } + + next_ext = bp->rcursor_next; + if (!next_ext) { + next = ext2fs_rb_next(&rcursor->node); + if (next) + next_ext = node_to_extent(next); + bp->rcursor_next = next_ext; + } + if (next_ext) { + if ((bit >= rcursor->start + rcursor->count) && + (bit < next_ext->start)) { +#ifdef BMAP_STATS_OPS + bp->test_hit++; +#endif + return 0; + } + } + bp->rcursor = NULL; + bp->rcursor_next = NULL; + + rcursor = bp->wcursor; + if (!rcursor) + goto search_tree; + + if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) + return 1; + +search_tree: + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (bit < ext->start) + n = &(*n)->rb_left; + else if (bit >= (ext->start + ext->count)) + n = &(*n)->rb_right; + else { + bp->rcursor = ext; + bp->rcursor_next = NULL; + return 1; + } + } + return 0; +} + +static int rb_insert_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *bp) +{ + struct rb_root *root = &bp->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *new_node, *node, *next; + struct bmap_rb_extent *new_ext; + struct bmap_rb_extent *ext; + int retval = 0; + + bp->rcursor_next = NULL; + ext = bp->wcursor; + if (ext) { + if (start >= ext->start && + start <= (ext->start + ext->count)) { +#ifdef ENABLE_BMAP_STATS_OPS + bp->mark_hit++; +#endif + goto got_extent; + } + } + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start > (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { +got_extent: + if ((start + count) <= (ext->start + ext->count)) + return 1; + + if ((ext->start + ext->count) == start) + retval = 0; + else + retval = 1; + + count += (start - ext->start); + start = ext->start; + new_ext = ext; + new_node = &ext->node; + + goto skip_insert; + } + } + + rb_get_new_extent(&new_ext, start, count); + + new_node = &new_ext->node; + ext2fs_rb_link_node(new_node, parent, n); + ext2fs_rb_insert_color(new_node, root); + bp->wcursor = new_ext; + + node = ext2fs_rb_prev(new_node); + if (node) { + ext = node_to_extent(node); + if ((ext->start + ext->count) == start) { + start = ext->start; + count += ext->count; + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + } + } + +skip_insert: + /* See if we can merge extent to the right */ + for (node = ext2fs_rb_next(new_node); node != NULL; node = next) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + + if ((ext->start + ext->count) <= start) + continue; + + /* No more merging */ + if ((start + count) < ext->start) + break; + + /* ext is embedded in new_ext interval */ + if ((start + count) >= (ext->start + ext->count)) { + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + continue; + } else { + /* merge ext with new_ext */ + count += ((ext->start + ext->count) - + (start + count)); + ext2fs_rb_erase(node, root); + rb_free_extent(bp, ext); + break; + } + } + + new_ext->start = start; + new_ext->count = count; + + return retval; +} + +static int rb_remove_extent(__u64 start, __u64 count, + struct ext2fs_rb_private *bp) +{ + struct rb_root *root = &bp->root; + struct rb_node *parent = NULL, **n = &root->rb_node; + struct rb_node *node; + struct bmap_rb_extent *ext; + __u64 new_start, new_count; + int retval = 0; + + if (ext2fs_rb_empty_root(root)) + return 0; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + continue; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + continue; + } + + if ((start > ext->start) && + (start + count) < (ext->start + ext->count)) { + /* We have to split extent into two */ + new_start = start + count; + new_count = (ext->start + ext->count) - new_start; + + ext->count = start - ext->start; + + rb_insert_extent(new_start, new_count, bp); + return 1; + } + + if ((start + count) >= (ext->start + ext->count)) { + ext->count = start - ext->start; + retval = 1; + } + + if (0 == ext->count) { + parent = ext2fs_rb_next(&ext->node); + ext2fs_rb_erase(&ext->node, root); + rb_free_extent(bp, ext); + break; + } + + if (start == ext->start) { + ext->start += count; + ext->count -= count; + return 1; + } + } + + /* See if we should delete or truncate extent on the right */ + for (; parent != NULL; parent = node) { + node = ext2fs_rb_next(parent); + ext = node_to_extent(parent); + if ((ext->start + ext->count) <= start) + continue; + + /* No more extents to be removed/truncated */ + if ((start + count) < ext->start) + break; + + /* The entire extent is within the region to be removed */ + if ((start + count) >= (ext->start + ext->count)) { + ext2fs_rb_erase(parent, root); + rb_free_extent(bp, ext); + retval = 1; + continue; + } else { + /* modify the last extent in region to be removed */ + ext->count -= ((start + count) - ext->start); + ext->start = start + count; + retval = 1; + break; + } + } + + return retval; +} + +static int rb_mark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + int retval; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + retval = rb_insert_extent(arg, 1, bp); + check_tree(&bp->root, __func__); + return retval; +} + +static int rb_unmark_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + int retval; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + retval = rb_remove_extent(arg, 1, bp); + check_tree(&bp->root, __func__); + + return retval; +} + +inline +static int rb_test_bmap(ext2fs_generic_bitmap bitmap, __u64 arg) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + return rb_test_bit(bp, arg); +} + +static void rb_mark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + rb_insert_extent(arg, num, bp); + check_tree(&bp->root, __func__); +} + +static void rb_unmark_bmap_extent(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + arg -= bitmap->start; + + rb_remove_extent(arg, num, bp); + check_tree(&bp->root, __func__); +} + +static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int len) +{ + struct rb_node *parent = NULL, **n; + struct rb_node *node, *next; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + int retval = 1; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + + if (len == 0 || ext2fs_rb_empty_root(&bp->root)) + return 1; + + /* + * If we find nothing, we should examine whole extent, but + * when we find match, the extent is not clean, thus be return + * false. + */ + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { + /* + * We found extent int the tree -> extent is not + * clean + */ + return 0; + } + } + + node = parent; + while (node) { + next = ext2fs_rb_next(node); + ext = node_to_extent(node); + node = next; + + if ((ext->start + ext->count) <= start) + continue; + + /* No more merging */ + if ((start + len) <= ext->start) + break; + + retval = 0; + break; + } + return retval; +} + +static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in) +{ + struct ext2fs_rb_private *bp; + unsigned char *cp = in; + size_t i; + int first_set = -1; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + for (i = 0; i < num; i++) { + if ((i & 7) == 0) { + unsigned char c = cp[i/8]; + if (c == 0xFF) { + if (first_set == -1) + first_set = i; + i += 7; + continue; + } + if ((c == 0x00) && (first_set == -1)) { + i += 7; + continue; + } + } + if (ext2fs_test_bit(i, in)) { + if (first_set == -1) + first_set = i; + continue; + } + if (first_set == -1) + continue; + + rb_insert_extent(start + first_set - bitmap->start, + i - first_set, bp); + check_tree(&bp->root, __func__); + first_set = -1; + } + if (first_set != -1) { + rb_insert_extent(start + first_set - bitmap->start, + num - first_set, bp); + check_tree(&bp->root, __func__); + } + + return 0; +} + +static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out) +{ + + struct rb_node *parent = NULL, *next, **n; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + __u64 count, pos; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + + if (ext2fs_rb_empty_root(&bp->root)) + return 0; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else + break; + } + + memset(out, 0, (num + 7) >> 3); + + for (; parent != NULL; parent = next) { + next = ext2fs_rb_next(parent); + ext = node_to_extent(parent); + + pos = ext->start; + count = ext->count; + if (pos >= start + num) + break; + if (pos < start) { + if (pos + count < start) + continue; + count -= start - pos; + pos = start; + } + if (pos + count > start + num) + count = start + num - pos; + + while (count > 0) { + if ((count >= 8) && + ((pos - start) % 8) == 0) { + int nbytes = count >> 3; + int offset = (pos - start) >> 3; + + memset(((char *) out) + offset, 0xFF, nbytes); + pos += nbytes << 3; + count -= nbytes << 3; + continue; + } + ext2fs_fast_set_bit64((pos - start), out); + pos++; + count--; + } + } + return 0; +} + +static void rb_clear_bmap(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + + bp = (struct ext2fs_rb_private *) bitmap->private; + + rb_free_tree(&bp->root); + bp->rcursor = NULL; + bp->rcursor_next = NULL; + bp->wcursor = NULL; + check_tree(&bp->root, __func__); +} + +static errcode_t rb_find_first_zero(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + struct rb_node *parent = NULL, **n; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + end -= bitmap->start; + + if (start > end) + return EINVAL; + + if (ext2fs_rb_empty_root(&bp->root)) + return ENOENT; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else if (ext->start + ext->count <= end) { + *out = ext->start + ext->count + bitmap->start; + return 0; + } else + return ENOENT; + } + + *out = start + bitmap->start; + return 0; +} + +static errcode_t rb_find_first_set(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + struct rb_node *parent = NULL, **n; + struct rb_node *node; + struct ext2fs_rb_private *bp; + struct bmap_rb_extent *ext; + + bp = (struct ext2fs_rb_private *) bitmap->private; + n = &bp->root.rb_node; + start -= bitmap->start; + end -= bitmap->start; + + if (start > end) + return EINVAL; + + if (ext2fs_rb_empty_root(&bp->root)) + return ENOENT; + + while (*n) { + parent = *n; + ext = node_to_extent(parent); + if (start < ext->start) { + n = &(*n)->rb_left; + } else if (start >= (ext->start + ext->count)) { + n = &(*n)->rb_right; + } else { + /* The start bit is set */ + *out = start + bitmap->start; + return 0; + } + } + + node = parent; + ext = node_to_extent(node); + if (ext->start < start) { + node = ext2fs_rb_next(node); + if (node == NULL) + return ENOENT; + ext = node_to_extent(node); + } + if (ext->start <= end) { + *out = ext->start + bitmap->start; + return 0; + } + return ENOENT; +} + +#ifdef ENABLE_BMAP_STATS +static void rb_print_stats(ext2fs_generic_bitmap bitmap) +{ + struct ext2fs_rb_private *bp; + struct rb_node *node = NULL; + struct bmap_rb_extent *ext; + __u64 count = 0; + __u64 max_size = 0; + __u64 min_size = ULONG_MAX; + __u64 size = 0, avg_size = 0; + double eff; +#ifdef ENABLE_BMAP_STATS_OPS + __u64 mark_all, test_all; + double m_hit = 0.0, t_hit = 0.0; +#endif + + bp = (struct ext2fs_rb_private *) bitmap->private; + + for (node = ext2fs_rb_first(&bp->root); node != NULL; + node = ext2fs_rb_next(node)) { + ext = node_to_extent(node); + count++; + if (ext->count > max_size) + max_size = ext->count; + if (ext->count < min_size) + min_size = ext->count; + size += ext->count; + } + + if (count) + avg_size = size / count; + if (min_size == ULONG_MAX) + min_size = 0; + eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) / + (bitmap->real_end - bitmap->start); +#ifdef ENABLE_BMAP_STATS_OPS + mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count; + test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count; + if (mark_all) + m_hit = ((double)bp->mark_hit / mark_all) * 100; + if (test_all) + t_hit = ((double)bp->test_hit / test_all) * 100; + + fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n" + "%16llu cache hits on mark (%.2f%%)\n", + bp->test_hit, t_hit, bp->mark_hit, m_hit); +#endif + fprintf(stderr, "%16llu extents (%llu bytes)\n", + count, ((count * sizeof(struct bmap_rb_extent)) + + sizeof(struct ext2fs_rb_private))); + fprintf(stderr, "%16llu bits minimum size\n", + min_size); + fprintf(stderr, "%16llu bits maximum size\n" + "%16llu bits average size\n", + max_size, avg_size); + fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n", size, + bitmap->real_end - bitmap->start); + fprintf(stderr, + "%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n", + eff); +} +#else +static void rb_print_stats(ext2fs_generic_bitmap bitmap EXT2FS_ATTR((unused))) +{ +} +#endif + +struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = { + .type = EXT2FS_BMAP64_RBTREE, + .new_bmap = rb_new_bmap, + .free_bmap = rb_free_bmap, + .copy_bmap = rb_copy_bmap, + .resize_bmap = rb_resize_bmap, + .mark_bmap = rb_mark_bmap, + .unmark_bmap = rb_unmark_bmap, + .test_bmap = rb_test_bmap, + .test_clear_bmap_extent = rb_test_clear_bmap_extent, + .mark_bmap_extent = rb_mark_bmap_extent, + .unmark_bmap_extent = rb_unmark_bmap_extent, + .set_bmap_range = rb_set_bmap_range, + .get_bmap_range = rb_get_bmap_range, + .clear_bmap = rb_clear_bmap, + .print_stats = rb_print_stats, + .find_first_zero = rb_find_first_zero, + .find_first_set = rb_find_first_set, +}; diff --git a/src/ext2fs/blknum.c b/src/ext2fs/blknum.c new file mode 100644 index 00000000..aa0e9118 --- /dev/null +++ b/src/ext2fs/blknum.c @@ -0,0 +1,543 @@ +/* + * blknum.c --- Functions to handle blk64_t and high/low 64-bit block + * number. + * + * Copyright IBM Corporation, 2007 + * Author Jose R. Santos + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include "ext2fs.h" + +/* + * Return the group # of a block + */ +dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk) +{ + return (blk - fs->super->s_first_data_block) / + fs->super->s_blocks_per_group; +} + +/* + * Return the first block (inclusive) in a group + */ +blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group) +{ + return fs->super->s_first_data_block + + EXT2_GROUPS_TO_BLOCKS(fs->super, group); +} + +/* + * Return the last block (inclusive) in a group + */ +blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group) +{ + return (group == fs->group_desc_count - 1 ? + ext2fs_blocks_count(fs->super) - 1 : + ext2fs_group_first_block2(fs, group) + + (fs->super->s_blocks_per_group - 1)); +} + +/* + * Return the number of blocks in a group + */ +int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group) +{ + int num_blocks; + + if (group == fs->group_desc_count - 1) { + num_blocks = (ext2fs_blocks_count(fs->super) - + fs->super->s_first_data_block) % + fs->super->s_blocks_per_group; + if (!num_blocks) + num_blocks = fs->super->s_blocks_per_group; + } else + num_blocks = fs->super->s_blocks_per_group; + + return num_blocks; +} + +/* + * Return the inode data block count + */ +blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (inode->i_blocks | + (ext2fs_has_feature_huge_file(fs->super) ? + (__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) - + (inode->i_file_acl ? EXT2_CLUSTER_SIZE(fs->super) >> 9 : 0); +} + +/* + * Return the inode i_blocks count + */ +blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (inode->i_blocks | + (ext2fs_has_feature_huge_file(fs->super) ? + (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0)); +} + +/* + * Return the fs block count + */ +blk64_t ext2fs_blocks_count(struct ext2_super_block *super) +{ + return super->s_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_blocks_count_hi << 32 : 0); +} + +/* + * Set the fs block count + */ +void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_blocks_count_hi = (__u64) blk >> 32; +} + +/* + * Add to the current fs block count + */ +void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_blocks_count(super) + blk; + ext2fs_blocks_count_set(super, tmp); +} + +/* + * Return the fs reserved block count + */ +blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super) +{ + return super->s_r_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_r_blocks_count_hi << 32 : 0); +} + +/* + * Set the fs reserved block count + */ +void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_r_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_r_blocks_count_hi = (__u64) blk >> 32; +} + +/* + * Add to the current reserved fs block count + */ +void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_r_blocks_count(super) + blk; + ext2fs_r_blocks_count_set(super, tmp); +} + +/* + * Return the fs free block count + */ +blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super) +{ + return super->s_free_blocks_count | + (ext2fs_has_feature_64bit(super) ? + (__u64) super->s_free_blocks_hi << 32 : 0); +} + +/* + * Set the fs free block count + */ +void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk) +{ + super->s_free_blocks_count = blk; + if (ext2fs_has_feature_64bit(super)) + super->s_free_blocks_hi = (__u64) blk >> 32; +} + +/* + * Add to the current free fs block count + */ +void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk) +{ + blk64_t tmp; + tmp = ext2fs_free_blocks_count(super) + blk; + ext2fs_free_blocks_count_set(super, tmp); +} + +/* + * Get a pointer to a block group descriptor. We need the explicit + * pointer to the group desc for code that swaps block group + * descriptors before writing them out, as it wants to make a copy and + * do the swap there. + */ +struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group) +{ + int desc_size = EXT2_DESC_SIZE(fs->super) & ~7; + + return (struct ext2_group_desc *)((char *)gdp + group * desc_size); +} + +/* Do the same but as an ext4 group desc for internal use here */ +static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group) +{ + return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group); +} + +/* + * Return the block bitmap checksum of a group + */ +__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + __u32 csum; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + csum = gdp->bg_block_bitmap_csum_lo; + if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16); + return csum; +} + +/* + * Return the block bitmap block of a group + */ +blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_block_bitmap | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64)gdp->bg_block_bitmap_hi << 32 : 0); +} + +/* + * Set the block bitmap block of a group + */ +void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_block_bitmap = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_block_bitmap_hi = (__u64) blk >> 32; +} + +/* + * Return the inode bitmap checksum of a group + */ +__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + __u32 csum; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + csum = gdp->bg_inode_bitmap_csum_lo; + if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16); + return csum; +} + +/* + * Return the inode bitmap block of a group + */ +blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_inode_bitmap | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64) gdp->bg_inode_bitmap_hi << 32 : 0); +} + +/* + * Set the inode bitmap block of a group + */ +void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_inode_bitmap = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_inode_bitmap_hi = (__u64) blk >> 32; +} + +/* + * Return the inode table block of a group + */ +blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_inode_table | + (ext2fs_has_feature_64bit(fs->super) ? + (__u64) gdp->bg_inode_table_hi << 32 : 0); +} + +/* + * Set the inode table block of a group + */ +void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_inode_table = blk; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_inode_table_hi = (__u64) blk >> 32; +} + +/* + * Return the free blocks count of a group + */ +__u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_free_blocks_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_free_blocks_count_hi << 16 : 0); +} + +/* + * Set the free blocks count of a group + */ +void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_free_blocks_count = n; + + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_free_blocks_count_hi = (__u32) n >> 16; +} + +/* + * Return the free inodes count of a group + */ +__u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_free_inodes_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_free_inodes_count_hi << 16 : 0); +} + +/* + * Set the free inodes count of a group + */ +void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_free_inodes_count = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_free_inodes_count_hi = (__u32) n >> 16; +} + +/* + * Return the used dirs count of a group + */ +__u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_used_dirs_count | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_used_dirs_count_hi << 16 : 0); +} + +/* + * Set the used dirs count of a group + */ +void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_used_dirs_count = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_used_dirs_count_hi = (__u32) n >> 16; +} + +/* + * Return the unused inodes count of a group + */ +__u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_itable_unused | + (ext2fs_has_feature_64bit(fs->super) ? + (__u32) gdp->bg_itable_unused_hi << 16 : 0); +} + +/* + * Set the unused inodes count of a group + */ +void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_itable_unused = n; + if (ext2fs_has_feature_64bit(fs->super)) + gdp->bg_itable_unused_hi = (__u32) n >> 16; +} + +/* + * Get the flags for this block group + */ +__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_flags; +} + +/* + * Zero out the flags for this block group + */ +void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags = 0; + return; +} + +/* + * Get the value of a particular flag for this block group + */ +int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_flags & bg_flag; +} + +/* + * Set a flag or set of flags for this block group + */ +void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags |= bg_flags; + return; +} + +/* + * Clear a flag or set of flags for this block group + */ +void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_flags &= ~bg_flags; + return; +} + +/* + * Get the checksum for this block group + */ +__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + return gdp->bg_checksum; +} + +/* + * Set the checksum for this block group to a previously calculated value + */ +void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum) +{ + struct ext4_group_desc *gdp; + + gdp = ext4fs_group_desc(fs, fs->group_desc, group); + gdp->bg_checksum = checksum; + return; +} + +/* + * Get the acl block of a file + */ +blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode) +{ + blk64_t blk = inode->i_file_acl; + + if (fs && ext2fs_has_feature_64bit(fs->super)) + blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32; + return blk; +} + +/* + * Set the acl block of a file + */ +void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode, + blk64_t blk) +{ + inode->i_file_acl = blk; + if (fs && ext2fs_has_feature_64bit(fs->super)) + inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32; +} + +/* + * Set the size of the inode + */ +errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size) +{ + /* Only regular files get to be larger than 4GB */ + if (!LINUX_S_ISREG(inode->i_mode) && (size >> 32)) + return EXT2_ET_FILE_TOO_BIG; + + /* If we're writing a large file, set the large_file flag */ + if (LINUX_S_ISREG(inode->i_mode) && + ext2fs_needs_large_file_feature(size) && + (!ext2fs_has_feature_large_file(fs->super) || + fs->super->s_rev_level == EXT2_GOOD_OLD_REV)) { + ext2fs_set_feature_large_file(fs->super); + ext2fs_update_dynamic_rev(fs); + ext2fs_mark_super_dirty(fs); + } + + inode->i_size = size & 0xffffffff; + inode->i_size_high = (size >> 32); + + return 0; +} + diff --git a/src/ext2fs/block.c b/src/ext2fs/block.c new file mode 100644 index 00000000..06eed6e0 --- /dev/null +++ b/src/ext2fs/block.c @@ -0,0 +1,659 @@ +/* + * block.c --- iterate over all blocks in an inode + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct block_context { + ext2_filsys fs; + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t bcount, + blk64_t ref_blk, + int ref_offset, + void *priv_data); + e2_blkcnt_t bcount; + int bsize; + int flags; + errcode_t errcode; + char *ind_buf; + char *dind_buf; + char *tind_buf; + void *priv_data; +}; + +#define check_for_ro_violation_return(ctx, ret) \ + do { \ + if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \ + ((ret) & BLOCK_CHANGED)) { \ + (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \ + ret |= BLOCK_ABORT | BLOCK_ERROR; \ + return ret; \ + } \ + } while (0) + +#define check_for_ro_violation_goto(ctx, ret, label) \ + do { \ + if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \ + ((ret) & BLOCK_CHANGED)) { \ + (ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \ + ret |= BLOCK_ABORT | BLOCK_ERROR; \ + goto label; \ + } \ + } while (0) + +static int block_iterate_ind(blk_t *ind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY)) { + blk64 = *ind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_IND, ref_block, + ref_offset, ctx->priv_data); + *ind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*ind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += limit; + return ret; + } + if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) || + *ind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_IND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block, + ctx->ind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->ind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { + blk64 = *block_nr; + flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, + *ind_block, offset, + ctx->priv_data); + *block_nr = blk64; + changed |= flags; + if (flags & BLOCK_ABORT) { + ret |= BLOCK_ABORT; + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) { + if (*block_nr == 0) + goto skip_sparse; + blk64 = *block_nr; + flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount, + *ind_block, offset, + ctx->priv_data); + *block_nr = blk64; + changed |= flags; + if (flags & BLOCK_ABORT) { + ret |= BLOCK_ABORT; + break; + } + skip_sparse: + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block, + ctx->ind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *ind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_IND, ref_block, + ref_offset, ctx->priv_data); + *ind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +static int block_iterate_dind(blk_t *dind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | + BLOCK_FLAG_DATA_ONLY))) { + blk64 = *dind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_DIND, ref_block, + ref_offset, ctx->priv_data); + *dind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*dind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += limit*limit; + return ret; + } + if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) || + *dind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_DIND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block, + ctx->dind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->dind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, block_nr++) { + flags = block_iterate_ind(block_nr, + *dind_block, offset, + ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, block_nr++) { + if (*block_nr == 0) { + ctx->bcount += limit; + continue; + } + flags = block_iterate_ind(block_nr, + *dind_block, offset, + ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block, + ctx->dind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *dind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_DIND, ref_block, + ref_offset, ctx->priv_data); + *dind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +static int block_iterate_tind(blk_t *tind_block, blk_t ref_block, + int ref_offset, struct block_context *ctx) +{ + int ret = 0, changed = 0; + int i, flags, limit, offset; + blk_t *block_nr; + blk64_t blk64; + + limit = ctx->fs->blocksize >> 2; + if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE | + BLOCK_FLAG_DATA_ONLY))) { + blk64 = *tind_block; + ret = (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_TIND, ref_block, + ref_offset, ctx->priv_data); + *tind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + if (!*tind_block || (ret & BLOCK_ABORT)) { + ctx->bcount += ((unsigned long long) limit)*limit*limit; + return ret; + } + if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) || + *tind_block < ctx->fs->super->s_first_data_block) { + ctx->errcode = EXT2_ET_BAD_TIND_BLOCK; + ret |= BLOCK_ERROR; + return ret; + } + ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block, + ctx->tind_buf); + if (ctx->errcode) { + ret |= BLOCK_ERROR; + return ret; + } + + block_nr = (blk_t *) ctx->tind_buf; + offset = 0; + if (ctx->flags & BLOCK_FLAG_APPEND) { + for (i = 0; i < limit; i++, block_nr++) { + flags = block_iterate_dind(block_nr, + *tind_block, + offset, ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } else { + for (i = 0; i < limit; i++, block_nr++) { + if (*block_nr == 0) { + ctx->bcount += limit*limit; + continue; + } + flags = block_iterate_dind(block_nr, + *tind_block, + offset, ctx); + changed |= flags; + if (flags & (BLOCK_ABORT | BLOCK_ERROR)) { + ret |= flags & (BLOCK_ABORT | BLOCK_ERROR); + break; + } + offset += sizeof(blk_t); + } + } + check_for_ro_violation_return(ctx, changed); + if (changed & BLOCK_CHANGED) { + ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block, + ctx->tind_buf); + if (ctx->errcode) + ret |= BLOCK_ERROR | BLOCK_ABORT; + } + if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) && + !(ctx->flags & BLOCK_FLAG_DATA_ONLY) && + !(ret & BLOCK_ABORT)) { + blk64 = *tind_block; + ret |= (*ctx->func)(ctx->fs, &blk64, + BLOCK_COUNT_TIND, ref_block, + ref_offset, ctx->priv_data); + *tind_block = blk64; + } + check_for_ro_violation_return(ctx, ret); + return ret; +} + +errcode_t ext2fs_block_iterate3(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data) +{ + int i; + int r, ret = 0; + struct ext2_inode inode; + errcode_t retval; + struct block_context ctx; + int limit; + blk64_t blk64; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + ctx.errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx.errcode) + return ctx.errcode; + + /* + * An inode with inline data has no blocks over which to + * iterate, so return an error code indicating this fact. + */ + if (inode.i_flags & EXT4_INLINE_DATA_FL) + return EXT2_ET_INLINE_DATA_CANT_ITERATE; + + /* + * Check to see if we need to limit large files + */ + if (flags & BLOCK_FLAG_NO_LARGE) { + if (!LINUX_S_ISDIR(inode.i_mode) && + (inode.i_size_high != 0)) + return EXT2_ET_FILE_TOO_BIG; + } + + limit = fs->blocksize >> 2; + + ctx.fs = fs; + ctx.func = func; + ctx.priv_data = priv_data; + ctx.flags = flags; + ctx.bcount = 0; + if (block_buf) { + ctx.ind_buf = block_buf; + } else { + retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf); + if (retval) + return retval; + } + ctx.dind_buf = ctx.ind_buf + fs->blocksize; + ctx.tind_buf = ctx.dind_buf + fs->blocksize; + + /* + * Iterate over the HURD translator block (if present) + */ + if ((fs->super->s_creator_os == EXT2_OS_HURD) && + !(flags & BLOCK_FLAG_DATA_ONLY)) { + if (inode.osd1.hurd1.h_i_translator) { + blk64 = inode.osd1.hurd1.h_i_translator; + ret |= (*ctx.func)(fs, &blk64, + BLOCK_COUNT_TRANSLATOR, + 0, 0, priv_data); + inode.osd1.hurd1.h_i_translator = (blk_t) blk64; + if (ret & BLOCK_ABORT) + goto abort_exit; + check_for_ro_violation_goto(&ctx, ret, abort_exit); + } + } + + if (inode.i_flags & EXT4_EXTENTS_FL) { + ext2_extent_handle_t handle; + struct ext2fs_extent extent, next; + e2_blkcnt_t blockcnt = 0; + blk64_t blk, new_blk; + int op = EXT2_EXTENT_ROOT; + int uninit; + unsigned int j; + + ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle); + if (ctx.errcode) + goto abort_exit; + + while (1) { + if (op == EXT2_EXTENT_CURRENT) + ctx.errcode = 0; + else + ctx.errcode = ext2fs_extent_get(handle, op, + &extent); + if (ctx.errcode) { + if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT) + break; + ctx.errcode = 0; + if (!(flags & BLOCK_FLAG_APPEND)) + break; + next_block_set: + blk = 0; + r = (*ctx.func)(fs, &blk, blockcnt, + 0, 0, priv_data); + ret |= r; + check_for_ro_violation_goto(&ctx, ret, + extent_done); + if (r & BLOCK_CHANGED) { + ctx.errcode = + ext2fs_extent_set_bmap(handle, + (blk64_t) blockcnt++, + (blk64_t) blk, 0); + if (ctx.errcode || (ret & BLOCK_ABORT)) + break; + if (blk) + goto next_block_set; + } + break; + } + + op = EXT2_EXTENT_NEXT; + blk = extent.e_pblk; + if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { + if (ctx.flags & BLOCK_FLAG_DATA_ONLY) + continue; + if ((!(extent.e_flags & + EXT2_EXTENT_FLAGS_SECOND_VISIT) && + !(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) || + ((extent.e_flags & + EXT2_EXTENT_FLAGS_SECOND_VISIT) && + (ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) { + ret |= (*ctx.func)(fs, &blk, + -1, 0, 0, priv_data); + if (ret & BLOCK_CHANGED) { + extent.e_pblk = blk; + ctx.errcode = + ext2fs_extent_replace(handle, 0, &extent); + if (ctx.errcode) + break; + } + if (ret & BLOCK_ABORT) + break; + } + continue; + } + uninit = 0; + if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + uninit = EXT2_EXTENT_SET_BMAP_UNINIT; + + /* + * Get the next extent before we start messing + * with the current extent + */ + retval = ext2fs_extent_get(handle, op, &next); + +#if 0 + printf("lblk %llu pblk %llu len %d blockcnt %llu\n", + extent.e_lblk, extent.e_pblk, + extent.e_len, blockcnt); +#endif + if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt) + continue; + if (extent.e_lblk > (blk64_t) blockcnt) + blockcnt = extent.e_lblk; + j = blockcnt - extent.e_lblk; + blk += j; + for (blockcnt = extent.e_lblk, j = 0; + j < extent.e_len; + blk++, blockcnt++, j++) { + new_blk = blk; + r = (*ctx.func)(fs, &new_blk, blockcnt, + 0, 0, priv_data); + ret |= r; + check_for_ro_violation_goto(&ctx, ret, + extent_done); + if (r & BLOCK_CHANGED) { + ctx.errcode = + ext2fs_extent_set_bmap(handle, + (blk64_t) blockcnt, + new_blk, uninit); + if (ctx.errcode) + goto extent_done; + } + if (ret & BLOCK_ABORT) + goto extent_done; + } + if (retval == 0) { + extent = next; + op = EXT2_EXTENT_CURRENT; + } + } + + extent_done: + ext2fs_extent_free(handle); + ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */ + goto errout; + } + + /* + * Iterate over normal data blocks + */ + for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) { + if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) { + blk64 = inode.i_block[i]; + ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i, + priv_data); + inode.i_block[i] = (blk_t) blk64; + if (ret & BLOCK_ABORT) + goto abort_exit; + } + } + check_for_ro_violation_goto(&ctx, ret, abort_exit); + if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK], + 0, EXT2_IND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } else + ctx.bcount += limit; + if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK], + 0, EXT2_DIND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } else + ctx.bcount += limit * limit; + if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) { + ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK], + 0, EXT2_TIND_BLOCK, &ctx); + if (ret & BLOCK_ABORT) + goto abort_exit; + } + +abort_exit: + if (ret & BLOCK_CHANGED) { + retval = ext2fs_write_inode(fs, ino, &inode); + if (retval) { + ret |= BLOCK_ERROR; + ctx.errcode = retval; + } + } +errout: + if (!block_buf) + ext2fs_free_mem(&ctx.ind_buf); + + return (ret & BLOCK_ERROR) ? ctx.errcode : 0; +} + +/* + * Emulate the old ext2fs_block_iterate function! + */ + +struct xlate64 { + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data); + void *real_private; +}; + +static int xlate64_func(ext2_filsys fs, blk64_t *blocknr, + e2_blkcnt_t blockcnt, blk64_t ref_blk, + int ref_offset, void *priv_data) +{ + struct xlate64 *xl = (struct xlate64 *) priv_data; + int ret; + blk_t block32 = *blocknr; + + ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset, + xl->real_private); + *blocknr = block32; + return ret; +} + +errcode_t ext2fs_block_iterate2(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data) +{ + struct xlate64 xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_block_iterate3(fs, ino, flags, block_buf, + xlate64_func, &xl); +} + + +struct xlate { + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int bcount, + void *priv_data); + void *real_private; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt, + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct xlate *xl = (struct xlate *) priv_data; + + return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private); +} + +errcode_t ext2fs_block_iterate(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + void *priv_data), + void *priv_data) +{ + struct xlate xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, + block_buf, xlate_func, &xl); +} + diff --git a/src/ext2fs/bmap.c b/src/ext2fs/bmap.c new file mode 100644 index 00000000..1ed98aa4 --- /dev/null +++ b/src/ext2fs/bmap.c @@ -0,0 +1,497 @@ +/* + * bmap.c --- logical to physical block mapping + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS) +#define _BMAP_INLINE_ __inline__ +#else +#define _BMAP_INLINE_ +#endif + +extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, + blk_t block, blk_t *phys_blk); + +#define inode_bmap(inode, nr) ((inode)->i_block[(nr)]) + +static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags, + blk_t ind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + errcode_t retval; + blk_t b; + + if (!ind) { + if (flags & BMAP_SET) + return EXT2_ET_SET_BMAP_NO_IND; + *ret_blk = 0; + return 0; + } + retval = io_channel_read_blk(fs->io, ind, 1, block_buf); + if (retval) + return retval; + + if (flags & BMAP_SET) { + b = *ret_blk; +#ifdef WORDS_BIGENDIAN + b = ext2fs_swab32(b); +#endif + ((blk_t *) block_buf)[nr] = b; + return io_channel_write_blk(fs->io, ind, 1, block_buf); + } + + b = ((blk_t *) block_buf)[nr]; + +#ifdef WORDS_BIGENDIAN + b = ext2fs_swab32(b); +#endif + + if (!b && (flags & BMAP_ALLOC)) { + b = nr ? ext2fs_le32_to_cpu(((blk_t *)block_buf)[nr - 1]) : ind; + retval = ext2fs_alloc_block(fs, b, + block_buf + fs->blocksize, &b); + if (retval) + return retval; + +#ifdef WORDS_BIGENDIAN + ((blk_t *) block_buf)[nr] = ext2fs_swab32(b); +#else + ((blk_t *) block_buf)[nr] = b; +#endif + + retval = io_channel_write_blk(fs->io, ind, 1, block_buf); + if (retval) + return retval; + + (*blocks_alloc)++; + } + + *ret_blk = b; + return 0; +} + +static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags, + blk_t dind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + blk_t b = 0; + errcode_t retval; + blk_t addr_per_block; + + addr_per_block = (blk_t) fs->blocksize >> 2; + + retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf, + blocks_alloc, nr / addr_per_block, &b); + if (retval) + return retval; + retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, + nr % addr_per_block, ret_blk); + return retval; +} + +static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags, + blk_t tind, char *block_buf, + int *blocks_alloc, + blk_t nr, blk_t *ret_blk) +{ + blk_t b = 0; + errcode_t retval; + blk_t addr_per_block; + + addr_per_block = (blk_t) fs->blocksize >> 2; + + retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf, + blocks_alloc, nr / addr_per_block, &b); + if (retval) + return retval; + retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc, + nr % addr_per_block, ret_blk); + return retval; +} + +static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, int *blocks_alloc, + blk64_t *phys_blk); + +static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + blk64_t lblk, blk64_t *phys_blk) +{ + blk64_t base_block, pblock = 0; + int i; + + if (!ext2fs_has_feature_bigalloc(fs->super)) + return 0; + + base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs); + /* + * Except for the logical block (lblk) that was passed in, search all + * blocks in this logical cluster for a mapping to a physical cluster. + * If any such map exists, calculate the physical block that maps to + * the logical block and return that. + * + * The old code wouldn't even look if (block % cluster_ratio) == 0; + * this is incorrect if we're allocating blocks in reverse order. + */ + for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) { + if (base_block + i == lblk) + continue; + extent_bmap(fs, ino, inode, handle, 0, 0, + base_block + i, 0, 0, &pblock); + if (pblock) + break; + } + if (pblock == 0) + return 0; + *phys_blk = pblock - i + (lblk - base_block); + return 0; +} + +/* Try to map a logical block to an already-allocated physical cluster. */ +errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk, + blk64_t *pblk) +{ + ext2_extent_handle_t handle; + errcode_t retval; + + /* Need bigalloc and extents to be enabled */ + *pblk = 0; + if (!ext2fs_has_feature_bigalloc(fs->super) || + !(inode->i_flags & EXT4_EXTENTS_FL)) + return 0; + + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + goto out; + + retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk); + if (retval) + goto out2; + +out2: + ext2fs_extent_free(handle); +out: + return retval; +} + +static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t handle, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, int *blocks_alloc, + blk64_t *phys_blk) +{ + struct blk_alloc_ctx alloc_ctx; + struct ext2fs_extent extent; + unsigned int offset; + errcode_t retval = 0; + blk64_t blk64 = 0; + int alloc = 0; + int set_flags; + + set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0; + + if (bmap_flags & BMAP_SET) { + retval = ext2fs_extent_set_bmap(handle, block, + *phys_blk, set_flags); + return retval; + } + retval = ext2fs_extent_goto(handle, block); + if (retval) { + /* If the extent is not found, return phys_blk = 0 */ + if (retval == EXT2_ET_EXTENT_NOT_FOUND) + goto got_block; + return retval; + } + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + return retval; + offset = block - extent.e_lblk; + if (block >= extent.e_lblk && (offset <= extent.e_len)) { + *phys_blk = extent.e_pblk + offset; + if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + *ret_flags |= BMAP_RET_UNINIT; + } +got_block: + if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + implied_cluster_alloc(fs, ino, inode, handle, block, &blk64); + if (blk64) + goto set_extent; + retval = extent_bmap(fs, ino, inode, handle, block_buf, + 0, block-1, 0, blocks_alloc, &blk64); + if (retval) + blk64 = ext2fs_find_inode_goal(fs, ino, inode, block); + alloc_ctx.ino = ino; + alloc_ctx.inode = inode; + alloc_ctx.lblk = extent.e_lblk; + alloc_ctx.flags = BLOCK_ALLOC_DATA; + retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64, + &alloc_ctx); + if (retval) + return retval; + blk64 &= ~EXT2FS_CLUSTER_MASK(fs); + blk64 += EXT2FS_CLUSTER_MASK(fs) & block; + alloc++; + set_extent: + retval = ext2fs_extent_set_bmap(handle, block, + blk64, set_flags); + if (retval) { + ext2fs_block_alloc_stats2(fs, blk64, -1); + return retval; + } + /* Update inode after setting extent */ + retval = ext2fs_read_inode(fs, ino, inode); + if (retval) + return retval; + *blocks_alloc += alloc; + *phys_blk = blk64; + } + return 0; +} + +int ext2fs_file_block_offset_too_big(ext2_filsys fs, + struct ext2_inode *inode, + blk64_t offset) +{ + blk64_t addr_per_block, max_map_block; + + /* Kernel seems to cut us off at 4294967294 blocks */ + if (offset >= (1ULL << 32) - 1) + return 1; + + if (inode->i_flags & EXT4_EXTENTS_FL) + return 0; + + addr_per_block = fs->blocksize >> 2; + max_map_block = addr_per_block; + max_map_block += addr_per_block * addr_per_block; + max_map_block += addr_per_block * addr_per_block * addr_per_block; + max_map_block += 12; + + return offset >= max_map_block; +} + +errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, blk64_t *phys_blk) +{ + struct ext2_inode inode_buf; + ext2_extent_handle_t handle = 0; + blk_t addr_per_block; + blk_t b, blk32; + blk64_t b64; + char *buf = 0; + errcode_t retval = 0; + int blocks_alloc = 0, inode_dirty = 0; + struct blk_alloc_ctx alloc_ctx = { + .ino = ino, + .inode = inode, + .lblk = 0, + .flags = BLOCK_ALLOC_DATA, + }; + + if (!(bmap_flags & BMAP_SET)) + *phys_blk = 0; + + if (ret_flags) + *ret_flags = 0; + + /* Read inode structure if necessary */ + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + addr_per_block = (blk_t) fs->blocksize >> 2; + + if (ext2fs_file_block_offset_too_big(fs, inode, block)) + return EXT2_ET_FILE_TOO_BIG; + + /* + * If an inode has inline data, that means that it doesn't have + * any blocks and we shouldn't map any blocks for it. + */ + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return EXT2_ET_INLINE_DATA_NO_BLOCK; + + if (!block_buf) { + retval = ext2fs_get_array(2, fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + if (inode->i_flags & EXT4_EXTENTS_FL) { + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + goto done; + retval = extent_bmap(fs, ino, inode, handle, block_buf, + bmap_flags, block, ret_flags, + &blocks_alloc, phys_blk); + goto done; + } + + if (block < EXT2_NDIR_BLOCKS) { + if (bmap_flags & BMAP_SET) { + b = *phys_blk; + inode_bmap(inode, block) = b; + inode_dirty++; + goto done; + } + + *phys_blk = inode_bmap(inode, block); + b = block ? inode_bmap(inode, block - 1) : + ext2fs_find_inode_goal(fs, ino, inode, block); + + if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) { + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, block) = b; + blocks_alloc++; + *phys_blk = b; + } + goto done; + } + + /* Indirect block */ + block -= EXT2_NDIR_BLOCKS; + blk32 = *phys_blk; + if (block < addr_per_block) { + b = inode_bmap(inode, EXT2_IND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_IND_BLOCK-1); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_IND_BLOCK) = b; + blocks_alloc++; + } + retval = block_ind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; + goto done; + } + + /* Doubly indirect block */ + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + b = inode_bmap(inode, EXT2_DIND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_IND_BLOCK); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_DIND_BLOCK) = b; + blocks_alloc++; + } + retval = block_dind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; + goto done; + } + + /* Triply indirect block */ + block -= addr_per_block * addr_per_block; + b = inode_bmap(inode, EXT2_TIND_BLOCK); + if (!b) { + if (!(bmap_flags & BMAP_ALLOC)) { + if (bmap_flags & BMAP_SET) + retval = EXT2_ET_SET_BMAP_NO_IND; + goto done; + } + + b = inode_bmap(inode, EXT2_DIND_BLOCK); + b64 = b; + retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64, + &alloc_ctx); + b = b64; + if (retval) + goto done; + inode_bmap(inode, EXT2_TIND_BLOCK) = b; + blocks_alloc++; + } + retval = block_tind_bmap(fs, bmap_flags, b, block_buf, + &blocks_alloc, block, &blk32); + if (retval == 0) + *phys_blk = blk32; +done: + if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO)) + retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL); + if (buf) + ext2fs_free_mem(&buf); + if (handle) + ext2fs_extent_free(handle); + if ((retval == 0) && (blocks_alloc || inode_dirty)) { + ext2fs_iblk_add_blocks(fs, inode, blocks_alloc); + retval = ext2fs_write_inode(fs, ino, inode); + } + return retval; +} + +errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk_t block, + blk_t *phys_blk) +{ + errcode_t ret; + blk64_t ret_blk = *phys_blk; + + ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block, + 0, &ret_blk); + if (ret) + return ret; + if (ret_blk >= ((long long) 1 << 32)) + return EOVERFLOW; + *phys_blk = ret_blk; + return 0; +} diff --git a/src/ext2fs/bmap64.h b/src/ext2fs/bmap64.h new file mode 100644 index 00000000..d8c7a3c3 --- /dev/null +++ b/src/ext2fs/bmap64.h @@ -0,0 +1,104 @@ +/* + * bmap64.h --- 64-bit bitmap structure + * + * Copyright (C) 2007, 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +struct ext2_bmap_statistics { + int type; + struct timeval created; + +#ifdef ENABLE_BMAP_STATS_OPS + unsigned long copy_count; + unsigned long resize_count; + unsigned long mark_count; + unsigned long unmark_count; + unsigned long test_count; + unsigned long mark_ext_count; + unsigned long unmark_ext_count; + unsigned long test_ext_count; + unsigned long set_range_count; + unsigned long get_range_count; + unsigned long clear_count; + + blk64_t last_marked; + blk64_t last_tested; + blk64_t mark_back; + blk64_t test_back; + + unsigned long mark_seq; + unsigned long test_seq; +#endif /* ENABLE_BMAP_STATS_OPS */ +}; + + +struct ext2fs_struct_generic_bitmap { + errcode_t magic; + ext2_filsys fs; + struct ext2_bitmap_ops *bitmap_ops; + int flags; + __u64 start, end; + __u64 real_end; + int cluster_bits; + char *description; + void *private; + errcode_t base_error_code; +#ifdef ENABLE_BMAP_STATS + struct ext2_bmap_statistics stats; +#endif +}; + +#define EXT2FS_IS_32_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP)) + +#define EXT2FS_IS_64_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64)) + +struct ext2_bitmap_ops { + int type; + /* Generic bmap operators */ + errcode_t (*new_bmap)(ext2_filsys fs, ext2fs_generic_bitmap bmap); + void (*free_bmap)(ext2fs_generic_bitmap bitmap); + errcode_t (*copy_bmap)(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap dest); + errcode_t (*resize_bmap)(ext2fs_generic_bitmap bitmap, + __u64 new_end, + __u64 new_real_end); + /* bit set/test operators */ + int (*mark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + int (*unmark_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + int (*test_bmap)(ext2fs_generic_bitmap bitmap, __u64 arg); + void (*mark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num); + void (*unmark_bmap_extent)(ext2fs_generic_bitmap bitmap, __u64 arg, + unsigned int num); + int (*test_clear_bmap_extent)(ext2fs_generic_bitmap bitmap, + __u64 arg, unsigned int num); + errcode_t (*set_bmap_range)(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *in); + errcode_t (*get_bmap_range)(ext2fs_generic_bitmap bitmap, + __u64 start, size_t num, void *out); + void (*clear_bmap)(ext2fs_generic_bitmap bitmap); + void (*print_stats)(ext2fs_generic_bitmap); + + /* Find the first zero bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + errcode_t (*find_first_zero)(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out); + /* Find the first set bit between start and end, inclusive. + * May be NULL, in which case a generic function is used. */ + errcode_t (*find_first_set)(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out); +}; + +extern struct ext2_bitmap_ops ext2fs_blkmap64_bitarray; +extern struct ext2_bitmap_ops ext2fs_blkmap64_rbtree; diff --git a/src/ext2fs/closefs.c b/src/ext2fs/closefs.c new file mode 100644 index 00000000..1d4d5b7f --- /dev/null +++ b/src/ext2fs/closefs.c @@ -0,0 +1,512 @@ +/* + * closefs.c --- close an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +static int test_root(unsigned int a, unsigned int b) +{ + while (1) { + if (a < b) + return 0; + if (a == b) + return 1; + if (a % b) + return 0; + a = a / b; + } +} + +int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group) +{ + if (group == 0) + return 1; + if (ext2fs_has_feature_sparse_super2(fs->super)) { + if (group == fs->super->s_backup_bgs[0] || + group == fs->super->s_backup_bgs[1]) + return 1; + return 0; + } + if ((group <= 1) || !ext2fs_has_feature_sparse_super(fs->super)) + return 1; + if (!(group & 1)) + return 0; + if (test_root(group, 3) || (test_root(group, 5)) || + test_root(group, 7)) + return 1; + + return 0; +} + +/* + * ext2fs_super_and_bgd_loc2() + * @fs: ext2 fs pointer + * @group given block group + * @ret_super_blk: if !NULL, returns super block location + * @ret_old_desc_blk: if !NULL, returns location of the old block + * group descriptor + * @ret_new_desc_blk: if !NULL, returns location of meta_bg block + * group descriptor + * @ret_used_blks: if !NULL, returns number of blocks used by + * super block and group_descriptors. + * + * Returns errcode_t of 0 + */ +errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, + dgrp_t group, + blk64_t *ret_super_blk, + blk64_t *ret_old_desc_blk, + blk64_t *ret_new_desc_blk, + blk_t *ret_used_blks) +{ + blk64_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0; + unsigned int meta_bg, meta_bg_size; + blk_t numblocks = 0; + blk64_t old_desc_blocks; + int has_super; + + group_block = ext2fs_group_first_block2(fs, group); + if (group_block == 0 && fs->blocksize == 1024) + group_block = 1; /* Deal with 1024 blocksize && bigalloc */ + + if (ext2fs_has_feature_meta_bg(fs->super)) + old_desc_blocks = fs->super->s_first_meta_bg; + else + old_desc_blocks = + fs->desc_blocks + fs->super->s_reserved_gdt_blocks; + + has_super = ext2fs_bg_has_super(fs, group); + + if (has_super) { + super_blk = group_block; + numblocks++; + } + meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); + meta_bg = group / meta_bg_size; + + if (!ext2fs_has_feature_meta_bg(fs->super) || + (meta_bg < fs->super->s_first_meta_bg)) { + if (has_super) { + old_desc_blk = group_block + 1; + numblocks += old_desc_blocks; + } + } else { + if (((group % meta_bg_size) == 0) || + ((group % meta_bg_size) == 1) || + ((group % meta_bg_size) == (meta_bg_size-1))) { + if (has_super) + has_super = 1; + new_desc_blk = group_block + has_super; + numblocks++; + } + } + + if (ret_super_blk) + *ret_super_blk = super_blk; + if (ret_old_desc_blk) + *ret_old_desc_blk = old_desc_blk; + if (ret_new_desc_blk) + *ret_new_desc_blk = new_desc_blk; + if (ret_used_blks) + *ret_used_blks = numblocks; + + return 0; +} + +/* + * This function returns the location of the superblock, block group + * descriptors for a given block group. It currently returns the + * number of free blocks assuming that inode table and allocation + * bitmaps will be in the group. This is not necessarily the case + * when the flex_bg feature is enabled, so callers should take care! + * It was only really intended for use by mke2fs, and even there it's + * not that useful. + * + * The ext2fs_super_and_bgd_loc2() function is 64-bit block number + * capable and returns the number of blocks used by super block and + * group descriptors. + */ +int ext2fs_super_and_bgd_loc(ext2_filsys fs, + dgrp_t group, + blk_t *ret_super_blk, + blk_t *ret_old_desc_blk, + blk_t *ret_new_desc_blk, + int *ret_meta_bg) +{ + blk64_t ret_super_blk2; + blk64_t ret_old_desc_blk2; + blk64_t ret_new_desc_blk2; + blk_t ret_used_blks; + blk_t numblocks; + unsigned int meta_bg_size; + + ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2, + &ret_old_desc_blk2, + &ret_new_desc_blk2, + &ret_used_blks); + + numblocks = ext2fs_group_blocks_count(fs, group); + + if (ret_super_blk) + *ret_super_blk = (blk_t)ret_super_blk2; + if (ret_old_desc_blk) + *ret_old_desc_blk = (blk_t)ret_old_desc_blk2; + if (ret_new_desc_blk) + *ret_new_desc_blk = (blk_t)ret_new_desc_blk2; + if (ret_meta_bg) { + meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super); + *ret_meta_bg = group / meta_bg_size; + } + + numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks; + + return numblocks; +} + +/* + * This function forces out the primary superblock. We need to only + * write out those fields which we have changed, since if the + * filesystem is mounted, it may have changed some of the other + * fields. + * + * It takes as input a superblock which has already been byte swapped + * (if necessary). + * + */ +static errcode_t write_primary_superblock(ext2_filsys fs, + struct ext2_super_block *super) +{ + __u16 *old_super, *new_super; + int check_idx, write_idx, size; + errcode_t retval; + + if (!fs->io->manager->write_byte || !fs->orig_super) { + fallback: + io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET); + retval = io_channel_write_blk64(fs->io, 1, -SUPERBLOCK_SIZE, + super); + io_channel_set_blksize(fs->io, fs->blocksize); + return retval; + } + + old_super = (__u16 *) fs->orig_super; + new_super = (__u16 *) super; + + for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) { + if (old_super[check_idx] == new_super[check_idx]) + continue; + write_idx = check_idx; + for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++) + if (old_super[check_idx] == new_super[check_idx]) + break; + size = 2 * (check_idx - write_idx); +#if 0 + printf("Writing %d bytes starting at %d\n", + size, write_idx*2); +#endif + retval = io_channel_write_byte(fs->io, + SUPERBLOCK_OFFSET + (2 * write_idx), size, + new_super + write_idx); + if (retval == EXT2_ET_UNIMPLEMENTED) + goto fallback; + if (retval) + return retval; + } + memcpy(fs->orig_super, super, SUPERBLOCK_SIZE); + return 0; +} + + +/* + * Updates the revision to EXT2_DYNAMIC_REV + */ +void ext2fs_update_dynamic_rev(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + + if (sb->s_rev_level > EXT2_GOOD_OLD_REV) + return; + + sb->s_rev_level = EXT2_DYNAMIC_REV; + sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + /* s_uuid is handled by e2fsck already */ + /* other fields should be left alone */ +} + +static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group, + blk64_t group_block, + struct ext2_super_block *super_shadow) +{ + errcode_t retval; + dgrp_t sgrp = group; + + if (sgrp > ((1 << 16) - 1)) + sgrp = (1 << 16) - 1; + + super_shadow->s_block_group_nr = ext2fs_cpu_to_le16(sgrp); + + retval = ext2fs_superblock_csum_set(fs, super_shadow); + if (retval) + return retval; + + return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE, + super_shadow); +} + +errcode_t ext2fs_flush(ext2_filsys fs) +{ + return ext2fs_flush2(fs, 0); +} + +errcode_t ext2fs_flush2(ext2_filsys fs, int flags) +{ + dgrp_t i; + errcode_t retval; + unsigned long fs_state; + __u32 feature_incompat; + struct ext2_super_block *super_shadow = 0; + struct opaque_ext2_group_desc *group_shadow = 0; +#ifdef WORDS_BIGENDIAN + struct ext2_group_desc *gdp; + dgrp_t j; +#endif + char *group_ptr; + blk64_t old_desc_blocks; + struct ext2fs_numeric_progress_struct progress; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + fs_state = fs->super->s_state; + feature_incompat = fs->super->s_feature_incompat; + + fs->super->s_wtime = fs->now ? fs->now : time(NULL); + fs->super->s_block_group_nr = 0; + + /* + * If the write_bitmaps() function is present, call it to + * flush the bitmaps. This is done this way so that a simple + * program that doesn't mess with the bitmaps doesn't need to + * drag in the bitmaps.c code. + * + * Bitmap checksums live in the group descriptor, so the + * bitmaps need to be written before the descriptors. + */ + if (fs->write_bitmaps) { + retval = fs->write_bitmaps(fs); + if (retval) + goto errout; + } + + /* + * Set the state of the FS to be non-valid. (The state has + * already been backed up earlier, and will be restored after + * we write out the backup superblocks.) + */ + fs->super->s_state &= ~EXT2_VALID_FS; + ext2fs_clear_feature_journal_needs_recovery(fs->super); + + /* Byte swap the superblock and the group descriptors if necessary */ +#ifdef WORDS_BIGENDIAN + retval = EXT2_ET_NO_MEMORY; + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); + if (retval) + goto errout; + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &group_shadow); + if (retval) + goto errout; + memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block)); + memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize * + fs->desc_blocks); + + ext2fs_swap_super(super_shadow); + for (j = 0; j < fs->group_desc_count; j++) { + gdp = ext2fs_group_desc(fs, group_shadow, j); + ext2fs_swap_group_desc2(fs, gdp); + } +#else + super_shadow = fs->super; + group_shadow = fs->group_desc; +#endif + + /* + * If this is an external journal device, don't write out the + * block group descriptors or any of the backup superblocks + */ + if (ext2fs_has_feature_journal_dev(fs->super)) + goto write_primary_superblock_only; + + /* + * Write out the master group descriptors, and the backup + * superblocks and group descriptors. + */ + group_ptr = (char *) group_shadow; + if (ext2fs_has_feature_meta_bg(fs->super)) { + old_desc_blocks = fs->super->s_first_meta_bg; + if (old_desc_blocks > fs->desc_blocks) + old_desc_blocks = fs->desc_blocks; + } else + old_desc_blocks = fs->desc_blocks; + + if (fs->progress_ops && fs->progress_ops->init) + (fs->progress_ops->init)(fs, &progress, NULL, + fs->group_desc_count); + + + for (i = 0; i < fs->group_desc_count; i++) { + blk64_t super_blk, old_desc_blk, new_desc_blk; + + if (fs->progress_ops && fs->progress_ops->update) + (fs->progress_ops->update)(fs, &progress, i); + ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk, + &new_desc_blk, 0); + + if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) { + retval = write_backup_super(fs, i, super_blk, + super_shadow); + if (retval) + goto errout; + } + if (fs->flags & EXT2_FLAG_SUPER_ONLY) + continue; + if ((old_desc_blk) && + (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) { + retval = io_channel_write_blk64(fs->io, + old_desc_blk, old_desc_blocks, group_ptr); + if (retval) + goto errout; + } + if (new_desc_blk) { + int meta_bg = i / EXT2_DESC_PER_BLOCK(fs->super); + + retval = io_channel_write_blk64(fs->io, new_desc_blk, + 1, group_ptr + (meta_bg*fs->blocksize)); + if (retval) + goto errout; + } + } + + if (fs->progress_ops && fs->progress_ops->close) + (fs->progress_ops->close)(fs, &progress, NULL); + +write_primary_superblock_only: + /* + * Write out master superblock. This has to be done + * separately, since it is located at a fixed location + * (SUPERBLOCK_OFFSET). We flush all other pending changes + * out to disk first, just to avoid a race condition with an + * insy-tinsy window.... + */ + + fs->super->s_block_group_nr = 0; + fs->super->s_state = fs_state; + fs->super->s_feature_incompat = feature_incompat; +#ifdef WORDS_BIGENDIAN + *super_shadow = *fs->super; + ext2fs_swap_super(super_shadow); +#endif + + retval = ext2fs_superblock_csum_set(fs, super_shadow); + if (retval) + return retval; + + if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) { + retval = io_channel_flush(fs->io); + if (retval) + goto errout; + } + retval = write_primary_superblock(fs, super_shadow); + if (retval) + goto errout; + + fs->flags &= ~EXT2_FLAG_DIRTY; + + if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) { + retval = io_channel_flush(fs->io); + if (retval) + goto errout; + } +errout: + fs->super->s_state = fs_state; +#ifdef WORDS_BIGENDIAN + if (super_shadow) + ext2fs_free_mem(&super_shadow); + if (group_shadow) + ext2fs_free_mem(&group_shadow); +#endif + return retval; +} + +errcode_t ext2fs_close_free(ext2_filsys *fs_ptr) +{ + errcode_t ret; + ext2_filsys fs = *fs_ptr; + + ret = ext2fs_close2(fs, 0); + if (ret) + ext2fs_free(fs); + *fs_ptr = NULL; + return ret; +} + +errcode_t ext2fs_close(ext2_filsys fs) +{ + return ext2fs_close2(fs, 0); +} + +errcode_t ext2fs_close2(ext2_filsys fs, int flags) +{ + errcode_t retval; + int meta_blks; + io_stats stats = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (fs->write_bitmaps) { + retval = fs->write_bitmaps(fs); + if (retval) + return retval; + } + if (fs->super->s_kbytes_written && + fs->io->manager->get_stats) + fs->io->manager->get_stats(fs->io, &stats); + if (stats && stats->bytes_written && (fs->flags & EXT2_FLAG_RW)) { + fs->super->s_kbytes_written += stats->bytes_written >> 10; + meta_blks = fs->desc_blocks + 1; + if (!(fs->flags & EXT2_FLAG_SUPER_ONLY)) + fs->super->s_kbytes_written += meta_blks / + (fs->blocksize / 1024); + if ((fs->flags & EXT2_FLAG_DIRTY) == 0) + fs->flags |= EXT2_FLAG_SUPER_ONLY | EXT2_FLAG_DIRTY; + } + if (fs->flags & EXT2_FLAG_DIRTY) { + retval = ext2fs_flush2(fs, flags); + if (retval) + return retval; + } + + retval = ext2fs_mmp_stop(fs); + if (retval) + return retval; + + ext2fs_free(fs); + return 0; +} + diff --git a/src/ext2fs/com_err.h b/src/ext2fs/com_err.h new file mode 100644 index 00000000..1725f816 --- /dev/null +++ b/src/ext2fs/com_err.h @@ -0,0 +1,66 @@ +/* + * Header file for common error description library. + * + * Copyright 1988, Student Information Processing Board of the + * Massachusetts Institute of Technology. + * + * For copyright and distribution info, see the documentation supplied + * with this package. + */ + +#if !defined(__COM_ERR_H) && !defined(__COM_ERR_H__) + +#ifdef __GNUC__ +#define COM_ERR_ATTR(x) __attribute__(x) +#else +#define COM_ERR_ATTR(x) +#endif + +#include +#include + +#include "rufus.h" + +typedef long errcode_t; + +struct error_table { + char const * const * msgs; + long base; + int n_msgs; +}; +struct et_list; + +#define VA_ARGS(...) , ##__VA_ARGS__ +#define com_err(src, err, fmt, ...) uprintf("%s: [%d] " # fmt, src?src:"ext2fs", err VA_ARGS(__VA_ARGS__)) + +extern char const *error_message (long); +extern void (*com_err_hook) (const char *, long, const char *, va_list); +extern void (*set_com_err_hook (void (*) (const char *, long, + const char *, va_list))) + (const char *, long, const char *, va_list); +extern void (*reset_com_err_hook (void)) (const char *, long, + const char *, va_list); +extern int init_error_table(const char * const *msgs, long base, int count); +extern char *(*set_com_err_gettext (char *(*) (const char *))) + (const char *); + +extern errcode_t add_error_table(const struct error_table * et); +extern errcode_t remove_error_table(const struct error_table * et); +extern void add_to_error_table(struct et_list *new_table); + +/* Provided for Heimdall compatibility */ +extern const char *com_right(struct et_list *list, long code); +extern const char *com_right_r(struct et_list *list, long code, char *str, size_t len); +extern void initialize_error_table_r(struct et_list **list, + const char **messages, + int num_errors, + long base); +extern void free_error_table(struct et_list *et); + +/* Provided for compatibility with other com_err libraries */ +extern int et_list_lock(void); +extern int et_list_unlock(void); + +#define __COM_ERR_H +#define __COM_ERR_H__ +#endif /* !defined(__COM_ERR_H) && !defined(__COM_ERR_H__)*/ diff --git a/src/ext2fs/config.h b/src/ext2fs/config.h new file mode 100644 index 00000000..7a0eaef5 --- /dev/null +++ b/src/ext2fs/config.h @@ -0,0 +1,428 @@ +#ifdef _CRTDBG_MAP_ALLOC +#include +#include +#endif + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#define ENABLE_NLS 0 + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have the `asprintf' function. */ +#define HAVE_ASPRINTF 1 + +/* Define to 1 if the compiler understands __builtin_expect. */ +#define HAVE_BUILTIN_EXPECT 1 + +/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_FEOF_UNLOCKED 0 + +/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if + you don't. */ +#define HAVE_DECL_FGETS_UNLOCKED 0 + +/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you + don't. */ +#define HAVE_DECL_GETC_UNLOCKED 0 + +/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you + don't. */ +#define HAVE_DECL__SNPRINTF 1 + +/* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you + don't. */ +#define HAVE_DECL__SNWPRINTF 1 + +/* Define to 1 if you have the `fwprintf' function. */ +#define HAVE_FWPRINTF 1 + +/* Define to 1 if you have the `getcwd' function. */ +#define HAVE_GETCWD 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define if you have the iconv() function and it works. */ +#define HAVE_ICONV 1 + +/* Define if you have the 'intmax_t' type in or . */ +#define HAVE_INTMAX_T 1 + +/* Define to 1 if the system has the type `intptr_t'. */ +#define HAVE_INTPTR_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define if exists, doesn't clash with , and + declares uintmax_t. */ +#define HAVE_INTTYPES_H_WITH_UINTMAX 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if the system has the type 'long long int'. */ +#define HAVE_LONG_LONG_INT 1 + +/* Define to 1 if lseek64 declared in unistd.h */ +#define HAVE_LSEEK64_PROTOTYPE 1 + +/* Define to 1 if you have the `mbrtowc' function. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mempcpy' function. */ +#define HAVE_MEMPCPY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define if the defines PTHREAD_MUTEX_RECURSIVE. */ +#define HAVE_PTHREAD_MUTEX_RECURSIVE 1 + +/* Define if the POSIX multithreading library has read/write locks. */ +#define HAVE_PTHREAD_RWLOCK 1 + +/* Define to 1 if you have the `putenv' function. */ +#define HAVE_PUTENV 1 + +/* Define to 1 if dirent has d_reclen */ +#define HAVE_RECLEN_DIRENT 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define if exists, doesn't clash with , and declares + uintmax_t. */ +#define HAVE_STDINT_H_WITH_UINTMAX 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `tsearch' function. */ +#define HAVE_TSEARCH 1 + +/* Define to 1 if ssize_t declared */ +#define HAVE_TYPE_SSIZE_T 1 + +/* Define if you have the 'uintmax_t' type in or . */ +#define HAVE_UINTMAX_T 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type 'unsigned long long int'. */ +#define HAVE_UNSIGNED_LONG_LONG_INT 1 + +/* Define to 1 or 0, depending whether the compiler supports simple visibility + declarations. */ +#define HAVE_VISIBILITY 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define if you have the 'wchar_t' type. */ +#define HAVE_WCHAR_T 1 + +/* Define to 1 if you have the `wcrtomb' function. */ +#define HAVE_WCRTOMB 1 + +/* Define to 1 if you have the `wcslen' function. */ +#define HAVE_WCSLEN 1 + +/* Define to 1 if you have the `wcsnlen' function. */ +#define HAVE_WCSNLEN 1 + +/* Define if you have the 'wint_t' type. */ +#define HAVE_WINT_T 1 + +/* Define to 1 if O_NOATIME works. */ +#define HAVE_WORKING_O_NOATIME 0 + +/* Define to 1 if O_NOFOLLOW works. */ +#define HAVE_WORKING_O_NOFOLLOW 0 + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define if integer division by zero raises signal SIGFPE. */ +#define INTDIV0_RAISES_SIGFPE 1 + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT sizeof(int) + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG sizeof(long) + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG sizeof(long long) + +/* The size of `off_t', as computed by sizeof. */ +#define SIZEOF_OFF_T 4 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* The size of `time_t', as computed by sizeof. */ +#define SIZEOF_TIME_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* If the compiler supports a TLS storage class define it to that here */ +#define TLS __thread + +/* Define if the POSIX multithreading library can be used. */ +#define USE_POSIX_THREADS 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + +/* Define to 1 to build uuidd */ +#define USE_UUIDD 1 + +/* Define if the native Windows multithreading API can be used. */ +/* #undef USE_WINDOWS_THREADS */ +#define USE_WINDOWS_THREADS 1 + +/* version for gettext */ +//#define VERSION "0.14.1" + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Please see the Gnulib manual for how to use these macros. + + Suppress extern inline with HP-UX cc, as it appears to be broken; see + . + + Suppress extern inline with Sun C in standards-conformance mode, as it + mishandles inline functions that call each other. E.g., for 'inline void f + (void) { } inline void g (void) { f (); }', c99 incorrectly complains + 'reference to static identifier "f" in extern inline function'. + This bug was observed with Sun C 5.12 SunOS_i386 2011/11/16. + + Suppress extern inline (with or without __attribute__ ((__gnu_inline__))) + on configurations that mistakenly use 'static inline' to implement + functions or macros in standard C headers like . For example, + if isdigit is mistakenly implemented via a static inline function, + a program containing an extern inline function that calls isdigit + may not work since the C standard prohibits extern inline functions + from calling static functions. This bug is known to occur on: + + OS X 10.8 and earlier; see: + http://lists.gnu.org/archive/html/bug-gnulib/2012-12/msg00023.html + + DragonFly; see + http://muscles.dragonflybsd.org/bulk/bleeding-edge-potential/latest-per-pkg/ah-tty-0.3.12.log + + FreeBSD; see: + http://lists.gnu.org/archive/html/bug-gnulib/2014-07/msg00104.html + + OS X 10.9 has a macro __header_inline indicating the bug is fixed for C and + for clang but remains for g++; see . + Assume DragonFly and FreeBSD will be similar. */ +#if (((defined __APPLE__ && defined __MACH__) \ + || defined __DragonFly__ || defined __FreeBSD__) \ + && (defined __header_inline \ + ? (defined __cplusplus && defined __GNUC_STDC_INLINE__ \ + && ! defined __clang__) \ + : ((! defined _DONT_USE_CTYPE_INLINE_ \ + && (defined __GNUC__ || defined __cplusplus)) \ + || (defined _FORTIFY_SOURCE && 0 < _FORTIFY_SOURCE \ + && defined __GNUC__ && ! defined __cplusplus)))) +# define _GL_EXTERN_INLINE_STDHEADER_BUG +#endif +#if ((__GNUC__ \ + ? defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ \ + : (199901L <= __STDC_VERSION__ \ + && !defined __HP_cc \ + && !defined __PGI \ + && !(defined __SUNPRO_C && __STDC__))) \ + && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) +# define _GL_INLINE inline +# define _GL_EXTERN_INLINE extern inline +# define _GL_EXTERN_INLINE_IN_USE +#elif (2 < __GNUC__ + (7 <= __GNUC_MINOR__) && !defined __STRICT_ANSI__ \ + && !defined _GL_EXTERN_INLINE_STDHEADER_BUG) +# if defined __GNUC_GNU_INLINE__ && __GNUC_GNU_INLINE__ + /* __gnu_inline__ suppresses a GCC 4.2 diagnostic. */ +# define _GL_INLINE extern inline __attribute__ ((__gnu_inline__)) +# else +# define _GL_INLINE extern inline +# endif +# define _GL_EXTERN_INLINE extern +# define _GL_EXTERN_INLINE_IN_USE +#else +# define _GL_INLINE static _GL_UNUSED +# define _GL_EXTERN_INLINE static _GL_UNUSED +#endif + +/* In GCC 4.6 (inclusive) to 5.1 (exclusive), + suppress bogus "no previous prototype for 'FOO'" + and "no previous declaration for 'FOO'" diagnostics, + when FOO is an inline function in the header; see + and + . */ +#if __GNUC__ == 4 && 6 <= __GNUC_MINOR__ +# if defined __GNUC_STDC_INLINE__ && __GNUC_STDC_INLINE__ +# define _GL_INLINE_HEADER_CONST_PRAGMA +# else +# define _GL_INLINE_HEADER_CONST_PRAGMA \ + _Pragma ("GCC diagnostic ignored \"-Wsuggest-attribute=const\"") +# endif +# define _GL_INLINE_HEADER_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wmissing-prototypes\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmissing-declarations\"") \ + _GL_INLINE_HEADER_CONST_PRAGMA +# define _GL_INLINE_HEADER_END \ + _Pragma ("GCC diagnostic pop") +#else +# define _GL_INLINE_HEADER_BEGIN +# define _GL_INLINE_HEADER_END +#endif + +/* Define as a marker that can be attached to declarations that might not + be used. This helps to reduce warnings, such as from + GCC -Wunused-parameter. */ +#ifndef _GL_UNUSED +# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) +# define _GL_UNUSED __attribute__ ((__unused__)) +# else +# define _GL_UNUSED +# endif +#endif + +/* The __pure__ attribute was added in gcc 2.96. */ +#ifndef _GL_ATTRIBUTE_PURE +# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) +# define _GL_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define _GL_ATTRIBUTE_PURE /* empty */ +# endif +#endif + +#ifdef _MSC_VER +#define __attribute__(x) +#endif + + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define as the type of the result of subtracting two pointers, if the system + doesn't define it. */ +/* #undef ptrdiff_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to unsigned long or unsigned long long if and + don't define. */ +/* #undef uintmax_t */ + +#define __libc_lock_t gl_lock_t +#define __libc_lock_define gl_lock_define +#define __libc_lock_define_initialized gl_lock_define_initialized +#define __libc_lock_init gl_lock_init +#define __libc_lock_lock gl_lock_lock +#define __libc_lock_unlock gl_lock_unlock +#define __libc_lock_recursive_t gl_recursive_lock_t +#define __libc_lock_define_recursive gl_recursive_lock_define +#define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized +#define __libc_lock_init_recursive gl_recursive_lock_init +#define __libc_lock_lock_recursive gl_recursive_lock_lock +#define __libc_lock_unlock_recursive gl_recursive_lock_unlock +#define glthread_in_use libintl_thread_in_use +#define glthread_lock_init_func libintl_lock_init_func +#define glthread_lock_lock_func libintl_lock_lock_func +#define glthread_lock_unlock_func libintl_lock_unlock_func +#define glthread_lock_destroy_func libintl_lock_destroy_func +#define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded +#define glthread_rwlock_init_func libintl_rwlock_init_func +#define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded +#define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func +#define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded +#define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func +#define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded +#define glthread_rwlock_unlock_func libintl_rwlock_unlock_func +#define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded +#define glthread_rwlock_destroy_func libintl_rwlock_destroy_func +#define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded +#define glthread_recursive_lock_init_func libintl_recursive_lock_init_func +#define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded +#define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func +#define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded +#define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func +#define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded +#define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func +#define glthread_once_func libintl_once_func +#define glthread_once_singlethreaded libintl_once_singlethreaded +#define glthread_once_multithreaded libintl_once_multithreaded diff --git a/src/ext2fs/crc16.c b/src/ext2fs/crc16.c new file mode 100644 index 00000000..2fdeb24e --- /dev/null +++ b/src/ext2fs/crc16.c @@ -0,0 +1,74 @@ +/* + * crc16.c + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include "config.h" +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +#include "crc16.h" + +/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */ +static __u16 const crc16_table[256] = { + 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, + 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, + 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, + 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, + 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, + 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, + 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, + 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, + 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, + 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, + 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, + 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, + 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, + 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, + 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, + 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, + 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, + 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, + 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, + 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, + 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, + 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, + 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, + 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, + 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, + 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, + 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, + 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, + 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, + 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, + 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, + 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 +}; + +/** + * Compute the CRC-16 for the data buffer + * + * @param crc previous CRC value + * @param buffer data pointer + * @param len number of bytes in the buffer + * @return the updated CRC value + */ +crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len) +{ + const unsigned char *cp = buffer; + + while (len--) + /* + * for an unknown reason, PPC treats __u16 as signed + * and keeps doing sign extension on the value. + * Instead, use only the low 16 bits of an unsigned + * int for holding the CRC value to avoid this. + */ + crc = (((crc >> 8) & 0xffU) ^ + crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU; + return crc; +} diff --git a/src/ext2fs/crc16.h b/src/ext2fs/crc16.h new file mode 100644 index 00000000..322e68dd --- /dev/null +++ b/src/ext2fs/crc16.h @@ -0,0 +1,26 @@ +/* + * crc16.h - CRC-16 routine + * + * Implements the standard CRC-16: + * Width 16 + * Poly 0x8005 (x16 + x15 + x2 + 1) + * Init 0 + * + * Copyright (c) 2005 Ben Gardner + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#ifndef __CRC16_H +#define __CRC16_H + +/* for an unknown reason, PPC treats __u16 as signed and keeps doing sign + * extension on the value. Instead, use only the low 16 bits of an + * unsigned int for holding the CRC value to avoid this. + */ +typedef unsigned int crc16_t; + +extern crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len); + +#endif /* __CRC16_H */ diff --git a/src/ext2fs/crc32c.c b/src/ext2fs/crc32c.c new file mode 100644 index 00000000..533a0d55 --- /dev/null +++ b/src/ext2fs/crc32c.c @@ -0,0 +1,934 @@ +/* + * crc32c.c + * + * August 26, 2011 Darrick J. Wong + * Reuse Bob Pearson's slice-by-8 implementation for e2fsprogs. + * + * July 20, 2011 Bob Pearson + * added slice by 8 algorithm to the existing conventional and + * slice by 4 algorithms. + * + * Oct 15, 2000 Matt Domsch + * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! + * Code was from the public domain, copyright abandoned. Code was + * subsequently included in the kernel, thus was re-licensed under the + * GNU GPL v2. + * + * Oct 12, 2000 Matt Domsch + * Same crc32 function was used in 5 other places in the kernel. + * I made one version, and deleted the others. + * There are various incantations of crc32(). Some use a seed of 0 or ~0. + * Some xor at the end with ~0. The generic crc32() function takes + * seed as an argument, and doesn't xor at the end. Then individual + * users can do whatever they need. + * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. + * fs/jffs2 uses seed 0, doesn't xor with ~0. + * fs/partitions/efi.c uses seed ~0, xor's with ~0. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ +#include "config.h" +#include +#include +#include +#ifndef min +#define min(x, y) ((x) > (y) ? (y) : (x)) +#endif +#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1) +#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define PTR_ALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a))) +#include "crc32c_defs.h" + +#include "ext2fs.h" +#ifdef WORDS_BIGENDIAN +#define __constant_cpu_to_le32(x) ___constant_swab32((x)) +#define __constant_cpu_to_be32(x) (x) +#define __be32_to_cpu(x) (x) +#define __cpu_to_be32(x) (x) +#define __cpu_to_le32(x) (ext2fs_cpu_to_le32((x))) +#define __le32_to_cpu(x) (ext2fs_le32_to_cpu((x))) +#else +#define __constant_cpu_to_le32(x) (x) +#define __constant_cpu_to_be32(x) ___constant_swab32((x)) +#define __be32_to_cpu(x) (ext2fs_be32_to_cpu((x))) +#define __cpu_to_be32(x) (ext2fs_cpu_to_be32((x))) +#define __cpu_to_le32(x) (x) +#define __le32_to_cpu(x) (x) +#endif + +#if CRC_LE_BITS > 8 +# define tole(x) __constant_cpu_to_le32(x) +#else +# define tole(x) (x) +#endif + +#if CRC_BE_BITS > 8 +# define tobe(x) __constant_cpu_to_be32(x) +#else +# define tobe(x) (x) +#endif + +#include "crc32c_table.h" + +#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 + +/* implements slicing-by-4 or slicing-by-8 algorithm */ +static inline uint32_t +crc32_body(uint32_t crc, unsigned char const *buf, size_t len, + const uint32_t (*tab)[256]) +{ +# ifndef WORDS_BIGENDIAN +# define DO_CRC(x) (crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8)) +# define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \ + t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255]) +# define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \ + t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255]) +# else +# define DO_CRC(x) (crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8)) +# define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \ + t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255]) +# define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \ + t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255]) +# endif + const uint32_t *b; + size_t rem_len; + const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3]; + const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7]; + uint32_t q; + + /* Align it */ + if (unlikely((uintptr_t)buf & 3 && len)) { + do { + DO_CRC(*buf++); + } while ((--len) && ((uintptr_t)buf)&3); + } + +# if CRC_LE_BITS == 32 + rem_len = len & 3; + len = len >> 2; +# else + rem_len = len & 7; + len = len >> 3; +# endif + + b = (const uint32_t *)buf; + for (--b; len; --len) { + q = crc ^ *++b; /* use pre increment for speed */ +# if CRC_LE_BITS == 32 + crc = DO_CRC4; +# else + crc = DO_CRC8; + q = *++b; + crc ^= DO_CRC4; +# endif + } + len = rem_len; + /* And the last few bytes */ + if (len) { + const uint8_t *p = (const uint8_t *)(b + 1) - 1; + do { + DO_CRC(*++p); /* use pre increment for speed */ + } while (--len); + } + return crc; +#undef DO_CRC +#undef DO_CRC4 +#undef DO_CRC8 +} +#endif + +/** + * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32 + * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for + * other uses, or the previous crc32 value if computing incrementally. + * @p: pointer to buffer over which CRC is run + * @len: length of buffer @p + */ +static inline uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p, + size_t len, const uint32_t (*tab)[256], + uint32_t polynomial EXT2FS_ATTR((unused))) +{ +#if CRC_LE_BITS == 1 + int i; + while (len--) { + crc ^= *p++; + for (i = 0; i < 8; i++) + crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); + } +# elif CRC_LE_BITS == 2 + while (len--) { + crc ^= *p++; + crc = (crc >> 2) ^ tab[0][crc & 3]; + crc = (crc >> 2) ^ tab[0][crc & 3]; + crc = (crc >> 2) ^ tab[0][crc & 3]; + crc = (crc >> 2) ^ tab[0][crc & 3]; + } +# elif CRC_LE_BITS == 4 + while (len--) { + crc ^= *p++; + crc = (crc >> 4) ^ tab[0][crc & 15]; + crc = (crc >> 4) ^ tab[0][crc & 15]; + } +# elif CRC_LE_BITS == 8 + /* aka Sarwate algorithm */ + while (len--) { + crc ^= *p++; + crc = (crc >> 8) ^ tab[0][crc & 255]; + } +# else + crc = __cpu_to_le32(crc); + crc = crc32_body(crc, p, len, tab); + crc = __le32_to_cpu(crc); +#endif + return crc; +} + +uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len) +{ + return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE); +} + +/** + * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32 + * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for + * other uses, or the previous crc32 value if computing incrementally. + * @p: pointer to buffer over which CRC is run + * @len: length of buffer @p + */ +static inline uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p, + size_t len, const uint32_t (*tab)[256], + uint32_t polynomial EXT2FS_ATTR((unused))) +{ +#if CRC_BE_BITS == 1 + int i; + while (len--) { + crc ^= *p++ << 24; + for (i = 0; i < 8; i++) + crc = + (crc << 1) ^ ((crc & 0x80000000) ? polynomial : + 0); + } +# elif CRC_BE_BITS == 2 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + crc = (crc << 2) ^ tab[0][crc >> 30]; + } +# elif CRC_BE_BITS == 4 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 4) ^ tab[0][crc >> 28]; + crc = (crc << 4) ^ tab[0][crc >> 28]; + } +# elif CRC_BE_BITS == 8 + while (len--) { + crc ^= *p++ << 24; + crc = (crc << 8) ^ tab[0][crc >> 24]; + } +# else + crc = __cpu_to_be32(crc); + crc = crc32_body(crc, p, len, tab); + crc = __be32_to_cpu(crc); +# endif + return crc; +} + +uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len) +{ + return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE); +} + +#ifdef UNITTEST +static uint8_t test_buf[] = { + 0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48, + 0xda, 0xad, 0x14, 0xbd, 0x03, 0x3a, 0x58, 0x5e, + 0x6e, 0xd1, 0x56, 0xc9, 0x2e, 0xc4, 0xcb, 0x6b, + 0xe8, 0x77, 0x52, 0x37, 0x4e, 0x0f, 0x55, 0xd2, + 0x12, 0x65, 0x90, 0xc2, 0x41, 0x49, 0x81, 0x01, + 0xf5, 0x01, 0xeb, 0x2d, 0x78, 0x74, 0x23, 0x5d, + 0x84, 0x5c, 0x81, 0x92, 0x21, 0xe9, 0x8d, 0x1d, + 0x89, 0xf2, 0x4a, 0xac, 0xdd, 0xf9, 0xaf, 0xee, + 0x44, 0xe7, 0x6e, 0xed, 0xfb, 0xd8, 0x89, 0x0e, + 0x96, 0x62, 0xcd, 0xa4, 0x4b, 0xa9, 0xe5, 0x45, + 0xb1, 0x29, 0x9b, 0x0f, 0xfc, 0xbd, 0x83, 0xab, + 0xa8, 0x54, 0x96, 0x44, 0x2c, 0x7f, 0xbb, 0xe7, + 0x52, 0x29, 0x08, 0xee, 0x14, 0xc5, 0xc2, 0xec, + 0x5a, 0xeb, 0x40, 0x40, 0xea, 0xd1, 0x3d, 0x15, + 0x73, 0xaa, 0x8c, 0x73, 0xfc, 0xf2, 0x2b, 0x49, + 0x0b, 0x13, 0x96, 0xd9, 0x8e, 0x4b, 0xbc, 0xe0, + 0xf4, 0xd2, 0xe0, 0x2e, 0x7a, 0xf0, 0x5d, 0x1f, + 0xd2, 0x92, 0x97, 0xe0, 0xaa, 0x59, 0xab, 0xc9, + 0x5c, 0xa6, 0x51, 0x1a, 0xe3, 0xd6, 0x06, 0xb9, + 0xae, 0xb8, 0x76, 0x36, 0x79, 0x37, 0x52, 0xf6, + 0x34, 0xaf, 0x27, 0x19, 0xe1, 0xc0, 0x2b, 0xdd, + 0x01, 0x15, 0xcd, 0xce, 0x44, 0xf6, 0x4c, 0x18, + 0x92, 0x69, 0xbe, 0x8a, 0x76, 0x23, 0x52, 0x13, + 0x3f, 0xf9, 0xe0, 0xf5, 0x06, 0x28, 0x7c, 0xc7, + 0xf3, 0x42, 0x0f, 0xdd, 0x40, 0x33, 0xf7, 0x99, + 0xe2, 0xad, 0x26, 0xd9, 0x53, 0x10, 0x72, 0x0c, + 0x4e, 0x43, 0x4c, 0x61, 0xfe, 0xd9, 0xc1, 0x16, + 0xa1, 0x93, 0xca, 0x3c, 0x75, 0x7f, 0x07, 0x7a, + 0x65, 0xb3, 0x53, 0x2a, 0x52, 0x00, 0xa0, 0x62, + 0xe0, 0xa3, 0x1f, 0xad, 0xd7, 0xbb, 0xc0, 0x83, + 0x5d, 0x54, 0x87, 0x5f, 0xc8, 0x2f, 0xc8, 0xbf, + 0x69, 0x04, 0x91, 0xc8, 0xa6, 0x1d, 0x4d, 0x46, + 0x91, 0xfc, 0x26, 0xf4, 0x16, 0xd1, 0xa4, 0xbf, + 0x5c, 0xa2, 0x6c, 0xdd, 0xb4, 0x40, 0xf2, 0x2e, + 0xa2, 0xad, 0xf7, 0xf4, 0xa5, 0x8a, 0x3e, 0x23, + 0x64, 0x08, 0xc8, 0xa1, 0xa0, 0xf0, 0x5d, 0x70, + 0xd2, 0x77, 0xfd, 0xc8, 0x50, 0x83, 0x0f, 0xd6, + 0x2b, 0xe4, 0x1f, 0x52, 0x34, 0x33, 0x68, 0xfd, + 0x92, 0xbe, 0x9f, 0x97, 0x6b, 0x8d, 0x81, 0x91, + 0x0f, 0xef, 0x65, 0xc8, 0x0d, 0x15, 0x01, 0x77, + 0x58, 0xb2, 0xf4, 0x1b, 0x06, 0x7e, 0xf5, 0xca, + 0x15, 0x2e, 0x38, 0xd8, 0x81, 0x1c, 0x1c, 0xa0, + 0xb6, 0x13, 0x6a, 0x2b, 0x71, 0x34, 0x52, 0xd7, + 0x1d, 0xbd, 0x37, 0x59, 0xbc, 0x86, 0x25, 0x2b, + 0xa8, 0x93, 0xce, 0x1a, 0x03, 0x16, 0xfe, 0x01, + 0x57, 0x99, 0x24, 0x25, 0x2c, 0xb3, 0xab, 0x1e, + 0x2d, 0x65, 0x20, 0x89, 0x17, 0x02, 0x0e, 0x0a, + 0xf5, 0x1e, 0xc7, 0xff, 0x1f, 0x61, 0xa9, 0x54, + 0x18, 0xd4, 0xba, 0x50, 0x57, 0x02, 0xa1, 0xab, + 0x22, 0x2e, 0x07, 0xea, 0xa9, 0xa3, 0x83, 0x4f, + 0x27, 0xf5, 0xc5, 0xee, 0x3c, 0x3b, 0x10, 0xad, + 0x32, 0x2b, 0x1c, 0x03, 0xcb, 0xaf, 0x98, 0x83, + 0x54, 0xc3, 0x68, 0x63, 0xd4, 0xe0, 0x0e, 0x3c, + 0x1a, 0x4e, 0xc0, 0x81, 0xd0, 0xe8, 0x6a, 0x62, + 0x6b, 0x3e, 0x6f, 0xc4, 0xc6, 0x33, 0x4e, 0x26, + 0x21, 0xf5, 0x04, 0xdf, 0xfa, 0xce, 0x45, 0xaf, + 0xdc, 0x5e, 0x1b, 0xad, 0x93, 0xca, 0xf5, 0xcf, + 0xd7, 0xee, 0x0c, 0x5c, 0x5e, 0xb4, 0xf0, 0x92, + 0xd2, 0xf2, 0xf0, 0xa9, 0x1e, 0xab, 0x80, 0x68, + 0x46, 0xef, 0xcc, 0x26, 0x0c, 0x5c, 0xdd, 0x4e, + 0x83, 0xb8, 0xb9, 0x53, 0x6e, 0xf8, 0x93, 0x38, + 0x67, 0xa4, 0x41, 0x87, 0x72, 0xe7, 0x7e, 0x86, + 0xc9, 0x49, 0x00, 0x33, 0xb1, 0x38, 0x6c, 0x71, + 0xd7, 0x1d, 0x8e, 0x61, 0x01, 0xb6, 0x57, 0xa9, + 0xf1, 0xac, 0x15, 0xc2, 0x83, 0x77, 0xca, 0x64, + 0xca, 0x7b, 0x6c, 0xa1, 0x10, 0x1b, 0x13, 0xd0, + 0xd3, 0x9e, 0x9e, 0x10, 0x70, 0xc8, 0x1a, 0xbb, + 0x3f, 0x19, 0x86, 0xab, 0x01, 0x0e, 0xea, 0x34, + 0x22, 0xea, 0xe2, 0x15, 0xb7, 0xed, 0x21, 0x21, + 0x75, 0xa5, 0xe7, 0x08, 0xa1, 0x38, 0xe0, 0x91, + 0x05, 0x60, 0xea, 0xa7, 0x50, 0x27, 0x18, 0x07, + 0x9d, 0xe0, 0x18, 0x2b, 0xd4, 0x07, 0x59, 0x00, + 0xe6, 0x45, 0x18, 0x2a, 0x30, 0x6e, 0xf3, 0xb4, + 0xd0, 0xef, 0xa6, 0x5b, 0x71, 0xa2, 0x5a, 0x3b, + 0x89, 0x4c, 0xaf, 0x3f, 0xcb, 0x9f, 0x03, 0xfb, + 0x43, 0x7c, 0x6b, 0xd3, 0x6a, 0xea, 0xce, 0x4a, + 0x5f, 0x64, 0xb5, 0x62, 0xda, 0x5d, 0x27, 0xb7, + 0xb8, 0x11, 0xca, 0x33, 0x30, 0xec, 0x70, 0xf0, + 0x1b, 0x03, 0x50, 0xff, 0x5e, 0xa6, 0x08, 0xde, + 0x37, 0x70, 0xc0, 0x81, 0x55, 0x60, 0x17, 0xa1, + 0x85, 0xae, 0x26, 0x44, 0xe4, 0x67, 0x3c, 0x91, + 0xfd, 0xc4, 0x3d, 0x97, 0x72, 0x23, 0xf3, 0x3c, + 0x8f, 0xe0, 0xe2, 0xf2, 0x09, 0x96, 0x10, 0x67, + 0xb5, 0xfe, 0xff, 0x3d, 0x4a, 0xc8, 0x62, 0x11, + 0xa5, 0x98, 0xc1, 0x2d, 0x40, 0x82, 0x88, 0x8b, + 0xe5, 0xb0, 0x75, 0xbf, 0x2f, 0xa8, 0x6a, 0x55, + 0x49, 0x2e, 0x9c, 0x29, 0xd2, 0x7c, 0xbf, 0xf3, + 0xaa, 0x3a, 0x16, 0x4a, 0xa4, 0x15, 0xf3, 0x48, + 0xde, 0x38, 0x13, 0x44, 0x26, 0x02, 0xe6, 0xe9, + 0xa8, 0x24, 0x89, 0xb5, 0x43, 0x95, 0xe4, 0x4c, + 0xc3, 0xa0, 0xdf, 0xcc, 0x42, 0xf8, 0x8d, 0xb0, + 0x3b, 0xea, 0x10, 0xb7, 0xe1, 0x40, 0x54, 0xb9, + 0xa3, 0x2d, 0xfb, 0xb4, 0x91, 0xc0, 0x3e, 0x94, + 0xf1, 0xa1, 0x3c, 0xbe, 0xef, 0xb8, 0x70, 0x55, + 0x0a, 0x26, 0x93, 0xbf, 0xe6, 0x21, 0x92, 0x32, + 0x3c, 0x39, 0x27, 0x6a, 0x23, 0x48, 0x02, 0x35, + 0x3c, 0xd4, 0xcc, 0x04, 0xc0, 0x4e, 0xa7, 0x02, + 0x63, 0x37, 0xc2, 0xb8, 0x56, 0x1d, 0x57, 0x57, + 0x42, 0x04, 0x8d, 0xee, 0xcf, 0x8b, 0xc9, 0xc3, + 0xba, 0x3b, 0x15, 0xd7, 0xaf, 0xbf, 0x9e, 0xcd, + 0x44, 0xcf, 0xf0, 0x00, 0xb7, 0x3a, 0xfc, 0xa8, + 0x12, 0xab, 0x3a, 0x62, 0x01, 0x21, 0x46, 0xe9, + 0x1e, 0x48, 0x37, 0xfc, 0x13, 0x4d, 0xf6, 0x2a, + 0x72, 0x40, 0x75, 0x38, 0x71, 0xf2, 0x17, 0x20, + 0x2c, 0xdd, 0xc0, 0x49, 0xbc, 0x63, 0x33, 0xea, + 0x06, 0x75, 0x41, 0xe7, 0x5c, 0x1f, 0xfb, 0xf9, + 0x68, 0x83, 0xc2, 0x5a, 0x4a, 0x1e, 0x61, 0x08, + 0x57, 0xf3, 0x00, 0xba, 0x77, 0x92, 0x63, 0xa5, + 0xb7, 0xfe, 0x97, 0x22, 0xda, 0x5e, 0xd3, 0xaf, + 0xbc, 0x89, 0x0d, 0x4c, 0x37, 0xa9, 0x27, 0x4a, + 0x7f, 0xdb, 0x81, 0x39, 0x11, 0x86, 0x12, 0xf9, + 0x10, 0x50, 0xe4, 0xdb, 0x72, 0xf9, 0xae, 0x10, + 0x7c, 0xed, 0x50, 0x5c, 0x61, 0xeb, 0x42, 0x1e, + 0xa4, 0xf4, 0xf0, 0xfa, 0x45, 0x4d, 0x95, 0x2b, + 0xd4, 0x67, 0x4a, 0xe3, 0x8a, 0x15, 0x55, 0x92, + 0x77, 0x64, 0x8c, 0x51, 0x38, 0xf9, 0x26, 0x3e, + 0x68, 0xe2, 0xac, 0xbb, 0x64, 0x77, 0xe2, 0x82, + 0xa4, 0x42, 0x41, 0x38, 0xa0, 0xf0, 0xc9, 0xd8, + 0x6c, 0xe0, 0xef, 0x4c, 0xda, 0xb4, 0x92, 0xef, + 0x1b, 0xe3, 0x9b, 0xc1, 0x44, 0x3c, 0xb9, 0xb7, + 0x39, 0xac, 0x5c, 0x32, 0x39, 0xb4, 0x21, 0x85, + 0x93, 0xbc, 0xf2, 0x51, 0x43, 0xb7, 0xae, 0x1e, + 0x61, 0x9c, 0x38, 0x9c, 0xaa, 0xff, 0xde, 0xfc, + 0xbf, 0x85, 0xef, 0x17, 0x34, 0x36, 0x71, 0x5f, + 0x04, 0x16, 0xa6, 0x9e, 0xfd, 0x3a, 0x03, 0xd8, + 0xbf, 0x71, 0x70, 0x20, 0x8f, 0x7c, 0xfb, 0xff, + 0x61, 0xe0, 0xe2, 0x60, 0xa7, 0xb1, 0xc0, 0xe0, + 0xd9, 0x3f, 0xdc, 0x8d, 0x4a, 0xa4, 0x52, 0x61, + 0xaf, 0x9d, 0xdf, 0x8a, 0x0d, 0x41, 0xc0, 0x25, + 0x68, 0x12, 0x7b, 0xd5, 0xc7, 0xdb, 0x68, 0x70, + 0x2d, 0x7d, 0x95, 0x12, 0x03, 0x23, 0x0c, 0xe8, + 0x14, 0x41, 0x11, 0x28, 0xec, 0x9d, 0xd3, 0x28, + 0x77, 0x7a, 0x3c, 0x93, 0x8e, 0x5c, 0x7e, 0xb3, + 0x42, 0x9a, 0x18, 0x25, 0x93, 0xc8, 0xea, 0x43, + 0x1b, 0xbe, 0xd5, 0x27, 0xf1, 0xd4, 0xe0, 0x1e, + 0xce, 0xc7, 0xc7, 0x2c, 0x25, 0x35, 0x58, 0xb8, + 0x6c, 0xf3, 0xa2, 0xad, 0xe7, 0x58, 0x49, 0x47, + 0xf7, 0xca, 0xde, 0x8b, 0x81, 0xb7, 0x75, 0xf4, + 0x95, 0xa7, 0x5c, 0xc3, 0x2c, 0x0e, 0x1c, 0x52, + 0x9a, 0xc3, 0x2a, 0x00, 0x21, 0xa7, 0x51, 0x6b, + 0xf0, 0x05, 0x87, 0x8c, 0x42, 0x1b, 0xc3, 0x2e, + 0xa3, 0x76, 0x22, 0xd5, 0x7f, 0x56, 0x10, 0xef, + 0x98, 0x85, 0x65, 0x86, 0x71, 0x87, 0xd2, 0x8c, + 0xc0, 0x47, 0x20, 0xe8, 0xb5, 0x1c, 0xe3, 0xdd, + 0x3c, 0x5c, 0x03, 0xbb, 0x0e, 0x97, 0x3b, 0xe1, + 0x56, 0x9a, 0xd5, 0x0a, 0x63, 0xd5, 0x33, 0xaf, + 0x36, 0xca, 0xcf, 0x8f, 0x00, 0x28, 0xa3, 0x45, + 0xb8, 0xcd, 0xde, 0x73, 0xd4, 0xfa, 0x2d, 0x6f, + 0xdb, 0x93, 0xaa, 0xdd, 0x7f, 0xd2, 0x22, 0x9c, + 0x96, 0x48, 0x1e, 0xa8, 0x63, 0xbe, 0xbc, 0x0d, + 0x14, 0x3c, 0x2e, 0x11, 0x1f, 0xd2, 0xf4, 0x57, + 0xb3, 0x47, 0xf8, 0xa6, 0x1b, 0xc3, 0xa7, 0x95, + 0x2d, 0xd4, 0xca, 0xb8, 0x0d, 0xfb, 0x06, 0x85, + 0xda, 0x63, 0xf0, 0x3e, 0x9d, 0x5e, 0xee, 0xce, + 0xed, 0x74, 0x1d, 0x2c, 0x97, 0x3f, 0x71, 0x95, + 0x12, 0x03, 0xc5, 0x92, 0x46, 0x84, 0x1b, 0x07, + 0xe6, 0xb4, 0x1d, 0x3a, 0xf1, 0x89, 0x90, 0x50, + 0x10, 0x29, 0x34, 0xc0, 0x90, 0xbe, 0x4a, 0xa9, + 0x0d, 0xb0, 0x7b, 0xfb, 0x35, 0xee, 0x4e, 0x34, + 0xec, 0x5a, 0x58, 0xbc, 0xb8, 0xda, 0x38, 0x88, + 0x8c, 0x74, 0x1e, 0xc9, 0xab, 0x78, 0x2e, 0x2a, + 0x17, 0x8a, 0x43, 0x3d, 0xa1, 0x2a, 0x41, 0xb5, + 0xd6, 0xe8, 0x5b, 0xc5, 0x4a, 0x1c, 0x3c, 0x9f, + 0x8d, 0x3a, 0x69, 0x88, 0xf8, 0x80, 0xd2, 0x11, + 0xfc, 0x7e, 0x80, 0x8e, 0x7f, 0x85, 0x64, 0x9c, + 0x46, 0x58, 0xc8, 0x48, 0x98, 0x4b, 0xf5, 0x73, + 0x3f, 0x49, 0xce, 0x53, 0x2c, 0xd5, 0xfc, 0x33, + 0xf1, 0x6f, 0xd8, 0xe9, 0x2e, 0x70, 0x2e, 0xdc, + 0xe5, 0x43, 0x80, 0x38, 0xf2, 0x87, 0xed, 0x85, + 0xe4, 0x3e, 0x45, 0x14, 0x20, 0xcf, 0xa0, 0x61, + 0x4f, 0xe8, 0xd7, 0x5b, 0xb3, 0x0d, 0x0e, 0x4e, + 0x4d, 0xce, 0xbe, 0xba, 0xaa, 0x90, 0x09, 0xcb, + 0x4b, 0x5d, 0x08, 0xff, 0x52, 0xd5, 0x23, 0xbc, + 0xad, 0x8d, 0xd3, 0x06, 0x4a, 0xa0, 0x51, 0x56, + 0xa7, 0xd8, 0x33, 0xab, 0xbc, 0xd0, 0xdf, 0x92, + 0x87, 0x20, 0x2d, 0x7b, 0x5e, 0xfa, 0x30, 0xa7, + 0x06, 0x06, 0xe5, 0x4f, 0x2c, 0xb5, 0x61, 0xd7, + 0x54, 0xd3, 0xdf, 0xd0, 0x0a, 0xb0, 0x06, 0xce, + 0xf6, 0x86, 0xb7, 0x8e, 0xaa, 0x7b, 0x78, 0xd5, + 0xb9, 0xeb, 0x07, 0xac, 0x5f, 0xc5, 0xd2, 0x8c, + 0x40, 0xe0, 0x7f, 0x98, 0xd4, 0xe5, 0x4b, 0xca, + 0xfb, 0x47, 0xef, 0xef, 0xb9, 0x4d, 0x6d, 0x8f, + 0x82, 0x68, 0x74, 0x84, 0xe0, 0x0a, 0x93, 0x0f, + 0xb2, 0x01, 0xa9, 0x9f, 0x68, 0x6a, 0xe8, 0xf7, + 0xfb, 0x0b, 0xde, 0x17, 0xe0, 0x30, 0x38, 0x51, + 0xbc, 0x07, 0xb8, 0x2c, 0x91, 0x0f, 0xc1, 0x0e, + 0xa6, 0xf9, 0xf0, 0xd5, 0x48, 0x76, 0x8a, 0xde, + 0x74, 0xe3, 0x30, 0x65, 0x56, 0xb3, 0x5c, 0xe2, + 0x89, 0x8d, 0xda, 0x80, 0xad, 0x0f, 0x22, 0xfb, + 0x24, 0x1d, 0x16, 0xdd, 0x34, 0x4b, 0x90, 0x58, + 0x4e, 0x0c, 0x13, 0x28, 0xcf, 0x1d, 0xa4, 0xaa, + 0xb7, 0xf3, 0xb1, 0x66, 0xad, 0x3b, 0xcf, 0x79, + 0x12, 0x04, 0xd7, 0x79, 0xd9, 0x5f, 0xdf, 0x89, + 0xb2, 0x5b, 0xa7, 0x9a, 0x26, 0x1e, 0x67, 0x46, + 0x7c, 0x66, 0x95, 0x67, 0xe6, 0x45, 0x8b, 0x1f, + 0x65, 0x79, 0x9f, 0x6d, 0x11, 0x81, 0x17, 0x0d, + 0x11, 0xb0, 0x5c, 0xb4, 0xc7, 0x27, 0x87, 0xab, + 0x5d, 0x0a, 0x18, 0xae, 0x4e, 0x06, 0xa3, 0x3d, + 0xc7, 0xb0, 0x22, 0xba, 0x03, 0xa4, 0x0f, 0xe5, + 0x1c, 0x72, 0x2a, 0x04, 0xce, 0x83, 0xe9, 0xf3, + 0xd7, 0xc9, 0x67, 0x6c, 0x1e, 0x6b, 0x3c, 0x9b, + 0x0b, 0x5e, 0x6a, 0xa6, 0x79, 0x0a, 0xf1, 0xbe, + 0xd7, 0xb4, 0x6f, 0x45, 0x1e, 0xfb, 0x78, 0x97, + 0xaf, 0x34, 0x76, 0x95, 0x52, 0xf7, 0x3d, 0x5d, + 0x07, 0x28, 0x57, 0x9c, 0x4a, 0x0f, 0xcf, 0x0b, + 0x1b, 0xc4, 0xc2, 0x72, 0xd7, 0x72, 0x38, 0x9b, + 0xea, 0xeb, 0xee, 0xae, 0x34, 0xc8, 0x01, 0xd7, + 0xa5, 0xe3, 0xce, 0x41, 0xad, 0x02, 0x60, 0x23, + 0x18, 0x36, 0xba, 0x17, 0xfa, 0xcf, 0xe4, 0xda, + 0xdc, 0xfc, 0x82, 0xdc, 0x7c, 0x11, 0xf4, 0xb8, + 0x52, 0x5d, 0xf7, 0x2f, 0xc8, 0xfe, 0x4a, 0xe6, + 0xb9, 0xaf, 0x4b, 0x17, 0x18, 0x91, 0xc2, 0xfe, + 0xd7, 0x3a, 0x77, 0x0c, 0xa0, 0x43, 0x9c, 0x6f, + 0x13, 0x06, 0xbe, 0x6e, 0xe0, 0x1a, 0x3c, 0xf3, + 0xf5, 0xcc, 0x78, 0xfb, 0x5d, 0xd5, 0xda, 0xb7, + 0x58, 0xea, 0x86, 0x42, 0x6b, 0x32, 0xff, 0xb2, + 0xe2, 0xee, 0x03, 0x1f, 0xf4, 0xef, 0xdb, 0x53, + 0x79, 0xd5, 0x4e, 0xaf, 0x60, 0x8e, 0x02, 0xc2, + 0xcc, 0x39, 0x97, 0x7b, 0xfd, 0xa1, 0xf8, 0x7a, + 0x26, 0xe8, 0x55, 0xd6, 0xa4, 0x8b, 0xa0, 0x1b, + 0x2d, 0x63, 0xaa, 0x73, 0x71, 0x6e, 0xbf, 0x8b, + 0x3b, 0xe3, 0x1b, 0x0d, 0xbb, 0x2e, 0x44, 0x09, + 0x64, 0xac, 0xc7, 0x9e, 0xb5, 0xc6, 0x77, 0xb0, + 0x79, 0xb3, 0xaa, 0xfc, 0x67, 0x57, 0x9a, 0x50, + 0x81, 0x37, 0x14, 0x7c, 0xd7, 0xa0, 0xd4, 0x6a, + 0x79, 0x84, 0x51, 0x0e, 0x95, 0x0a, 0x30, 0xa3, + 0x60, 0x55, 0x48, 0x05, 0x16, 0xae, 0x43, 0x90, + 0xdc, 0x8e, 0x09, 0xbe, 0x79, 0xf6, 0x90, 0x74, + 0xf8, 0x20, 0x96, 0x4d, 0xa7, 0xf5, 0x1a, 0x2b, + 0xc7, 0x15, 0x9d, 0x18, 0xf7, 0x94, 0x87, 0xf7, + 0xf4, 0xfb, 0x0d, 0x61, 0xb6, 0xd7, 0xbe, 0x10, + 0x8e, 0x47, 0x3c, 0x10, 0x44, 0x90, 0x52, 0x21, + 0x83, 0xc0, 0xf5, 0x99, 0xaa, 0xbc, 0xf6, 0x55, + 0xae, 0xf5, 0xb2, 0xa4, 0xcd, 0x4d, 0xb9, 0x38, + 0x6c, 0xbc, 0x80, 0xc3, 0xad, 0xf4, 0x46, 0x31, + 0x01, 0x58, 0x2d, 0x88, 0x57, 0xc3, 0x23, 0xd1, + 0x64, 0xc9, 0xa3, 0x21, 0x6b, 0x8b, 0x8a, 0x23, + 0x2c, 0x4f, 0xa9, 0xcd, 0x67, 0xfa, 0x77, 0xad, + 0xa3, 0x16, 0xa2, 0xe5, 0x19, 0x14, 0x70, 0x41, + 0x5b, 0xda, 0x14, 0xde, 0xe3, 0xe5, 0xc1, 0x15, + 0xb4, 0x77, 0xa4, 0x9b, 0xb8, 0xb1, 0x28, 0x51, + 0x30, 0xb4, 0xf1, 0xf3, 0xf8, 0x6d, 0xd0, 0xc3, + 0x8c, 0x4c, 0x76, 0xb0, 0x9a, 0xdf, 0xc8, 0xbe, + 0xf8, 0x4a, 0x61, 0x6e, 0x3e, 0xd6, 0x3c, 0xe8, + 0xde, 0x56, 0xa0, 0x9c, 0x25, 0xbe, 0xce, 0x93, + 0x1f, 0x88, 0xfb, 0x9a, 0x1a, 0xe2, 0xff, 0x88, + 0xad, 0x10, 0xcb, 0x6c, 0xd6, 0xe7, 0x39, 0x0b, + 0xe5, 0x1a, 0x06, 0x05, 0x64, 0x5b, 0x0a, 0xdf, + 0x22, 0x58, 0xd7, 0xfb, 0x88, 0x12, 0xdd, 0xb7, + 0x52, 0x3a, 0xc9, 0xbf, 0x49, 0xdf, 0x8c, 0x87, + 0x9f, 0x84, 0xb5, 0x0a, 0xf6, 0x00, 0x52, 0xae, + 0x67, 0x12, 0x1a, 0x8c, 0x71, 0x15, 0xf5, 0xa1, + 0x13, 0x39, 0xf0, 0x91, 0x7e, 0x88, 0x7c, 0xb3, + 0x95, 0x50, 0x02, 0xa6, 0x63, 0xb5, 0x64, 0xfb, + 0x90, 0x87, 0x61, 0xe2, 0x27, 0xaf, 0x11, 0x0c, + 0x73, 0x83, 0xef, 0xa9, 0x28, 0xfe, 0xc8, 0x85, + 0x1a, 0x3a, 0xde, 0xf2, 0xe5, 0x25, 0x64, 0x6d, + 0xaa, 0x41, 0x4c, 0x80, 0x2e, 0x84, 0xff, 0xc1, + 0xc0, 0x54, 0x0c, 0x29, 0x1b, 0xa3, 0x07, 0x7c, + 0x33, 0x4c, 0x10, 0xf6, 0x6f, 0x79, 0xdf, 0xd3, + 0xf0, 0x24, 0x57, 0xf1, 0x60, 0xe1, 0xf0, 0xbd, + 0xc4, 0x1f, 0xf4, 0x67, 0xd2, 0xd3, 0xcc, 0x6a, + 0x07, 0x72, 0x44, 0x16, 0x85, 0x46, 0xd0, 0x73, + 0x87, 0xa9, 0xc7, 0x2f, 0xd1, 0xf5, 0xec, 0xe3, + 0x28, 0xa3, 0x93, 0x4f, 0xd7, 0x76, 0xc1, 0x3c, + 0x0d, 0x13, 0x33, 0xcf, 0x5b, 0xbd, 0x6a, 0x52, + 0x4e, 0xee, 0xc8, 0x5e, 0xa1, 0x58, 0x4a, 0x08, + 0x81, 0xd9, 0x23, 0xcc, 0xfb, 0x1c, 0xb2, 0xd8, + 0xa3, 0xe4, 0x53, 0xfe, 0xf4, 0x4b, 0x48, 0xc1, + 0x20, 0xa4, 0x97, 0xf8, 0x38, 0xa3, 0x69, 0xc1, + 0x11, 0xf0, 0xa1, 0x3b, 0xa9, 0x9a, 0x12, 0x61, + 0xe8, 0x8d, 0x99, 0x44, 0x3f, 0x94, 0x72, 0x82, + 0x19, 0x96, 0x62, 0xb0, 0xa6, 0x64, 0x05, 0x19, + 0x8f, 0xd6, 0x5d, 0x05, 0xbf, 0x79, 0x9e, 0x9d, + 0xe4, 0x93, 0x4c, 0xad, 0x61, 0x8c, 0x18, 0xda, + 0xb6, 0x2e, 0xb3, 0xca, 0x14, 0x4d, 0x53, 0xa4, + 0x97, 0x27, 0x10, 0x56, 0xa2, 0x67, 0x5a, 0x5a, + 0x5e, 0x13, 0xc0, 0xdb, 0xa7, 0x9f, 0x45, 0x5b, + 0xeb, 0x1a, 0x14, 0x0c, 0x8c, 0x38, 0x5e, 0x77, + 0x9a, 0xec, 0x75, 0x68, 0x93, 0x65, 0x02, 0x9c, + 0xfb, 0x62, 0x60, 0x49, 0xdd, 0xb2, 0x2a, 0x67, + 0x86, 0xe3, 0x8a, 0x7d, 0x8c, 0x46, 0x78, 0x81, + 0x60, 0x69, 0xf2, 0x3f, 0x74, 0x11, 0x35, 0xff, + 0x77, 0xa3, 0x66, 0x20, 0xfc, 0x98, 0x4a, 0x35, + 0x7a, 0x52, 0xe4, 0x90, 0x13, 0x80, 0xb9, 0xa6, + 0x73, 0x7a, 0x7d, 0x66, 0x6e, 0x6b, 0xb6, 0x43, + 0x10, 0xd5, 0x91, 0x2b, 0x66, 0xdd, 0x89, 0x87, + 0xe3, 0x8c, 0x58, 0x53, 0x2f, 0x40, 0x74, 0x45, + 0x1b, 0x77, 0x7a, 0xa4, 0x44, 0x19, 0x78, 0xba, + 0x87, 0x10, 0x41, 0x31, 0x32, 0x5f, 0x87, 0x68, + 0xde, 0x43, 0x4a, 0xef, 0x33, 0xb3, 0x11, 0x83, + 0xa9, 0xc2, 0x6f, 0x8d, 0x34, 0xe2, 0x95, 0x84, + 0x3a, 0x4f, 0x6f, 0x8c, 0x31, 0x1d, 0xb6, 0xf5, + 0x95, 0x0d, 0x01, 0x11, 0x20, 0xdf, 0x72, 0xf3, + 0x3f, 0x9a, 0x33, 0xaa, 0xb1, 0x06, 0x6a, 0x63, + 0x47, 0x91, 0x01, 0xdf, 0xb3, 0x54, 0x36, 0xfd, + 0x06, 0x2d, 0xb8, 0x08, 0xe3, 0xd3, 0x65, 0xac, + 0x66, 0x03, 0xee, 0xa4, 0x63, 0xbd, 0xd4, 0xce, + 0xbd, 0x79, 0xa7, 0x48, 0x38, 0xc5, 0x7d, 0xb5, + 0x71, 0x9a, 0x3c, 0x11, 0x7c, 0x6c, 0xe2, 0x54, + 0x02, 0x5d, 0x42, 0xab, 0x25, 0x93, 0x66, 0x01, + 0x37, 0x78, 0x35, 0x4a, 0x8c, 0x19, 0x4d, 0x00, + 0x75, 0x4f, 0xcc, 0xc0, 0x26, 0x82, 0xc1, 0x35, + 0x8c, 0xc7, 0xc2, 0x59, 0x01, 0x3e, 0x98, 0x22, + 0x88, 0x9c, 0x90, 0x75, 0x05, 0x33, 0x07, 0xb9, + 0x39, 0x81, 0x38, 0x58, 0x10, 0x29, 0xcf, 0xc8, + 0x98, 0xb2, 0x03, 0xd7, 0x5b, 0xb3, 0x18, 0xba, + 0x34, 0x0c, 0x9f, 0xab, 0xd7, 0xed, 0x29, 0x82, + 0x41, 0xe0, 0x20, 0x97, 0x57, 0x92, 0xb2, 0xb8, + 0x10, 0x2d, 0x0b, 0xa2, 0xc5, 0x8f, 0x90, 0x6f, + 0xed, 0x12, 0x56, 0x25, 0xbe, 0xfd, 0x75, 0xf7, + 0xb6, 0xf8, 0x40, 0x67, 0x39, 0x11, 0xfa, 0x15, + 0xae, 0x6a, 0x54, 0x5f, 0x32, 0x2b, 0xf8, 0x48, + 0x55, 0xbe, 0x86, 0x2f, 0x69, 0x48, 0x5b, 0x5d, + 0x4d, 0xb7, 0x35, 0xaa, 0xb6, 0x91, 0x88, 0x19, + 0x96, 0x1c, 0x68, 0xf6, 0x85, 0x9e, 0xb3, 0xb2, + 0xa3, 0x32, 0xd4, 0x52, 0x70, 0xb7, 0x62, 0xe3, + 0x14, 0xb6, 0x78, 0x5f, 0x1b, 0x1d, 0x04, 0x9c, + 0x26, 0x0c, 0x33, 0x94, 0xb1, 0x97, 0x08, 0xdb, + 0x0b, 0x39, 0x29, 0xd4, 0xbc, 0x6d, 0xdf, 0x02, + 0xc6, 0x99, 0xab, 0x99, 0x32, 0xe5, 0xce, 0x51, + 0x4f, 0xae, 0xb8, 0x8b, 0xe0, 0xaf, 0x07, 0xc4, + 0xf9, 0x41, 0x7c, 0x59, 0xa0, 0xac, 0x74, 0x4d, + 0x7e, 0x43, 0x77, 0x9c, 0x06, 0x49, 0x79, 0x8a, + 0x14, 0x73, 0x93, 0xa8, 0x5b, 0x1b, 0x34, 0x29, + 0x78, 0x04, 0x2f, 0xd7, 0x1f, 0x13, 0x90, 0xe0, + 0xdd, 0x3b, 0x42, 0x6b, 0x79, 0x6e, 0x52, 0xc7, + 0x0f, 0x38, 0xda, 0x01, 0x2c, 0x8d, 0xe6, 0x94, + 0x5d, 0x59, 0x27, 0x1d, 0x10, 0x4e, 0x11, 0x36, + 0xfb, 0x53, 0x16, 0x05, 0x25, 0xf2, 0x64, 0xd8, + 0xf9, 0xcd, 0x5c, 0xfe, 0xb4, 0x18, 0x44, 0x80, + 0x10, 0xbc, 0x3d, 0xf3, 0x1d, 0x5a, 0xf0, 0xc1, + 0xc3, 0x55, 0xff, 0x41, 0x3e, 0xe3, 0xef, 0x44, + 0xb2, 0xc0, 0x01, 0x18, 0xa2, 0x49, 0x88, 0x78, + 0x0d, 0x4c, 0xc8, 0x73, 0xcf, 0x30, 0x85, 0x3a, + 0x88, 0x90, 0x01, 0xcf, 0x69, 0x53, 0xa3, 0x18, + 0x3f, 0xd6, 0xe7, 0x94, 0x14, 0xa7, 0xae, 0xcd, + 0x6f, 0x11, 0x72, 0xfe, 0x2b, 0xb0, 0x81, 0x53, + 0xea, 0x67, 0xd6, 0xe4, 0xca, 0x42, 0xa0, 0xf9, + 0xb1, 0xd4, 0xb5, 0x3b, 0xc9, 0xf0, 0x36, 0xc1, + 0x1c, 0xf4, 0xb1, 0xf6, 0x84, 0xd0, 0x86, 0x6c, + 0x76, 0x9a, 0x03, 0xc2, 0xb6, 0x2e, 0x9a, 0x46, + 0xf5, 0x5f, 0x2c, 0x38, 0xac, 0xad, 0x6f, 0x2e, + 0x7a, 0x18, 0x2d, 0x22, 0x95, 0x5e, 0x5e, 0xc9, + 0x7a, 0x0a, 0x56, 0xe1, 0xc7, 0x15, 0xfd, 0xbf, + 0xff, 0xf7, 0x7e, 0x85, 0x20, 0xa9, 0x8a, 0x9c, + 0xa9, 0x7d, 0xe8, 0xed, 0xfc, 0x7f, 0xbb, 0xf0, + 0x05, 0x3f, 0xce, 0x4f, 0x4c, 0xee, 0xa4, 0xa0, + 0xcc, 0x9c, 0x62, 0x1e, 0xd6, 0xd0, 0x30, 0x37, + 0xb8, 0x98, 0x56, 0x1d, 0xaa, 0xd6, 0x5e, 0x73, + 0x12, 0xe4, 0x88, 0x82, 0x48, 0x64, 0x06, 0xd7, + 0x2a, 0x31, 0x50, 0x7b, 0x10, 0x17, 0xb8, 0x4c, + 0x5a, 0x8d, 0xf1, 0xfc, 0xf1, 0x33, 0x3b, 0x98, + 0x42, 0x18, 0x5b, 0x35, 0x78, 0xca, 0x8e, 0x41, + 0x52, 0xae, 0x6d, 0xe1, 0xa2, 0x9d, 0x5b, 0xbd, + 0xf3, 0x5f, 0x49, 0xc1, 0x27, 0x06, 0xc1, 0xaf, + 0xc0, 0xa3, 0x9d, 0xf3, 0x1c, 0x8e, 0x90, 0x8a, + 0xb0, 0x69, 0xb0, 0xc5, 0x11, 0x0c, 0x91, 0x14, + 0x1f, 0x5e, 0x10, 0xe1, 0x1d, 0x14, 0x30, 0x54, + 0x1e, 0x17, 0x3d, 0x31, 0x7b, 0xbf, 0x2f, 0x9d, + 0x6d, 0x63, 0x32, 0xf0, 0x9d, 0x9f, 0x95, 0x3d, + 0x0b, 0xd2, 0x4d, 0x10, 0xe2, 0x3f, 0x67, 0x69, + 0x43, 0x9a, 0x4a, 0x2c, 0x54, 0x71, 0xa8, 0xa0, + 0x9e, 0x9f, 0x10, 0xaf, 0x1b, 0xce, 0x99, 0xe3, + 0x25, 0x32, 0x10, 0x54, 0x80, 0xfe, 0xda, 0x57, + 0xd0, 0xb2, 0x92, 0x7f, 0xbb, 0x5f, 0xe7, 0x4d, + 0x1b, 0x3d, 0x46, 0x4d, 0xe4, 0x4c, 0xd6, 0xaf, + 0x1a, 0x32, 0x12, 0x40, 0xb8, 0x84, 0x8e, 0xe4, + 0x80, 0xce, 0x7e, 0xc1, 0x13, 0x8b, 0xb0, 0xb7, + 0x6f, 0x24, 0xba, 0x85, 0x50, 0x83, 0xc3, 0xcf, + 0x19, 0xb3, 0xf0, 0xc7, 0xee, 0x68, 0xbe, 0x9e, + 0x6d, 0xb9, 0xfb, 0xd5, 0x29, 0xce, 0x82, 0xcd, + 0x69, 0x16, 0x68, 0x6b, 0x6a, 0xf4, 0x02, 0x32, + 0xce, 0x60, 0x37, 0x0c, 0xb9, 0x38, 0x92, 0x9c, + 0x42, 0xa9, 0x0b, 0x53, 0x96, 0xfe, 0x39, 0xc1, + 0x24, 0x65, 0x9b, 0xcd, 0xe7, 0x8d, 0x36, 0x07, + 0x9f, 0x1d, 0x35, 0x8e, 0xdc, 0x4c, 0xb5, 0x68, + 0xc5, 0xfd, 0x44, 0x19, 0xf2, 0x6c, 0x59, 0x1c, + 0xb1, 0x0b, 0x35, 0x48, 0x86, 0x1a, 0x05, 0x22, + 0x03, 0x0c, 0x0c, 0xa2, 0x92, 0x90, 0x35, 0xfb, + 0x37, 0x94, 0xc7, 0x15, 0x84, 0xae, 0xe8, 0x05, + 0xa0, 0xf7, 0x30, 0x11, 0x5c, 0xe4, 0x5d, 0x3e, + 0x12, 0x54, 0x80, 0x54, 0x6b, 0x09, 0x8c, 0xce, + 0x80, 0x5e, 0xa7, 0xc8, 0x6a, 0x0c, 0x56, 0xe1, + 0x18, 0x7d, 0xc9, 0x39, 0xc1, 0xef, 0xe3, 0x25, + 0xa0, 0x8b, 0x2f, 0x60, 0x3a, 0x43, 0x39, 0xa6, + 0x28, 0x28, 0x7b, 0x4c, 0x77, 0xd4, 0x49, 0x61, + 0x46, 0xe9, 0x1b, 0x45, 0xd6, 0xb1, 0x56, 0xe1, + 0x7d, 0x34, 0xcd, 0x06, 0xb6, 0x67, 0x8d, 0x7d, + 0x7a, 0xe2, 0xbe, 0x68, 0x35, 0xa6, 0x78, 0xe5, + 0x47, 0x48, 0xb7, 0xc7, 0xde, 0xcd, 0xc9, 0x05, + 0xb4, 0xe7, 0x50, 0x48, 0xe1, 0x4b, 0xfe, 0x76, + 0x77, 0xc6, 0xf7, 0x5f, 0xcb, 0xc2, 0xa8, 0xd7, + 0xd6, 0x8a, 0xe5, 0x49, 0xd9, 0xca, 0x45, 0xf4, + 0xda, 0xcd, 0x33, 0xd1, 0x59, 0x2d, 0x9e, 0xc1, + 0x5c, 0xe6, 0x01, 0x18, 0xb8, 0xf0, 0x5e, 0xb1, + 0x69, 0x95, 0x2f, 0x02, 0x2a, 0xe7, 0x4a, 0xd7, + 0xd1, 0xc3, 0xd5, 0x6f, 0x15, 0xc8, 0xdc, 0x29, + 0xde, 0xb9, 0x3f, 0x8b, 0xa6, 0xbc, 0xdd, 0x25, + 0x84, 0x35, 0x3c, 0x90, 0x2d, 0xc2, 0x1e, 0x98, + 0x8a, 0x50, 0x09, 0x77, 0x42, 0xe9, 0x35, 0x8a, + 0x7c, 0x97, 0xbf, 0xe8, 0xbf, 0x56, 0xd0, 0x8b, + 0x65, 0xd3, 0xaf, 0x1e, 0x05, 0x94, 0xfa, 0xac, + 0xa8, 0x2b, 0x28, 0xcb, 0x37, 0x3e, 0xe8, 0xbb, + 0x66, 0x3a, 0xed, 0xb2, 0x48, 0x10, 0x0f, 0x3a, + 0x5a, 0xc5, 0xdb, 0x26, 0x0e, 0xaa, 0x5e, 0x69, + 0x15, 0xd6, 0x81, 0xae, 0xbd, 0xe6, 0x03, 0xf1, + 0xf6, 0x37, 0xc8, 0xde, 0x70, 0x1f, 0x64, 0xb9, + 0x5e, 0xbf, 0x2e, 0x4f, 0xb1, 0xea, 0xa0, 0x17, + 0xe6, 0x7c, 0xf9, 0x2f, 0x1e, 0xd8, 0x58, 0xde, + 0xa7, 0xf0, 0x46, 0x52, 0x95, 0xdf, 0xa4, 0x96, + 0xd0, 0xc4, 0x97, 0x2b, 0x95, 0xcd, 0x5e, 0x40, + 0x23, 0x5c, 0x10, 0xee, 0xba, 0x72, 0x9b, 0xcf, + 0x0b, 0xe8, 0x18, 0x3a, 0x70, 0xd2, 0x5e, 0x07, + 0x68, 0x93, 0xef, 0x4a, 0x5b, 0x8d, 0x72, 0x41, + 0x4e, 0xea, 0x33, 0x6a, 0x0a, 0x5e, 0xfb, 0x02, + 0x3f, 0xd4, 0xed, 0x5b, 0xe0, 0x42, 0x84, 0xd4, + 0xaa, 0x85, 0xdc, 0x5b, 0x67, 0xee, 0x71, 0x67, + 0xba, 0x8e, 0xd2, 0xbe, 0x61, 0xdf, 0x5a, 0x26, + 0xb9, 0xf0, 0x77, 0x81, 0x53, 0x24, 0x16, 0xcb, + 0x8c, 0xb8, 0x06, 0x6e, 0x68, 0xda, 0xc8, 0x2d, + 0x17, 0x54, 0xdb, 0x46, 0xcb, 0xfd, 0x1f, 0x3d, + 0x94, 0x81, 0x09, 0x4b, 0xfa, 0xb1, 0x46, 0xd9, + 0x11, 0xa3, 0xb7, 0x31, 0x9c, 0xd2, 0x38, 0xd6, + 0xba, 0x3d, 0xa3, 0x74, 0xd8, 0xf1, 0x24, 0xe8, + 0x9c, 0xcb, 0x1d, 0xf9, 0x4a, 0xf7, 0xc8, 0x4b, + 0xfe, 0x97, 0x7c, 0xa1, 0x02, 0xeb, 0x40, 0xc3, + 0x89, 0x71, 0x01, 0xcd, 0x33, 0x2a, 0xc2, 0x82, + 0xce, 0x62, 0x8d, 0x53, 0x7c, 0xdf, 0xce, 0xd7, + 0xf5, 0xa8, 0x4f, 0xf2, 0xf2, 0x2e, 0xc1, 0xeb, + 0x97, 0x99, 0x37, 0x3c, 0x53, 0xa6, 0xb4, 0x46, + 0x05, 0x64, 0x92, 0x87, 0x08, 0x3c, 0x23, 0x4b, + 0x9d, 0x67, 0x18, 0xf9, 0xe2, 0x0b, 0x1c, 0x39, + 0xd3, 0x87, 0x70, 0xc0, 0xb9, 0x1e, 0x52, 0x0a, + 0x0f, 0x48, 0xe2, 0xe7, 0x51, 0x72, 0x94, 0xf7, + 0xa3, 0xdc, 0xe5, 0x66, 0x33, 0x39, 0x54, 0x06, + 0x55, 0x93, 0x30, 0xf9, 0x5e, 0x76, 0x8f, 0xe0, + 0x59, 0x4d, 0x0d, 0xa7, 0xf5, 0xbe, 0xdb, 0x20, + 0xad, 0x0d, 0x76, 0x88, 0x5f, 0x9c, 0x7c, 0x75, + 0x2f, 0x2a, 0x0b, 0x79, 0x6e, 0xd3, 0xe2, 0x66, + 0xf5, 0x4a, 0x2d, 0x87, 0x87, 0x49, 0x84, 0x17, + 0xa2, 0x62, 0x4c, 0xbb, 0xe4, 0x6e, 0x98, 0x10, + 0xc9, 0xfb, 0x8a, 0x04, 0x68, 0x8d, 0x22, 0x66, + 0xad, 0xea, 0x2a, 0xc9, 0x97, 0x2d, 0x3c, 0xbc, + 0xd0, 0x77, 0x5f, 0xe6, 0xb8, 0x7f, 0xe6, 0xf6, + 0x39, 0xbf, 0x56, 0x0e, 0x26, 0x6d, 0xc5, 0x3e, + 0x53, 0x19, 0xd6, 0xb4, 0x57, 0x36, 0xa3, 0xc6, + 0xd3, 0x3d, 0x66, 0x79, 0x30, 0x5c, 0x14, 0x0c, + 0x0f, 0x3e, 0x96, 0xae, 0x90, 0x97, 0xab, 0x0d, + 0x9f, 0xc3, 0xe7, 0x66, 0x3e, 0xe0, 0x31, 0x43, + 0x4b, 0x01, 0xb3, 0x0e, 0x9e, 0x8c, 0x82, 0x4a, + 0x8c, 0xc7, 0x79, 0x85, 0xdf, 0x75, 0x0d, 0xb4, + 0x2b, 0x03, 0x14, 0xef, 0x72, 0x58, 0xfd, 0x64, + 0xc8, 0xe3, 0x0d, 0x9a, 0x14, 0x6f, 0x76, 0xf9, + 0x46, 0xd1, 0xd2, 0x81, 0xb3, 0x16, 0x6e, 0xc7, + 0x76, 0x82, 0xce, 0xf4, 0xee, 0x33, 0x00, 0xe6, + 0x77, 0xc4, 0xad, 0x4f, 0x06, 0xa7, 0x48, 0x80, + 0x9e, 0x21, 0x66, 0xca, 0x75, 0x69, 0x57, 0xcb, + 0xf0, 0x67, 0x6a, 0xaa, 0x8f, 0x88, 0x14, 0xbd, + 0x65, 0x62, 0xe2, 0xad, 0xcc, 0x22, 0x88, 0x7b, + 0x94, 0xbd, 0x0e, 0xcd, 0xb6, 0x69, 0xa2, 0xcb, + 0x7d, 0x57, 0x5c, 0xb4, 0x92, 0x80, 0x13, 0x99, + 0x84, 0xf3, 0x79, 0x0a, 0x2d, 0x70, 0xa4, 0xe0, + 0xde, 0xc6, 0x32, 0xb0, 0x8a, 0x62, 0xb5, 0xcf, + 0xfa, 0x5e, 0x5a, 0x92, 0x32, 0x7d, 0x34, 0x07, + 0xb5, 0x52, 0x3a, 0xb5, 0x7d, 0x0f, 0xa1, 0xba, + 0x56, 0xd0, 0x07, 0x76, 0x11, 0xf2, 0xc3, 0x33, + 0x9d, 0xbd, 0x12, 0x35, 0x5e, 0xf7, 0x05, 0x88, + 0x76, 0x94, 0xa6, 0xbf, 0xed, 0xb8, 0xa4, 0xa2, + 0x0c, 0xbe, 0x0f, 0x6a, 0xaf, 0xf3, 0x1b, 0x33, + 0x4a, 0xb7, 0x68, 0x3f, 0xbe, 0x95, 0x13, 0x97, + 0x0f, 0x15, 0x17, 0x1b, 0x23, 0xaa, 0x08, 0x78, + 0xa6, 0x5b, 0x08, 0xa2, 0x9d, 0x03, 0xa8, 0xa7, + 0x39, 0xdc, 0xbc, 0x9a, 0x85, 0xf5, 0xe5, 0x55, + 0x59, 0x3c, 0xef, 0xf9, 0x3f, 0x22, 0x8e, 0xf8, + 0xd8, 0x3e, 0x02, 0x0b, 0xd8, 0x78, 0x4b, 0x15, + 0x7f, 0xaa, 0x2c, 0xff, 0xbe, 0x77, 0x33, 0xc7, + 0x6a, 0x12, 0xaa, 0xa4, 0xbe, 0xc0, 0x3b, 0xcb, + 0x13, 0x9d, 0x9c, 0x5a, 0x9f, 0x8a, 0x57, 0x36, + 0x4f, 0x02, 0x5a, 0xf8, 0x1d, 0x97, 0x77, 0x43, + 0xc8, 0xa5, 0xb7, 0x9b, 0x10, 0x98, 0xfd, 0x58, + 0xbf, 0x42, 0xf6, 0xbf, 0xff, 0x6c, 0x40, 0x18, + 0x18, 0xdf, 0xac, 0x57, 0x71, 0xea, 0xcc, 0x8e, + 0xfd, 0xfe, 0x10, 0xfb, 0xb9, 0xfe, 0xbc, 0x9a, + 0x9c, 0x27, 0xe4, 0x10, 0x15, 0x94, 0x41, 0xa1, + 0xcc, 0xf6, 0x25, 0x49, 0x4f, 0x96, 0xc1, 0x8c, + 0x9e, 0x3e, 0x18, 0x29, 0x49, 0x92, 0xe7, 0xfe, + 0x22, 0xff, 0xed, 0x02, 0x16, 0x90, 0xef, 0xac, + 0xec, 0x95, 0x1d, 0x5b, 0x94, 0x9c, 0xf6, 0x7c, + 0x1b, 0x5a, 0x9d, 0xb0, 0x9b, 0x05, 0x36, 0xbf, + 0xef, 0xec, 0x63, 0x35, 0x40, 0x24, 0x45, 0x40, + 0x30, 0x1a, 0x9b, 0x90, 0xc3, 0xc2, 0xf7, 0x37, + 0xfb, 0x08, 0x8e, 0x48, 0x19, 0x48, 0xed, 0xa8, + 0xa8, 0x04, 0x6f, 0xd0, 0x33, 0xe9, 0xb8, 0x8d, + 0xe7, 0x1e, 0x5c, 0x47, 0x74, 0xc0, 0x66, 0x30, + 0x4e, 0xa7, 0x86, 0x73, 0xf1, 0xe5, 0x78, 0xa6, + 0xe0, 0xc1, 0xda, 0x13, 0x72, 0x07, 0x85, 0x34, + 0x63, 0x95, 0x49, 0x30, 0x4b, 0x9d, 0x03, 0xf1, + 0x7a, 0x6b, 0x91, 0xa2, 0x85, 0x41, 0xf9, 0x4a, + 0xd6, 0xff, 0xff, 0x86, 0xf7, 0xf0, 0xce, 0xb9, + 0x07, 0xf1, 0x88, 0x04, 0x33, 0xaa, 0xeb, 0x54, + 0xb2, 0x1c, 0x8e, 0x2e, 0x7b, 0x04, 0xa8, 0xcc, + 0x2c, 0x7a, 0xb3, 0xad, 0x1a, 0x89, 0x38, 0x89, + 0xd7, 0x11, 0x3a, 0x8c, 0xcf, 0xe3, 0xc5, 0xba, + 0xb0, 0xcc, 0xc4, 0xe3, 0x33, 0xf3, 0x18, 0xba, + 0xec, 0x56, 0xd9, 0x1c, 0x40, 0x70, 0x0d, 0x4e, + 0x97, 0x01, 0x23, 0xf3, 0x5a, 0xdc, 0xbf, 0x68, + 0x93, 0xc2, 0x1d, 0x8a, 0x96, 0xb7, 0xac, 0x18, + 0x6f, 0xf7, 0x84, 0x71, 0x0d, 0x3d, 0xf8, 0xba, + 0xdf, 0xb6, 0x89, 0x1d, 0x78, 0x19, 0xf2, 0x59, + 0xe9, 0x15, 0x55, 0x29, 0x73, 0x50, 0x59, 0x14, + 0x02, 0x21, 0x16, 0x8f, 0x0f, 0xdf, 0xa5, 0xf0, +}; + +static struct crc_test { + uint32_t crc; /* random starting crc */ + uint32_t start; /* random offset in buf */ + uint32_t length; /* random length of test */ + uint32_t crc32c_le; /* expected crc32c_le result */ + uint32_t crc32_be; /* expected crc32_be result */ +} test[] = { + {0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3}, + {0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8}, + {0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4}, + {0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56}, + {0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201}, + {0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be}, + {0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9}, + {0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c}, + {0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b}, + {0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7}, + {0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd}, + {0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7}, + {0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5}, + {0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707}, + {0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1}, + {0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f}, + {0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85}, + {0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe}, + {0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6}, + {0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1}, + {0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339}, + {0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979}, + {0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed}, + {0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b}, + {0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6}, + {0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78}, + {0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627}, + {0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656}, + {0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974}, + {0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c}, + {0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644}, + {0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396}, + {0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee}, + {0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74}, + {0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b}, + {0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be}, + {0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2}, + {0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672}, + {0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2}, + {0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd}, + {0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b}, + {0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b}, + {0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee}, + {0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753}, + {0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5}, + {0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b}, + {0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6}, + {0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e}, + {0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523}, + {0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa}, + {0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736}, + {0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994}, + {0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78}, + {0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5}, + {0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b}, + {0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743}, + {0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809}, + {0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f}, + {0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c}, + {0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091}, + {0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1}, + {0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905}, + {0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57}, + {0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4}, + {0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3}, + {0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32}, + {0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e}, + {0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4}, + {0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021}, + {0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e}, + {0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d}, + {0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05}, + {0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1}, + {0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e}, + {0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb}, + {0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0}, + {0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c}, + {0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7}, + {0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d}, + {0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a}, + {0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35}, + {0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1}, + {0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66}, + {0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534}, + {0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f}, + {0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06}, + {0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba}, + {0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8}, + {0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b}, + {0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d}, + {0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c}, + {0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003}, + {0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687}, + {0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957}, + {0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255}, + {0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93}, + {0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509}, + {0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9}, + {0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c}, + {0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff}, + {0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5}, + {0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c}, + {0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa}, + {0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed}, + {0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e}, + {0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798}, + {0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a}, + {0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637}, + {0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e}, + {0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121}, + {0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380}, + {0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559}, + {0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b}, + {0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a}, + {0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09}, + {0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c}, + {0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12}, + {0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf}, + {0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235}, + {0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521}, + {0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088}, + {0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd}, + {0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02}, + {0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8}, + {0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f}, + {0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61}, + {0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6}, + {0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72}, + {0, 0, 0, 0, 0}, +}; + +static int test_crc32c(void) +{ + struct crc_test *t = test; + int failures = 0; + + while (t->length) { + uint32_t be, le; + le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length); + be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length); + if (le != t->crc32c_le) { + printf("Test %d LE fails, %x != %x\n", + (int) (t - test), le, t->crc32c_le); + failures++; + } + if (be != t->crc32_be) { + printf("Test %d BE fails, %x != %x\n", + (int) (t - test), be, t->crc32_be); + failures++; + } + t++; + } + + return failures; +} + +int main(int argc, char *argv[]) +{ + int ret; + + ret = test_crc32c(); + if (!ret) + printf("No failures.\n"); + + return ret; +} +#endif /* UNITTEST */ diff --git a/src/ext2fs/crc32c_defs.h b/src/ext2fs/crc32c_defs.h new file mode 100644 index 00000000..3f9a09e5 --- /dev/null +++ b/src/ext2fs/crc32c_defs.h @@ -0,0 +1,59 @@ +/* + * There are multiple 16-bit CRC polynomials in common use, but this is + * *the* standard CRC-32 polynomial, first popularized by Ethernet. + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 + */ +#define CRCPOLY_LE 0xedb88320 +#define CRCPOLY_BE 0x04c11db7 + +/* + * This is the CRC32c polynomial, as outlined by Castagnoli. + * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+ + * x^8+x^6+x^0 + */ +#define CRC32C_POLY_LE 0x82F63B78 +#define CRC32C_POLY_BE 0x1EDC6F41 + +/* How many bits at a time to use. Valid values are 1, 2, 4, 8, 32 and 64. */ +/* For less performance-sensitive, use 4 */ +#ifndef CRC_LE_BITS +# define CRC_LE_BITS 64 +#endif +#ifndef CRC_BE_BITS +# define CRC_BE_BITS 64 +#endif + +/* + * Little-endian CRC computation. Used with serial bit streams sent + * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC. + */ +#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \ + CRC_LE_BITS & CRC_LE_BITS-1 +# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}" +#endif + +/* + * Big-endian CRC computation. Used with serial bit streams sent + * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC. + */ +#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \ + CRC_BE_BITS & CRC_BE_BITS-1 +# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}" +#endif + + +#define ___constant_swab32(x) \ + ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))) + + +#if (__GNUC__ >= 3) +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif diff --git a/src/ext2fs/crc32c_table.h b/src/ext2fs/crc32c_table.h new file mode 100644 index 00000000..847429ed --- /dev/null +++ b/src/ext2fs/crc32c_table.h @@ -0,0 +1,1044 @@ +/* this file is generated - do not edit */ + +static const uint32_t crc32table_be[8][256] = {{ + tobe(0x00000000L), tobe(0x04c11db7L), tobe(0x09823b6eL), tobe(0x0d4326d9L), + tobe(0x130476dcL), tobe(0x17c56b6bL), tobe(0x1a864db2L), tobe(0x1e475005L), + tobe(0x2608edb8L), tobe(0x22c9f00fL), tobe(0x2f8ad6d6L), tobe(0x2b4bcb61L), + tobe(0x350c9b64L), tobe(0x31cd86d3L), tobe(0x3c8ea00aL), tobe(0x384fbdbdL), + tobe(0x4c11db70L), tobe(0x48d0c6c7L), tobe(0x4593e01eL), tobe(0x4152fda9L), + tobe(0x5f15adacL), tobe(0x5bd4b01bL), tobe(0x569796c2L), tobe(0x52568b75L), + tobe(0x6a1936c8L), tobe(0x6ed82b7fL), tobe(0x639b0da6L), tobe(0x675a1011L), + tobe(0x791d4014L), tobe(0x7ddc5da3L), tobe(0x709f7b7aL), tobe(0x745e66cdL), + tobe(0x9823b6e0L), tobe(0x9ce2ab57L), tobe(0x91a18d8eL), tobe(0x95609039L), + tobe(0x8b27c03cL), tobe(0x8fe6dd8bL), tobe(0x82a5fb52L), tobe(0x8664e6e5L), + tobe(0xbe2b5b58L), tobe(0xbaea46efL), tobe(0xb7a96036L), tobe(0xb3687d81L), + tobe(0xad2f2d84L), tobe(0xa9ee3033L), tobe(0xa4ad16eaL), tobe(0xa06c0b5dL), + tobe(0xd4326d90L), tobe(0xd0f37027L), tobe(0xddb056feL), tobe(0xd9714b49L), + tobe(0xc7361b4cL), tobe(0xc3f706fbL), tobe(0xceb42022L), tobe(0xca753d95L), + tobe(0xf23a8028L), tobe(0xf6fb9d9fL), tobe(0xfbb8bb46L), tobe(0xff79a6f1L), + tobe(0xe13ef6f4L), tobe(0xe5ffeb43L), tobe(0xe8bccd9aL), tobe(0xec7dd02dL), + tobe(0x34867077L), tobe(0x30476dc0L), tobe(0x3d044b19L), tobe(0x39c556aeL), + tobe(0x278206abL), tobe(0x23431b1cL), tobe(0x2e003dc5L), tobe(0x2ac12072L), + tobe(0x128e9dcfL), tobe(0x164f8078L), tobe(0x1b0ca6a1L), tobe(0x1fcdbb16L), + tobe(0x018aeb13L), tobe(0x054bf6a4L), tobe(0x0808d07dL), tobe(0x0cc9cdcaL), + tobe(0x7897ab07L), tobe(0x7c56b6b0L), tobe(0x71159069L), tobe(0x75d48ddeL), + tobe(0x6b93dddbL), tobe(0x6f52c06cL), tobe(0x6211e6b5L), tobe(0x66d0fb02L), + tobe(0x5e9f46bfL), tobe(0x5a5e5b08L), tobe(0x571d7dd1L), tobe(0x53dc6066L), + tobe(0x4d9b3063L), tobe(0x495a2dd4L), tobe(0x44190b0dL), tobe(0x40d816baL), + tobe(0xaca5c697L), tobe(0xa864db20L), tobe(0xa527fdf9L), tobe(0xa1e6e04eL), + tobe(0xbfa1b04bL), tobe(0xbb60adfcL), tobe(0xb6238b25L), tobe(0xb2e29692L), + tobe(0x8aad2b2fL), tobe(0x8e6c3698L), tobe(0x832f1041L), tobe(0x87ee0df6L), + tobe(0x99a95df3L), tobe(0x9d684044L), tobe(0x902b669dL), tobe(0x94ea7b2aL), + tobe(0xe0b41de7L), tobe(0xe4750050L), tobe(0xe9362689L), tobe(0xedf73b3eL), + tobe(0xf3b06b3bL), tobe(0xf771768cL), tobe(0xfa325055L), tobe(0xfef34de2L), + tobe(0xc6bcf05fL), tobe(0xc27dede8L), tobe(0xcf3ecb31L), tobe(0xcbffd686L), + tobe(0xd5b88683L), tobe(0xd1799b34L), tobe(0xdc3abdedL), tobe(0xd8fba05aL), + tobe(0x690ce0eeL), tobe(0x6dcdfd59L), tobe(0x608edb80L), tobe(0x644fc637L), + tobe(0x7a089632L), tobe(0x7ec98b85L), tobe(0x738aad5cL), tobe(0x774bb0ebL), + tobe(0x4f040d56L), tobe(0x4bc510e1L), tobe(0x46863638L), tobe(0x42472b8fL), + tobe(0x5c007b8aL), tobe(0x58c1663dL), tobe(0x558240e4L), tobe(0x51435d53L), + tobe(0x251d3b9eL), tobe(0x21dc2629L), tobe(0x2c9f00f0L), tobe(0x285e1d47L), + tobe(0x36194d42L), tobe(0x32d850f5L), tobe(0x3f9b762cL), tobe(0x3b5a6b9bL), + tobe(0x0315d626L), tobe(0x07d4cb91L), tobe(0x0a97ed48L), tobe(0x0e56f0ffL), + tobe(0x1011a0faL), tobe(0x14d0bd4dL), tobe(0x19939b94L), tobe(0x1d528623L), + tobe(0xf12f560eL), tobe(0xf5ee4bb9L), tobe(0xf8ad6d60L), tobe(0xfc6c70d7L), + tobe(0xe22b20d2L), tobe(0xe6ea3d65L), tobe(0xeba91bbcL), tobe(0xef68060bL), + tobe(0xd727bbb6L), tobe(0xd3e6a601L), tobe(0xdea580d8L), tobe(0xda649d6fL), + tobe(0xc423cd6aL), tobe(0xc0e2d0ddL), tobe(0xcda1f604L), tobe(0xc960ebb3L), + tobe(0xbd3e8d7eL), tobe(0xb9ff90c9L), tobe(0xb4bcb610L), tobe(0xb07daba7L), + tobe(0xae3afba2L), tobe(0xaafbe615L), tobe(0xa7b8c0ccL), tobe(0xa379dd7bL), + tobe(0x9b3660c6L), tobe(0x9ff77d71L), tobe(0x92b45ba8L), tobe(0x9675461fL), + tobe(0x8832161aL), tobe(0x8cf30badL), tobe(0x81b02d74L), tobe(0x857130c3L), + tobe(0x5d8a9099L), tobe(0x594b8d2eL), tobe(0x5408abf7L), tobe(0x50c9b640L), + tobe(0x4e8ee645L), tobe(0x4a4ffbf2L), tobe(0x470cdd2bL), tobe(0x43cdc09cL), + tobe(0x7b827d21L), tobe(0x7f436096L), tobe(0x7200464fL), tobe(0x76c15bf8L), + tobe(0x68860bfdL), tobe(0x6c47164aL), tobe(0x61043093L), tobe(0x65c52d24L), + tobe(0x119b4be9L), tobe(0x155a565eL), tobe(0x18197087L), tobe(0x1cd86d30L), + tobe(0x029f3d35L), tobe(0x065e2082L), tobe(0x0b1d065bL), tobe(0x0fdc1becL), + tobe(0x3793a651L), tobe(0x3352bbe6L), tobe(0x3e119d3fL), tobe(0x3ad08088L), + tobe(0x2497d08dL), tobe(0x2056cd3aL), tobe(0x2d15ebe3L), tobe(0x29d4f654L), + tobe(0xc5a92679L), tobe(0xc1683bceL), tobe(0xcc2b1d17L), tobe(0xc8ea00a0L), + tobe(0xd6ad50a5L), tobe(0xd26c4d12L), tobe(0xdf2f6bcbL), tobe(0xdbee767cL), + tobe(0xe3a1cbc1L), tobe(0xe760d676L), tobe(0xea23f0afL), tobe(0xeee2ed18L), + tobe(0xf0a5bd1dL), tobe(0xf464a0aaL), tobe(0xf9278673L), tobe(0xfde69bc4L), + tobe(0x89b8fd09L), tobe(0x8d79e0beL), tobe(0x803ac667L), tobe(0x84fbdbd0L), + tobe(0x9abc8bd5L), tobe(0x9e7d9662L), tobe(0x933eb0bbL), tobe(0x97ffad0cL), + tobe(0xafb010b1L), tobe(0xab710d06L), tobe(0xa6322bdfL), tobe(0xa2f33668L), + tobe(0xbcb4666dL), tobe(0xb8757bdaL), tobe(0xb5365d03L), tobe(0xb1f740b4L)}, + { + tobe(0x00000000L), tobe(0xd219c1dcL), tobe(0xa0f29e0fL), tobe(0x72eb5fd3L), + tobe(0x452421a9L), tobe(0x973de075L), tobe(0xe5d6bfa6L), tobe(0x37cf7e7aL), + tobe(0x8a484352L), tobe(0x5851828eL), tobe(0x2abadd5dL), tobe(0xf8a31c81L), + tobe(0xcf6c62fbL), tobe(0x1d75a327L), tobe(0x6f9efcf4L), tobe(0xbd873d28L), + tobe(0x10519b13L), tobe(0xc2485acfL), tobe(0xb0a3051cL), tobe(0x62bac4c0L), + tobe(0x5575babaL), tobe(0x876c7b66L), tobe(0xf58724b5L), tobe(0x279ee569L), + tobe(0x9a19d841L), tobe(0x4800199dL), tobe(0x3aeb464eL), tobe(0xe8f28792L), + tobe(0xdf3df9e8L), tobe(0x0d243834L), tobe(0x7fcf67e7L), tobe(0xadd6a63bL), + tobe(0x20a33626L), tobe(0xf2baf7faL), tobe(0x8051a829L), tobe(0x524869f5L), + tobe(0x6587178fL), tobe(0xb79ed653L), tobe(0xc5758980L), tobe(0x176c485cL), + tobe(0xaaeb7574L), tobe(0x78f2b4a8L), tobe(0x0a19eb7bL), tobe(0xd8002aa7L), + tobe(0xefcf54ddL), tobe(0x3dd69501L), tobe(0x4f3dcad2L), tobe(0x9d240b0eL), + tobe(0x30f2ad35L), tobe(0xe2eb6ce9L), tobe(0x9000333aL), tobe(0x4219f2e6L), + tobe(0x75d68c9cL), tobe(0xa7cf4d40L), tobe(0xd5241293L), tobe(0x073dd34fL), + tobe(0xbabaee67L), tobe(0x68a32fbbL), tobe(0x1a487068L), tobe(0xc851b1b4L), + tobe(0xff9ecfceL), tobe(0x2d870e12L), tobe(0x5f6c51c1L), tobe(0x8d75901dL), + tobe(0x41466c4cL), tobe(0x935fad90L), tobe(0xe1b4f243L), tobe(0x33ad339fL), + tobe(0x04624de5L), tobe(0xd67b8c39L), tobe(0xa490d3eaL), tobe(0x76891236L), + tobe(0xcb0e2f1eL), tobe(0x1917eec2L), tobe(0x6bfcb111L), tobe(0xb9e570cdL), + tobe(0x8e2a0eb7L), tobe(0x5c33cf6bL), tobe(0x2ed890b8L), tobe(0xfcc15164L), + tobe(0x5117f75fL), tobe(0x830e3683L), tobe(0xf1e56950L), tobe(0x23fca88cL), + tobe(0x1433d6f6L), tobe(0xc62a172aL), tobe(0xb4c148f9L), tobe(0x66d88925L), + tobe(0xdb5fb40dL), tobe(0x094675d1L), tobe(0x7bad2a02L), tobe(0xa9b4ebdeL), + tobe(0x9e7b95a4L), tobe(0x4c625478L), tobe(0x3e890babL), tobe(0xec90ca77L), + tobe(0x61e55a6aL), tobe(0xb3fc9bb6L), tobe(0xc117c465L), tobe(0x130e05b9L), + tobe(0x24c17bc3L), tobe(0xf6d8ba1fL), tobe(0x8433e5ccL), tobe(0x562a2410L), + tobe(0xebad1938L), tobe(0x39b4d8e4L), tobe(0x4b5f8737L), tobe(0x994646ebL), + tobe(0xae893891L), tobe(0x7c90f94dL), tobe(0x0e7ba69eL), tobe(0xdc626742L), + tobe(0x71b4c179L), tobe(0xa3ad00a5L), tobe(0xd1465f76L), tobe(0x035f9eaaL), + tobe(0x3490e0d0L), tobe(0xe689210cL), tobe(0x94627edfL), tobe(0x467bbf03L), + tobe(0xfbfc822bL), tobe(0x29e543f7L), tobe(0x5b0e1c24L), tobe(0x8917ddf8L), + tobe(0xbed8a382L), tobe(0x6cc1625eL), tobe(0x1e2a3d8dL), tobe(0xcc33fc51L), + tobe(0x828cd898L), tobe(0x50951944L), tobe(0x227e4697L), tobe(0xf067874bL), + tobe(0xc7a8f931L), tobe(0x15b138edL), tobe(0x675a673eL), tobe(0xb543a6e2L), + tobe(0x08c49bcaL), tobe(0xdadd5a16L), tobe(0xa83605c5L), tobe(0x7a2fc419L), + tobe(0x4de0ba63L), tobe(0x9ff97bbfL), tobe(0xed12246cL), tobe(0x3f0be5b0L), + tobe(0x92dd438bL), tobe(0x40c48257L), tobe(0x322fdd84L), tobe(0xe0361c58L), + tobe(0xd7f96222L), tobe(0x05e0a3feL), tobe(0x770bfc2dL), tobe(0xa5123df1L), + tobe(0x189500d9L), tobe(0xca8cc105L), tobe(0xb8679ed6L), tobe(0x6a7e5f0aL), + tobe(0x5db12170L), tobe(0x8fa8e0acL), tobe(0xfd43bf7fL), tobe(0x2f5a7ea3L), + tobe(0xa22feebeL), tobe(0x70362f62L), tobe(0x02dd70b1L), tobe(0xd0c4b16dL), + tobe(0xe70bcf17L), tobe(0x35120ecbL), tobe(0x47f95118L), tobe(0x95e090c4L), + tobe(0x2867adecL), tobe(0xfa7e6c30L), tobe(0x889533e3L), tobe(0x5a8cf23fL), + tobe(0x6d438c45L), tobe(0xbf5a4d99L), tobe(0xcdb1124aL), tobe(0x1fa8d396L), + tobe(0xb27e75adL), tobe(0x6067b471L), tobe(0x128ceba2L), tobe(0xc0952a7eL), + tobe(0xf75a5404L), tobe(0x254395d8L), tobe(0x57a8ca0bL), tobe(0x85b10bd7L), + tobe(0x383636ffL), tobe(0xea2ff723L), tobe(0x98c4a8f0L), tobe(0x4add692cL), + tobe(0x7d121756L), tobe(0xaf0bd68aL), tobe(0xdde08959L), tobe(0x0ff94885L), + tobe(0xc3cab4d4L), tobe(0x11d37508L), tobe(0x63382adbL), tobe(0xb121eb07L), + tobe(0x86ee957dL), tobe(0x54f754a1L), tobe(0x261c0b72L), tobe(0xf405caaeL), + tobe(0x4982f786L), tobe(0x9b9b365aL), tobe(0xe9706989L), tobe(0x3b69a855L), + tobe(0x0ca6d62fL), tobe(0xdebf17f3L), tobe(0xac544820L), tobe(0x7e4d89fcL), + tobe(0xd39b2fc7L), tobe(0x0182ee1bL), tobe(0x7369b1c8L), tobe(0xa1707014L), + tobe(0x96bf0e6eL), tobe(0x44a6cfb2L), tobe(0x364d9061L), tobe(0xe45451bdL), + tobe(0x59d36c95L), tobe(0x8bcaad49L), tobe(0xf921f29aL), tobe(0x2b383346L), + tobe(0x1cf74d3cL), tobe(0xceee8ce0L), tobe(0xbc05d333L), tobe(0x6e1c12efL), + tobe(0xe36982f2L), tobe(0x3170432eL), tobe(0x439b1cfdL), tobe(0x9182dd21L), + tobe(0xa64da35bL), tobe(0x74546287L), tobe(0x06bf3d54L), tobe(0xd4a6fc88L), + tobe(0x6921c1a0L), tobe(0xbb38007cL), tobe(0xc9d35fafL), tobe(0x1bca9e73L), + tobe(0x2c05e009L), tobe(0xfe1c21d5L), tobe(0x8cf77e06L), tobe(0x5eeebfdaL), + tobe(0xf33819e1L), tobe(0x2121d83dL), tobe(0x53ca87eeL), tobe(0x81d34632L), + tobe(0xb61c3848L), tobe(0x6405f994L), tobe(0x16eea647L), tobe(0xc4f7679bL), + tobe(0x79705ab3L), tobe(0xab699b6fL), tobe(0xd982c4bcL), tobe(0x0b9b0560L), + tobe(0x3c547b1aL), tobe(0xee4dbac6L), tobe(0x9ca6e515L), tobe(0x4ebf24c9L)}, + { + tobe(0x00000000L), tobe(0x01d8ac87L), tobe(0x03b1590eL), tobe(0x0269f589L), + tobe(0x0762b21cL), tobe(0x06ba1e9bL), tobe(0x04d3eb12L), tobe(0x050b4795L), + tobe(0x0ec56438L), tobe(0x0f1dc8bfL), tobe(0x0d743d36L), tobe(0x0cac91b1L), + tobe(0x09a7d624L), tobe(0x087f7aa3L), tobe(0x0a168f2aL), tobe(0x0bce23adL), + tobe(0x1d8ac870L), tobe(0x1c5264f7L), tobe(0x1e3b917eL), tobe(0x1fe33df9L), + tobe(0x1ae87a6cL), tobe(0x1b30d6ebL), tobe(0x19592362L), tobe(0x18818fe5L), + tobe(0x134fac48L), tobe(0x129700cfL), tobe(0x10fef546L), tobe(0x112659c1L), + tobe(0x142d1e54L), tobe(0x15f5b2d3L), tobe(0x179c475aL), tobe(0x1644ebddL), + tobe(0x3b1590e0L), tobe(0x3acd3c67L), tobe(0x38a4c9eeL), tobe(0x397c6569L), + tobe(0x3c7722fcL), tobe(0x3daf8e7bL), tobe(0x3fc67bf2L), tobe(0x3e1ed775L), + tobe(0x35d0f4d8L), tobe(0x3408585fL), tobe(0x3661add6L), tobe(0x37b90151L), + tobe(0x32b246c4L), tobe(0x336aea43L), tobe(0x31031fcaL), tobe(0x30dbb34dL), + tobe(0x269f5890L), tobe(0x2747f417L), tobe(0x252e019eL), tobe(0x24f6ad19L), + tobe(0x21fdea8cL), tobe(0x2025460bL), tobe(0x224cb382L), tobe(0x23941f05L), + tobe(0x285a3ca8L), tobe(0x2982902fL), tobe(0x2beb65a6L), tobe(0x2a33c921L), + tobe(0x2f388eb4L), tobe(0x2ee02233L), tobe(0x2c89d7baL), tobe(0x2d517b3dL), + tobe(0x762b21c0L), tobe(0x77f38d47L), tobe(0x759a78ceL), tobe(0x7442d449L), + tobe(0x714993dcL), tobe(0x70913f5bL), tobe(0x72f8cad2L), tobe(0x73206655L), + tobe(0x78ee45f8L), tobe(0x7936e97fL), tobe(0x7b5f1cf6L), tobe(0x7a87b071L), + tobe(0x7f8cf7e4L), tobe(0x7e545b63L), tobe(0x7c3daeeaL), tobe(0x7de5026dL), + tobe(0x6ba1e9b0L), tobe(0x6a794537L), tobe(0x6810b0beL), tobe(0x69c81c39L), + tobe(0x6cc35bacL), tobe(0x6d1bf72bL), tobe(0x6f7202a2L), tobe(0x6eaaae25L), + tobe(0x65648d88L), tobe(0x64bc210fL), tobe(0x66d5d486L), tobe(0x670d7801L), + tobe(0x62063f94L), tobe(0x63de9313L), tobe(0x61b7669aL), tobe(0x606fca1dL), + tobe(0x4d3eb120L), tobe(0x4ce61da7L), tobe(0x4e8fe82eL), tobe(0x4f5744a9L), + tobe(0x4a5c033cL), tobe(0x4b84afbbL), tobe(0x49ed5a32L), tobe(0x4835f6b5L), + tobe(0x43fbd518L), tobe(0x4223799fL), tobe(0x404a8c16L), tobe(0x41922091L), + tobe(0x44996704L), tobe(0x4541cb83L), tobe(0x47283e0aL), tobe(0x46f0928dL), + tobe(0x50b47950L), tobe(0x516cd5d7L), tobe(0x5305205eL), tobe(0x52dd8cd9L), + tobe(0x57d6cb4cL), tobe(0x560e67cbL), tobe(0x54679242L), tobe(0x55bf3ec5L), + tobe(0x5e711d68L), tobe(0x5fa9b1efL), tobe(0x5dc04466L), tobe(0x5c18e8e1L), + tobe(0x5913af74L), tobe(0x58cb03f3L), tobe(0x5aa2f67aL), tobe(0x5b7a5afdL), + tobe(0xec564380L), tobe(0xed8eef07L), tobe(0xefe71a8eL), tobe(0xee3fb609L), + tobe(0xeb34f19cL), tobe(0xeaec5d1bL), tobe(0xe885a892L), tobe(0xe95d0415L), + tobe(0xe29327b8L), tobe(0xe34b8b3fL), tobe(0xe1227eb6L), tobe(0xe0fad231L), + tobe(0xe5f195a4L), tobe(0xe4293923L), tobe(0xe640ccaaL), tobe(0xe798602dL), + tobe(0xf1dc8bf0L), tobe(0xf0042777L), tobe(0xf26dd2feL), tobe(0xf3b57e79L), + tobe(0xf6be39ecL), tobe(0xf766956bL), tobe(0xf50f60e2L), tobe(0xf4d7cc65L), + tobe(0xff19efc8L), tobe(0xfec1434fL), tobe(0xfca8b6c6L), tobe(0xfd701a41L), + tobe(0xf87b5dd4L), tobe(0xf9a3f153L), tobe(0xfbca04daL), tobe(0xfa12a85dL), + tobe(0xd743d360L), tobe(0xd69b7fe7L), tobe(0xd4f28a6eL), tobe(0xd52a26e9L), + tobe(0xd021617cL), tobe(0xd1f9cdfbL), tobe(0xd3903872L), tobe(0xd24894f5L), + tobe(0xd986b758L), tobe(0xd85e1bdfL), tobe(0xda37ee56L), tobe(0xdbef42d1L), + tobe(0xdee40544L), tobe(0xdf3ca9c3L), tobe(0xdd555c4aL), tobe(0xdc8df0cdL), + tobe(0xcac91b10L), tobe(0xcb11b797L), tobe(0xc978421eL), tobe(0xc8a0ee99L), + tobe(0xcdaba90cL), tobe(0xcc73058bL), tobe(0xce1af002L), tobe(0xcfc25c85L), + tobe(0xc40c7f28L), tobe(0xc5d4d3afL), tobe(0xc7bd2626L), tobe(0xc6658aa1L), + tobe(0xc36ecd34L), tobe(0xc2b661b3L), tobe(0xc0df943aL), tobe(0xc10738bdL), + tobe(0x9a7d6240L), tobe(0x9ba5cec7L), tobe(0x99cc3b4eL), tobe(0x981497c9L), + tobe(0x9d1fd05cL), tobe(0x9cc77cdbL), tobe(0x9eae8952L), tobe(0x9f7625d5L), + tobe(0x94b80678L), tobe(0x9560aaffL), tobe(0x97095f76L), tobe(0x96d1f3f1L), + tobe(0x93dab464L), tobe(0x920218e3L), tobe(0x906bed6aL), tobe(0x91b341edL), + tobe(0x87f7aa30L), tobe(0x862f06b7L), tobe(0x8446f33eL), tobe(0x859e5fb9L), + tobe(0x8095182cL), tobe(0x814db4abL), tobe(0x83244122L), tobe(0x82fceda5L), + tobe(0x8932ce08L), tobe(0x88ea628fL), tobe(0x8a839706L), tobe(0x8b5b3b81L), + tobe(0x8e507c14L), tobe(0x8f88d093L), tobe(0x8de1251aL), tobe(0x8c39899dL), + tobe(0xa168f2a0L), tobe(0xa0b05e27L), tobe(0xa2d9abaeL), tobe(0xa3010729L), + tobe(0xa60a40bcL), tobe(0xa7d2ec3bL), tobe(0xa5bb19b2L), tobe(0xa463b535L), + tobe(0xafad9698L), tobe(0xae753a1fL), tobe(0xac1ccf96L), tobe(0xadc46311L), + tobe(0xa8cf2484L), tobe(0xa9178803L), tobe(0xab7e7d8aL), tobe(0xaaa6d10dL), + tobe(0xbce23ad0L), tobe(0xbd3a9657L), tobe(0xbf5363deL), tobe(0xbe8bcf59L), + tobe(0xbb8088ccL), tobe(0xba58244bL), tobe(0xb831d1c2L), tobe(0xb9e97d45L), + tobe(0xb2275ee8L), tobe(0xb3fff26fL), tobe(0xb19607e6L), tobe(0xb04eab61L), + tobe(0xb545ecf4L), tobe(0xb49d4073L), tobe(0xb6f4b5faL), tobe(0xb72c197dL)}, + { + tobe(0x00000000L), tobe(0xdc6d9ab7L), tobe(0xbc1a28d9L), tobe(0x6077b26eL), + tobe(0x7cf54c05L), tobe(0xa098d6b2L), tobe(0xc0ef64dcL), tobe(0x1c82fe6bL), + tobe(0xf9ea980aL), tobe(0x258702bdL), tobe(0x45f0b0d3L), tobe(0x999d2a64L), + tobe(0x851fd40fL), tobe(0x59724eb8L), tobe(0x3905fcd6L), tobe(0xe5686661L), + tobe(0xf7142da3L), tobe(0x2b79b714L), tobe(0x4b0e057aL), tobe(0x97639fcdL), + tobe(0x8be161a6L), tobe(0x578cfb11L), tobe(0x37fb497fL), tobe(0xeb96d3c8L), + tobe(0x0efeb5a9L), tobe(0xd2932f1eL), tobe(0xb2e49d70L), tobe(0x6e8907c7L), + tobe(0x720bf9acL), tobe(0xae66631bL), tobe(0xce11d175L), tobe(0x127c4bc2L), + tobe(0xeae946f1L), tobe(0x3684dc46L), tobe(0x56f36e28L), tobe(0x8a9ef49fL), + tobe(0x961c0af4L), tobe(0x4a719043L), tobe(0x2a06222dL), tobe(0xf66bb89aL), + tobe(0x1303defbL), tobe(0xcf6e444cL), tobe(0xaf19f622L), tobe(0x73746c95L), + tobe(0x6ff692feL), tobe(0xb39b0849L), tobe(0xd3ecba27L), tobe(0x0f812090L), + tobe(0x1dfd6b52L), tobe(0xc190f1e5L), tobe(0xa1e7438bL), tobe(0x7d8ad93cL), + tobe(0x61082757L), tobe(0xbd65bde0L), tobe(0xdd120f8eL), tobe(0x017f9539L), + tobe(0xe417f358L), tobe(0x387a69efL), tobe(0x580ddb81L), tobe(0x84604136L), + tobe(0x98e2bf5dL), tobe(0x448f25eaL), tobe(0x24f89784L), tobe(0xf8950d33L), + tobe(0xd1139055L), tobe(0x0d7e0ae2L), tobe(0x6d09b88cL), tobe(0xb164223bL), + tobe(0xade6dc50L), tobe(0x718b46e7L), tobe(0x11fcf489L), tobe(0xcd916e3eL), + tobe(0x28f9085fL), tobe(0xf49492e8L), tobe(0x94e32086L), tobe(0x488eba31L), + tobe(0x540c445aL), tobe(0x8861deedL), tobe(0xe8166c83L), tobe(0x347bf634L), + tobe(0x2607bdf6L), tobe(0xfa6a2741L), tobe(0x9a1d952fL), tobe(0x46700f98L), + tobe(0x5af2f1f3L), tobe(0x869f6b44L), tobe(0xe6e8d92aL), tobe(0x3a85439dL), + tobe(0xdfed25fcL), tobe(0x0380bf4bL), tobe(0x63f70d25L), tobe(0xbf9a9792L), + tobe(0xa31869f9L), tobe(0x7f75f34eL), tobe(0x1f024120L), tobe(0xc36fdb97L), + tobe(0x3bfad6a4L), tobe(0xe7974c13L), tobe(0x87e0fe7dL), tobe(0x5b8d64caL), + tobe(0x470f9aa1L), tobe(0x9b620016L), tobe(0xfb15b278L), tobe(0x277828cfL), + tobe(0xc2104eaeL), tobe(0x1e7dd419L), tobe(0x7e0a6677L), tobe(0xa267fcc0L), + tobe(0xbee502abL), tobe(0x6288981cL), tobe(0x02ff2a72L), tobe(0xde92b0c5L), + tobe(0xcceefb07L), tobe(0x108361b0L), tobe(0x70f4d3deL), tobe(0xac994969L), + tobe(0xb01bb702L), tobe(0x6c762db5L), tobe(0x0c019fdbL), tobe(0xd06c056cL), + tobe(0x3504630dL), tobe(0xe969f9baL), tobe(0x891e4bd4L), tobe(0x5573d163L), + tobe(0x49f12f08L), tobe(0x959cb5bfL), tobe(0xf5eb07d1L), tobe(0x29869d66L), + tobe(0xa6e63d1dL), tobe(0x7a8ba7aaL), tobe(0x1afc15c4L), tobe(0xc6918f73L), + tobe(0xda137118L), tobe(0x067eebafL), tobe(0x660959c1L), tobe(0xba64c376L), + tobe(0x5f0ca517L), tobe(0x83613fa0L), tobe(0xe3168dceL), tobe(0x3f7b1779L), + tobe(0x23f9e912L), tobe(0xff9473a5L), tobe(0x9fe3c1cbL), tobe(0x438e5b7cL), + tobe(0x51f210beL), tobe(0x8d9f8a09L), tobe(0xede83867L), tobe(0x3185a2d0L), + tobe(0x2d075cbbL), tobe(0xf16ac60cL), tobe(0x911d7462L), tobe(0x4d70eed5L), + tobe(0xa81888b4L), tobe(0x74751203L), tobe(0x1402a06dL), tobe(0xc86f3adaL), + tobe(0xd4edc4b1L), tobe(0x08805e06L), tobe(0x68f7ec68L), tobe(0xb49a76dfL), + tobe(0x4c0f7becL), tobe(0x9062e15bL), tobe(0xf0155335L), tobe(0x2c78c982L), + tobe(0x30fa37e9L), tobe(0xec97ad5eL), tobe(0x8ce01f30L), tobe(0x508d8587L), + tobe(0xb5e5e3e6L), tobe(0x69887951L), tobe(0x09ffcb3fL), tobe(0xd5925188L), + tobe(0xc910afe3L), tobe(0x157d3554L), tobe(0x750a873aL), tobe(0xa9671d8dL), + tobe(0xbb1b564fL), tobe(0x6776ccf8L), tobe(0x07017e96L), tobe(0xdb6ce421L), + tobe(0xc7ee1a4aL), tobe(0x1b8380fdL), tobe(0x7bf43293L), tobe(0xa799a824L), + tobe(0x42f1ce45L), tobe(0x9e9c54f2L), tobe(0xfeebe69cL), tobe(0x22867c2bL), + tobe(0x3e048240L), tobe(0xe26918f7L), tobe(0x821eaa99L), tobe(0x5e73302eL), + tobe(0x77f5ad48L), tobe(0xab9837ffL), tobe(0xcbef8591L), tobe(0x17821f26L), + tobe(0x0b00e14dL), tobe(0xd76d7bfaL), tobe(0xb71ac994L), tobe(0x6b775323L), + tobe(0x8e1f3542L), tobe(0x5272aff5L), tobe(0x32051d9bL), tobe(0xee68872cL), + tobe(0xf2ea7947L), tobe(0x2e87e3f0L), tobe(0x4ef0519eL), tobe(0x929dcb29L), + tobe(0x80e180ebL), tobe(0x5c8c1a5cL), tobe(0x3cfba832L), tobe(0xe0963285L), + tobe(0xfc14cceeL), tobe(0x20795659L), tobe(0x400ee437L), tobe(0x9c637e80L), + tobe(0x790b18e1L), tobe(0xa5668256L), tobe(0xc5113038L), tobe(0x197caa8fL), + tobe(0x05fe54e4L), tobe(0xd993ce53L), tobe(0xb9e47c3dL), tobe(0x6589e68aL), + tobe(0x9d1cebb9L), tobe(0x4171710eL), tobe(0x2106c360L), tobe(0xfd6b59d7L), + tobe(0xe1e9a7bcL), tobe(0x3d843d0bL), tobe(0x5df38f65L), tobe(0x819e15d2L), + tobe(0x64f673b3L), tobe(0xb89be904L), tobe(0xd8ec5b6aL), tobe(0x0481c1ddL), + tobe(0x18033fb6L), tobe(0xc46ea501L), tobe(0xa419176fL), tobe(0x78748dd8L), + tobe(0x6a08c61aL), tobe(0xb6655cadL), tobe(0xd612eec3L), tobe(0x0a7f7474L), + tobe(0x16fd8a1fL), tobe(0xca9010a8L), tobe(0xaae7a2c6L), tobe(0x768a3871L), + tobe(0x93e25e10L), tobe(0x4f8fc4a7L), tobe(0x2ff876c9L), tobe(0xf395ec7eL), + tobe(0xef171215L), tobe(0x337a88a2L), tobe(0x530d3accL), tobe(0x8f60a07bL)}, + { + tobe(0x00000000L), tobe(0x490d678dL), tobe(0x921acf1aL), tobe(0xdb17a897L), + tobe(0x20f48383L), tobe(0x69f9e40eL), tobe(0xb2ee4c99L), tobe(0xfbe32b14L), + tobe(0x41e90706L), tobe(0x08e4608bL), tobe(0xd3f3c81cL), tobe(0x9afeaf91L), + tobe(0x611d8485L), tobe(0x2810e308L), tobe(0xf3074b9fL), tobe(0xba0a2c12L), + tobe(0x83d20e0cL), tobe(0xcadf6981L), tobe(0x11c8c116L), tobe(0x58c5a69bL), + tobe(0xa3268d8fL), tobe(0xea2bea02L), tobe(0x313c4295L), tobe(0x78312518L), + tobe(0xc23b090aL), tobe(0x8b366e87L), tobe(0x5021c610L), tobe(0x192ca19dL), + tobe(0xe2cf8a89L), tobe(0xabc2ed04L), tobe(0x70d54593L), tobe(0x39d8221eL), + tobe(0x036501afL), tobe(0x4a686622L), tobe(0x917fceb5L), tobe(0xd872a938L), + tobe(0x2391822cL), tobe(0x6a9ce5a1L), tobe(0xb18b4d36L), tobe(0xf8862abbL), + tobe(0x428c06a9L), tobe(0x0b816124L), tobe(0xd096c9b3L), tobe(0x999bae3eL), + tobe(0x6278852aL), tobe(0x2b75e2a7L), tobe(0xf0624a30L), tobe(0xb96f2dbdL), + tobe(0x80b70fa3L), tobe(0xc9ba682eL), tobe(0x12adc0b9L), tobe(0x5ba0a734L), + tobe(0xa0438c20L), tobe(0xe94eebadL), tobe(0x3259433aL), tobe(0x7b5424b7L), + tobe(0xc15e08a5L), tobe(0x88536f28L), tobe(0x5344c7bfL), tobe(0x1a49a032L), + tobe(0xe1aa8b26L), tobe(0xa8a7ecabL), tobe(0x73b0443cL), tobe(0x3abd23b1L), + tobe(0x06ca035eL), tobe(0x4fc764d3L), tobe(0x94d0cc44L), tobe(0xddddabc9L), + tobe(0x263e80ddL), tobe(0x6f33e750L), tobe(0xb4244fc7L), tobe(0xfd29284aL), + tobe(0x47230458L), tobe(0x0e2e63d5L), tobe(0xd539cb42L), tobe(0x9c34accfL), + tobe(0x67d787dbL), tobe(0x2edae056L), tobe(0xf5cd48c1L), tobe(0xbcc02f4cL), + tobe(0x85180d52L), tobe(0xcc156adfL), tobe(0x1702c248L), tobe(0x5e0fa5c5L), + tobe(0xa5ec8ed1L), tobe(0xece1e95cL), tobe(0x37f641cbL), tobe(0x7efb2646L), + tobe(0xc4f10a54L), tobe(0x8dfc6dd9L), tobe(0x56ebc54eL), tobe(0x1fe6a2c3L), + tobe(0xe40589d7L), tobe(0xad08ee5aL), tobe(0x761f46cdL), tobe(0x3f122140L), + tobe(0x05af02f1L), tobe(0x4ca2657cL), tobe(0x97b5cdebL), tobe(0xdeb8aa66L), + tobe(0x255b8172L), tobe(0x6c56e6ffL), tobe(0xb7414e68L), tobe(0xfe4c29e5L), + tobe(0x444605f7L), tobe(0x0d4b627aL), tobe(0xd65ccaedL), tobe(0x9f51ad60L), + tobe(0x64b28674L), tobe(0x2dbfe1f9L), tobe(0xf6a8496eL), tobe(0xbfa52ee3L), + tobe(0x867d0cfdL), tobe(0xcf706b70L), tobe(0x1467c3e7L), tobe(0x5d6aa46aL), + tobe(0xa6898f7eL), tobe(0xef84e8f3L), tobe(0x34934064L), tobe(0x7d9e27e9L), + tobe(0xc7940bfbL), tobe(0x8e996c76L), tobe(0x558ec4e1L), tobe(0x1c83a36cL), + tobe(0xe7608878L), tobe(0xae6deff5L), tobe(0x757a4762L), tobe(0x3c7720efL), + tobe(0x0d9406bcL), tobe(0x44996131L), tobe(0x9f8ec9a6L), tobe(0xd683ae2bL), + tobe(0x2d60853fL), tobe(0x646de2b2L), tobe(0xbf7a4a25L), tobe(0xf6772da8L), + tobe(0x4c7d01baL), tobe(0x05706637L), tobe(0xde67cea0L), tobe(0x976aa92dL), + tobe(0x6c898239L), tobe(0x2584e5b4L), tobe(0xfe934d23L), tobe(0xb79e2aaeL), + tobe(0x8e4608b0L), tobe(0xc74b6f3dL), tobe(0x1c5cc7aaL), tobe(0x5551a027L), + tobe(0xaeb28b33L), tobe(0xe7bfecbeL), tobe(0x3ca84429L), tobe(0x75a523a4L), + tobe(0xcfaf0fb6L), tobe(0x86a2683bL), tobe(0x5db5c0acL), tobe(0x14b8a721L), + tobe(0xef5b8c35L), tobe(0xa656ebb8L), tobe(0x7d41432fL), tobe(0x344c24a2L), + tobe(0x0ef10713L), tobe(0x47fc609eL), tobe(0x9cebc809L), tobe(0xd5e6af84L), + tobe(0x2e058490L), tobe(0x6708e31dL), tobe(0xbc1f4b8aL), tobe(0xf5122c07L), + tobe(0x4f180015L), tobe(0x06156798L), tobe(0xdd02cf0fL), tobe(0x940fa882L), + tobe(0x6fec8396L), tobe(0x26e1e41bL), tobe(0xfdf64c8cL), tobe(0xb4fb2b01L), + tobe(0x8d23091fL), tobe(0xc42e6e92L), tobe(0x1f39c605L), tobe(0x5634a188L), + tobe(0xadd78a9cL), tobe(0xe4daed11L), tobe(0x3fcd4586L), tobe(0x76c0220bL), + tobe(0xccca0e19L), tobe(0x85c76994L), tobe(0x5ed0c103L), tobe(0x17dda68eL), + tobe(0xec3e8d9aL), tobe(0xa533ea17L), tobe(0x7e244280L), tobe(0x3729250dL), + tobe(0x0b5e05e2L), tobe(0x4253626fL), tobe(0x9944caf8L), tobe(0xd049ad75L), + tobe(0x2baa8661L), tobe(0x62a7e1ecL), tobe(0xb9b0497bL), tobe(0xf0bd2ef6L), + tobe(0x4ab702e4L), tobe(0x03ba6569L), tobe(0xd8adcdfeL), tobe(0x91a0aa73L), + tobe(0x6a438167L), tobe(0x234ee6eaL), tobe(0xf8594e7dL), tobe(0xb15429f0L), + tobe(0x888c0beeL), tobe(0xc1816c63L), tobe(0x1a96c4f4L), tobe(0x539ba379L), + tobe(0xa878886dL), tobe(0xe175efe0L), tobe(0x3a624777L), tobe(0x736f20faL), + tobe(0xc9650ce8L), tobe(0x80686b65L), tobe(0x5b7fc3f2L), tobe(0x1272a47fL), + tobe(0xe9918f6bL), tobe(0xa09ce8e6L), tobe(0x7b8b4071L), tobe(0x328627fcL), + tobe(0x083b044dL), tobe(0x413663c0L), tobe(0x9a21cb57L), tobe(0xd32cacdaL), + tobe(0x28cf87ceL), tobe(0x61c2e043L), tobe(0xbad548d4L), tobe(0xf3d82f59L), + tobe(0x49d2034bL), tobe(0x00df64c6L), tobe(0xdbc8cc51L), tobe(0x92c5abdcL), + tobe(0x692680c8L), tobe(0x202be745L), tobe(0xfb3c4fd2L), tobe(0xb231285fL), + tobe(0x8be90a41L), tobe(0xc2e46dccL), tobe(0x19f3c55bL), tobe(0x50fea2d6L), + tobe(0xab1d89c2L), tobe(0xe210ee4fL), tobe(0x390746d8L), tobe(0x700a2155L), + tobe(0xca000d47L), tobe(0x830d6acaL), tobe(0x581ac25dL), tobe(0x1117a5d0L), + tobe(0xeaf48ec4L), tobe(0xa3f9e949L), tobe(0x78ee41deL), tobe(0x31e32653L)}, + { + tobe(0x00000000L), tobe(0x1b280d78L), tobe(0x36501af0L), tobe(0x2d781788L), + tobe(0x6ca035e0L), tobe(0x77883898L), tobe(0x5af02f10L), tobe(0x41d82268L), + tobe(0xd9406bc0L), tobe(0xc26866b8L), tobe(0xef107130L), tobe(0xf4387c48L), + tobe(0xb5e05e20L), tobe(0xaec85358L), tobe(0x83b044d0L), tobe(0x989849a8L), + tobe(0xb641ca37L), tobe(0xad69c74fL), tobe(0x8011d0c7L), tobe(0x9b39ddbfL), + tobe(0xdae1ffd7L), tobe(0xc1c9f2afL), tobe(0xecb1e527L), tobe(0xf799e85fL), + tobe(0x6f01a1f7L), tobe(0x7429ac8fL), tobe(0x5951bb07L), tobe(0x4279b67fL), + tobe(0x03a19417L), tobe(0x1889996fL), tobe(0x35f18ee7L), tobe(0x2ed9839fL), + tobe(0x684289d9L), tobe(0x736a84a1L), tobe(0x5e129329L), tobe(0x453a9e51L), + tobe(0x04e2bc39L), tobe(0x1fcab141L), tobe(0x32b2a6c9L), tobe(0x299aabb1L), + tobe(0xb102e219L), tobe(0xaa2aef61L), tobe(0x8752f8e9L), tobe(0x9c7af591L), + tobe(0xdda2d7f9L), tobe(0xc68ada81L), tobe(0xebf2cd09L), tobe(0xf0dac071L), + tobe(0xde0343eeL), tobe(0xc52b4e96L), tobe(0xe853591eL), tobe(0xf37b5466L), + tobe(0xb2a3760eL), tobe(0xa98b7b76L), tobe(0x84f36cfeL), tobe(0x9fdb6186L), + tobe(0x0743282eL), tobe(0x1c6b2556L), tobe(0x311332deL), tobe(0x2a3b3fa6L), + tobe(0x6be31dceL), tobe(0x70cb10b6L), tobe(0x5db3073eL), tobe(0x469b0a46L), + tobe(0xd08513b2L), tobe(0xcbad1ecaL), tobe(0xe6d50942L), tobe(0xfdfd043aL), + tobe(0xbc252652L), tobe(0xa70d2b2aL), tobe(0x8a753ca2L), tobe(0x915d31daL), + tobe(0x09c57872L), tobe(0x12ed750aL), tobe(0x3f956282L), tobe(0x24bd6ffaL), + tobe(0x65654d92L), tobe(0x7e4d40eaL), tobe(0x53355762L), tobe(0x481d5a1aL), + tobe(0x66c4d985L), tobe(0x7decd4fdL), tobe(0x5094c375L), tobe(0x4bbcce0dL), + tobe(0x0a64ec65L), tobe(0x114ce11dL), tobe(0x3c34f695L), tobe(0x271cfbedL), + tobe(0xbf84b245L), tobe(0xa4acbf3dL), tobe(0x89d4a8b5L), tobe(0x92fca5cdL), + tobe(0xd32487a5L), tobe(0xc80c8addL), tobe(0xe5749d55L), tobe(0xfe5c902dL), + tobe(0xb8c79a6bL), tobe(0xa3ef9713L), tobe(0x8e97809bL), tobe(0x95bf8de3L), + tobe(0xd467af8bL), tobe(0xcf4fa2f3L), tobe(0xe237b57bL), tobe(0xf91fb803L), + tobe(0x6187f1abL), tobe(0x7aaffcd3L), tobe(0x57d7eb5bL), tobe(0x4cffe623L), + tobe(0x0d27c44bL), tobe(0x160fc933L), tobe(0x3b77debbL), tobe(0x205fd3c3L), + tobe(0x0e86505cL), tobe(0x15ae5d24L), tobe(0x38d64aacL), tobe(0x23fe47d4L), + tobe(0x622665bcL), tobe(0x790e68c4L), tobe(0x54767f4cL), tobe(0x4f5e7234L), + tobe(0xd7c63b9cL), tobe(0xccee36e4L), tobe(0xe196216cL), tobe(0xfabe2c14L), + tobe(0xbb660e7cL), tobe(0xa04e0304L), tobe(0x8d36148cL), tobe(0x961e19f4L), + tobe(0xa5cb3ad3L), tobe(0xbee337abL), tobe(0x939b2023L), tobe(0x88b32d5bL), + tobe(0xc96b0f33L), tobe(0xd243024bL), tobe(0xff3b15c3L), tobe(0xe41318bbL), + tobe(0x7c8b5113L), tobe(0x67a35c6bL), tobe(0x4adb4be3L), tobe(0x51f3469bL), + tobe(0x102b64f3L), tobe(0x0b03698bL), tobe(0x267b7e03L), tobe(0x3d53737bL), + tobe(0x138af0e4L), tobe(0x08a2fd9cL), tobe(0x25daea14L), tobe(0x3ef2e76cL), + tobe(0x7f2ac504L), tobe(0x6402c87cL), tobe(0x497adff4L), tobe(0x5252d28cL), + tobe(0xcaca9b24L), tobe(0xd1e2965cL), tobe(0xfc9a81d4L), tobe(0xe7b28cacL), + tobe(0xa66aaec4L), tobe(0xbd42a3bcL), tobe(0x903ab434L), tobe(0x8b12b94cL), + tobe(0xcd89b30aL), tobe(0xd6a1be72L), tobe(0xfbd9a9faL), tobe(0xe0f1a482L), + tobe(0xa12986eaL), tobe(0xba018b92L), tobe(0x97799c1aL), tobe(0x8c519162L), + tobe(0x14c9d8caL), tobe(0x0fe1d5b2L), tobe(0x2299c23aL), tobe(0x39b1cf42L), + tobe(0x7869ed2aL), tobe(0x6341e052L), tobe(0x4e39f7daL), tobe(0x5511faa2L), + tobe(0x7bc8793dL), tobe(0x60e07445L), tobe(0x4d9863cdL), tobe(0x56b06eb5L), + tobe(0x17684cddL), tobe(0x0c4041a5L), tobe(0x2138562dL), tobe(0x3a105b55L), + tobe(0xa28812fdL), tobe(0xb9a01f85L), tobe(0x94d8080dL), tobe(0x8ff00575L), + tobe(0xce28271dL), tobe(0xd5002a65L), tobe(0xf8783dedL), tobe(0xe3503095L), + tobe(0x754e2961L), tobe(0x6e662419L), tobe(0x431e3391L), tobe(0x58363ee9L), + tobe(0x19ee1c81L), tobe(0x02c611f9L), tobe(0x2fbe0671L), tobe(0x34960b09L), + tobe(0xac0e42a1L), tobe(0xb7264fd9L), tobe(0x9a5e5851L), tobe(0x81765529L), + tobe(0xc0ae7741L), tobe(0xdb867a39L), tobe(0xf6fe6db1L), tobe(0xedd660c9L), + tobe(0xc30fe356L), tobe(0xd827ee2eL), tobe(0xf55ff9a6L), tobe(0xee77f4deL), + tobe(0xafafd6b6L), tobe(0xb487dbceL), tobe(0x99ffcc46L), tobe(0x82d7c13eL), + tobe(0x1a4f8896L), tobe(0x016785eeL), tobe(0x2c1f9266L), tobe(0x37379f1eL), + tobe(0x76efbd76L), tobe(0x6dc7b00eL), tobe(0x40bfa786L), tobe(0x5b97aafeL), + tobe(0x1d0ca0b8L), tobe(0x0624adc0L), tobe(0x2b5cba48L), tobe(0x3074b730L), + tobe(0x71ac9558L), tobe(0x6a849820L), tobe(0x47fc8fa8L), tobe(0x5cd482d0L), + tobe(0xc44ccb78L), tobe(0xdf64c600L), tobe(0xf21cd188L), tobe(0xe934dcf0L), + tobe(0xa8ecfe98L), tobe(0xb3c4f3e0L), tobe(0x9ebce468L), tobe(0x8594e910L), + tobe(0xab4d6a8fL), tobe(0xb06567f7L), tobe(0x9d1d707fL), tobe(0x86357d07L), + tobe(0xc7ed5f6fL), tobe(0xdcc55217L), tobe(0xf1bd459fL), tobe(0xea9548e7L), + tobe(0x720d014fL), tobe(0x69250c37L), tobe(0x445d1bbfL), tobe(0x5f7516c7L), + tobe(0x1ead34afL), tobe(0x058539d7L), tobe(0x28fd2e5fL), tobe(0x33d52327L)}, + { + tobe(0x00000000L), tobe(0x4f576811L), tobe(0x9eaed022L), tobe(0xd1f9b833L), + tobe(0x399cbdf3L), tobe(0x76cbd5e2L), tobe(0xa7326dd1L), tobe(0xe86505c0L), + tobe(0x73397be6L), tobe(0x3c6e13f7L), tobe(0xed97abc4L), tobe(0xa2c0c3d5L), + tobe(0x4aa5c615L), tobe(0x05f2ae04L), tobe(0xd40b1637L), tobe(0x9b5c7e26L), + tobe(0xe672f7ccL), tobe(0xa9259fddL), tobe(0x78dc27eeL), tobe(0x378b4fffL), + tobe(0xdfee4a3fL), tobe(0x90b9222eL), tobe(0x41409a1dL), tobe(0x0e17f20cL), + tobe(0x954b8c2aL), tobe(0xda1ce43bL), tobe(0x0be55c08L), tobe(0x44b23419L), + tobe(0xacd731d9L), tobe(0xe38059c8L), tobe(0x3279e1fbL), tobe(0x7d2e89eaL), + tobe(0xc824f22fL), tobe(0x87739a3eL), tobe(0x568a220dL), tobe(0x19dd4a1cL), + tobe(0xf1b84fdcL), tobe(0xbeef27cdL), tobe(0x6f169ffeL), tobe(0x2041f7efL), + tobe(0xbb1d89c9L), tobe(0xf44ae1d8L), tobe(0x25b359ebL), tobe(0x6ae431faL), + tobe(0x8281343aL), tobe(0xcdd65c2bL), tobe(0x1c2fe418L), tobe(0x53788c09L), + tobe(0x2e5605e3L), tobe(0x61016df2L), tobe(0xb0f8d5c1L), tobe(0xffafbdd0L), + tobe(0x17cab810L), tobe(0x589dd001L), tobe(0x89646832L), tobe(0xc6330023L), + tobe(0x5d6f7e05L), tobe(0x12381614L), tobe(0xc3c1ae27L), tobe(0x8c96c636L), + tobe(0x64f3c3f6L), tobe(0x2ba4abe7L), tobe(0xfa5d13d4L), tobe(0xb50a7bc5L), + tobe(0x9488f9e9L), tobe(0xdbdf91f8L), tobe(0x0a2629cbL), tobe(0x457141daL), + tobe(0xad14441aL), tobe(0xe2432c0bL), tobe(0x33ba9438L), tobe(0x7cedfc29L), + tobe(0xe7b1820fL), tobe(0xa8e6ea1eL), tobe(0x791f522dL), tobe(0x36483a3cL), + tobe(0xde2d3ffcL), tobe(0x917a57edL), tobe(0x4083efdeL), tobe(0x0fd487cfL), + tobe(0x72fa0e25L), tobe(0x3dad6634L), tobe(0xec54de07L), tobe(0xa303b616L), + tobe(0x4b66b3d6L), tobe(0x0431dbc7L), tobe(0xd5c863f4L), tobe(0x9a9f0be5L), + tobe(0x01c375c3L), tobe(0x4e941dd2L), tobe(0x9f6da5e1L), tobe(0xd03acdf0L), + tobe(0x385fc830L), tobe(0x7708a021L), tobe(0xa6f11812L), tobe(0xe9a67003L), + tobe(0x5cac0bc6L), tobe(0x13fb63d7L), tobe(0xc202dbe4L), tobe(0x8d55b3f5L), + tobe(0x6530b635L), tobe(0x2a67de24L), tobe(0xfb9e6617L), tobe(0xb4c90e06L), + tobe(0x2f957020L), tobe(0x60c21831L), tobe(0xb13ba002L), tobe(0xfe6cc813L), + tobe(0x1609cdd3L), tobe(0x595ea5c2L), tobe(0x88a71df1L), tobe(0xc7f075e0L), + tobe(0xbadefc0aL), tobe(0xf589941bL), tobe(0x24702c28L), tobe(0x6b274439L), + tobe(0x834241f9L), tobe(0xcc1529e8L), tobe(0x1dec91dbL), tobe(0x52bbf9caL), + tobe(0xc9e787ecL), tobe(0x86b0effdL), tobe(0x574957ceL), tobe(0x181e3fdfL), + tobe(0xf07b3a1fL), tobe(0xbf2c520eL), tobe(0x6ed5ea3dL), tobe(0x2182822cL), + tobe(0x2dd0ee65L), tobe(0x62878674L), tobe(0xb37e3e47L), tobe(0xfc295656L), + tobe(0x144c5396L), tobe(0x5b1b3b87L), tobe(0x8ae283b4L), tobe(0xc5b5eba5L), + tobe(0x5ee99583L), tobe(0x11befd92L), tobe(0xc04745a1L), tobe(0x8f102db0L), + tobe(0x67752870L), tobe(0x28224061L), tobe(0xf9dbf852L), tobe(0xb68c9043L), + tobe(0xcba219a9L), tobe(0x84f571b8L), tobe(0x550cc98bL), tobe(0x1a5ba19aL), + tobe(0xf23ea45aL), tobe(0xbd69cc4bL), tobe(0x6c907478L), tobe(0x23c71c69L), + tobe(0xb89b624fL), tobe(0xf7cc0a5eL), tobe(0x2635b26dL), tobe(0x6962da7cL), + tobe(0x8107dfbcL), tobe(0xce50b7adL), tobe(0x1fa90f9eL), tobe(0x50fe678fL), + tobe(0xe5f41c4aL), tobe(0xaaa3745bL), tobe(0x7b5acc68L), tobe(0x340da479L), + tobe(0xdc68a1b9L), tobe(0x933fc9a8L), tobe(0x42c6719bL), tobe(0x0d91198aL), + tobe(0x96cd67acL), tobe(0xd99a0fbdL), tobe(0x0863b78eL), tobe(0x4734df9fL), + tobe(0xaf51da5fL), tobe(0xe006b24eL), tobe(0x31ff0a7dL), tobe(0x7ea8626cL), + tobe(0x0386eb86L), tobe(0x4cd18397L), tobe(0x9d283ba4L), tobe(0xd27f53b5L), + tobe(0x3a1a5675L), tobe(0x754d3e64L), tobe(0xa4b48657L), tobe(0xebe3ee46L), + tobe(0x70bf9060L), tobe(0x3fe8f871L), tobe(0xee114042L), tobe(0xa1462853L), + tobe(0x49232d93L), tobe(0x06744582L), tobe(0xd78dfdb1L), tobe(0x98da95a0L), + tobe(0xb958178cL), tobe(0xf60f7f9dL), tobe(0x27f6c7aeL), tobe(0x68a1afbfL), + tobe(0x80c4aa7fL), tobe(0xcf93c26eL), tobe(0x1e6a7a5dL), tobe(0x513d124cL), + tobe(0xca616c6aL), tobe(0x8536047bL), tobe(0x54cfbc48L), tobe(0x1b98d459L), + tobe(0xf3fdd199L), tobe(0xbcaab988L), tobe(0x6d5301bbL), tobe(0x220469aaL), + tobe(0x5f2ae040L), tobe(0x107d8851L), tobe(0xc1843062L), tobe(0x8ed35873L), + tobe(0x66b65db3L), tobe(0x29e135a2L), tobe(0xf8188d91L), tobe(0xb74fe580L), + tobe(0x2c139ba6L), tobe(0x6344f3b7L), tobe(0xb2bd4b84L), tobe(0xfdea2395L), + tobe(0x158f2655L), tobe(0x5ad84e44L), tobe(0x8b21f677L), tobe(0xc4769e66L), + tobe(0x717ce5a3L), tobe(0x3e2b8db2L), tobe(0xefd23581L), tobe(0xa0855d90L), + tobe(0x48e05850L), tobe(0x07b73041L), tobe(0xd64e8872L), tobe(0x9919e063L), + tobe(0x02459e45L), tobe(0x4d12f654L), tobe(0x9ceb4e67L), tobe(0xd3bc2676L), + tobe(0x3bd923b6L), tobe(0x748e4ba7L), tobe(0xa577f394L), tobe(0xea209b85L), + tobe(0x970e126fL), tobe(0xd8597a7eL), tobe(0x09a0c24dL), tobe(0x46f7aa5cL), + tobe(0xae92af9cL), tobe(0xe1c5c78dL), tobe(0x303c7fbeL), tobe(0x7f6b17afL), + tobe(0xe4376989L), tobe(0xab600198L), tobe(0x7a99b9abL), tobe(0x35ced1baL), + tobe(0xddabd47aL), tobe(0x92fcbc6bL), tobe(0x43050458L), tobe(0x0c526c49L)}, + { + tobe(0x00000000L), tobe(0x5ba1dccaL), tobe(0xb743b994L), tobe(0xece2655eL), + tobe(0x6a466e9fL), tobe(0x31e7b255L), tobe(0xdd05d70bL), tobe(0x86a40bc1L), + tobe(0xd48cdd3eL), tobe(0x8f2d01f4L), tobe(0x63cf64aaL), tobe(0x386eb860L), + tobe(0xbecab3a1L), tobe(0xe56b6f6bL), tobe(0x09890a35L), tobe(0x5228d6ffL), + tobe(0xadd8a7cbL), tobe(0xf6797b01L), tobe(0x1a9b1e5fL), tobe(0x413ac295L), + tobe(0xc79ec954L), tobe(0x9c3f159eL), tobe(0x70dd70c0L), tobe(0x2b7cac0aL), + tobe(0x79547af5L), tobe(0x22f5a63fL), tobe(0xce17c361L), tobe(0x95b61fabL), + tobe(0x1312146aL), tobe(0x48b3c8a0L), tobe(0xa451adfeL), tobe(0xfff07134L), + tobe(0x5f705221L), tobe(0x04d18eebL), tobe(0xe833ebb5L), tobe(0xb392377fL), + tobe(0x35363cbeL), tobe(0x6e97e074L), tobe(0x8275852aL), tobe(0xd9d459e0L), + tobe(0x8bfc8f1fL), tobe(0xd05d53d5L), tobe(0x3cbf368bL), tobe(0x671eea41L), + tobe(0xe1bae180L), tobe(0xba1b3d4aL), tobe(0x56f95814L), tobe(0x0d5884deL), + tobe(0xf2a8f5eaL), tobe(0xa9092920L), tobe(0x45eb4c7eL), tobe(0x1e4a90b4L), + tobe(0x98ee9b75L), tobe(0xc34f47bfL), tobe(0x2fad22e1L), tobe(0x740cfe2bL), + tobe(0x262428d4L), tobe(0x7d85f41eL), tobe(0x91679140L), tobe(0xcac64d8aL), + tobe(0x4c62464bL), tobe(0x17c39a81L), tobe(0xfb21ffdfL), tobe(0xa0802315L), + tobe(0xbee0a442L), tobe(0xe5417888L), tobe(0x09a31dd6L), tobe(0x5202c11cL), + tobe(0xd4a6caddL), tobe(0x8f071617L), tobe(0x63e57349L), tobe(0x3844af83L), + tobe(0x6a6c797cL), tobe(0x31cda5b6L), tobe(0xdd2fc0e8L), tobe(0x868e1c22L), + tobe(0x002a17e3L), tobe(0x5b8bcb29L), tobe(0xb769ae77L), tobe(0xecc872bdL), + tobe(0x13380389L), tobe(0x4899df43L), tobe(0xa47bba1dL), tobe(0xffda66d7L), + tobe(0x797e6d16L), tobe(0x22dfb1dcL), tobe(0xce3dd482L), tobe(0x959c0848L), + tobe(0xc7b4deb7L), tobe(0x9c15027dL), tobe(0x70f76723L), tobe(0x2b56bbe9L), + tobe(0xadf2b028L), tobe(0xf6536ce2L), tobe(0x1ab109bcL), tobe(0x4110d576L), + tobe(0xe190f663L), tobe(0xba312aa9L), tobe(0x56d34ff7L), tobe(0x0d72933dL), + tobe(0x8bd698fcL), tobe(0xd0774436L), tobe(0x3c952168L), tobe(0x6734fda2L), + tobe(0x351c2b5dL), tobe(0x6ebdf797L), tobe(0x825f92c9L), tobe(0xd9fe4e03L), + tobe(0x5f5a45c2L), tobe(0x04fb9908L), tobe(0xe819fc56L), tobe(0xb3b8209cL), + tobe(0x4c4851a8L), tobe(0x17e98d62L), tobe(0xfb0be83cL), tobe(0xa0aa34f6L), + tobe(0x260e3f37L), tobe(0x7dafe3fdL), tobe(0x914d86a3L), tobe(0xcaec5a69L), + tobe(0x98c48c96L), tobe(0xc365505cL), tobe(0x2f873502L), tobe(0x7426e9c8L), + tobe(0xf282e209L), tobe(0xa9233ec3L), tobe(0x45c15b9dL), tobe(0x1e608757L), + tobe(0x79005533L), tobe(0x22a189f9L), tobe(0xce43eca7L), tobe(0x95e2306dL), + tobe(0x13463bacL), tobe(0x48e7e766L), tobe(0xa4058238L), tobe(0xffa45ef2L), + tobe(0xad8c880dL), tobe(0xf62d54c7L), tobe(0x1acf3199L), tobe(0x416eed53L), + tobe(0xc7cae692L), tobe(0x9c6b3a58L), tobe(0x70895f06L), tobe(0x2b2883ccL), + tobe(0xd4d8f2f8L), tobe(0x8f792e32L), tobe(0x639b4b6cL), tobe(0x383a97a6L), + tobe(0xbe9e9c67L), tobe(0xe53f40adL), tobe(0x09dd25f3L), tobe(0x527cf939L), + tobe(0x00542fc6L), tobe(0x5bf5f30cL), tobe(0xb7179652L), tobe(0xecb64a98L), + tobe(0x6a124159L), tobe(0x31b39d93L), tobe(0xdd51f8cdL), tobe(0x86f02407L), + tobe(0x26700712L), tobe(0x7dd1dbd8L), tobe(0x9133be86L), tobe(0xca92624cL), + tobe(0x4c36698dL), tobe(0x1797b547L), tobe(0xfb75d019L), tobe(0xa0d40cd3L), + tobe(0xf2fcda2cL), tobe(0xa95d06e6L), tobe(0x45bf63b8L), tobe(0x1e1ebf72L), + tobe(0x98bab4b3L), tobe(0xc31b6879L), tobe(0x2ff90d27L), tobe(0x7458d1edL), + tobe(0x8ba8a0d9L), tobe(0xd0097c13L), tobe(0x3ceb194dL), tobe(0x674ac587L), + tobe(0xe1eece46L), tobe(0xba4f128cL), tobe(0x56ad77d2L), tobe(0x0d0cab18L), + tobe(0x5f247de7L), tobe(0x0485a12dL), tobe(0xe867c473L), tobe(0xb3c618b9L), + tobe(0x35621378L), tobe(0x6ec3cfb2L), tobe(0x8221aaecL), tobe(0xd9807626L), + tobe(0xc7e0f171L), tobe(0x9c412dbbL), tobe(0x70a348e5L), tobe(0x2b02942fL), + tobe(0xada69feeL), tobe(0xf6074324L), tobe(0x1ae5267aL), tobe(0x4144fab0L), + tobe(0x136c2c4fL), tobe(0x48cdf085L), tobe(0xa42f95dbL), tobe(0xff8e4911L), + tobe(0x792a42d0L), tobe(0x228b9e1aL), tobe(0xce69fb44L), tobe(0x95c8278eL), + tobe(0x6a3856baL), tobe(0x31998a70L), tobe(0xdd7bef2eL), tobe(0x86da33e4L), + tobe(0x007e3825L), tobe(0x5bdfe4efL), tobe(0xb73d81b1L), tobe(0xec9c5d7bL), + tobe(0xbeb48b84L), tobe(0xe515574eL), tobe(0x09f73210L), tobe(0x5256eedaL), + tobe(0xd4f2e51bL), tobe(0x8f5339d1L), tobe(0x63b15c8fL), tobe(0x38108045L), + tobe(0x9890a350L), tobe(0xc3317f9aL), tobe(0x2fd31ac4L), tobe(0x7472c60eL), + tobe(0xf2d6cdcfL), tobe(0xa9771105L), tobe(0x4595745bL), tobe(0x1e34a891L), + tobe(0x4c1c7e6eL), tobe(0x17bda2a4L), tobe(0xfb5fc7faL), tobe(0xa0fe1b30L), + tobe(0x265a10f1L), tobe(0x7dfbcc3bL), tobe(0x9119a965L), tobe(0xcab875afL), + tobe(0x3548049bL), tobe(0x6ee9d851L), tobe(0x820bbd0fL), tobe(0xd9aa61c5L), + tobe(0x5f0e6a04L), tobe(0x04afb6ceL), tobe(0xe84dd390L), tobe(0xb3ec0f5aL), + tobe(0xe1c4d9a5L), tobe(0xba65056fL), tobe(0x56876031L), tobe(0x0d26bcfbL), + tobe(0x8b82b73aL), tobe(0xd0236bf0L), tobe(0x3cc10eaeL), tobe(0x6760d264L)}, + }; + static const uint32_t crc32ctable_le[8][256] = {{ + tole(0x00000000L), tole(0xf26b8303L), tole(0xe13b70f7L), tole(0x1350f3f4L), + tole(0xc79a971fL), tole(0x35f1141cL), tole(0x26a1e7e8L), tole(0xd4ca64ebL), + tole(0x8ad958cfL), tole(0x78b2dbccL), tole(0x6be22838L), tole(0x9989ab3bL), + tole(0x4d43cfd0L), tole(0xbf284cd3L), tole(0xac78bf27L), tole(0x5e133c24L), + tole(0x105ec76fL), tole(0xe235446cL), tole(0xf165b798L), tole(0x030e349bL), + tole(0xd7c45070L), tole(0x25afd373L), tole(0x36ff2087L), tole(0xc494a384L), + tole(0x9a879fa0L), tole(0x68ec1ca3L), tole(0x7bbcef57L), tole(0x89d76c54L), + tole(0x5d1d08bfL), tole(0xaf768bbcL), tole(0xbc267848L), tole(0x4e4dfb4bL), + tole(0x20bd8edeL), tole(0xd2d60dddL), tole(0xc186fe29L), tole(0x33ed7d2aL), + tole(0xe72719c1L), tole(0x154c9ac2L), tole(0x061c6936L), tole(0xf477ea35L), + tole(0xaa64d611L), tole(0x580f5512L), tole(0x4b5fa6e6L), tole(0xb93425e5L), + tole(0x6dfe410eL), tole(0x9f95c20dL), tole(0x8cc531f9L), tole(0x7eaeb2faL), + tole(0x30e349b1L), tole(0xc288cab2L), tole(0xd1d83946L), tole(0x23b3ba45L), + tole(0xf779deaeL), tole(0x05125dadL), tole(0x1642ae59L), tole(0xe4292d5aL), + tole(0xba3a117eL), tole(0x4851927dL), tole(0x5b016189L), tole(0xa96ae28aL), + tole(0x7da08661L), tole(0x8fcb0562L), tole(0x9c9bf696L), tole(0x6ef07595L), + tole(0x417b1dbcL), tole(0xb3109ebfL), tole(0xa0406d4bL), tole(0x522bee48L), + tole(0x86e18aa3L), tole(0x748a09a0L), tole(0x67dafa54L), tole(0x95b17957L), + tole(0xcba24573L), tole(0x39c9c670L), tole(0x2a993584L), tole(0xd8f2b687L), + tole(0x0c38d26cL), tole(0xfe53516fL), tole(0xed03a29bL), tole(0x1f682198L), + tole(0x5125dad3L), tole(0xa34e59d0L), tole(0xb01eaa24L), tole(0x42752927L), + tole(0x96bf4dccL), tole(0x64d4cecfL), tole(0x77843d3bL), tole(0x85efbe38L), + tole(0xdbfc821cL), tole(0x2997011fL), tole(0x3ac7f2ebL), tole(0xc8ac71e8L), + tole(0x1c661503L), tole(0xee0d9600L), tole(0xfd5d65f4L), tole(0x0f36e6f7L), + tole(0x61c69362L), tole(0x93ad1061L), tole(0x80fde395L), tole(0x72966096L), + tole(0xa65c047dL), tole(0x5437877eL), tole(0x4767748aL), tole(0xb50cf789L), + tole(0xeb1fcbadL), tole(0x197448aeL), tole(0x0a24bb5aL), tole(0xf84f3859L), + tole(0x2c855cb2L), tole(0xdeeedfb1L), tole(0xcdbe2c45L), tole(0x3fd5af46L), + tole(0x7198540dL), tole(0x83f3d70eL), tole(0x90a324faL), tole(0x62c8a7f9L), + tole(0xb602c312L), tole(0x44694011L), tole(0x5739b3e5L), tole(0xa55230e6L), + tole(0xfb410cc2L), tole(0x092a8fc1L), tole(0x1a7a7c35L), tole(0xe811ff36L), + tole(0x3cdb9bddL), tole(0xceb018deL), tole(0xdde0eb2aL), tole(0x2f8b6829L), + tole(0x82f63b78L), tole(0x709db87bL), tole(0x63cd4b8fL), tole(0x91a6c88cL), + tole(0x456cac67L), tole(0xb7072f64L), tole(0xa457dc90L), tole(0x563c5f93L), + tole(0x082f63b7L), tole(0xfa44e0b4L), tole(0xe9141340L), tole(0x1b7f9043L), + tole(0xcfb5f4a8L), tole(0x3dde77abL), tole(0x2e8e845fL), tole(0xdce5075cL), + tole(0x92a8fc17L), tole(0x60c37f14L), tole(0x73938ce0L), tole(0x81f80fe3L), + tole(0x55326b08L), tole(0xa759e80bL), tole(0xb4091bffL), tole(0x466298fcL), + tole(0x1871a4d8L), tole(0xea1a27dbL), tole(0xf94ad42fL), tole(0x0b21572cL), + tole(0xdfeb33c7L), tole(0x2d80b0c4L), tole(0x3ed04330L), tole(0xccbbc033L), + tole(0xa24bb5a6L), tole(0x502036a5L), tole(0x4370c551L), tole(0xb11b4652L), + tole(0x65d122b9L), tole(0x97baa1baL), tole(0x84ea524eL), tole(0x7681d14dL), + tole(0x2892ed69L), tole(0xdaf96e6aL), tole(0xc9a99d9eL), tole(0x3bc21e9dL), + tole(0xef087a76L), tole(0x1d63f975L), tole(0x0e330a81L), tole(0xfc588982L), + tole(0xb21572c9L), tole(0x407ef1caL), tole(0x532e023eL), tole(0xa145813dL), + tole(0x758fe5d6L), tole(0x87e466d5L), tole(0x94b49521L), tole(0x66df1622L), + tole(0x38cc2a06L), tole(0xcaa7a905L), tole(0xd9f75af1L), tole(0x2b9cd9f2L), + tole(0xff56bd19L), tole(0x0d3d3e1aL), tole(0x1e6dcdeeL), tole(0xec064eedL), + tole(0xc38d26c4L), tole(0x31e6a5c7L), tole(0x22b65633L), tole(0xd0ddd530L), + tole(0x0417b1dbL), tole(0xf67c32d8L), tole(0xe52cc12cL), tole(0x1747422fL), + tole(0x49547e0bL), tole(0xbb3ffd08L), tole(0xa86f0efcL), tole(0x5a048dffL), + tole(0x8ecee914L), tole(0x7ca56a17L), tole(0x6ff599e3L), tole(0x9d9e1ae0L), + tole(0xd3d3e1abL), tole(0x21b862a8L), tole(0x32e8915cL), tole(0xc083125fL), + tole(0x144976b4L), tole(0xe622f5b7L), tole(0xf5720643L), tole(0x07198540L), + tole(0x590ab964L), tole(0xab613a67L), tole(0xb831c993L), tole(0x4a5a4a90L), + tole(0x9e902e7bL), tole(0x6cfbad78L), tole(0x7fab5e8cL), tole(0x8dc0dd8fL), + tole(0xe330a81aL), tole(0x115b2b19L), tole(0x020bd8edL), tole(0xf0605beeL), + tole(0x24aa3f05L), tole(0xd6c1bc06L), tole(0xc5914ff2L), tole(0x37faccf1L), + tole(0x69e9f0d5L), tole(0x9b8273d6L), tole(0x88d28022L), tole(0x7ab90321L), + tole(0xae7367caL), tole(0x5c18e4c9L), tole(0x4f48173dL), tole(0xbd23943eL), + tole(0xf36e6f75L), tole(0x0105ec76L), tole(0x12551f82L), tole(0xe03e9c81L), + tole(0x34f4f86aL), tole(0xc69f7b69L), tole(0xd5cf889dL), tole(0x27a40b9eL), + tole(0x79b737baL), tole(0x8bdcb4b9L), tole(0x988c474dL), tole(0x6ae7c44eL), + tole(0xbe2da0a5L), tole(0x4c4623a6L), tole(0x5f16d052L), tole(0xad7d5351L)}, + { + tole(0x00000000L), tole(0x13a29877L), tole(0x274530eeL), tole(0x34e7a899L), + tole(0x4e8a61dcL), tole(0x5d28f9abL), tole(0x69cf5132L), tole(0x7a6dc945L), + tole(0x9d14c3b8L), tole(0x8eb65bcfL), tole(0xba51f356L), tole(0xa9f36b21L), + tole(0xd39ea264L), tole(0xc03c3a13L), tole(0xf4db928aL), tole(0xe7790afdL), + tole(0x3fc5f181L), tole(0x2c6769f6L), tole(0x1880c16fL), tole(0x0b225918L), + tole(0x714f905dL), tole(0x62ed082aL), tole(0x560aa0b3L), tole(0x45a838c4L), + tole(0xa2d13239L), tole(0xb173aa4eL), tole(0x859402d7L), tole(0x96369aa0L), + tole(0xec5b53e5L), tole(0xfff9cb92L), tole(0xcb1e630bL), tole(0xd8bcfb7cL), + tole(0x7f8be302L), tole(0x6c297b75L), tole(0x58ced3ecL), tole(0x4b6c4b9bL), + tole(0x310182deL), tole(0x22a31aa9L), tole(0x1644b230L), tole(0x05e62a47L), + tole(0xe29f20baL), tole(0xf13db8cdL), tole(0xc5da1054L), tole(0xd6788823L), + tole(0xac154166L), tole(0xbfb7d911L), tole(0x8b507188L), tole(0x98f2e9ffL), + tole(0x404e1283L), tole(0x53ec8af4L), tole(0x670b226dL), tole(0x74a9ba1aL), + tole(0x0ec4735fL), tole(0x1d66eb28L), tole(0x298143b1L), tole(0x3a23dbc6L), + tole(0xdd5ad13bL), tole(0xcef8494cL), tole(0xfa1fe1d5L), tole(0xe9bd79a2L), + tole(0x93d0b0e7L), tole(0x80722890L), tole(0xb4958009L), tole(0xa737187eL), + tole(0xff17c604L), tole(0xecb55e73L), tole(0xd852f6eaL), tole(0xcbf06e9dL), + tole(0xb19da7d8L), tole(0xa23f3fafL), tole(0x96d89736L), tole(0x857a0f41L), + tole(0x620305bcL), tole(0x71a19dcbL), tole(0x45463552L), tole(0x56e4ad25L), + tole(0x2c896460L), tole(0x3f2bfc17L), tole(0x0bcc548eL), tole(0x186eccf9L), + tole(0xc0d23785L), tole(0xd370aff2L), tole(0xe797076bL), tole(0xf4359f1cL), + tole(0x8e585659L), tole(0x9dface2eL), tole(0xa91d66b7L), tole(0xbabffec0L), + tole(0x5dc6f43dL), tole(0x4e646c4aL), tole(0x7a83c4d3L), tole(0x69215ca4L), + tole(0x134c95e1L), tole(0x00ee0d96L), tole(0x3409a50fL), tole(0x27ab3d78L), + tole(0x809c2506L), tole(0x933ebd71L), tole(0xa7d915e8L), tole(0xb47b8d9fL), + tole(0xce1644daL), tole(0xddb4dcadL), tole(0xe9537434L), tole(0xfaf1ec43L), + tole(0x1d88e6beL), tole(0x0e2a7ec9L), tole(0x3acdd650L), tole(0x296f4e27L), + tole(0x53028762L), tole(0x40a01f15L), tole(0x7447b78cL), tole(0x67e52ffbL), + tole(0xbf59d487L), tole(0xacfb4cf0L), tole(0x981ce469L), tole(0x8bbe7c1eL), + tole(0xf1d3b55bL), tole(0xe2712d2cL), tole(0xd69685b5L), tole(0xc5341dc2L), + tole(0x224d173fL), tole(0x31ef8f48L), tole(0x050827d1L), tole(0x16aabfa6L), + tole(0x6cc776e3L), tole(0x7f65ee94L), tole(0x4b82460dL), tole(0x5820de7aL), + tole(0xfbc3faf9L), tole(0xe861628eL), tole(0xdc86ca17L), tole(0xcf245260L), + tole(0xb5499b25L), tole(0xa6eb0352L), tole(0x920cabcbL), tole(0x81ae33bcL), + tole(0x66d73941L), tole(0x7575a136L), tole(0x419209afL), tole(0x523091d8L), + tole(0x285d589dL), tole(0x3bffc0eaL), tole(0x0f186873L), tole(0x1cbaf004L), + tole(0xc4060b78L), tole(0xd7a4930fL), tole(0xe3433b96L), tole(0xf0e1a3e1L), + tole(0x8a8c6aa4L), tole(0x992ef2d3L), tole(0xadc95a4aL), tole(0xbe6bc23dL), + tole(0x5912c8c0L), tole(0x4ab050b7L), tole(0x7e57f82eL), tole(0x6df56059L), + tole(0x1798a91cL), tole(0x043a316bL), tole(0x30dd99f2L), tole(0x237f0185L), + tole(0x844819fbL), tole(0x97ea818cL), tole(0xa30d2915L), tole(0xb0afb162L), + tole(0xcac27827L), tole(0xd960e050L), tole(0xed8748c9L), tole(0xfe25d0beL), + tole(0x195cda43L), tole(0x0afe4234L), tole(0x3e19eaadL), tole(0x2dbb72daL), + tole(0x57d6bb9fL), tole(0x447423e8L), tole(0x70938b71L), tole(0x63311306L), + tole(0xbb8de87aL), tole(0xa82f700dL), tole(0x9cc8d894L), tole(0x8f6a40e3L), + tole(0xf50789a6L), tole(0xe6a511d1L), tole(0xd242b948L), tole(0xc1e0213fL), + tole(0x26992bc2L), tole(0x353bb3b5L), tole(0x01dc1b2cL), tole(0x127e835bL), + tole(0x68134a1eL), tole(0x7bb1d269L), tole(0x4f567af0L), tole(0x5cf4e287L), + tole(0x04d43cfdL), tole(0x1776a48aL), tole(0x23910c13L), tole(0x30339464L), + tole(0x4a5e5d21L), tole(0x59fcc556L), tole(0x6d1b6dcfL), tole(0x7eb9f5b8L), + tole(0x99c0ff45L), tole(0x8a626732L), tole(0xbe85cfabL), tole(0xad2757dcL), + tole(0xd74a9e99L), tole(0xc4e806eeL), tole(0xf00fae77L), tole(0xe3ad3600L), + tole(0x3b11cd7cL), tole(0x28b3550bL), tole(0x1c54fd92L), tole(0x0ff665e5L), + tole(0x759baca0L), tole(0x663934d7L), tole(0x52de9c4eL), tole(0x417c0439L), + tole(0xa6050ec4L), tole(0xb5a796b3L), tole(0x81403e2aL), tole(0x92e2a65dL), + tole(0xe88f6f18L), tole(0xfb2df76fL), tole(0xcfca5ff6L), tole(0xdc68c781L), + tole(0x7b5fdfffL), tole(0x68fd4788L), tole(0x5c1aef11L), tole(0x4fb87766L), + tole(0x35d5be23L), tole(0x26772654L), tole(0x12908ecdL), tole(0x013216baL), + tole(0xe64b1c47L), tole(0xf5e98430L), tole(0xc10e2ca9L), tole(0xd2acb4deL), + tole(0xa8c17d9bL), tole(0xbb63e5ecL), tole(0x8f844d75L), tole(0x9c26d502L), + tole(0x449a2e7eL), tole(0x5738b609L), tole(0x63df1e90L), tole(0x707d86e7L), + tole(0x0a104fa2L), tole(0x19b2d7d5L), tole(0x2d557f4cL), tole(0x3ef7e73bL), + tole(0xd98eedc6L), tole(0xca2c75b1L), tole(0xfecbdd28L), tole(0xed69455fL), + tole(0x97048c1aL), tole(0x84a6146dL), tole(0xb041bcf4L), tole(0xa3e32483L)}, + { + tole(0x00000000L), tole(0xa541927eL), tole(0x4f6f520dL), tole(0xea2ec073L), + tole(0x9edea41aL), tole(0x3b9f3664L), tole(0xd1b1f617L), tole(0x74f06469L), + tole(0x38513ec5L), tole(0x9d10acbbL), tole(0x773e6cc8L), tole(0xd27ffeb6L), + tole(0xa68f9adfL), tole(0x03ce08a1L), tole(0xe9e0c8d2L), tole(0x4ca15aacL), + tole(0x70a27d8aL), tole(0xd5e3eff4L), tole(0x3fcd2f87L), tole(0x9a8cbdf9L), + tole(0xee7cd990L), tole(0x4b3d4beeL), tole(0xa1138b9dL), tole(0x045219e3L), + tole(0x48f3434fL), tole(0xedb2d131L), tole(0x079c1142L), tole(0xa2dd833cL), + tole(0xd62de755L), tole(0x736c752bL), tole(0x9942b558L), tole(0x3c032726L), + tole(0xe144fb14L), tole(0x4405696aL), tole(0xae2ba919L), tole(0x0b6a3b67L), + tole(0x7f9a5f0eL), tole(0xdadbcd70L), tole(0x30f50d03L), tole(0x95b49f7dL), + tole(0xd915c5d1L), tole(0x7c5457afL), tole(0x967a97dcL), tole(0x333b05a2L), + tole(0x47cb61cbL), tole(0xe28af3b5L), tole(0x08a433c6L), tole(0xade5a1b8L), + tole(0x91e6869eL), tole(0x34a714e0L), tole(0xde89d493L), tole(0x7bc846edL), + tole(0x0f382284L), tole(0xaa79b0faL), tole(0x40577089L), tole(0xe516e2f7L), + tole(0xa9b7b85bL), tole(0x0cf62a25L), tole(0xe6d8ea56L), tole(0x43997828L), + tole(0x37691c41L), tole(0x92288e3fL), tole(0x78064e4cL), tole(0xdd47dc32L), + tole(0xc76580d9L), tole(0x622412a7L), tole(0x880ad2d4L), tole(0x2d4b40aaL), + tole(0x59bb24c3L), tole(0xfcfab6bdL), tole(0x16d476ceL), tole(0xb395e4b0L), + tole(0xff34be1cL), tole(0x5a752c62L), tole(0xb05bec11L), tole(0x151a7e6fL), + tole(0x61ea1a06L), tole(0xc4ab8878L), tole(0x2e85480bL), tole(0x8bc4da75L), + tole(0xb7c7fd53L), tole(0x12866f2dL), tole(0xf8a8af5eL), tole(0x5de93d20L), + tole(0x29195949L), tole(0x8c58cb37L), tole(0x66760b44L), tole(0xc337993aL), + tole(0x8f96c396L), tole(0x2ad751e8L), tole(0xc0f9919bL), tole(0x65b803e5L), + tole(0x1148678cL), tole(0xb409f5f2L), tole(0x5e273581L), tole(0xfb66a7ffL), + tole(0x26217bcdL), tole(0x8360e9b3L), tole(0x694e29c0L), tole(0xcc0fbbbeL), + tole(0xb8ffdfd7L), tole(0x1dbe4da9L), tole(0xf7908ddaL), tole(0x52d11fa4L), + tole(0x1e704508L), tole(0xbb31d776L), tole(0x511f1705L), tole(0xf45e857bL), + tole(0x80aee112L), tole(0x25ef736cL), tole(0xcfc1b31fL), tole(0x6a802161L), + tole(0x56830647L), tole(0xf3c29439L), tole(0x19ec544aL), tole(0xbcadc634L), + tole(0xc85da25dL), tole(0x6d1c3023L), tole(0x8732f050L), tole(0x2273622eL), + tole(0x6ed23882L), tole(0xcb93aafcL), tole(0x21bd6a8fL), tole(0x84fcf8f1L), + tole(0xf00c9c98L), tole(0x554d0ee6L), tole(0xbf63ce95L), tole(0x1a225cebL), + tole(0x8b277743L), tole(0x2e66e53dL), tole(0xc448254eL), tole(0x6109b730L), + tole(0x15f9d359L), tole(0xb0b84127L), tole(0x5a968154L), tole(0xffd7132aL), + tole(0xb3764986L), tole(0x1637dbf8L), tole(0xfc191b8bL), tole(0x595889f5L), + tole(0x2da8ed9cL), tole(0x88e97fe2L), tole(0x62c7bf91L), tole(0xc7862defL), + tole(0xfb850ac9L), tole(0x5ec498b7L), tole(0xb4ea58c4L), tole(0x11abcabaL), + tole(0x655baed3L), tole(0xc01a3cadL), tole(0x2a34fcdeL), tole(0x8f756ea0L), + tole(0xc3d4340cL), tole(0x6695a672L), tole(0x8cbb6601L), tole(0x29faf47fL), + tole(0x5d0a9016L), tole(0xf84b0268L), tole(0x1265c21bL), tole(0xb7245065L), + tole(0x6a638c57L), tole(0xcf221e29L), tole(0x250cde5aL), tole(0x804d4c24L), + tole(0xf4bd284dL), tole(0x51fcba33L), tole(0xbbd27a40L), tole(0x1e93e83eL), + tole(0x5232b292L), tole(0xf77320ecL), tole(0x1d5de09fL), tole(0xb81c72e1L), + tole(0xccec1688L), tole(0x69ad84f6L), tole(0x83834485L), tole(0x26c2d6fbL), + tole(0x1ac1f1ddL), tole(0xbf8063a3L), tole(0x55aea3d0L), tole(0xf0ef31aeL), + tole(0x841f55c7L), tole(0x215ec7b9L), tole(0xcb7007caL), tole(0x6e3195b4L), + tole(0x2290cf18L), tole(0x87d15d66L), tole(0x6dff9d15L), tole(0xc8be0f6bL), + tole(0xbc4e6b02L), tole(0x190ff97cL), tole(0xf321390fL), tole(0x5660ab71L), + tole(0x4c42f79aL), tole(0xe90365e4L), tole(0x032da597L), tole(0xa66c37e9L), + tole(0xd29c5380L), tole(0x77ddc1feL), tole(0x9df3018dL), tole(0x38b293f3L), + tole(0x7413c95fL), tole(0xd1525b21L), tole(0x3b7c9b52L), tole(0x9e3d092cL), + tole(0xeacd6d45L), tole(0x4f8cff3bL), tole(0xa5a23f48L), tole(0x00e3ad36L), + tole(0x3ce08a10L), tole(0x99a1186eL), tole(0x738fd81dL), tole(0xd6ce4a63L), + tole(0xa23e2e0aL), tole(0x077fbc74L), tole(0xed517c07L), tole(0x4810ee79L), + tole(0x04b1b4d5L), tole(0xa1f026abL), tole(0x4bdee6d8L), tole(0xee9f74a6L), + tole(0x9a6f10cfL), tole(0x3f2e82b1L), tole(0xd50042c2L), tole(0x7041d0bcL), + tole(0xad060c8eL), tole(0x08479ef0L), tole(0xe2695e83L), tole(0x4728ccfdL), + tole(0x33d8a894L), tole(0x96993aeaL), tole(0x7cb7fa99L), tole(0xd9f668e7L), + tole(0x9557324bL), tole(0x3016a035L), tole(0xda386046L), tole(0x7f79f238L), + tole(0x0b899651L), tole(0xaec8042fL), tole(0x44e6c45cL), tole(0xe1a75622L), + tole(0xdda47104L), tole(0x78e5e37aL), tole(0x92cb2309L), tole(0x378ab177L), + tole(0x437ad51eL), tole(0xe63b4760L), tole(0x0c158713L), tole(0xa954156dL), + tole(0xe5f54fc1L), tole(0x40b4ddbfL), tole(0xaa9a1dccL), tole(0x0fdb8fb2L), + tole(0x7b2bebdbL), tole(0xde6a79a5L), tole(0x3444b9d6L), tole(0x91052ba8L)}, + { + tole(0x00000000L), tole(0xdd45aab8L), tole(0xbf672381L), tole(0x62228939L), + tole(0x7b2231f3L), tole(0xa6679b4bL), tole(0xc4451272L), tole(0x1900b8caL), + tole(0xf64463e6L), tole(0x2b01c95eL), tole(0x49234067L), tole(0x9466eadfL), + tole(0x8d665215L), tole(0x5023f8adL), tole(0x32017194L), tole(0xef44db2cL), + tole(0xe964b13dL), tole(0x34211b85L), tole(0x560392bcL), tole(0x8b463804L), + tole(0x924680ceL), tole(0x4f032a76L), tole(0x2d21a34fL), tole(0xf06409f7L), + tole(0x1f20d2dbL), tole(0xc2657863L), tole(0xa047f15aL), tole(0x7d025be2L), + tole(0x6402e328L), tole(0xb9474990L), tole(0xdb65c0a9L), tole(0x06206a11L), + tole(0xd725148bL), tole(0x0a60be33L), tole(0x6842370aL), tole(0xb5079db2L), + tole(0xac072578L), tole(0x71428fc0L), tole(0x136006f9L), tole(0xce25ac41L), + tole(0x2161776dL), tole(0xfc24ddd5L), tole(0x9e0654ecL), tole(0x4343fe54L), + tole(0x5a43469eL), tole(0x8706ec26L), tole(0xe524651fL), tole(0x3861cfa7L), + tole(0x3e41a5b6L), tole(0xe3040f0eL), tole(0x81268637L), tole(0x5c632c8fL), + tole(0x45639445L), tole(0x98263efdL), tole(0xfa04b7c4L), tole(0x27411d7cL), + tole(0xc805c650L), tole(0x15406ce8L), tole(0x7762e5d1L), tole(0xaa274f69L), + tole(0xb327f7a3L), tole(0x6e625d1bL), tole(0x0c40d422L), tole(0xd1057e9aL), + tole(0xaba65fe7L), tole(0x76e3f55fL), tole(0x14c17c66L), tole(0xc984d6deL), + tole(0xd0846e14L), tole(0x0dc1c4acL), tole(0x6fe34d95L), tole(0xb2a6e72dL), + tole(0x5de23c01L), tole(0x80a796b9L), tole(0xe2851f80L), tole(0x3fc0b538L), + tole(0x26c00df2L), tole(0xfb85a74aL), tole(0x99a72e73L), tole(0x44e284cbL), + tole(0x42c2eedaL), tole(0x9f874462L), tole(0xfda5cd5bL), tole(0x20e067e3L), + tole(0x39e0df29L), tole(0xe4a57591L), tole(0x8687fca8L), tole(0x5bc25610L), + tole(0xb4868d3cL), tole(0x69c32784L), tole(0x0be1aebdL), tole(0xd6a40405L), + tole(0xcfa4bccfL), tole(0x12e11677L), tole(0x70c39f4eL), tole(0xad8635f6L), + tole(0x7c834b6cL), tole(0xa1c6e1d4L), tole(0xc3e468edL), tole(0x1ea1c255L), + tole(0x07a17a9fL), tole(0xdae4d027L), tole(0xb8c6591eL), tole(0x6583f3a6L), + tole(0x8ac7288aL), tole(0x57828232L), tole(0x35a00b0bL), tole(0xe8e5a1b3L), + tole(0xf1e51979L), tole(0x2ca0b3c1L), tole(0x4e823af8L), tole(0x93c79040L), + tole(0x95e7fa51L), tole(0x48a250e9L), tole(0x2a80d9d0L), tole(0xf7c57368L), + tole(0xeec5cba2L), tole(0x3380611aL), tole(0x51a2e823L), tole(0x8ce7429bL), + tole(0x63a399b7L), tole(0xbee6330fL), tole(0xdcc4ba36L), tole(0x0181108eL), + tole(0x1881a844L), tole(0xc5c402fcL), tole(0xa7e68bc5L), tole(0x7aa3217dL), + tole(0x52a0c93fL), tole(0x8fe56387L), tole(0xedc7eabeL), tole(0x30824006L), + tole(0x2982f8ccL), tole(0xf4c75274L), tole(0x96e5db4dL), tole(0x4ba071f5L), + tole(0xa4e4aad9L), tole(0x79a10061L), tole(0x1b838958L), tole(0xc6c623e0L), + tole(0xdfc69b2aL), tole(0x02833192L), tole(0x60a1b8abL), tole(0xbde41213L), + tole(0xbbc47802L), tole(0x6681d2baL), tole(0x04a35b83L), tole(0xd9e6f13bL), + tole(0xc0e649f1L), tole(0x1da3e349L), tole(0x7f816a70L), tole(0xa2c4c0c8L), + tole(0x4d801be4L), tole(0x90c5b15cL), tole(0xf2e73865L), tole(0x2fa292ddL), + tole(0x36a22a17L), tole(0xebe780afL), tole(0x89c50996L), tole(0x5480a32eL), + tole(0x8585ddb4L), tole(0x58c0770cL), tole(0x3ae2fe35L), tole(0xe7a7548dL), + tole(0xfea7ec47L), tole(0x23e246ffL), tole(0x41c0cfc6L), tole(0x9c85657eL), + tole(0x73c1be52L), tole(0xae8414eaL), tole(0xcca69dd3L), tole(0x11e3376bL), + tole(0x08e38fa1L), tole(0xd5a62519L), tole(0xb784ac20L), tole(0x6ac10698L), + tole(0x6ce16c89L), tole(0xb1a4c631L), tole(0xd3864f08L), tole(0x0ec3e5b0L), + tole(0x17c35d7aL), tole(0xca86f7c2L), tole(0xa8a47efbL), tole(0x75e1d443L), + tole(0x9aa50f6fL), tole(0x47e0a5d7L), tole(0x25c22ceeL), tole(0xf8878656L), + tole(0xe1873e9cL), tole(0x3cc29424L), tole(0x5ee01d1dL), tole(0x83a5b7a5L), + tole(0xf90696d8L), tole(0x24433c60L), tole(0x4661b559L), tole(0x9b241fe1L), + tole(0x8224a72bL), tole(0x5f610d93L), tole(0x3d4384aaL), tole(0xe0062e12L), + tole(0x0f42f53eL), tole(0xd2075f86L), tole(0xb025d6bfL), tole(0x6d607c07L), + tole(0x7460c4cdL), tole(0xa9256e75L), tole(0xcb07e74cL), tole(0x16424df4L), + tole(0x106227e5L), tole(0xcd278d5dL), tole(0xaf050464L), tole(0x7240aedcL), + tole(0x6b401616L), tole(0xb605bcaeL), tole(0xd4273597L), tole(0x09629f2fL), + tole(0xe6264403L), tole(0x3b63eebbL), tole(0x59416782L), tole(0x8404cd3aL), + tole(0x9d0475f0L), tole(0x4041df48L), tole(0x22635671L), tole(0xff26fcc9L), + tole(0x2e238253L), tole(0xf36628ebL), tole(0x9144a1d2L), tole(0x4c010b6aL), + tole(0x5501b3a0L), tole(0x88441918L), tole(0xea669021L), tole(0x37233a99L), + tole(0xd867e1b5L), tole(0x05224b0dL), tole(0x6700c234L), tole(0xba45688cL), + tole(0xa345d046L), tole(0x7e007afeL), tole(0x1c22f3c7L), tole(0xc167597fL), + tole(0xc747336eL), tole(0x1a0299d6L), tole(0x782010efL), tole(0xa565ba57L), + tole(0xbc65029dL), tole(0x6120a825L), tole(0x0302211cL), tole(0xde478ba4L), + tole(0x31035088L), tole(0xec46fa30L), tole(0x8e647309L), tole(0x5321d9b1L), + tole(0x4a21617bL), tole(0x9764cbc3L), tole(0xf54642faL), tole(0x2803e842L)}, + { + tole(0x00000000L), tole(0x38116facL), tole(0x7022df58L), tole(0x4833b0f4L), + tole(0xe045beb0L), tole(0xd854d11cL), tole(0x906761e8L), tole(0xa8760e44L), + tole(0xc5670b91L), tole(0xfd76643dL), tole(0xb545d4c9L), tole(0x8d54bb65L), + tole(0x2522b521L), tole(0x1d33da8dL), tole(0x55006a79L), tole(0x6d1105d5L), + tole(0x8f2261d3L), tole(0xb7330e7fL), tole(0xff00be8bL), tole(0xc711d127L), + tole(0x6f67df63L), tole(0x5776b0cfL), tole(0x1f45003bL), tole(0x27546f97L), + tole(0x4a456a42L), tole(0x725405eeL), tole(0x3a67b51aL), tole(0x0276dab6L), + tole(0xaa00d4f2L), tole(0x9211bb5eL), tole(0xda220baaL), tole(0xe2336406L), + tole(0x1ba8b557L), tole(0x23b9dafbL), tole(0x6b8a6a0fL), tole(0x539b05a3L), + tole(0xfbed0be7L), tole(0xc3fc644bL), tole(0x8bcfd4bfL), tole(0xb3debb13L), + tole(0xdecfbec6L), tole(0xe6ded16aL), tole(0xaeed619eL), tole(0x96fc0e32L), + tole(0x3e8a0076L), tole(0x069b6fdaL), tole(0x4ea8df2eL), tole(0x76b9b082L), + tole(0x948ad484L), tole(0xac9bbb28L), tole(0xe4a80bdcL), tole(0xdcb96470L), + tole(0x74cf6a34L), tole(0x4cde0598L), tole(0x04edb56cL), tole(0x3cfcdac0L), + tole(0x51eddf15L), tole(0x69fcb0b9L), tole(0x21cf004dL), tole(0x19de6fe1L), + tole(0xb1a861a5L), tole(0x89b90e09L), tole(0xc18abefdL), tole(0xf99bd151L), + tole(0x37516aaeL), tole(0x0f400502L), tole(0x4773b5f6L), tole(0x7f62da5aL), + tole(0xd714d41eL), tole(0xef05bbb2L), tole(0xa7360b46L), tole(0x9f2764eaL), + tole(0xf236613fL), tole(0xca270e93L), tole(0x8214be67L), tole(0xba05d1cbL), + tole(0x1273df8fL), tole(0x2a62b023L), tole(0x625100d7L), tole(0x5a406f7bL), + tole(0xb8730b7dL), tole(0x806264d1L), tole(0xc851d425L), tole(0xf040bb89L), + tole(0x5836b5cdL), tole(0x6027da61L), tole(0x28146a95L), tole(0x10050539L), + tole(0x7d1400ecL), tole(0x45056f40L), tole(0x0d36dfb4L), tole(0x3527b018L), + tole(0x9d51be5cL), tole(0xa540d1f0L), tole(0xed736104L), tole(0xd5620ea8L), + tole(0x2cf9dff9L), tole(0x14e8b055L), tole(0x5cdb00a1L), tole(0x64ca6f0dL), + tole(0xccbc6149L), tole(0xf4ad0ee5L), tole(0xbc9ebe11L), tole(0x848fd1bdL), + tole(0xe99ed468L), tole(0xd18fbbc4L), tole(0x99bc0b30L), tole(0xa1ad649cL), + tole(0x09db6ad8L), tole(0x31ca0574L), tole(0x79f9b580L), tole(0x41e8da2cL), + tole(0xa3dbbe2aL), tole(0x9bcad186L), tole(0xd3f96172L), tole(0xebe80edeL), + tole(0x439e009aL), tole(0x7b8f6f36L), tole(0x33bcdfc2L), tole(0x0badb06eL), + tole(0x66bcb5bbL), tole(0x5eadda17L), tole(0x169e6ae3L), tole(0x2e8f054fL), + tole(0x86f90b0bL), tole(0xbee864a7L), tole(0xf6dbd453L), tole(0xcecabbffL), + tole(0x6ea2d55cL), tole(0x56b3baf0L), tole(0x1e800a04L), tole(0x269165a8L), + tole(0x8ee76becL), tole(0xb6f60440L), tole(0xfec5b4b4L), tole(0xc6d4db18L), + tole(0xabc5decdL), tole(0x93d4b161L), tole(0xdbe70195L), tole(0xe3f66e39L), + tole(0x4b80607dL), tole(0x73910fd1L), tole(0x3ba2bf25L), tole(0x03b3d089L), + tole(0xe180b48fL), tole(0xd991db23L), tole(0x91a26bd7L), tole(0xa9b3047bL), + tole(0x01c50a3fL), tole(0x39d46593L), tole(0x71e7d567L), tole(0x49f6bacbL), + tole(0x24e7bf1eL), tole(0x1cf6d0b2L), tole(0x54c56046L), tole(0x6cd40feaL), + tole(0xc4a201aeL), tole(0xfcb36e02L), tole(0xb480def6L), tole(0x8c91b15aL), + tole(0x750a600bL), tole(0x4d1b0fa7L), tole(0x0528bf53L), tole(0x3d39d0ffL), + tole(0x954fdebbL), tole(0xad5eb117L), tole(0xe56d01e3L), tole(0xdd7c6e4fL), + tole(0xb06d6b9aL), tole(0x887c0436L), tole(0xc04fb4c2L), tole(0xf85edb6eL), + tole(0x5028d52aL), tole(0x6839ba86L), tole(0x200a0a72L), tole(0x181b65deL), + tole(0xfa2801d8L), tole(0xc2396e74L), tole(0x8a0ade80L), tole(0xb21bb12cL), + tole(0x1a6dbf68L), tole(0x227cd0c4L), tole(0x6a4f6030L), tole(0x525e0f9cL), + tole(0x3f4f0a49L), tole(0x075e65e5L), tole(0x4f6dd511L), tole(0x777cbabdL), + tole(0xdf0ab4f9L), tole(0xe71bdb55L), tole(0xaf286ba1L), tole(0x9739040dL), + tole(0x59f3bff2L), tole(0x61e2d05eL), tole(0x29d160aaL), tole(0x11c00f06L), + tole(0xb9b60142L), tole(0x81a76eeeL), tole(0xc994de1aL), tole(0xf185b1b6L), + tole(0x9c94b463L), tole(0xa485dbcfL), tole(0xecb66b3bL), tole(0xd4a70497L), + tole(0x7cd10ad3L), tole(0x44c0657fL), tole(0x0cf3d58bL), tole(0x34e2ba27L), + tole(0xd6d1de21L), tole(0xeec0b18dL), tole(0xa6f30179L), tole(0x9ee26ed5L), + tole(0x36946091L), tole(0x0e850f3dL), tole(0x46b6bfc9L), tole(0x7ea7d065L), + tole(0x13b6d5b0L), tole(0x2ba7ba1cL), tole(0x63940ae8L), tole(0x5b856544L), + tole(0xf3f36b00L), tole(0xcbe204acL), tole(0x83d1b458L), tole(0xbbc0dbf4L), + tole(0x425b0aa5L), tole(0x7a4a6509L), tole(0x3279d5fdL), tole(0x0a68ba51L), + tole(0xa21eb415L), tole(0x9a0fdbb9L), tole(0xd23c6b4dL), tole(0xea2d04e1L), + tole(0x873c0134L), tole(0xbf2d6e98L), tole(0xf71ede6cL), tole(0xcf0fb1c0L), + tole(0x6779bf84L), tole(0x5f68d028L), tole(0x175b60dcL), tole(0x2f4a0f70L), + tole(0xcd796b76L), tole(0xf56804daL), tole(0xbd5bb42eL), tole(0x854adb82L), + tole(0x2d3cd5c6L), tole(0x152dba6aL), tole(0x5d1e0a9eL), tole(0x650f6532L), + tole(0x081e60e7L), tole(0x300f0f4bL), tole(0x783cbfbfL), tole(0x402dd013L), + tole(0xe85bde57L), tole(0xd04ab1fbL), tole(0x9879010fL), tole(0xa0686ea3L)}, + { + tole(0x00000000L), tole(0xef306b19L), tole(0xdb8ca0c3L), tole(0x34bccbdaL), + tole(0xb2f53777L), tole(0x5dc55c6eL), tole(0x697997b4L), tole(0x8649fcadL), + tole(0x6006181fL), tole(0x8f367306L), tole(0xbb8ab8dcL), tole(0x54bad3c5L), + tole(0xd2f32f68L), tole(0x3dc34471L), tole(0x097f8fabL), tole(0xe64fe4b2L), + tole(0xc00c303eL), tole(0x2f3c5b27L), tole(0x1b8090fdL), tole(0xf4b0fbe4L), + tole(0x72f90749L), tole(0x9dc96c50L), tole(0xa975a78aL), tole(0x4645cc93L), + tole(0xa00a2821L), tole(0x4f3a4338L), tole(0x7b8688e2L), tole(0x94b6e3fbL), + tole(0x12ff1f56L), tole(0xfdcf744fL), tole(0xc973bf95L), tole(0x2643d48cL), + tole(0x85f4168dL), tole(0x6ac47d94L), tole(0x5e78b64eL), tole(0xb148dd57L), + tole(0x370121faL), tole(0xd8314ae3L), tole(0xec8d8139L), tole(0x03bdea20L), + tole(0xe5f20e92L), tole(0x0ac2658bL), tole(0x3e7eae51L), tole(0xd14ec548L), + tole(0x570739e5L), tole(0xb83752fcL), tole(0x8c8b9926L), tole(0x63bbf23fL), + tole(0x45f826b3L), tole(0xaac84daaL), tole(0x9e748670L), tole(0x7144ed69L), + tole(0xf70d11c4L), tole(0x183d7addL), tole(0x2c81b107L), tole(0xc3b1da1eL), + tole(0x25fe3eacL), tole(0xcace55b5L), tole(0xfe729e6fL), tole(0x1142f576L), + tole(0x970b09dbL), tole(0x783b62c2L), tole(0x4c87a918L), tole(0xa3b7c201L), + tole(0x0e045bebL), tole(0xe13430f2L), tole(0xd588fb28L), tole(0x3ab89031L), + tole(0xbcf16c9cL), tole(0x53c10785L), tole(0x677dcc5fL), tole(0x884da746L), + tole(0x6e0243f4L), tole(0x813228edL), tole(0xb58ee337L), tole(0x5abe882eL), + tole(0xdcf77483L), tole(0x33c71f9aL), tole(0x077bd440L), tole(0xe84bbf59L), + tole(0xce086bd5L), tole(0x213800ccL), tole(0x1584cb16L), tole(0xfab4a00fL), + tole(0x7cfd5ca2L), tole(0x93cd37bbL), tole(0xa771fc61L), tole(0x48419778L), + tole(0xae0e73caL), tole(0x413e18d3L), tole(0x7582d309L), tole(0x9ab2b810L), + tole(0x1cfb44bdL), tole(0xf3cb2fa4L), tole(0xc777e47eL), tole(0x28478f67L), + tole(0x8bf04d66L), tole(0x64c0267fL), tole(0x507ceda5L), tole(0xbf4c86bcL), + tole(0x39057a11L), tole(0xd6351108L), tole(0xe289dad2L), tole(0x0db9b1cbL), + tole(0xebf65579L), tole(0x04c63e60L), tole(0x307af5baL), tole(0xdf4a9ea3L), + tole(0x5903620eL), tole(0xb6330917L), tole(0x828fc2cdL), tole(0x6dbfa9d4L), + tole(0x4bfc7d58L), tole(0xa4cc1641L), tole(0x9070dd9bL), tole(0x7f40b682L), + tole(0xf9094a2fL), tole(0x16392136L), tole(0x2285eaecL), tole(0xcdb581f5L), + tole(0x2bfa6547L), tole(0xc4ca0e5eL), tole(0xf076c584L), tole(0x1f46ae9dL), + tole(0x990f5230L), tole(0x763f3929L), tole(0x4283f2f3L), tole(0xadb399eaL), + tole(0x1c08b7d6L), tole(0xf338dccfL), tole(0xc7841715L), tole(0x28b47c0cL), + tole(0xaefd80a1L), tole(0x41cdebb8L), tole(0x75712062L), tole(0x9a414b7bL), + tole(0x7c0eafc9L), tole(0x933ec4d0L), tole(0xa7820f0aL), tole(0x48b26413L), + tole(0xcefb98beL), tole(0x21cbf3a7L), tole(0x1577387dL), tole(0xfa475364L), + tole(0xdc0487e8L), tole(0x3334ecf1L), tole(0x0788272bL), tole(0xe8b84c32L), + tole(0x6ef1b09fL), tole(0x81c1db86L), tole(0xb57d105cL), tole(0x5a4d7b45L), + tole(0xbc029ff7L), tole(0x5332f4eeL), tole(0x678e3f34L), tole(0x88be542dL), + tole(0x0ef7a880L), tole(0xe1c7c399L), tole(0xd57b0843L), tole(0x3a4b635aL), + tole(0x99fca15bL), tole(0x76ccca42L), tole(0x42700198L), tole(0xad406a81L), + tole(0x2b09962cL), tole(0xc439fd35L), tole(0xf08536efL), tole(0x1fb55df6L), + tole(0xf9fab944L), tole(0x16cad25dL), tole(0x22761987L), tole(0xcd46729eL), + tole(0x4b0f8e33L), tole(0xa43fe52aL), tole(0x90832ef0L), tole(0x7fb345e9L), + tole(0x59f09165L), tole(0xb6c0fa7cL), tole(0x827c31a6L), tole(0x6d4c5abfL), + tole(0xeb05a612L), tole(0x0435cd0bL), tole(0x308906d1L), tole(0xdfb96dc8L), + tole(0x39f6897aL), tole(0xd6c6e263L), tole(0xe27a29b9L), tole(0x0d4a42a0L), + tole(0x8b03be0dL), tole(0x6433d514L), tole(0x508f1eceL), tole(0xbfbf75d7L), + tole(0x120cec3dL), tole(0xfd3c8724L), tole(0xc9804cfeL), tole(0x26b027e7L), + tole(0xa0f9db4aL), tole(0x4fc9b053L), tole(0x7b757b89L), tole(0x94451090L), + tole(0x720af422L), tole(0x9d3a9f3bL), tole(0xa98654e1L), tole(0x46b63ff8L), + tole(0xc0ffc355L), tole(0x2fcfa84cL), tole(0x1b736396L), tole(0xf443088fL), + tole(0xd200dc03L), tole(0x3d30b71aL), tole(0x098c7cc0L), tole(0xe6bc17d9L), + tole(0x60f5eb74L), tole(0x8fc5806dL), tole(0xbb794bb7L), tole(0x544920aeL), + tole(0xb206c41cL), tole(0x5d36af05L), tole(0x698a64dfL), tole(0x86ba0fc6L), + tole(0x00f3f36bL), tole(0xefc39872L), tole(0xdb7f53a8L), tole(0x344f38b1L), + tole(0x97f8fab0L), tole(0x78c891a9L), tole(0x4c745a73L), tole(0xa344316aL), + tole(0x250dcdc7L), tole(0xca3da6deL), tole(0xfe816d04L), tole(0x11b1061dL), + tole(0xf7fee2afL), tole(0x18ce89b6L), tole(0x2c72426cL), tole(0xc3422975L), + tole(0x450bd5d8L), tole(0xaa3bbec1L), tole(0x9e87751bL), tole(0x71b71e02L), + tole(0x57f4ca8eL), tole(0xb8c4a197L), tole(0x8c786a4dL), tole(0x63480154L), + tole(0xe501fdf9L), tole(0x0a3196e0L), tole(0x3e8d5d3aL), tole(0xd1bd3623L), + tole(0x37f2d291L), tole(0xd8c2b988L), tole(0xec7e7252L), tole(0x034e194bL), + tole(0x8507e5e6L), tole(0x6a378effL), tole(0x5e8b4525L), tole(0xb1bb2e3cL)}, + { + tole(0x00000000L), tole(0x68032cc8L), tole(0xd0065990L), tole(0xb8057558L), + tole(0xa5e0c5d1L), tole(0xcde3e919L), tole(0x75e69c41L), tole(0x1de5b089L), + tole(0x4e2dfd53L), tole(0x262ed19bL), tole(0x9e2ba4c3L), tole(0xf628880bL), + tole(0xebcd3882L), tole(0x83ce144aL), tole(0x3bcb6112L), tole(0x53c84ddaL), + tole(0x9c5bfaa6L), tole(0xf458d66eL), tole(0x4c5da336L), tole(0x245e8ffeL), + tole(0x39bb3f77L), tole(0x51b813bfL), tole(0xe9bd66e7L), tole(0x81be4a2fL), + tole(0xd27607f5L), tole(0xba752b3dL), tole(0x02705e65L), tole(0x6a7372adL), + tole(0x7796c224L), tole(0x1f95eeecL), tole(0xa7909bb4L), tole(0xcf93b77cL), + tole(0x3d5b83bdL), tole(0x5558af75L), tole(0xed5dda2dL), tole(0x855ef6e5L), + tole(0x98bb466cL), tole(0xf0b86aa4L), tole(0x48bd1ffcL), tole(0x20be3334L), + tole(0x73767eeeL), tole(0x1b755226L), tole(0xa370277eL), tole(0xcb730bb6L), + tole(0xd696bb3fL), tole(0xbe9597f7L), tole(0x0690e2afL), tole(0x6e93ce67L), + tole(0xa100791bL), tole(0xc90355d3L), tole(0x7106208bL), tole(0x19050c43L), + tole(0x04e0bccaL), tole(0x6ce39002L), tole(0xd4e6e55aL), tole(0xbce5c992L), + tole(0xef2d8448L), tole(0x872ea880L), tole(0x3f2bddd8L), tole(0x5728f110L), + tole(0x4acd4199L), tole(0x22ce6d51L), tole(0x9acb1809L), tole(0xf2c834c1L), + tole(0x7ab7077aL), tole(0x12b42bb2L), tole(0xaab15eeaL), tole(0xc2b27222L), + tole(0xdf57c2abL), tole(0xb754ee63L), tole(0x0f519b3bL), tole(0x6752b7f3L), + tole(0x349afa29L), tole(0x5c99d6e1L), tole(0xe49ca3b9L), tole(0x8c9f8f71L), + tole(0x917a3ff8L), tole(0xf9791330L), tole(0x417c6668L), tole(0x297f4aa0L), + tole(0xe6ecfddcL), tole(0x8eefd114L), tole(0x36eaa44cL), tole(0x5ee98884L), + tole(0x430c380dL), tole(0x2b0f14c5L), tole(0x930a619dL), tole(0xfb094d55L), + tole(0xa8c1008fL), tole(0xc0c22c47L), tole(0x78c7591fL), tole(0x10c475d7L), + tole(0x0d21c55eL), tole(0x6522e996L), tole(0xdd279cceL), tole(0xb524b006L), + tole(0x47ec84c7L), tole(0x2fefa80fL), tole(0x97eadd57L), tole(0xffe9f19fL), + tole(0xe20c4116L), tole(0x8a0f6ddeL), tole(0x320a1886L), tole(0x5a09344eL), + tole(0x09c17994L), tole(0x61c2555cL), tole(0xd9c72004L), tole(0xb1c40cccL), + tole(0xac21bc45L), tole(0xc422908dL), tole(0x7c27e5d5L), tole(0x1424c91dL), + tole(0xdbb77e61L), tole(0xb3b452a9L), tole(0x0bb127f1L), tole(0x63b20b39L), + tole(0x7e57bbb0L), tole(0x16549778L), tole(0xae51e220L), tole(0xc652cee8L), + tole(0x959a8332L), tole(0xfd99affaL), tole(0x459cdaa2L), tole(0x2d9ff66aL), + tole(0x307a46e3L), tole(0x58796a2bL), tole(0xe07c1f73L), tole(0x887f33bbL), + tole(0xf56e0ef4L), tole(0x9d6d223cL), tole(0x25685764L), tole(0x4d6b7bacL), + tole(0x508ecb25L), tole(0x388de7edL), tole(0x808892b5L), tole(0xe88bbe7dL), + tole(0xbb43f3a7L), tole(0xd340df6fL), tole(0x6b45aa37L), tole(0x034686ffL), + tole(0x1ea33676L), tole(0x76a01abeL), tole(0xcea56fe6L), tole(0xa6a6432eL), + tole(0x6935f452L), tole(0x0136d89aL), tole(0xb933adc2L), tole(0xd130810aL), + tole(0xccd53183L), tole(0xa4d61d4bL), tole(0x1cd36813L), tole(0x74d044dbL), + tole(0x27180901L), tole(0x4f1b25c9L), tole(0xf71e5091L), tole(0x9f1d7c59L), + tole(0x82f8ccd0L), tole(0xeafbe018L), tole(0x52fe9540L), tole(0x3afdb988L), + tole(0xc8358d49L), tole(0xa036a181L), tole(0x1833d4d9L), tole(0x7030f811L), + tole(0x6dd54898L), tole(0x05d66450L), tole(0xbdd31108L), tole(0xd5d03dc0L), + tole(0x8618701aL), tole(0xee1b5cd2L), tole(0x561e298aL), tole(0x3e1d0542L), + tole(0x23f8b5cbL), tole(0x4bfb9903L), tole(0xf3feec5bL), tole(0x9bfdc093L), + tole(0x546e77efL), tole(0x3c6d5b27L), tole(0x84682e7fL), tole(0xec6b02b7L), + tole(0xf18eb23eL), tole(0x998d9ef6L), tole(0x2188ebaeL), tole(0x498bc766L), + tole(0x1a438abcL), tole(0x7240a674L), tole(0xca45d32cL), tole(0xa246ffe4L), + tole(0xbfa34f6dL), tole(0xd7a063a5L), tole(0x6fa516fdL), tole(0x07a63a35L), + tole(0x8fd9098eL), tole(0xe7da2546L), tole(0x5fdf501eL), tole(0x37dc7cd6L), + tole(0x2a39cc5fL), tole(0x423ae097L), tole(0xfa3f95cfL), tole(0x923cb907L), + tole(0xc1f4f4ddL), tole(0xa9f7d815L), tole(0x11f2ad4dL), tole(0x79f18185L), + tole(0x6414310cL), tole(0x0c171dc4L), tole(0xb412689cL), tole(0xdc114454L), + tole(0x1382f328L), tole(0x7b81dfe0L), tole(0xc384aab8L), tole(0xab878670L), + tole(0xb66236f9L), tole(0xde611a31L), tole(0x66646f69L), tole(0x0e6743a1L), + tole(0x5daf0e7bL), tole(0x35ac22b3L), tole(0x8da957ebL), tole(0xe5aa7b23L), + tole(0xf84fcbaaL), tole(0x904ce762L), tole(0x2849923aL), tole(0x404abef2L), + tole(0xb2828a33L), tole(0xda81a6fbL), tole(0x6284d3a3L), tole(0x0a87ff6bL), + tole(0x17624fe2L), tole(0x7f61632aL), tole(0xc7641672L), tole(0xaf673abaL), + tole(0xfcaf7760L), tole(0x94ac5ba8L), tole(0x2ca92ef0L), tole(0x44aa0238L), + tole(0x594fb2b1L), tole(0x314c9e79L), tole(0x8949eb21L), tole(0xe14ac7e9L), + tole(0x2ed97095L), tole(0x46da5c5dL), tole(0xfedf2905L), tole(0x96dc05cdL), + tole(0x8b39b544L), tole(0xe33a998cL), tole(0x5b3fecd4L), tole(0x333cc01cL), + tole(0x60f48dc6L), tole(0x08f7a10eL), tole(0xb0f2d456L), tole(0xd8f1f89eL), + tole(0xc5144817L), tole(0xad1764dfL), tole(0x15121187L), tole(0x7d113d4fL)}, + { + tole(0x00000000L), tole(0x493c7d27L), tole(0x9278fa4eL), tole(0xdb448769L), + tole(0x211d826dL), tole(0x6821ff4aL), tole(0xb3657823L), tole(0xfa590504L), + tole(0x423b04daL), tole(0x0b0779fdL), tole(0xd043fe94L), tole(0x997f83b3L), + tole(0x632686b7L), tole(0x2a1afb90L), tole(0xf15e7cf9L), tole(0xb86201deL), + tole(0x847609b4L), tole(0xcd4a7493L), tole(0x160ef3faL), tole(0x5f328eddL), + tole(0xa56b8bd9L), tole(0xec57f6feL), tole(0x37137197L), tole(0x7e2f0cb0L), + tole(0xc64d0d6eL), tole(0x8f717049L), tole(0x5435f720L), tole(0x1d098a07L), + tole(0xe7508f03L), tole(0xae6cf224L), tole(0x7528754dL), tole(0x3c14086aL), + tole(0x0d006599L), tole(0x443c18beL), tole(0x9f789fd7L), tole(0xd644e2f0L), + tole(0x2c1de7f4L), tole(0x65219ad3L), tole(0xbe651dbaL), tole(0xf759609dL), + tole(0x4f3b6143L), tole(0x06071c64L), tole(0xdd439b0dL), tole(0x947fe62aL), + tole(0x6e26e32eL), tole(0x271a9e09L), tole(0xfc5e1960L), tole(0xb5626447L), + tole(0x89766c2dL), tole(0xc04a110aL), tole(0x1b0e9663L), tole(0x5232eb44L), + tole(0xa86bee40L), tole(0xe1579367L), tole(0x3a13140eL), tole(0x732f6929L), + tole(0xcb4d68f7L), tole(0x827115d0L), tole(0x593592b9L), tole(0x1009ef9eL), + tole(0xea50ea9aL), tole(0xa36c97bdL), tole(0x782810d4L), tole(0x31146df3L), + tole(0x1a00cb32L), tole(0x533cb615L), tole(0x8878317cL), tole(0xc1444c5bL), + tole(0x3b1d495fL), tole(0x72213478L), tole(0xa965b311L), tole(0xe059ce36L), + tole(0x583bcfe8L), tole(0x1107b2cfL), tole(0xca4335a6L), tole(0x837f4881L), + tole(0x79264d85L), tole(0x301a30a2L), tole(0xeb5eb7cbL), tole(0xa262caecL), + tole(0x9e76c286L), tole(0xd74abfa1L), tole(0x0c0e38c8L), tole(0x453245efL), + tole(0xbf6b40ebL), tole(0xf6573dccL), tole(0x2d13baa5L), tole(0x642fc782L), + tole(0xdc4dc65cL), tole(0x9571bb7bL), tole(0x4e353c12L), tole(0x07094135L), + tole(0xfd504431L), tole(0xb46c3916L), tole(0x6f28be7fL), tole(0x2614c358L), + tole(0x1700aeabL), tole(0x5e3cd38cL), tole(0x857854e5L), tole(0xcc4429c2L), + tole(0x361d2cc6L), tole(0x7f2151e1L), tole(0xa465d688L), tole(0xed59abafL), + tole(0x553baa71L), tole(0x1c07d756L), tole(0xc743503fL), tole(0x8e7f2d18L), + tole(0x7426281cL), tole(0x3d1a553bL), tole(0xe65ed252L), tole(0xaf62af75L), + tole(0x9376a71fL), tole(0xda4ada38L), tole(0x010e5d51L), tole(0x48322076L), + tole(0xb26b2572L), tole(0xfb575855L), tole(0x2013df3cL), tole(0x692fa21bL), + tole(0xd14da3c5L), tole(0x9871dee2L), tole(0x4335598bL), tole(0x0a0924acL), + tole(0xf05021a8L), tole(0xb96c5c8fL), tole(0x6228dbe6L), tole(0x2b14a6c1L), + tole(0x34019664L), tole(0x7d3deb43L), tole(0xa6796c2aL), tole(0xef45110dL), + tole(0x151c1409L), tole(0x5c20692eL), tole(0x8764ee47L), tole(0xce589360L), + tole(0x763a92beL), tole(0x3f06ef99L), tole(0xe44268f0L), tole(0xad7e15d7L), + tole(0x572710d3L), tole(0x1e1b6df4L), tole(0xc55fea9dL), tole(0x8c6397baL), + tole(0xb0779fd0L), tole(0xf94be2f7L), tole(0x220f659eL), tole(0x6b3318b9L), + tole(0x916a1dbdL), tole(0xd856609aL), tole(0x0312e7f3L), tole(0x4a2e9ad4L), + tole(0xf24c9b0aL), tole(0xbb70e62dL), tole(0x60346144L), tole(0x29081c63L), + tole(0xd3511967L), tole(0x9a6d6440L), tole(0x4129e329L), tole(0x08159e0eL), + tole(0x3901f3fdL), tole(0x703d8edaL), tole(0xab7909b3L), tole(0xe2457494L), + tole(0x181c7190L), tole(0x51200cb7L), tole(0x8a648bdeL), tole(0xc358f6f9L), + tole(0x7b3af727L), tole(0x32068a00L), tole(0xe9420d69L), tole(0xa07e704eL), + tole(0x5a27754aL), tole(0x131b086dL), tole(0xc85f8f04L), tole(0x8163f223L), + tole(0xbd77fa49L), tole(0xf44b876eL), tole(0x2f0f0007L), tole(0x66337d20L), + tole(0x9c6a7824L), tole(0xd5560503L), tole(0x0e12826aL), tole(0x472eff4dL), + tole(0xff4cfe93L), tole(0xb67083b4L), tole(0x6d3404ddL), tole(0x240879faL), + tole(0xde517cfeL), tole(0x976d01d9L), tole(0x4c2986b0L), tole(0x0515fb97L), + tole(0x2e015d56L), tole(0x673d2071L), tole(0xbc79a718L), tole(0xf545da3fL), + tole(0x0f1cdf3bL), tole(0x4620a21cL), tole(0x9d642575L), tole(0xd4585852L), + tole(0x6c3a598cL), tole(0x250624abL), tole(0xfe42a3c2L), tole(0xb77edee5L), + tole(0x4d27dbe1L), tole(0x041ba6c6L), tole(0xdf5f21afL), tole(0x96635c88L), + tole(0xaa7754e2L), tole(0xe34b29c5L), tole(0x380faeacL), tole(0x7133d38bL), + tole(0x8b6ad68fL), tole(0xc256aba8L), tole(0x19122cc1L), tole(0x502e51e6L), + tole(0xe84c5038L), tole(0xa1702d1fL), tole(0x7a34aa76L), tole(0x3308d751L), + tole(0xc951d255L), tole(0x806daf72L), tole(0x5b29281bL), tole(0x1215553cL), + tole(0x230138cfL), tole(0x6a3d45e8L), tole(0xb179c281L), tole(0xf845bfa6L), + tole(0x021cbaa2L), tole(0x4b20c785L), tole(0x906440ecL), tole(0xd9583dcbL), + tole(0x613a3c15L), tole(0x28064132L), tole(0xf342c65bL), tole(0xba7ebb7cL), + tole(0x4027be78L), tole(0x091bc35fL), tole(0xd25f4436L), tole(0x9b633911L), + tole(0xa777317bL), tole(0xee4b4c5cL), tole(0x350fcb35L), tole(0x7c33b612L), + tole(0x866ab316L), tole(0xcf56ce31L), tole(0x14124958L), tole(0x5d2e347fL), + tole(0xe54c35a1L), tole(0xac704886L), tole(0x7734cfefL), tole(0x3e08b2c8L), + tole(0xc451b7ccL), tole(0x8d6dcaebL), tole(0x56294d82L), tole(0x1f1530a5L)}, +}; diff --git a/src/ext2fs/csum.c b/src/ext2fs/csum.c new file mode 100644 index 00000000..d755b9a7 --- /dev/null +++ b/src/ext2fs/csum.c @@ -0,0 +1,1015 @@ +/* + * csum.c --- checksumming of ext3 structures + * + * Copyright (C) 2006 Cluster File Systems, Inc. + * Copyright (C) 2006, 2007 by Andreas Dilger + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "crc16.h" +#include + +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#ifdef DEBUG +#define STATIC +#else +#define STATIC static +#endif + +void ext2fs_init_csum_seed(ext2_filsys fs) +{ + if (ext2fs_has_feature_csum_seed(fs->super)) + fs->csum_seed = fs->super->s_checksum_seed; + else if (ext2fs_has_feature_metadata_csum(fs->super) || + ext2fs_has_feature_ea_inode(fs->super)) + fs->csum_seed = ext2fs_crc32c_le(~0, fs->super->s_uuid, + sizeof(fs->super->s_uuid)); +} + +static __u32 ext2fs_mmp_csum(ext2_filsys fs, struct mmp_struct *mmp) +{ + int offset = offsetof(struct mmp_struct, mmp_checksum); + + return ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)mmp, offset); +} + +int ext2fs_mmp_csum_verify(ext2_filsys fs, struct mmp_struct *mmp) +{ + __u32 calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + calculated = ext2fs_mmp_csum(fs, mmp); + + return ext2fs_le32_to_cpu(mmp->mmp_checksum) == calculated; +} + +errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp) +{ + __u32 crc; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_mmp_csum(fs, mmp); + mmp->mmp_checksum = ext2fs_cpu_to_le32(crc); + + return 0; +} + +int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + return sb->s_checksum_type == EXT2_CRC32C_CHKSUM; +} + +static __u32 ext2fs_superblock_csum(ext2_filsys fs EXT2FS_ATTR((unused)), + struct ext2_super_block *sb) +{ + int offset = offsetof(struct ext2_super_block, s_checksum); + + return ext2fs_crc32c_le(~0, (unsigned char *)sb, offset); +} + +/* NOTE: The input to this function MUST be in LE order */ +int ext2fs_superblock_csum_verify(ext2_filsys fs, struct ext2_super_block *sb) +{ + __u32 flag, calculated; + + if (fs->flags & EXT2_FLAG_SWAP_BYTES) + flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; + else + flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) + return 1; + + calculated = ext2fs_superblock_csum(fs, sb); + + return ext2fs_le32_to_cpu(sb->s_checksum) == calculated; +} + +/* NOTE: The input to this function MUST be in LE order */ +errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, + struct ext2_super_block *sb) +{ + __u32 flag, crc; + + if (fs->flags & EXT2_FLAG_SWAP_BYTES) + flag = EXT4_FEATURE_RO_COMPAT_METADATA_CSUM; + else + flag = ext2fs_cpu_to_le32(EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); + + if (!EXT2_HAS_RO_COMPAT_FEATURE(fs->super, flag)) + return 0; + + crc = ext2fs_superblock_csum(fs, sb); + sb->s_checksum = ext2fs_cpu_to_le32(crc); + + return 0; +} + +static errcode_t ext2fs_ext_attr_block_csum(ext2_filsys fs, + ext2_ino_t inum EXT2FS_ATTR((unused)), + blk64_t block, + struct ext2_ext_attr_header *hdr, + __u32 *crc) +{ + char *buf = (char *)hdr; + __u32 old_crc = hdr->h_checksum; + + hdr->h_checksum = 0; + block = ext2fs_cpu_to_le64(block); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&block, + sizeof(block)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, fs->blocksize); + hdr->h_checksum = old_crc; + + return 0; +} + +int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr) +{ + __u32 calculated; + errcode_t retval; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &calculated); + if (retval) + return 0; + + return ext2fs_le32_to_cpu(hdr->h_checksum) == calculated; +} + +errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr) +{ + errcode_t retval; + __u32 crc; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + retval = ext2fs_ext_attr_block_csum(fs, inum, block, hdr, &crc); + if (retval) + return retval; + hdr->h_checksum = ext2fs_cpu_to_le32(crc); + return 0; +} + +static __u16 do_nothing16(__u16 x) +{ + return x; +} + +static __u16 disk_to_host16(__u16 x) +{ + return ext2fs_le16_to_cpu(x); +} + +static errcode_t __get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset, + int need_swab) +{ + struct ext2_dir_entry *dp; + struct ext2_dx_root_info *root; + struct ext2_dx_countlimit *c; + int count_offset, max_sane_entries; + unsigned int rec_len; + __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16); + + rec_len = translate(dirent->rec_len); + + if (rec_len == fs->blocksize && translate(dirent->name_len) == 0) + count_offset = 8; + else if (rec_len == 12) { + dp = (struct ext2_dir_entry *)(((char *)dirent) + rec_len); + rec_len = translate(dp->rec_len); + if (rec_len != fs->blocksize - 12) + return EXT2_ET_DB_NOT_FOUND; + root = (struct ext2_dx_root_info *)(((char *)dp + 12)); + if (root->reserved_zero || + root->info_length != sizeof(struct ext2_dx_root_info)) + return EXT2_ET_DB_NOT_FOUND; + count_offset = 32; + } else + return EXT2_ET_DB_NOT_FOUND; + + c = (struct ext2_dx_countlimit *)(((char *)dirent) + count_offset); + max_sane_entries = (fs->blocksize - count_offset) / + sizeof(struct ext2_dx_entry); + if (ext2fs_le16_to_cpu(c->limit) > max_sane_entries || + ext2fs_le16_to_cpu(c->count) > max_sane_entries) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + if (offset) + *offset = count_offset; + if (cc) + *cc = c; + + return 0; +} + +errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset) +{ + return __get_dx_countlimit(fs, dirent, cc, offset, 0); +} + +void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t) +{ + memset(t, 0, sizeof(struct ext2_dir_entry_tail)); + ext2fs_set_rec_len(fs, sizeof(struct ext2_dir_entry_tail), + (struct ext2_dir_entry *)t); + t->det_reserved_name_len = EXT2_DIR_NAME_LEN_CSUM; +} + +static errcode_t __get_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dir_entry_tail **tt, + int need_swab) +{ + struct ext2_dir_entry *d; + void *top; + struct ext2_dir_entry_tail *t; + unsigned int rec_len; + errcode_t retval = 0; + __u16 (*translate)(__u16) = (need_swab ? disk_to_host16 : do_nothing16); + + d = dirent; + top = EXT2_DIRENT_TAIL(dirent, fs->blocksize); + + rec_len = translate(d->rec_len); + while (rec_len && !(rec_len & 0x3)) { + d = (struct ext2_dir_entry *)(((char *)d) + rec_len); + if ((void *)d >= top) + break; + rec_len = translate(d->rec_len); + } + + if (d != top) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + t = (struct ext2_dir_entry_tail *)d; + if (t->det_reserved_zero1 || + translate(t->det_rec_len) != sizeof(struct ext2_dir_entry_tail) || + translate(t->det_reserved_name_len) != EXT2_DIR_NAME_LEN_CSUM) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + + if (tt) + *tt = t; + return retval; +} + +int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent) +{ + return __get_dirent_tail(fs, dirent, NULL, 0) == 0; +} + +static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, __u32 *crc, + int size) +{ + errcode_t retval; + char *buf = (char *)dirent; + __u32 gen; + struct ext2_inode inode; + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); + + return 0; +} + +int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 calculated; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return 1; + + /* + * The checksum field is overlaid with the dirent->name field + * so the swapfs.c functions won't change the endianness. + */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &calculated, + (char *)t - (char *)dirent); + if (retval) + return 0; + return ext2fs_le32_to_cpu(t->det_checksum) == calculated; +} + +static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + errcode_t retval; + __u32 crc; + struct ext2_dir_entry_tail *t; + + retval = __get_dirent_tail(fs, dirent, &t, 1); + if (retval) + return retval; + + /* swapfs.c functions don't change the checksum endianness */ + retval = ext2fs_dirent_csum(fs, inum, dirent, &crc, + (char *)t - (char *)dirent); + if (retval) + return retval; + t->det_checksum = ext2fs_cpu_to_le32(crc); + return 0; +} + +static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, + __u32 *crc, int count_offset, int count, + struct ext2_dx_tail *t) +{ + errcode_t retval; + char *buf = (char *)dirent; + int size; + __u32 old_csum, gen; + struct ext2_inode inode; + + size = count_offset + (count * sizeof(struct ext2_dx_entry)); + old_csum = t->dt_checksum; + t->dt_checksum = 0; + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t, + sizeof(struct ext2_dx_tail)); + t->dt_checksum = old_csum; + + return 0; +} + +static int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + __u32 calculated; + errcode_t retval; + struct ext2_dx_countlimit *c; + struct ext2_dx_tail *t; + int count_offset, limit, count; + + retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); + if (retval) + return 1; + limit = ext2fs_le16_to_cpu(c->limit); + count = ext2fs_le16_to_cpu(c->count); + if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > + fs->blocksize - sizeof(struct ext2_dx_tail)) + return 0; + /* htree structs are accessed in LE order */ + t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); + retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset, + count, t); + if (retval) + return 0; + + return ext2fs_le32_to_cpu(t->dt_checksum) == calculated; +} + +static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + __u32 crc; + errcode_t retval = 0; + struct ext2_dx_countlimit *c; + struct ext2_dx_tail *t; + int count_offset, limit, count; + + retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); + if (retval) + return retval; + limit = ext2fs_le16_to_cpu(c->limit); + count = ext2fs_le16_to_cpu(c->count); + if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > + fs->blocksize - sizeof(struct ext2_dx_tail)) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); + + /* htree structs are accessed in LE order */ + retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t); + if (retval) + return retval; + t->dt_checksum = ext2fs_cpu_to_le32(crc); + return retval; +} + +int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_verify(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_verify(fs, inum, dirent); + + return 0; +} + +errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent) +{ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + if (__get_dirent_tail(fs, dirent, NULL, 1) == 0) + return ext2fs_dirent_csum_set(fs, inum, dirent); + if (__get_dx_countlimit(fs, dirent, NULL, NULL, 1) == 0) + return ext2fs_dx_csum_set(fs, inum, dirent); + + if (fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) + return 0; + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; +} + +#define EXT3_EXTENT_TAIL_OFFSET(hdr) (sizeof(struct ext3_extent_header) + \ + (sizeof(struct ext3_extent) * ext2fs_le16_to_cpu((hdr)->eh_max))) + +static struct ext3_extent_tail *get_extent_tail(struct ext3_extent_header *h) +{ + return (struct ext3_extent_tail *)(((char *)h) + + EXT3_EXTENT_TAIL_OFFSET(h)); +} + +static errcode_t ext2fs_extent_block_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh, + __u32 *crc) +{ + int size; + __u32 gen; + errcode_t retval; + struct ext2_inode inode; + + size = EXT3_EXTENT_TAIL_OFFSET(eh) + offsetof(struct ext3_extent_tail, + et_checksum); + + retval = ext2fs_read_inode(fs, inum, &inode); + if (retval) + return retval; + inum = ext2fs_cpu_to_le32(inum); + gen = ext2fs_cpu_to_le32(inode.i_generation); + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)eh, size); + + return 0; +} + +int ext2fs_extent_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh) +{ + errcode_t retval; + __u32 provided, calculated; + struct ext3_extent_tail *t = get_extent_tail(eh); + + /* + * The extent tree structures are accessed in LE order, so we must + * swap the checksum bytes here. + */ + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + provided = ext2fs_le32_to_cpu(t->et_checksum); + retval = ext2fs_extent_block_csum(fs, inum, eh, &calculated); + if (retval) + return 0; + + return provided == calculated; +} + +errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext3_extent_header *eh) +{ + errcode_t retval; + __u32 crc; + struct ext3_extent_tail *t = get_extent_tail(eh); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + /* + * The extent tree structures are accessed in LE order, so we must + * swap the checksum bytes here. + */ + retval = ext2fs_extent_block_csum(fs, inum, eh, &crc); + if (retval) + return retval; + t->et_checksum = ext2fs_cpu_to_le32(crc); + return retval; +} + +int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + __u32 provided, calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + provided = gdp->bg_inode_bitmap_csum_lo; + calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, + size); + if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + provided |= (__u32)gdp->bg_inode_bitmap_csum_hi << 16; + else + calculated &= 0xFFFF; + + return provided == calculated; +} + +errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + __u32 crc; + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size); + gdp->bg_inode_bitmap_csum_lo = crc & 0xFFFF; + if (fs->super->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) + gdp->bg_inode_bitmap_csum_hi = crc >> 16; + + return 0; +} + +int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + __u32 provided, calculated; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + provided = gdp->bg_block_bitmap_csum_lo; + calculated = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, + size); + if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + provided |= (__u32)gdp->bg_block_bitmap_csum_hi << 16; + else + calculated &= 0xFFFF; + + return provided == calculated; +} + +errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size) +{ + __u32 crc; + struct ext4_group_desc *gdp = (struct ext4_group_desc *) + ext2fs_group_desc(fs, fs->group_desc, group); + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)bitmap, size); + gdp->bg_block_bitmap_csum_lo = crc & 0xFFFF; + if (fs->super->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION) + gdp->bg_block_bitmap_csum_hi = crc >> 16; + + return 0; +} + +static errcode_t ext2fs_inode_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode, + __u32 *crc, int has_hi) +{ + __u32 gen; + struct ext2_inode_large *desc = inode; + size_t size = EXT2_INODE_SIZE(fs->super); + __u16 old_lo; + __u16 old_hi = 0; + + old_lo = inode->i_checksum_lo; + inode->i_checksum_lo = 0; + if (has_hi) { + old_hi = inode->i_checksum_hi; + inode->i_checksum_hi = 0; + } + + inum = ext2fs_cpu_to_le32(inum); + gen = inode->i_generation; + *crc = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&inum, + sizeof(inum)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)desc, size); + + inode->i_checksum_lo = old_lo; + if (has_hi) + inode->i_checksum_hi = old_hi; + return 0; +} + +int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode) +{ + errcode_t retval; + __u32 provided, calculated; + unsigned int i, has_hi; + char *cp; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 1; + + has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE && + inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END); + + provided = ext2fs_le16_to_cpu(inode->i_checksum_lo); + retval = ext2fs_inode_csum(fs, inum, inode, &calculated, has_hi); + if (retval) + return 0; + if (has_hi) { + __u32 hi = ext2fs_le16_to_cpu(inode->i_checksum_hi); + provided |= hi << 16; + } else + calculated &= 0xFFFF; + + if (provided == calculated) + return 1; + + /* + * If the checksum didn't match, it's possible it was due to + * the inode being all zero's. It's unlikely this is the + * case, but it can happen. So check for it here. (We only + * check the base inode since that's good enough, and it's not + * worth the bother to figure out how much of the extended + * inode, if any, is present.) + */ + for (cp = (char *) inode, i = 0; + i < sizeof(struct ext2_inode); + cp++, i++) + if (*cp) + return 0; + return 1; /* Inode must have been all zero's */ +} + +errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode) +{ + errcode_t retval; + __u32 crc; + int has_hi; + + if (!ext2fs_has_feature_metadata_csum(fs->super)) + return 0; + + has_hi = (EXT2_INODE_SIZE(fs->super) > EXT2_GOOD_OLD_INODE_SIZE && + inode->i_extra_isize >= EXT4_INODE_CSUM_HI_EXTRA_END); + + retval = ext2fs_inode_csum(fs, inum, inode, &crc, has_hi); + if (retval) + return retval; + inode->i_checksum_lo = ext2fs_cpu_to_le16(crc & 0xFFFF); + if (has_hi) + inode->i_checksum_hi = ext2fs_cpu_to_le16(crc >> 16); + return 0; +} + +__u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group) +{ + struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, + group); + size_t offset, size = EXT2_DESC_SIZE(fs->super); + __u16 crc = 0; +#ifdef WORDS_BIGENDIAN + struct ext4_group_desc swabdesc; + size_t save_size = size; + const size_t ext4_bg_size = sizeof(struct ext4_group_desc); + struct ext2_group_desc *save_desc = desc; + + /* Have to swab back to little-endian to do the checksum */ + if (size > ext4_bg_size) + size = ext4_bg_size; + memcpy(&swabdesc, desc, size); + ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc); + desc = (struct ext2_group_desc *) &swabdesc; + group = ext2fs_swab32(group); +#endif + + if (ext2fs_has_feature_metadata_csum(fs->super)) { + /* new metadata csum code */ + __u16 old_crc; + __u32 crc32; + + old_crc = desc->bg_checksum; + desc->bg_checksum = 0; + crc32 = ext2fs_crc32c_le(fs->csum_seed, (unsigned char *)&group, + sizeof(group)); + crc32 = ext2fs_crc32c_le(crc32, (unsigned char *)desc, + size); + desc->bg_checksum = old_crc; +#ifdef WORDS_BIGENDIAN + if (save_size > ext4_bg_size) + crc32 = ext2fs_crc32c_le(crc32, + (unsigned char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + crc = crc32 & 0xFFFF; + goto out; + } + + /* old crc16 code */ + offset = offsetof(struct ext2_group_desc, bg_checksum); + crc = ext2fs_crc16(~0, fs->super->s_uuid, + sizeof(fs->super->s_uuid)); + crc = ext2fs_crc16(crc, &group, sizeof(group)); + crc = ext2fs_crc16(crc, desc, offset); + offset += sizeof(desc->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if (offset < size) { + crc = ext2fs_crc16(crc, (char *)desc + offset, + size - offset); + } +#ifdef WORDS_BIGENDIAN + /* + * If the size of the bg descriptor is greater than 64 + * bytes, which is the size of the traditional ext4 bg + * descriptor, checksum the rest of the descriptor here + */ + if (save_size > ext4_bg_size) + crc = ext2fs_crc16(crc, (char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + +out: + return crc; +} + +int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group) +{ + if (ext2fs_has_group_desc_csum(fs) && + (ext2fs_bg_checksum(fs, group) != + ext2fs_group_desc_csum(fs, group))) + return 0; + + return 1; +} + +void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group) +{ + if (!ext2fs_has_group_desc_csum(fs)) + return; + + /* ext2fs_bg_checksum_set() sets the actual checksum field but + * does not calculate the checksum itself. */ + ext2fs_bg_checksum_set(fs, group, ext2fs_group_desc_csum(fs, group)); +} + +static __u32 find_last_inode_ingrp(ext2fs_inode_bitmap bitmap, + __u32 inodes_per_grp, dgrp_t grp_no) +{ + ext2_ino_t i, start_ino, end_ino; + + start_ino = grp_no * inodes_per_grp + 1; + end_ino = start_ino + inodes_per_grp - 1; + + for (i = end_ino; i >= start_ino; i--) { + if (ext2fs_fast_test_inode_bitmap2(bitmap, i)) + return i - start_ino + 1; + } + return inodes_per_grp; +} + +/* update the bitmap flags, set the itable high watermark, and calculate + * checksums for the group descriptors */ +errcode_t ext2fs_set_gdt_csum(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + int dirty = 0; + dgrp_t i; + + if (!fs->inode_map) + return EXT2_ET_NO_INODE_BITMAP; + + if (!ext2fs_has_group_desc_csum(fs)) + return 0; + + for (i = 0; i < fs->group_desc_count; i++) { + __u32 old_csum = ext2fs_bg_checksum(fs, i); + __u32 old_unused = ext2fs_bg_itable_unused(fs, i); + __u32 old_flags = ext2fs_bg_flags(fs, i); + __u32 old_free_inodes_count = ext2fs_bg_free_inodes_count(fs, i); + __u32 old_free_blocks_count = ext2fs_bg_free_blocks_count(fs, i); + + if (old_free_blocks_count == sb->s_blocks_per_group && + i != fs->group_desc_count - 1) + ext2fs_bg_flags_set(fs, i, EXT2_BG_BLOCK_UNINIT); + + if (old_free_inodes_count == sb->s_inodes_per_group) { + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); + ext2fs_bg_itable_unused_set(fs, i, sb->s_inodes_per_group); + } else { + int unused = + sb->s_inodes_per_group - + find_last_inode_ingrp(fs->inode_map, + sb->s_inodes_per_group, i); + + ext2fs_bg_flags_clear(fs, i, EXT2_BG_INODE_UNINIT); + ext2fs_bg_itable_unused_set(fs, i, unused); + } + + ext2fs_group_desc_csum_set(fs, i); + if (old_flags != ext2fs_bg_flags(fs, i)) + dirty = 1; + if (old_unused != ext2fs_bg_itable_unused(fs, i)) + dirty = 1; + if (old_csum != ext2fs_bg_checksum(fs, i)) + dirty = 1; + } + if (dirty) + ext2fs_mark_super_dirty(fs); + return 0; +} + +#ifdef DEBUG +#include "e2p/e2p.h" + +void print_csum(const char *msg, ext2_filsys fs, dgrp_t group) +{ + __u16 crc1, crc2, crc3; + dgrp_t swabgroup; + struct ext2_group_desc *desc = ext2fs_group_desc(fs, fs->group_desc, + group); + size_t size = EXT2_DESC_SIZE(fs->super); + struct ext2_super_block *sb = fs->super; + int offset = offsetof(struct ext2_group_desc, bg_checksum); +#ifdef WORDS_BIGENDIAN + struct ext4_group_desc swabdesc; + struct ext2_group_desc *save_desc = desc; + const size_t ext4_bg_size = sizeof(struct ext4_group_desc); + size_t save_size = size; +#endif + +#ifdef WORDS_BIGENDIAN + /* Have to swab back to little-endian to do the checksum */ + if (size > ext4_bg_size) + size = ext4_bg_size; + memcpy(&swabdesc, desc, size); + ext2fs_swap_group_desc2(fs, (struct ext2_group_desc *) &swabdesc); + desc = (struct ext2_group_desc *) &swabdesc; + + swabgroup = ext2fs_swab32(group); +#else + swabgroup = group; +#endif + + crc1 = ext2fs_crc16(~0, sb->s_uuid, sizeof(fs->super->s_uuid)); + crc2 = ext2fs_crc16(crc1, &swabgroup, sizeof(swabgroup)); + crc3 = ext2fs_crc16(crc2, desc, offset); + offset += sizeof(desc->bg_checksum); /* skip checksum */ + /* for checksum of struct ext4_group_desc do the rest...*/ + if (offset < size) + crc3 = ext2fs_crc16(crc3, (char *)desc + offset, size - offset); +#ifdef WORDS_BIGENDIAN + if (save_size > ext4_bg_size) + crc3 = ext2fs_crc16(crc3, (char *)save_desc + ext4_bg_size, + save_size - ext4_bg_size); +#endif + + printf("%s UUID %s=%04x, grp %u=%04x: %04x=%04x\n", + msg, e2p_uuid2str(sb->s_uuid), crc1, group, crc2, crc3, + ext2fs_group_desc_csum(fs, group)); +} + +unsigned char sb_uuid[16] = { 0x4f, 0x25, 0xe8, 0xcf, 0xe7, 0x97, 0x48, 0x23, + 0xbe, 0xfa, 0xa7, 0x88, 0x4b, 0xae, 0xec, 0xdb }; + +int main(int argc, char **argv) +{ + struct ext2_super_block param; + errcode_t retval; + ext2_filsys fs; + int i; + __u16 csum1, csum2, csum_known = 0xd3a4; + + memset(¶m, 0, sizeof(param)); + ext2fs_blocks_count_set(¶m, 32768); +#if 0 + param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT; + param.s_desc_size = 128; + csum_known = 0x5b6e; +#endif + + retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, + test_io_manager, &fs); + if (retval) { + com_err("setup", retval, + "While initializing filesystem"); + exit(1); + } + memcpy(fs->super->s_uuid, sb_uuid, 16); + fs->super->s_feature_ro_compat = EXT4_FEATURE_RO_COMPAT_GDT_CSUM; + + for (i=0; i < fs->group_desc_count; i++) { + ext2fs_block_bitmap_loc_set(fs, i, 124); + ext2fs_inode_bitmap_loc_set(fs, i, 125); + ext2fs_inode_table_loc_set(fs, i, 126); + ext2fs_bg_free_blocks_count_set(fs, i, 31119); + ext2fs_bg_free_inodes_count_set(fs, i, 15701); + ext2fs_bg_used_dirs_count_set(fs, i, 2); + ext2fs_bg_flags_zap(fs, i); + }; + + csum1 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum0000", fs, 0); + + if (csum1 != csum_known) { + printf("checksum for group 0 should be %04x\n", csum_known); + exit(1); + } + csum2 = ext2fs_group_desc_csum(fs, 1); + print_csum("csum0001", fs, 1); + if (csum1 == csum2) { + printf("checksums for different groups shouldn't match\n"); + exit(1); + } + csum2 = ext2fs_group_desc_csum(fs, 2); + print_csum("csumffff", fs, 2); + if (csum1 == csum2) { + printf("checksums for different groups shouldn't match\n"); + exit(1); + } + ext2fs_bg_checksum_set(fs, 0, csum1); + csum2 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum_set", fs, 0); + if (csum1 != csum2) { + printf("checksums should not depend on checksum field\n"); + exit(1); + } + if (!ext2fs_group_desc_csum_verify(fs, 0)) { + printf("checksums should verify against gd_checksum\n"); + exit(1); + } + memset(fs->super->s_uuid, 0x30, sizeof(fs->super->s_uuid)); + print_csum("new_uuid", fs, 0); + if (ext2fs_group_desc_csum_verify(fs, 0) != 0) { + printf("checksums for different filesystems shouldn't match\n"); + exit(1); + } + csum1 = ext2fs_group_desc_csum(fs, 0); + ext2fs_bg_checksum_set(fs, 0, csum1); + print_csum("csum_new", fs, 0); + ext2fs_bg_free_blocks_count_set(fs, 0, 1); + csum2 = ext2fs_group_desc_csum(fs, 0); + print_csum("csum_blk", fs, 0); + if (csum1 == csum2) { + printf("checksums for different data shouldn't match\n"); + exit(1); + } + ext2fs_free(fs); + + return 0; +} +#endif diff --git a/src/ext2fs/dir_iterate.c b/src/ext2fs/dir_iterate.c new file mode 100644 index 00000000..b2b77693 --- /dev/null +++ b/src/ext2fs/dir_iterate.c @@ -0,0 +1,311 @@ +/* + * dir_iterate.c --- ext2fs directory iteration operations + * + * Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +#define EXT4_MAX_REC_LEN ((1<<16)-1) + +errcode_t ext2fs_get_rec_len(ext2_filsys fs, + struct ext2_dir_entry *dirent, + unsigned int *rec_len) +{ + unsigned int len = dirent->rec_len; + + if (fs->blocksize < 65536) + *rec_len = len; + else if (len == EXT4_MAX_REC_LEN || len == 0) + *rec_len = fs->blocksize; + else + *rec_len = (len & 65532) | ((len & 3) << 16); + return 0; +} + +errcode_t ext2fs_set_rec_len(ext2_filsys fs, + unsigned int len, + struct ext2_dir_entry *dirent) +{ + if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3)) + return EINVAL; + if (len < 65536) { + dirent->rec_len = len; + return 0; + } + if (len == fs->blocksize) { + if (fs->blocksize == 65536) + dirent->rec_len = EXT4_MAX_REC_LEN; + else + dirent->rec_len = 0; + } else + dirent->rec_len = (len & 65532) | ((len >> 16) & 3); + return 0; +} + +/* + * This function checks to see whether or not a potential deleted + * directory entry looks valid. What we do is check the deleted entry + * and each successive entry to make sure that they all look valid and + * that the last deleted entry ends at the beginning of the next + * undeleted entry. Returns 1 if the deleted entry looks valid, zero + * if not valid. + */ +static int ext2fs_validate_entry(ext2_filsys fs, char *buf, + unsigned int offset, + unsigned int final_offset) +{ + struct ext2_dir_entry *dirent; + unsigned int rec_len; +#define DIRENT_MIN_LENGTH 12 + + while ((offset < final_offset) && + (offset <= fs->blocksize - DIRENT_MIN_LENGTH)) { + dirent = (struct ext2_dir_entry *)(buf + offset); + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return 0; + offset += rec_len; + if ((rec_len < 8) || + ((rec_len % 4) != 0) || + ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) + return 0; + } + return (offset == final_offset); +} + +errcode_t ext2fs_dir_iterate2(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data) +{ + struct dir_context ctx; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_check_directory(fs, dir); + if (retval) + return retval; + + ctx.dir = dir; + ctx.flags = flags; + if (block_buf) + ctx.buf = block_buf; + else { + retval = ext2fs_get_mem(fs->blocksize, &ctx.buf); + if (retval) + return retval; + } + ctx.func = func; + ctx.priv_data = priv_data; + ctx.errcode = 0; + retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0, + ext2fs_process_dir_block, &ctx); + if (!block_buf) + ext2fs_free_mem(&ctx.buf); + if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) { + (void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx); + retval = 0; + } + if (retval) + return retval; + return ctx.errcode; +} + +struct xlate { + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data); + void *real_private; +}; + +static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)), + int entry EXT2FS_ATTR((unused)), + struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + struct xlate *xl = (struct xlate *) priv_data; + + return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private); +} + +errcode_t ext2fs_dir_iterate(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data) +{ + struct xlate xl; + + xl.real_private = priv_data; + xl.func = func; + + return ext2fs_dir_iterate2(fs, dir, flags, block_buf, + xlate_func, &xl); +} + + +/* + * Helper function which is private to this module. Used by + * ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate() + */ +int ext2fs_process_dir_block(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct dir_context *ctx = (struct dir_context *) priv_data; + unsigned int offset = 0; + unsigned int next_real_entry = 0; + int ret = 0; + int changed = 0; + int do_abort = 0; + unsigned int rec_len, size, buflen; + int entry; + struct ext2_dir_entry *dirent; + int csum_size = 0; + int inline_data; + errcode_t retval = 0; + + if (blockcnt < 0) + return 0; + + entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE; + + /* If a dir has inline data, we don't need to read block */ + inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA); + if (!inline_data) { + ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0, + ctx->dir); + if (ctx->errcode) + return BLOCK_ABORT; + /* If we handle a normal dir, we traverse the entire block */ + buflen = fs->blocksize; + } else { + buflen = ctx->buflen; + } + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + while (offset < buflen - 8) { + dirent = (struct ext2_dir_entry *) (ctx->buf + offset); + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return BLOCK_ABORT; + if (((offset + rec_len) > buflen) || + (rec_len < 8) || + ((rec_len % 4) != 0) || + ((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) { + ctx->errcode = EXT2_ET_DIR_CORRUPTED; + return BLOCK_ABORT; + } + if (!dirent->inode) { + /* + * We just need to check metadata_csum when this + * dir hasn't inline data. That means that 'buflen' + * should be blocksize. + */ + if (!inline_data && + (offset == buflen - csum_size) && + (dirent->rec_len == csum_size) && + (dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) { + if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM)) + goto next; + entry = DIRENT_CHECKSUM; + } else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY)) + goto next; + } + + ret = (ctx->func)(ctx->dir, + (next_real_entry > offset) ? + DIRENT_DELETED_FILE : entry, + dirent, offset, + buflen, ctx->buf, + ctx->priv_data); + if (entry < DIRENT_OTHER_FILE) + entry++; + + if (ret & DIRENT_CHANGED) { + if (ext2fs_get_rec_len(fs, dirent, &rec_len)) + return BLOCK_ABORT; + changed++; + } + if (ret & DIRENT_ABORT) { + do_abort++; + break; + } +next: + if (next_real_entry == offset) + next_real_entry += rec_len; + + if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) { + size = (ext2fs_dirent_name_len(dirent) + 11) & ~3; + + if (rec_len != size) { + unsigned int final_offset; + + final_offset = offset + rec_len; + offset += size; + while (offset < final_offset && + !ext2fs_validate_entry(fs, ctx->buf, + offset, + final_offset)) + offset += 4; + continue; + } + } + offset += rec_len; + } + + if (changed) { + if (!inline_data) { + ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr, + ctx->buf, + 0, ctx->dir); + if (ctx->errcode) + return BLOCK_ABORT; + } else { + /* + * return BLOCK_INLINE_DATA_CHANGED to notify caller + * that inline data has been changed. + */ + retval = BLOCK_INLINE_DATA_CHANGED; + } + } + if (do_abort) + return retval | BLOCK_ABORT; + return retval; +} diff --git a/src/ext2fs/dirblock.c b/src/ext2fs/dirblock.c new file mode 100644 index 00000000..54b27772 --- /dev/null +++ b/src/ext2fs/dirblock.c @@ -0,0 +1,113 @@ +/* + * dirblock.c --- directory block routines. + * + * Copyright (C) 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) +{ + errcode_t retval; + int corrupt = 0; + + retval = io_channel_read_blk64(fs->io, block, 1, buf); + if (retval) + return retval; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_dir_block_csum_verify(fs, ino, + (struct ext2_dir_entry *)buf)) + corrupt = 1; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_in(fs, buf, flags); +#endif + if (!retval && corrupt) + retval = EXT2_ET_DIR_CSUM_INVALID; + return retval; +} + +errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_read_dir_block4(fs, block, buf, flags, 0); +} + +errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_read_dir_block3(fs, block, buf, flags); +} + +errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, + void *buf) +{ + return ext2fs_read_dir_block3(fs, block, buf, 0); +} + + +errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused)), + ext2_ino_t ino) +{ + errcode_t retval; + char *buf = inbuf; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + memcpy(buf, inbuf, fs->blocksize); + retval = ext2fs_dirent_swab_out(fs, buf, flags); + if (retval) + return retval; +#endif + retval = ext2fs_dir_block_csum_set(fs, ino, + (struct ext2_dir_entry *)buf); + if (retval) + goto out; + + retval = io_channel_write_blk64(fs->io, block, 1, buf); + +out: +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&buf); +#endif + return retval; +} + +errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, + void *inbuf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0); +} + +errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, + void *inbuf, int flags EXT2FS_ATTR((unused))) +{ + return ext2fs_write_dir_block3(fs, block, inbuf, flags); +} + +errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, + void *inbuf) +{ + return ext2fs_write_dir_block3(fs, block, inbuf, 0); +} + diff --git a/src/ext2fs/e2image.h b/src/ext2fs/e2image.h new file mode 100644 index 00000000..53b20cc7 --- /dev/null +++ b/src/ext2fs/e2image.h @@ -0,0 +1,37 @@ +/* + * e2image.h --- header file describing the ext2 image format + * + * Copyright (C) 2000 Theodore Ts'o. + * + * Note: this uses the POSIX IO interfaces, unlike most of the other + * functions in this library. So sue me. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +struct ext2_image_hdr { + __u32 magic_number; /* This must be EXT2_ET_MAGIC_E2IMAGE */ + char magic_descriptor[16]; /* "Ext2 Image 1.0", w/ null padding */ + char fs_hostname[64];/* Hostname of machine of image */ + char fs_netaddr[32]; /* Network address */ + __u32 fs_netaddr_type;/* 0 = IPV4, 1 = IPV6, etc. */ + __u32 fs_device; /* Device number of image */ + char fs_device_name[64]; /* Device name */ + char fs_uuid[16]; /* UUID of filesystem */ + __u32 fs_blocksize; /* Block size of the filesystem */ + __u32 fs_reserved[8]; + + __u32 image_device; /* Device number of image file */ + __u32 image_inode; /* Inode number of image file */ + __u32 image_time; /* Time of image creation */ + __u32 image_reserved[8]; + + __u32 offset_super; /* Byte offset of the sb and descriptors */ + __u32 offset_inode; /* Byte offset of the inode table */ + __u32 offset_inodemap; /* Byte offset of the inode bitmaps */ + __u32 offset_blockmap; /* Byte offset of the inode bitmaps */ + __u32 offset_reserved[8]; +}; diff --git a/src/ext2fs/ext2_err.h b/src/ext2fs/ext2_err.h new file mode 100644 index 00000000..6547a039 --- /dev/null +++ b/src/ext2fs/ext2_err.h @@ -0,0 +1,197 @@ +/* + * ext2_err.h: + * This file is automatically generated; please do not edit it. + */ + +#include "com_err.h" + +#define EXT2_ET_BASE (2133571328L) +#define EXT2_ET_MAGIC_EXT2FS_FILSYS (2133571329L) +#define EXT2_ET_MAGIC_BADBLOCKS_LIST (2133571330L) +#define EXT2_ET_MAGIC_BADBLOCKS_ITERATE (2133571331L) +#define EXT2_ET_MAGIC_INODE_SCAN (2133571332L) +#define EXT2_ET_MAGIC_IO_CHANNEL (2133571333L) +#define EXT2_ET_MAGIC_UNIX_IO_CHANNEL (2133571334L) +#define EXT2_ET_MAGIC_IO_MANAGER (2133571335L) +#define EXT2_ET_MAGIC_BLOCK_BITMAP (2133571336L) +#define EXT2_ET_MAGIC_INODE_BITMAP (2133571337L) +#define EXT2_ET_MAGIC_GENERIC_BITMAP (2133571338L) +#define EXT2_ET_MAGIC_TEST_IO_CHANNEL (2133571339L) +#define EXT2_ET_MAGIC_DBLIST (2133571340L) +#define EXT2_ET_MAGIC_ICOUNT (2133571341L) +#define EXT2_ET_MAGIC_PQ_IO_CHANNEL (2133571342L) +#define EXT2_ET_MAGIC_EXT2_FILE (2133571343L) +#define EXT2_ET_MAGIC_E2IMAGE (2133571344L) +#define EXT2_ET_MAGIC_INODE_IO_CHANNEL (2133571345L) +#define EXT2_ET_MAGIC_EXTENT_HANDLE (2133571346L) +#define EXT2_ET_BAD_MAGIC (2133571347L) +#define EXT2_ET_REV_TOO_HIGH (2133571348L) +#define EXT2_ET_RO_FILSYS (2133571349L) +#define EXT2_ET_GDESC_READ (2133571350L) +#define EXT2_ET_GDESC_WRITE (2133571351L) +#define EXT2_ET_GDESC_BAD_BLOCK_MAP (2133571352L) +#define EXT2_ET_GDESC_BAD_INODE_MAP (2133571353L) +#define EXT2_ET_GDESC_BAD_INODE_TABLE (2133571354L) +#define EXT2_ET_INODE_BITMAP_WRITE (2133571355L) +#define EXT2_ET_INODE_BITMAP_READ (2133571356L) +#define EXT2_ET_BLOCK_BITMAP_WRITE (2133571357L) +#define EXT2_ET_BLOCK_BITMAP_READ (2133571358L) +#define EXT2_ET_INODE_TABLE_WRITE (2133571359L) +#define EXT2_ET_INODE_TABLE_READ (2133571360L) +#define EXT2_ET_NEXT_INODE_READ (2133571361L) +#define EXT2_ET_UNEXPECTED_BLOCK_SIZE (2133571362L) +#define EXT2_ET_DIR_CORRUPTED (2133571363L) +#define EXT2_ET_SHORT_READ (2133571364L) +#define EXT2_ET_SHORT_WRITE (2133571365L) +#define EXT2_ET_DIR_NO_SPACE (2133571366L) +#define EXT2_ET_NO_INODE_BITMAP (2133571367L) +#define EXT2_ET_NO_BLOCK_BITMAP (2133571368L) +#define EXT2_ET_BAD_INODE_NUM (2133571369L) +#define EXT2_ET_BAD_BLOCK_NUM (2133571370L) +#define EXT2_ET_EXPAND_DIR_ERR (2133571371L) +#define EXT2_ET_TOOSMALL (2133571372L) +#define EXT2_ET_BAD_BLOCK_MARK (2133571373L) +#define EXT2_ET_BAD_BLOCK_UNMARK (2133571374L) +#define EXT2_ET_BAD_BLOCK_TEST (2133571375L) +#define EXT2_ET_BAD_INODE_MARK (2133571376L) +#define EXT2_ET_BAD_INODE_UNMARK (2133571377L) +#define EXT2_ET_BAD_INODE_TEST (2133571378L) +#define EXT2_ET_FUDGE_BLOCK_BITMAP_END (2133571379L) +#define EXT2_ET_FUDGE_INODE_BITMAP_END (2133571380L) +#define EXT2_ET_BAD_IND_BLOCK (2133571381L) +#define EXT2_ET_BAD_DIND_BLOCK (2133571382L) +#define EXT2_ET_BAD_TIND_BLOCK (2133571383L) +#define EXT2_ET_NEQ_BLOCK_BITMAP (2133571384L) +#define EXT2_ET_NEQ_INODE_BITMAP (2133571385L) +#define EXT2_ET_BAD_DEVICE_NAME (2133571386L) +#define EXT2_ET_MISSING_INODE_TABLE (2133571387L) +#define EXT2_ET_CORRUPT_SUPERBLOCK (2133571388L) +#define EXT2_ET_BAD_GENERIC_MARK (2133571389L) +#define EXT2_ET_BAD_GENERIC_UNMARK (2133571390L) +#define EXT2_ET_BAD_GENERIC_TEST (2133571391L) +#define EXT2_ET_SYMLINK_LOOP (2133571392L) +#define EXT2_ET_CALLBACK_NOTHANDLED (2133571393L) +#define EXT2_ET_BAD_BLOCK_IN_INODE_TABLE (2133571394L) +#define EXT2_ET_UNSUPP_FEATURE (2133571395L) +#define EXT2_ET_RO_UNSUPP_FEATURE (2133571396L) +#define EXT2_ET_LLSEEK_FAILED (2133571397L) +#define EXT2_ET_NO_MEMORY (2133571398L) +#define EXT2_ET_INVALID_ARGUMENT (2133571399L) +#define EXT2_ET_BLOCK_ALLOC_FAIL (2133571400L) +#define EXT2_ET_INODE_ALLOC_FAIL (2133571401L) +#define EXT2_ET_NO_DIRECTORY (2133571402L) +#define EXT2_ET_TOO_MANY_REFS (2133571403L) +#define EXT2_ET_FILE_NOT_FOUND (2133571404L) +#define EXT2_ET_FILE_RO (2133571405L) +#define EXT2_ET_DB_NOT_FOUND (2133571406L) +#define EXT2_ET_DIR_EXISTS (2133571407L) +#define EXT2_ET_UNIMPLEMENTED (2133571408L) +#define EXT2_ET_CANCEL_REQUESTED (2133571409L) +#define EXT2_ET_FILE_TOO_BIG (2133571410L) +#define EXT2_ET_JOURNAL_NOT_BLOCK (2133571411L) +#define EXT2_ET_NO_JOURNAL_SB (2133571412L) +#define EXT2_ET_JOURNAL_TOO_SMALL (2133571413L) +#define EXT2_ET_JOURNAL_UNSUPP_VERSION (2133571414L) +#define EXT2_ET_LOAD_EXT_JOURNAL (2133571415L) +#define EXT2_ET_NO_JOURNAL (2133571416L) +#define EXT2_ET_DIRHASH_UNSUPP (2133571417L) +#define EXT2_ET_BAD_EA_BLOCK_NUM (2133571418L) +#define EXT2_ET_TOO_MANY_INODES (2133571419L) +#define EXT2_ET_NOT_IMAGE_FILE (2133571420L) +#define EXT2_ET_RES_GDT_BLOCKS (2133571421L) +#define EXT2_ET_RESIZE_INODE_CORRUPT (2133571422L) +#define EXT2_ET_SET_BMAP_NO_IND (2133571423L) +#define EXT2_ET_TDB_SUCCESS (2133571424L) +#define EXT2_ET_TDB_ERR_CORRUPT (2133571425L) +#define EXT2_ET_TDB_ERR_IO (2133571426L) +#define EXT2_ET_TDB_ERR_LOCK (2133571427L) +#define EXT2_ET_TDB_ERR_OOM (2133571428L) +#define EXT2_ET_TDB_ERR_EXISTS (2133571429L) +#define EXT2_ET_TDB_ERR_NOLOCK (2133571430L) +#define EXT2_ET_TDB_ERR_EINVAL (2133571431L) +#define EXT2_ET_TDB_ERR_NOEXIST (2133571432L) +#define EXT2_ET_TDB_ERR_RDONLY (2133571433L) +#define EXT2_ET_DBLIST_EMPTY (2133571434L) +#define EXT2_ET_RO_BLOCK_ITERATE (2133571435L) +#define EXT2_ET_MAGIC_EXTENT_PATH (2133571436L) +#define EXT2_ET_MAGIC_GENERIC_BITMAP64 (2133571437L) +#define EXT2_ET_MAGIC_BLOCK_BITMAP64 (2133571438L) +#define EXT2_ET_MAGIC_INODE_BITMAP64 (2133571439L) +#define EXT2_ET_MAGIC_RESERVED_13 (2133571440L) +#define EXT2_ET_MAGIC_RESERVED_14 (2133571441L) +#define EXT2_ET_MAGIC_RESERVED_15 (2133571442L) +#define EXT2_ET_MAGIC_RESERVED_16 (2133571443L) +#define EXT2_ET_MAGIC_RESERVED_17 (2133571444L) +#define EXT2_ET_MAGIC_RESERVED_18 (2133571445L) +#define EXT2_ET_MAGIC_RESERVED_19 (2133571446L) +#define EXT2_ET_EXTENT_HEADER_BAD (2133571447L) +#define EXT2_ET_EXTENT_INDEX_BAD (2133571448L) +#define EXT2_ET_EXTENT_LEAF_BAD (2133571449L) +#define EXT2_ET_EXTENT_NO_SPACE (2133571450L) +#define EXT2_ET_INODE_NOT_EXTENT (2133571451L) +#define EXT2_ET_EXTENT_NO_NEXT (2133571452L) +#define EXT2_ET_EXTENT_NO_PREV (2133571453L) +#define EXT2_ET_EXTENT_NO_UP (2133571454L) +#define EXT2_ET_EXTENT_NO_DOWN (2133571455L) +#define EXT2_ET_NO_CURRENT_NODE (2133571456L) +#define EXT2_ET_OP_NOT_SUPPORTED (2133571457L) +#define EXT2_ET_CANT_INSERT_EXTENT (2133571458L) +#define EXT2_ET_CANT_SPLIT_EXTENT (2133571459L) +#define EXT2_ET_EXTENT_NOT_FOUND (2133571460L) +#define EXT2_ET_EXTENT_NOT_SUPPORTED (2133571461L) +#define EXT2_ET_EXTENT_INVALID_LENGTH (2133571462L) +#define EXT2_ET_IO_CHANNEL_NO_SUPPORT_64 (2133571463L) +#define EXT2_ET_NO_MTAB_FILE (2133571464L) +#define EXT2_ET_CANT_USE_LEGACY_BITMAPS (2133571465L) +#define EXT2_ET_MMP_MAGIC_INVALID (2133571466L) +#define EXT2_ET_MMP_FAILED (2133571467L) +#define EXT2_ET_MMP_FSCK_ON (2133571468L) +#define EXT2_ET_MMP_BAD_BLOCK (2133571469L) +#define EXT2_ET_MMP_UNKNOWN_SEQ (2133571470L) +#define EXT2_ET_MMP_CHANGE_ABORT (2133571471L) +#define EXT2_ET_MMP_OPEN_DIRECT (2133571472L) +#define EXT2_ET_BAD_DESC_SIZE (2133571473L) +#define EXT2_ET_INODE_CSUM_INVALID (2133571474L) +#define EXT2_ET_INODE_BITMAP_CSUM_INVALID (2133571475L) +#define EXT2_ET_EXTENT_CSUM_INVALID (2133571476L) +#define EXT2_ET_DIR_NO_SPACE_FOR_CSUM (2133571477L) +#define EXT2_ET_DIR_CSUM_INVALID (2133571478L) +#define EXT2_ET_EXT_ATTR_CSUM_INVALID (2133571479L) +#define EXT2_ET_SB_CSUM_INVALID (2133571480L) +#define EXT2_ET_UNKNOWN_CSUM (2133571481L) +#define EXT2_ET_MMP_CSUM_INVALID (2133571482L) +#define EXT2_ET_FILE_EXISTS (2133571483L) +#define EXT2_ET_BLOCK_BITMAP_CSUM_INVALID (2133571484L) +#define EXT2_ET_INLINE_DATA_CANT_ITERATE (2133571485L) +#define EXT2_ET_EA_BAD_NAME_LEN (2133571486L) +#define EXT2_ET_EA_BAD_VALUE_SIZE (2133571487L) +#define EXT2_ET_BAD_EA_HASH (2133571488L) +#define EXT2_ET_BAD_EA_HEADER (2133571489L) +#define EXT2_ET_EA_KEY_NOT_FOUND (2133571490L) +#define EXT2_ET_EA_NO_SPACE (2133571491L) +#define EXT2_ET_MISSING_EA_FEATURE (2133571492L) +#define EXT2_ET_NO_INLINE_DATA (2133571493L) +#define EXT2_ET_INLINE_DATA_NO_BLOCK (2133571494L) +#define EXT2_ET_INLINE_DATA_NO_SPACE (2133571495L) +#define EXT2_ET_MAGIC_EA_HANDLE (2133571496L) +#define EXT2_ET_INODE_IS_GARBAGE (2133571497L) +#define EXT2_ET_EA_BAD_VALUE_OFFSET (2133571498L) +#define EXT2_ET_JOURNAL_FLAGS_WRONG (2133571499L) +#define EXT2_ET_UNDO_FILE_CORRUPT (2133571500L) +#define EXT2_ET_UNDO_FILE_WRONG (2133571501L) +#define EXT2_ET_FILESYSTEM_CORRUPTED (2133571502L) +#define EXT2_ET_BAD_CRC (2133571503L) +#define EXT2_ET_CORRUPT_JOURNAL_SB (2133571504L) +#define EXT2_ET_INODE_CORRUPTED (2133571505L) +#define EXT2_ET_EA_INODE_CORRUPTED (2133571506L) +extern const struct error_table et_ext2_error_table; +extern void initialize_ext2_error_table(void); + +/* For compatibility with Heimdal */ +extern void initialize_ext2_error_table_r(struct et_list **list); + +#define ERROR_TABLE_BASE_ext2 (2133571328L) + +/* for compatibility with older versions... */ +#define init_ext2_err_tbl initialize_ext2_error_table +#define ext2_err_base ERROR_TABLE_BASE_ext2 diff --git a/src/ext2fs/ext2_ext_attr.h b/src/ext2fs/ext2_ext_attr.h new file mode 100644 index 00000000..f2042ed5 --- /dev/null +++ b/src/ext2fs/ext2_ext_attr.h @@ -0,0 +1,73 @@ +/* + File: linux/ext2_ext_attr.h + + On-disk format of extended attributes for the ext2 filesystem. + + (C) 2000 Andreas Gruenbacher, +*/ + +#ifndef _EXT2_EXT_ATTR_H +#define _EXT2_EXT_ATTR_H +/* Magic value in attribute blocks */ +#define EXT2_EXT_ATTR_MAGIC_v1 0xEA010000 +#define EXT2_EXT_ATTR_MAGIC 0xEA020000 + +/* Maximum number of references to one attribute block */ +#define EXT2_EXT_ATTR_REFCOUNT_MAX 1024 + +struct ext2_ext_attr_header { + __u32 h_magic; /* magic number for identification */ + __u32 h_refcount; /* reference count */ + __u32 h_blocks; /* number of disk blocks used */ + __u32 h_hash; /* hash value of all attributes */ + __u32 h_checksum; /* crc32c(uuid+id+xattrs) */ + /* id = inum if refcount = 1, else blknum */ + __u32 h_reserved[3]; /* zero right now */ +}; + +struct ext2_ext_attr_entry { + __u8 e_name_len; /* length of name */ + __u8 e_name_index; /* attribute name index */ + __u16 e_value_offs; /* offset in disk block of value */ + __u32 e_value_inum; /* inode in which the value is stored */ + __u32 e_value_size; /* size of attribute value */ + __u32 e_hash; /* hash value of name and value */ +#if 0 + char e_name[0]; /* attribute name */ +#endif +}; + +#define EXT2_EXT_ATTR_PAD_BITS 2 +#define EXT2_EXT_ATTR_PAD ((unsigned) 1<e_name_len)) ) +#define EXT2_EXT_ATTR_SIZE(size) \ + (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) +#define EXT2_EXT_IS_LAST_ENTRY(entry) (*((__u32 *)(entry)) == 0UL) +#define EXT2_EXT_ATTR_NAME(entry) \ + (((char *) (entry)) + sizeof(struct ext2_ext_attr_entry)) +#define EXT2_XATTR_LEN(name_len) \ + (((name_len) + EXT2_EXT_ATTR_ROUND + \ + sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND) +#define EXT2_XATTR_SIZE(size) \ + (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) + +#ifdef __KERNEL__ +# ifdef CONFIG_EXT2_FS_EXT_ATTR +extern int ext2_get_ext_attr(struct inode *, const char *, char *, size_t, int); +extern int ext2_set_ext_attr(struct inode *, const char *, char *, size_t, int); +extern void ext2_ext_attr_free_inode(struct inode *inode); +extern void ext2_ext_attr_put_super(struct super_block *sb); +extern int ext2_ext_attr_init(void); +extern void ext2_ext_attr_done(void); +# else +# define ext2_get_ext_attr NULL +# define ext2_set_ext_attr NULL +# endif +#endif /* __KERNEL__ */ +#endif /* _EXT2_EXT_ATTR_H */ diff --git a/src/ext2fs/ext2_fs.h b/src/ext2fs/ext2_fs.h new file mode 100644 index 00000000..73bab51c --- /dev/null +++ b/src/ext2fs/ext2_fs.h @@ -0,0 +1,1110 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994, 1995 + * Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +#include "ext2_types.h" /* Changed from linux/types.h */ + +#ifdef _MSC_VER +#define __attribute__(x) +#endif + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE +#define EXT2_DEFAULT_PREALLOC_BLOCKS 8 + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "95/08/09" +#define EXT2FS_VERSION "0.5b" + +/* + * Special inode numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT4_USR_QUOTA_INO 3 /* User quota inode */ +#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */ +#define EXT2_JOURNAL_INO 8 /* Journal inode */ +#define EXT2_EXCLUDE_INO 9 /* The "exclude" inode, for snapshots */ +#define EXT4_REPLICA_INO 10 /* Used by non-upstream feature */ + +/* First non-reserved inode for old ext2 filesystems */ +#define EXT2_GOOD_OLD_FIRST_INO 11 + +/* + * The second extended file system magic number + */ +#define EXT2_SUPER_MAGIC 0xEF53 + +#ifdef __KERNEL__ +#define EXT2_SB(sb) (&((sb)->u.ext2_sb)) +#else +/* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test + * macros from user land. */ +#define EXT2_SB(sb) (sb) +#endif + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 65000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */ +#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */ +#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE) +#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE) +#ifdef __KERNEL__ +#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits) +#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size) +#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino) +#else +#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size) +#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \ + EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino) +#endif +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32)) + +/* + * Macro-instructions used to manage allocation clusters + */ +#define EXT2_MIN_CLUSTER_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE +#define EXT2_MAX_CLUSTER_LOG_SIZE 29 /* 512MB */ +#define EXT2_MIN_CLUSTER_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_MAX_CLUSTER_SIZE (1 << EXT2_MAX_CLUSTER_LOG_SIZE) +#define EXT2_CLUSTER_SIZE(s) (EXT2_MIN_BLOCK_SIZE << \ + (s)->s_log_cluster_size) +#define EXT2_CLUSTER_SIZE_BITS(s) ((s)->s_log_cluster_size + 10) + +/* + * Macro-instructions used to manage fragments + * + * Note: for backwards compatibility only, for the dump program. + * Ext2/3/4 will never support fragments.... + */ +#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE +#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE +#define EXT2_FRAG_SIZE(s) EXT2_BLOCK_SIZE(s) +#define EXT2_FRAGS_PER_BLOCK(s) 1 + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + __u32 aclh_size; + __u32 aclh_file_count; + __u32 aclh_acle_count; + __u32 aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + __u32 acle_size; + __u16 acle_perms; /* Access permissions */ + __u16 acle_type; /* Type of entry */ + __u16 acle_tag; /* User or group identity */ + __u16 acle_pad1; + __u32 acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_flags; + __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ + __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_itable_unused; /* Unused inodes count */ + __u16 bg_checksum; /* crc16(s_uuid+group_num+group_desc)*/ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext4_group_desc +{ + __u32 bg_block_bitmap; /* Blocks bitmap block */ + __u32 bg_inode_bitmap; /* Inodes bitmap block */ + __u32 bg_inode_table; /* Inodes table block */ + __u16 bg_free_blocks_count; /* Free blocks count */ + __u16 bg_free_inodes_count; /* Free inodes count */ + __u16 bg_used_dirs_count; /* Directories count */ + __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ + __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ + __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */ + __u16 bg_itable_unused; /* Unused inodes count */ + __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */ + __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ + __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ + __u32 bg_inode_table_hi; /* Inodes table block MSB */ + __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */ + __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */ + __u16 bg_used_dirs_count_hi; /* Directories count MSB */ + __u16 bg_itable_unused_hi; /* Unused inodes count MSB */ + __u32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ + __u16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */ + __u16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */ + __u32 bg_reserved; +}; + +#define EXT4_BG_INODE_BITMAP_CSUM_HI_END \ + (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \ + sizeof(__u16)) +#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION \ + (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \ + sizeof(__u16)) + +#define EXT2_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not initialized */ +#define EXT2_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not initialized */ +#define EXT2_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ + +/* + * Data structures used by the directory indexing feature + * + * Note: all of the multibyte integer fields are little endian. + */ + +/* + * Note: dx_root_info is laid out so that if it should somehow get + * overlaid by a dirent the two low bits of the hash version will be + * zero. Therefore, the hash version mod 4 should never be 0. + * Sincerely, the paranoia department. + */ +struct ext2_dx_root_info { + __u32 reserved_zero; + __u8 hash_version; /* 0 now, 1 at release */ + __u8 info_length; /* 8 */ + __u8 indirect_levels; + __u8 unused_flags; +}; + +#define EXT2_HASH_LEGACY 0 +#define EXT2_HASH_HALF_MD4 1 +#define EXT2_HASH_TEA 2 +#define EXT2_HASH_LEGACY_UNSIGNED 3 /* reserved for userspace lib */ +#define EXT2_HASH_HALF_MD4_UNSIGNED 4 /* reserved for userspace lib */ +#define EXT2_HASH_TEA_UNSIGNED 5 /* reserved for userspace lib */ + +#define EXT2_HASH_FLAG_INCOMPAT 0x1 + +#define EXT4_DX_BLOCK_MASK 0x0fffffff + +struct ext2_dx_entry { + __le32 hash; + __le32 block; +}; + +struct ext2_dx_countlimit { + __le16 limit; + __le16 count; +}; + +/* + * This goes at the end of each htree block. + */ +struct ext2_dx_tail { + __le32 dt_reserved; + __le32 dt_checksum; /* crc32c(uuid+inum+dxblock) */ +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#define EXT2_MIN_DESC_SIZE 32 +#define EXT2_MIN_DESC_SIZE_64BIT 64 +#define EXT2_MAX_DESC_SIZE EXT2_MIN_BLOCK_SIZE +#define EXT2_DESC_SIZE(s) \ + ((EXT2_SB(s)->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? \ + (s)->s_desc_size : EXT2_MIN_DESC_SIZE) + +#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group) +#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group) +#define EXT2_CLUSTERS_PER_GROUP(s) (EXT2_SB(s)->s_clusters_per_group) +#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) +/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */ +#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((((unsigned) 1 << 16) - 8) * \ + (EXT2_CLUSTER_SIZE(s) / \ + EXT2_BLOCK_SIZE(s))) +#define EXT2_MAX_CLUSTERS_PER_GROUP(s) (((unsigned) 1 << 16) - 8) +#define EXT2_MAX_INODES_PER_GROUP(s) (((unsigned) 1 << 16) - \ + EXT2_INODES_PER_BLOCK(s)) +#ifdef __KERNEL__ +#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block) +#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits) +#else +#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s)) +#endif + +#define EXT2_GROUPS_TO_BLOCKS(s, g) ((blk64_t) EXT2_BLOCKS_PER_GROUP(s) * \ + (g)) +#define EXT2_GROUPS_TO_CLUSTERS(s, g) ((blk64_t) EXT2_CLUSTERS_PER_GROUP(s) * \ + (g)) + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x00000002 /* Undelete */ +#define EXT2_COMPR_FL 0x00000004 /* Compress file */ +#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */ +#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */ +#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */ +#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */ +#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */ +/* Reserved for compression usage... */ +#define EXT2_DIRTY_FL 0x00000100 +#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ +#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */ + /* nb: was previously EXT2_ECOMPR_FL */ +#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted inode */ +/* End compression flags --- maybe not all used */ +#define EXT2_BTREE_FL 0x00001000 /* btree format dir */ +#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */ +#define EXT2_IMAGIC_FL 0x00002000 +#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ +#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */ +#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */ +#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ +#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ +#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ +/* EXT4_EOFBLOCKS_FL 0x00400000 was here */ +#define FS_NOCOW_FL 0x00800000 /* Do not cow file */ +#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */ +#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */ +#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */ +#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data */ +#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ +#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ + +#define EXT2_FL_USER_VISIBLE 0x204BDFFF /* User visible flags */ +#define EXT2_FL_USER_MODIFIABLE 0x204B80FF /* User modifiable flags */ + +/* + * ioctl commands + */ + +/* Used for online resize */ +struct ext2_new_group_input { + __u32 group; /* Group number for this data */ + __u32 block_bitmap; /* Absolute block number of block bitmap */ + __u32 inode_bitmap; /* Absolute block number of inode bitmap */ + __u32 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; /* Number of reserved GDT blocks in group */ +}; + +struct ext4_new_group_input { + __u32 group; /* Group number for this data */ + __u64 block_bitmap; /* Absolute block number of block bitmap */ + __u64 inode_bitmap; /* Absolute block number of inode bitmap */ + __u64 inode_table; /* Absolute block number of inode table start */ + __u32 blocks_count; /* Total number of blocks in this group */ + __u16 reserved_blocks; /* Number of reserved blocks in this group */ + __u16 unused; +}; + +#ifdef __GNU__ /* Needed for the Hurd */ +#define _IOT_ext2_new_group_input _IOT (_IOTS(__u32), 5, _IOTS(__u16), 2, 0, 0) +#endif + +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) +#define EXT2_IOC_GETVERSION_NEW _IOR('f', 3, long) +#define EXT2_IOC_SETVERSION_NEW _IOW('f', 4, long) +#define EXT2_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) +#define EXT2_IOC_GROUP_ADD _IOW('f', 8,struct ext2_new_group_input) +#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input) +#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Inode change time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_version; /* was l_i_reserved1 */ + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_size_high; + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u16 l_i_blocks_hi; + __u16 l_i_file_acl_high; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */ + __u16 l_i_reserved; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + } osd2; /* OS dependent 2 */ +}; + +/* + * Permanent part of an large inode on the disk + */ +struct ext2_inode_large { + __u16 i_mode; /* File mode */ + __u16 i_uid; /* Low 16 bits of Owner Uid */ + __u32 i_size; /* Size in bytes */ + __u32 i_atime; /* Access time */ + __u32 i_ctime; /* Inode Change time */ + __u32 i_mtime; /* Modification time */ + __u32 i_dtime; /* Deletion Time */ + __u16 i_gid; /* Low 16 bits of Group Id */ + __u16 i_links_count; /* Links count */ + __u32 i_blocks; /* Blocks count */ + __u32 i_flags; /* File flags */ + union { + struct { + __u32 l_i_version; /* was l_i_reserved1 */ + } linux1; + struct { + __u32 h_i_translator; + } hurd1; + } osd1; /* OS dependent 1 */ + __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + __u32 i_generation; /* File version (for NFS) */ + __u32 i_file_acl; /* File ACL */ + __u32 i_size_high; + __u32 i_faddr; /* Fragment address */ + union { + struct { + __u16 l_i_blocks_hi; + __u16 l_i_file_acl_high; + __u16 l_i_uid_high; /* these 2 fields */ + __u16 l_i_gid_high; /* were reserved2[0] */ + __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */ + __u16 l_i_reserved; + } linux2; + struct { + __u8 h_i_frag; /* Fragment number */ + __u8 h_i_fsize; /* Fragment size */ + __u16 h_i_mode_high; + __u16 h_i_uid_high; + __u16 h_i_gid_high; + __u32 h_i_author; + } hurd2; + } osd2; /* OS dependent 2 */ + __u16 i_extra_isize; + __u16 i_checksum_hi; /* crc32c(uuid+inum+inode) */ + __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ + __u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */ + __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ + __u32 i_crtime; /* File creation time */ + __u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/ + __u32 i_version_hi; /* high 32 bits for 64-bit version */ + __u32 i_projid; /* Project ID */ +}; + +#define EXT4_INODE_CSUM_HI_EXTRA_END \ + (offsetof(struct ext2_inode_large, i_checksum_hi) + sizeof(__u16) - \ + EXT2_GOOD_OLD_INODE_SIZE) + +#define EXT4_EPOCH_BITS 2 +#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) + +#define i_checksum_lo osd2.linux2.l_i_checksum_lo + +#define inode_includes(size, field) \ + (size >= (sizeof(((struct ext2_inode_large *)0)->field) + \ + offsetof(struct ext2_inode_large, field))) + +#if defined(__KERNEL__) || defined(__linux__) +#define i_reserved1 osd1.linux1.l_i_reserved1 +#define i_frag osd2.linux2.l_i_frag +#define i_fsize osd2.linux2.l_i_fsize +#define i_uid_low i_uid +#define i_gid_low i_gid +#define i_uid_high osd2.linux2.l_i_uid_high +#define i_gid_high osd2.linux2.l_i_gid_high +#else +#if defined(__GNU__) + +#define i_translator osd1.hurd1.h_i_translator +#define i_frag osd2.hurd2.h_i_frag; +#define i_fsize osd2.hurd2.h_i_fsize; +#define i_uid_high osd2.hurd2.h_i_uid_high +#define i_gid_high osd2.hurd2.h_i_gid_high +#define i_author osd2.hurd2.h_i_author + +#endif /* __GNU__ */ +#endif /* defined(__KERNEL__) || defined(__linux__) */ + +#define inode_uid(inode) ((inode).i_uid | (inode).osd2.linux2.l_i_uid_high << 16) +#define inode_gid(inode) ((inode).i_gid | (inode).osd2.linux2.l_i_gid_high << 16) +#define inode_projid(inode) ((inode).i_projid) +#define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x)) +#define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x)) + +static inline +struct ext2_inode *EXT2_INODE(struct ext2_inode_large *large_inode) +{ + return (struct ext2_inode *) large_inode; +} + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ +#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ + +/* + * Misc. filesystem flags + */ +#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */ +#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */ +#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* OK for use on development code */ +#define EXT2_FLAGS_IS_SNAPSHOT 0x0010 /* This is a snapshot image */ +#define EXT2_FLAGS_FIX_SNAPSHOT 0x0020 /* Snapshot inodes corrupted */ +#define EXT2_FLAGS_FIX_EXCLUDE 0x0040 /* Exclude bitmaps corrupted */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ +#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +#if (__GNUC__ >= 4) +#define ext4_offsetof(TYPE,MEMBER) __builtin_offsetof(TYPE,MEMBER) +#else +#define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +/* Metadata checksum algorithms */ +#define EXT2_CRC32C_CHKSUM 1 + +/* Encryption algorithms, key size and key reference len */ +#define EXT4_ENCRYPTION_MODE_INVALID 0 +#define EXT4_ENCRYPTION_MODE_AES_256_XTS 1 +#define EXT4_ENCRYPTION_MODE_AES_256_GCM 2 +#define EXT4_ENCRYPTION_MODE_AES_256_CBC 3 +#define EXT4_ENCRYPTION_MODE_AES_256_CTS 4 + +#define EXT4_AES_256_XTS_KEY_SIZE 64 +#define EXT4_AES_256_GCM_KEY_SIZE 32 +#define EXT4_AES_256_CBC_KEY_SIZE 32 +#define EXT4_AES_256_CTS_KEY_SIZE 32 +#define EXT4_MAX_KEY_SIZE 64 + +#define EXT4_KEY_DESCRIPTOR_SIZE 8 +#define EXT4_CRYPTO_BLOCK_SIZE 16 + +/* Password derivation constants */ +#define EXT4_MAX_PASSPHRASE_SIZE 1024 +#define EXT4_MAX_SALT_SIZE 256 +#define EXT4_PBKDF2_ITERATIONS 0xFFFF + +#define EXT2_LABEL_LEN 16 + +/* + * Policy provided via an ioctl on the topmost directory. This + * structure is also in the kernel. + */ +struct ext4_encryption_policy { + char version; + char contents_encryption_mode; + char filenames_encryption_mode; + char flags; + char master_key_descriptor[EXT4_KEY_DESCRIPTOR_SIZE]; +} __attribute__((__packed__)); + +struct ext4_encryption_key { + __u32 mode; + char raw[EXT4_MAX_KEY_SIZE]; + __u32 size; +} __attribute__((__packed__)); + +/* + * Structure of the super block + */ +struct ext2_super_block { + __u32 s_inodes_count; /* Inodes count */ + __u32 s_blocks_count; /* Blocks count */ + __u32 s_r_blocks_count; /* Reserved blocks count */ + __u32 s_free_blocks_count; /* Free blocks count */ + __u32 s_free_inodes_count; /* Free inodes count */ + __u32 s_first_data_block; /* First Data Block */ + __u32 s_log_block_size; /* Block size */ + __u32 s_log_cluster_size; /* Allocation cluster size */ + __u32 s_blocks_per_group; /* # Blocks per group */ + __u32 s_clusters_per_group; /* # Fragments per group */ + __u32 s_inodes_per_group; /* # Inodes per group */ + __u32 s_mtime; /* Mount time */ + __u32 s_wtime; /* Write time */ + __u16 s_mnt_count; /* Mount count */ + __s16 s_max_mnt_count; /* Maximal mount count */ + __u16 s_magic; /* Magic signature */ + __u16 s_state; /* File system state */ + __u16 s_errors; /* Behaviour when detecting errors */ + __u16 s_minor_rev_level; /* minor revision level */ + __u32 s_lastcheck; /* time of last check */ + __u32 s_checkinterval; /* max. time between checks */ + __u32 s_creator_os; /* OS */ + __u32 s_rev_level; /* Revision level */ + __u16 s_def_resuid; /* Default uid for reserved blocks */ + __u16 s_def_resgid; /* Default gid for reserved blocks */ + /* + * These fields are for EXT2_DYNAMIC_REV superblocks only. + * + * Note: the difference between the compatible feature set and + * the incompatible feature set is that if there is a bit set + * in the incompatible feature set that the kernel doesn't + * know about, it should refuse to mount the filesystem. + * + * e2fsck's requirements are more strict; if it doesn't know + * about a feature in either the compatible or incompatible + * feature set, it must abort and not try to meddle with + * things it doesn't understand... + */ + __u32 s_first_ino; /* First non-reserved inode */ + __u16 s_inode_size; /* size of inode structure */ + __u16 s_block_group_nr; /* block group # of this superblock */ + __u32 s_feature_compat; /* compatible feature set */ + __u32 s_feature_incompat; /* incompatible feature set */ + __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __u8 s_uuid[16]; /* 128-bit uuid for volume */ + char s_volume_name[EXT2_LABEL_LEN]; /* volume name */ + char s_last_mounted[64]; /* directory where last mounted */ + __u32 s_algorithm_usage_bitmap; /* For compression */ + /* + * Performance hints. Directory preallocation should only + * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. + */ + __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + __u16 s_reserved_gdt_blocks; /* Per group table for online growth */ + /* + * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. + */ + __u8 s_journal_uuid[16]; /* uuid of journal superblock */ + __u32 s_journal_inum; /* inode number of journal file */ + __u32 s_journal_dev; /* device number of journal file */ + __u32 s_last_orphan; /* start of list of inodes to delete */ + __u32 s_hash_seed[4]; /* HTREE hash seed */ + __u8 s_def_hash_version; /* Default hash version to use */ + __u8 s_jnl_backup_type; /* Default type of journal backup */ + __u16 s_desc_size; /* Group desc. size: INCOMPAT_64BIT */ + __u32 s_default_mount_opts; + __u32 s_first_meta_bg; /* First metablock group */ + __u32 s_mkfs_time; /* When the filesystem was created */ + __u32 s_jnl_blocks[17]; /* Backup of the journal inode */ + __u32 s_blocks_count_hi; /* Blocks count high 32bits */ + __u32 s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/ + __u32 s_free_blocks_hi; /* Free blocks count */ + __u16 s_min_extra_isize; /* All inodes have at least # bytes */ + __u16 s_want_extra_isize; /* New inodes should reserve # bytes */ + __u32 s_flags; /* Miscellaneous flags */ + __u16 s_raid_stride; /* RAID stride */ + __u16 s_mmp_update_interval; /* # seconds to wait in MMP checking */ + __u64 s_mmp_block; /* Block for multi-mount protection */ + __u32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + __u8 s_log_groups_per_flex; /* FLEX_BG group size */ + __u8 s_checksum_type; /* metadata checksum algorithm */ + __u8 s_encryption_level; /* versioning level for encryption */ + __u8 s_reserved_pad; /* Padding to next 32bits */ + __u64 s_kbytes_written; /* nr of lifetime kilobytes written */ + __u32 s_snapshot_inum; /* Inode number of active snapshot */ + __u32 s_snapshot_id; /* sequential ID of active snapshot */ + __u64 s_snapshot_r_blocks_count; /* reserved blocks for active + snapshot's future use */ + __u32 s_snapshot_list; /* inode number of the head of the on-disk snapshot list */ +#define EXT4_S_ERR_START ext4_offsetof(struct ext2_super_block, s_error_count) + __u32 s_error_count; /* number of fs errors */ + __u32 s_first_error_time; /* first time an error happened */ + __u32 s_first_error_ino; /* inode involved in first error */ + __u64 s_first_error_block; /* block involved of first error */ + __u8 s_first_error_func[32]; /* function where the error happened */ + __u32 s_first_error_line; /* line number where error happened */ + __u32 s_last_error_time; /* most recent time of an error */ + __u32 s_last_error_ino; /* inode involved in last error */ + __u32 s_last_error_line; /* line number where error happened */ + __u64 s_last_error_block; /* block involved of last error */ + __u8 s_last_error_func[32]; /* function where the error happened */ +#define EXT4_S_ERR_END ext4_offsetof(struct ext2_super_block, s_mount_opts) + __u8 s_mount_opts[64]; + __u32 s_usr_quota_inum; /* inode number of user quota file */ + __u32 s_grp_quota_inum; /* inode number of group quota file */ + __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */ + __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */ + __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ + __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ + __le32 s_lpf_ino; /* Location of the lost+found inode */ + __le32 s_prj_quota_inum; /* inode for tracking project quota */ + __le32 s_checksum_seed; /* crc32c(orig_uuid) if csum_seed set */ + __le32 s_reserved[98]; /* Padding to the end of the block */ + __u32 s_checksum; /* crc32c(superblock) */ +}; + +#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) + +/* + * Codes for operating systems + */ +#define EXT2_OS_LINUX 0 +#define EXT2_OS_HURD 1 +#define EXT2_OS_WINDOWS 2 +#define EXT2_OS_FREEBSD 3 +#define EXT2_OS_LITES 4 + +/* + * Revision levels + */ +#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */ +#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ + +#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV +#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV + +#define EXT2_GOOD_OLD_INODE_SIZE 128 + +/* + * Journal inode backup types + */ +#define EXT3_JNL_BACKUP_BLOCKS 1 + +/* + * Feature set definitions + */ + +#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_compat & (mask) ) +#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_ro_compat & (mask) ) +#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ + ( EXT2_SB(sb)->s_feature_incompat & (mask) ) + +#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 +#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 +#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 +#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 +#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040 +/* #define EXT2_FEATURE_COMPAT_EXCLUDE_INODE 0x0080 not used, legacy */ +#define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100 +#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 + + +#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 +#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 +/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */ +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +#define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT 0x0080 +#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 +#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 +/* + * METADATA_CSUM implies GDT_CSUM. When METADATA_CSUM is set, group + * descriptor checksums use the same algorithm as all other data + * structures' checksums. + */ +#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 +#define EXT4_FEATURE_RO_COMPAT_REPLICA 0x0800 +#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000 +#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000 /* Project quota */ + + +#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 +#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 +#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 +#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 +#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 +#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 +#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ +#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ +#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 + +#define EXT4_FEATURE_COMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_compat & \ + EXT##ver##_FEATURE_COMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_compat |= \ + EXT##ver##_FEATURE_COMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_compat &= \ + ~EXT##ver##_FEATURE_COMPAT_##flagname; \ +} + +#define EXT4_FEATURE_RO_COMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_ro_compat & \ + EXT##ver##_FEATURE_RO_COMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_ro_compat |= \ + EXT##ver##_FEATURE_RO_COMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_ro_compat &= \ + ~EXT##ver##_FEATURE_RO_COMPAT_##flagname; \ +} + +#define EXT4_FEATURE_INCOMPAT_FUNCS(name, ver, flagname) \ +static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ +{ \ + return ((EXT2_SB(sb)->s_feature_incompat & \ + EXT##ver##_FEATURE_INCOMPAT_##flagname) != 0); \ +} \ +static inline void ext2fs_set_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_incompat |= \ + EXT##ver##_FEATURE_INCOMPAT_##flagname; \ +} \ +static inline void ext2fs_clear_feature_##name(struct ext2_super_block *sb) \ +{ \ + EXT2_SB(sb)->s_feature_incompat &= \ + ~EXT##ver##_FEATURE_INCOMPAT_##flagname; \ +} + +EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc, 2, DIR_PREALLOC) +EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes, 2, IMAGIC_INODES) +EXT4_FEATURE_COMPAT_FUNCS(journal, 3, HAS_JOURNAL) +EXT4_FEATURE_COMPAT_FUNCS(xattr, 2, EXT_ATTR) +EXT4_FEATURE_COMPAT_FUNCS(resize_inode, 2, RESIZE_INODE) +EXT4_FEATURE_COMPAT_FUNCS(dir_index, 2, DIR_INDEX) +EXT4_FEATURE_COMPAT_FUNCS(lazy_bg, 2, LAZY_BG) +EXT4_FEATURE_COMPAT_FUNCS(exclude_bitmap, 2, EXCLUDE_BITMAP) +EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, 4, SPARSE_SUPER2) + +EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, 2, SPARSE_SUPER) +EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, 2, LARGE_FILE) +EXT4_FEATURE_RO_COMPAT_FUNCS(huge_file, 4, HUGE_FILE) +EXT4_FEATURE_RO_COMPAT_FUNCS(gdt_csum, 4, GDT_CSUM) +EXT4_FEATURE_RO_COMPAT_FUNCS(dir_nlink, 4, DIR_NLINK) +EXT4_FEATURE_RO_COMPAT_FUNCS(extra_isize, 4, EXTRA_ISIZE) +EXT4_FEATURE_RO_COMPAT_FUNCS(has_snapshot, 4, HAS_SNAPSHOT) +EXT4_FEATURE_RO_COMPAT_FUNCS(quota, 4, QUOTA) +EXT4_FEATURE_RO_COMPAT_FUNCS(bigalloc, 4, BIGALLOC) +EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum, 4, METADATA_CSUM) +EXT4_FEATURE_RO_COMPAT_FUNCS(replica, 4, REPLICA) +EXT4_FEATURE_RO_COMPAT_FUNCS(readonly, 4, READONLY) +EXT4_FEATURE_RO_COMPAT_FUNCS(project, 4, PROJECT) + +EXT4_FEATURE_INCOMPAT_FUNCS(compression, 2, COMPRESSION) +EXT4_FEATURE_INCOMPAT_FUNCS(filetype, 2, FILETYPE) +EXT4_FEATURE_INCOMPAT_FUNCS(journal_needs_recovery, 3, RECOVER) +EXT4_FEATURE_INCOMPAT_FUNCS(journal_dev, 3, JOURNAL_DEV) +EXT4_FEATURE_INCOMPAT_FUNCS(meta_bg, 2, META_BG) +EXT4_FEATURE_INCOMPAT_FUNCS(extents, 3, EXTENTS) +EXT4_FEATURE_INCOMPAT_FUNCS(64bit, 4, 64BIT) +EXT4_FEATURE_INCOMPAT_FUNCS(mmp, 4, MMP) +EXT4_FEATURE_INCOMPAT_FUNCS(flex_bg, 4, FLEX_BG) +EXT4_FEATURE_INCOMPAT_FUNCS(ea_inode, 4, EA_INODE) +EXT4_FEATURE_INCOMPAT_FUNCS(dirdata, 4, DIRDATA) +EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, 4, CSUM_SEED) +EXT4_FEATURE_INCOMPAT_FUNCS(largedir, 4, LARGEDIR) +EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, 4, INLINE_DATA) +EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT) + +#define EXT2_FEATURE_COMPAT_SUPP 0 +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT4_FEATURE_INCOMPAT_MMP| \ + EXT4_FEATURE_INCOMPAT_LARGEDIR| \ + EXT4_FEATURE_INCOMPAT_EA_INODE) +#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) + +/* + * Default values for user and/or group using reserved blocks + */ +#define EXT2_DEF_RESUID 0 +#define EXT2_DEF_RESGID 0 + +/* + * Default mount options + */ +#define EXT2_DEFM_DEBUG 0x0001 +#define EXT2_DEFM_BSDGROUPS 0x0002 +#define EXT2_DEFM_XATTR_USER 0x0004 +#define EXT2_DEFM_ACL 0x0008 +#define EXT2_DEFM_UID16 0x0010 +#define EXT3_DEFM_JMODE 0x0060 +#define EXT3_DEFM_JMODE_DATA 0x0020 +#define EXT3_DEFM_JMODE_ORDERED 0x0040 +#define EXT3_DEFM_JMODE_WBACK 0x0060 +#define EXT4_DEFM_NOBARRIER 0x0100 +#define EXT4_DEFM_BLOCK_VALIDITY 0x0200 +#define EXT4_DEFM_DISCARD 0x0400 +#define EXT4_DEFM_NODELALLOC 0x0800 + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u16 name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * The new version of the directory entry. Since EXT2 structures are + * stored in intel byte order, and the name_len field could never be + * bigger than 255 chars, it's safe to reclaim the extra byte for the + * file_type field. + * + * This structure is deprecated due to endian issues. Please use struct + * ext2_dir_entry and accessor functions + * ext2fs_dirent_name_len + * ext2fs_dirent_set_name_len + * ext2fs_dirent_file_type + * ext2fs_dirent_set_file_type + * to get and set name_len and file_type fields. + */ +struct ext2_dir_entry_2 { + __u32 inode; /* Inode number */ + __u16 rec_len; /* Directory entry length */ + __u8 name_len; /* Name length */ + __u8 file_type; + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * This is a bogus directory entry at the end of each leaf block that + * records checksums. + */ +struct ext2_dir_entry_tail { + __u32 det_reserved_zero1; /* Pretend to be unused */ + __u16 det_rec_len; /* 12 */ + __u16 det_reserved_name_len; /* 0xDE00, fake namelen/filetype */ + __u32 det_checksum; /* crc32c(uuid+inode+dirent) */ +}; + +/* + * Ext2 directory file types. Only the low 3 bits are used. The + * other bits are reserved for now. + */ +#define EXT2_FT_UNKNOWN 0 +#define EXT2_FT_REG_FILE 1 +#define EXT2_FT_DIR 2 +#define EXT2_FT_CHRDEV 3 +#define EXT2_FT_BLKDEV 4 +#define EXT2_FT_FIFO 5 +#define EXT2_FT_SOCK 6 +#define EXT2_FT_SYMLINK 7 + +#define EXT2_FT_MAX 8 + +/* + * Annoyingly, e2fsprogs always swab16s ext2_dir_entry.name_len, so we + * have to build ext2_dir_entry_tail with that assumption too. This + * constant helps to build the dir_entry_tail to look like it has an + * "invalid" file type. + */ +#define EXT2_DIR_NAME_LEN_CSUM 0xDE00 + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_ENTRY_HEADER_LEN 8 +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + \ + EXT2_DIR_ENTRY_HEADER_LEN + \ + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + +/* + * Constants for ext4's extended time encoding + */ +#define EXT4_EPOCH_BITS 2 +#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) +#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) + +/* + * This structure is used for multiple mount protection. It is written + * into the block number saved in the s_mmp_block field in the superblock. + * Programs that check MMP should assume that if SEQ_FSCK (or any unknown + * code above SEQ_MAX) is present then it is NOT safe to use the filesystem, + * regardless of how old the timestamp is. + * + * The timestamp in the MMP structure will be updated by e2fsck at some + * arbitrary intervals (start of passes, after every few groups of inodes + * in pass1 and pass1b). There is no guarantee that e2fsck is updating + * the MMP block in a timely manner, and the updates it does are purely + * for the convenience of the sysadmin and not for automatic validation. + * + * Note: Only the mmp_seq value is used to determine whether the MMP block + * is being updated. The mmp_time, mmp_nodename, and mmp_bdevname + * fields are only for informational purposes for the administrator, + * due to clock skew between nodes and hostname HA service takeover. + */ +#define EXT4_MMP_MAGIC 0x004D4D50U /* ASCII for MMP */ +#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */ +#define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */ +#define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */ + +/* Not endian-annotated; it's swapped at read/write time */ +struct mmp_struct { + __u32 mmp_magic; /* Magic number for MMP */ + __u32 mmp_seq; /* Sequence no. updated periodically */ + __u64 mmp_time; /* Time last updated */ + char mmp_nodename[64]; /* Node which last updated MMP block */ + char mmp_bdevname[32]; /* Bdev which last updated MMP block */ + __u16 mmp_check_interval; /* Changed mmp_check_interval */ + __u16 mmp_pad1; + __u32 mmp_pad2[226]; + __u32 mmp_checksum; /* crc32c(uuid+mmp_block) */ +}; + +/* + * Default interval for MMP update in seconds. + */ +#define EXT4_MMP_UPDATE_INTERVAL 5 + +/* + * Maximum interval for MMP update in seconds. + */ +#define EXT4_MMP_MAX_UPDATE_INTERVAL 300 + +/* + * Minimum interval for MMP checking in seconds. + */ +#define EXT4_MMP_MIN_CHECK_INTERVAL 5 + +/* + * Minimum size of inline data. + */ +#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__u32) * EXT2_N_BLOCKS)) + +/* + * Size of a parent inode in inline data directory. + */ +#define EXT4_INLINE_DATA_DOTDOT_SIZE (4) + +#endif /* _LINUX_EXT2_FS_H */ diff --git a/src/ext2fs/ext2_io.h b/src/ext2fs/ext2_io.h new file mode 100644 index 00000000..c286ad1c --- /dev/null +++ b/src/ext2fs/ext2_io.h @@ -0,0 +1,169 @@ +/* + * io.h --- the I/O manager abstraction + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _EXT2FS_EXT2_IO_H +#define _EXT2FS_EXT2_IO_H + +#include "ext2_types.h" + +/* + * ext2_loff_t is defined here since unix_io.c needs it. + */ +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +/* llseek.c */ +ext2_loff_t ext2fs_llseek (int, ext2_loff_t, int); + +typedef struct struct_io_manager *io_manager; +typedef struct struct_io_channel *io_channel; +typedef struct struct_io_stats *io_stats; + +#define CHANNEL_FLAGS_WRITETHROUGH 0x01 +#define CHANNEL_FLAGS_DISCARD_ZEROES 0x02 +#define CHANNEL_FLAGS_BLOCK_DEVICE 0x04 + +#define io_channel_discard_zeroes_data(i) (i->flags & CHANNEL_FLAGS_DISCARD_ZEROES) + +struct struct_io_channel { + errcode_t magic; + io_manager manager; + char *name; + int block_size; + errcode_t (*read_error)(io_channel channel, + unsigned long block, + int count, + void *data, + size_t size, + int actual_bytes_read, + errcode_t error); + errcode_t (*write_error)(io_channel channel, + unsigned long block, + int count, + const void *data, + size_t size, + int actual_bytes_written, + errcode_t error); + int refcount; + int flags; + long reserved[14]; + void *private_data; + void *app_data; + int align; +}; + +struct struct_io_stats { + int num_fields; + int reserved; + unsigned long long bytes_read; + unsigned long long bytes_written; +}; + +struct struct_io_manager { + errcode_t magic; + const char *name; + errcode_t (*open)(const char *name, int flags, io_channel *channel); + errcode_t (*close)(io_channel channel); + errcode_t (*set_blksize)(io_channel channel, int blksize); + errcode_t (*read_blk)(io_channel channel, unsigned long block, + int count, void *data); + errcode_t (*write_blk)(io_channel channel, unsigned long block, + int count, const void *data); + errcode_t (*flush)(io_channel channel); + errcode_t (*write_byte)(io_channel channel, unsigned long offset, + int count, const void *data); + errcode_t (*set_option)(io_channel channel, const char *option, + const char *arg); + errcode_t (*get_stats)(io_channel channel, io_stats *io_stats); + errcode_t (*read_blk64)(io_channel channel, unsigned long long block, + int count, void *data); + errcode_t (*write_blk64)(io_channel channel, unsigned long long block, + int count, const void *data); + errcode_t (*discard)(io_channel channel, unsigned long long block, + unsigned long long count); + errcode_t (*cache_readahead)(io_channel channel, + unsigned long long block, + unsigned long long count); + errcode_t (*zeroout)(io_channel channel, unsigned long long block, + unsigned long long count); + long reserved[14]; +}; + +#define IO_FLAG_RW 0x0001 +#define IO_FLAG_EXCLUSIVE 0x0002 +#define IO_FLAG_DIRECT_IO 0x0004 +#define IO_FLAG_FORCE_BOUNCE 0x0008 + +/* + * Convenience functions.... + */ +#define io_channel_close(c) ((c)->manager->close((c))) +#define io_channel_set_blksize(c,s) ((c)->manager->set_blksize((c),s)) +#define io_channel_read_blk(c,b,n,d) ((c)->manager->read_blk((c),b,n,d)) +#define io_channel_write_blk(c,b,n,d) ((c)->manager->write_blk((c),b,n,d)) +#define io_channel_flush(c) ((c)->manager->flush((c))) +#define io_channel_bumpcount(c) ((c)->refcount++) + +/* io_manager.c */ +extern errcode_t io_channel_set_options(io_channel channel, + const char *options); +extern errcode_t io_channel_write_byte(io_channel channel, + unsigned long offset, + int count, const void *data); +extern errcode_t io_channel_read_blk64(io_channel channel, + unsigned long long block, + int count, void *data); +extern errcode_t io_channel_write_blk64(io_channel channel, + unsigned long long block, + int count, const void *data); +extern errcode_t io_channel_discard(io_channel channel, + unsigned long long block, + unsigned long long count); +extern errcode_t io_channel_zeroout(io_channel channel, + unsigned long long block, + unsigned long long count); +extern errcode_t io_channel_alloc_buf(io_channel channel, + int count, void *ptr); +extern errcode_t io_channel_cache_readahead(io_channel io, + unsigned long long block, + unsigned long long count); + +/* unix_io.c */ +extern io_manager unix_io_manager; +extern io_manager unixfd_io_manager; + +/* sparse_io.c */ +extern io_manager sparse_io_manager; +extern io_manager sparsefd_io_manager; + +/* undo_io.c */ +extern io_manager undo_io_manager; +extern errcode_t set_undo_io_backing_manager(io_manager manager); +extern errcode_t set_undo_io_backup_file(char *file_name); + +/* test_io.c */ +extern io_manager test_io_manager, test_io_backing_manager; +extern void (*test_io_cb_read_blk) + (unsigned long block, int count, errcode_t err); +extern void (*test_io_cb_write_blk) + (unsigned long block, int count, errcode_t err); +extern void (*test_io_cb_read_blk64) + (unsigned long long block, int count, errcode_t err); +extern void (*test_io_cb_write_blk64) + (unsigned long long block, int count, errcode_t err); +extern void (*test_io_cb_set_blksize) + (int blksize, errcode_t err); + +#endif /* _EXT2FS_EXT2_IO_H */ + diff --git a/src/ext2fs/ext2_types.h b/src/ext2fs/ext2_types.h new file mode 100644 index 00000000..8e26ec44 --- /dev/null +++ b/src/ext2fs/ext2_types.h @@ -0,0 +1,197 @@ +/* + * If linux/types.h is already been included, assume it has defined + * everything we need. (cross fingers) Other header files may have + * also defined the types that we need. + */ +#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \ + !defined(_EXT2_TYPES_H)) +#define _EXT2_TYPES_H + + +#ifndef HAVE___U8 +#define HAVE___U8 +#ifdef __U8_TYPEDEF +typedef __U8_TYPEDEF __u8; +#else +typedef unsigned char __u8; +#endif +#endif /* HAVE___U8 */ + +#ifndef HAVE___S8 +#define HAVE___S8 +#ifdef __S8_TYPEDEF +typedef __S8_TYPEDEF __s8; +#else +typedef signed char __s8; +#endif +#endif /* HAVE___S8 */ + +#ifndef HAVE___U16 +#define HAVE___U16 +#ifdef __U16_TYPEDEF +typedef __U16_TYPEDEF __u16; +#else +#if (4 == 2) +typedef unsigned int __u16; +#else +#if (2 == 2) +typedef unsigned short __u16; +#else +#undef HAVE___U16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __U16_TYPEDEF */ +#endif /* HAVE___U16 */ + +#ifndef HAVE___S16 +#define HAVE___S16 +#ifdef __S16_TYPEDEF +typedef __S16_TYPEDEF __s16; +#else +#if (4 == 2) +typedef int __s16; +#else +#if (2 == 2) +typedef short __s16; +#else +#undef HAVE___S16 + ?==error: undefined 16 bit type +#endif /* SIZEOF_SHORT == 2 */ +#endif /* SIZEOF_INT == 2 */ +#endif /* __S16_TYPEDEF */ +#endif /* HAVE___S16 */ + +#ifndef HAVE___U32 +#define HAVE___U32 +#ifdef __U32_TYPEDEF +typedef __U32_TYPEDEF __u32; +#else +#if (4 == 4) +typedef unsigned int __u32; +#else +#if (4 == 4) +typedef unsigned long __u32; +#else +#if (2 == 4) +typedef unsigned short __u32; +#else +#undef HAVE___U32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __U32_TYPEDEF */ +#endif /* HAVE___U32 */ + +#ifndef HAVE___S32 +#define HAVE___S32 +#ifdef __S32_TYPEDEF +typedef __S32_TYPEDEF __s32; +#else +#if (4 == 4) +typedef int __s32; +#else +#if (4 == 4) +typedef long __s32; +#else +#if (2 == 4) +typedef short __s32; +#else +#undef HAVE___S32 + ?== error: undefined 32 bit type +#endif /* SIZEOF_SHORT == 4 */ +#endif /* SIZEOF_LONG == 4 */ +#endif /* SIZEOF_INT == 4 */ +#endif /* __S32_TYPEDEF */ +#endif /* HAVE___S32 */ + +#ifndef HAVE___U64 +#define HAVE___U64 +#ifdef __U64_TYPEDEF +typedef __U64_TYPEDEF __u64; +#else +#if (4 == 8) +typedef unsigned int __u64; +#else +#if (8 == 8) +typedef unsigned long long __u64; +#else +#if (4 == 8) +typedef unsigned long __u64; +#else +#undef HAVE___U64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __U64_TYPEDEF */ +#endif /* HAVE___U64 */ + +#ifndef HAVE___S64 +#define HAVE___S64 +#ifdef __S64_TYPEDEF +typedef __S64_TYPEDEF __s64; +#else +#if (4 == 8) +typedef int __s64; +#else +#if (8 == 8) +#if defined(__GNUC__) +typedef __signed__ long long __s64; +#else +typedef signed long long __s64; +#endif /* __GNUC__ */ +#else +#if (4 == 8) +typedef long __s64; +#else +#undef HAVE___S64 + ?== error: undefined 64 bit type +#endif /* SIZEOF_LONG_LONG == 8 */ +#endif /* SIZEOF_LONG == 8 */ +#endif /* SIZEOF_INT == 8 */ +#endif /* __S64_TYPEDEF */ +#endif /* HAVE___S64 */ + +#undef __S8_TYPEDEF +#undef __U8_TYPEDEF +#undef __S16_TYPEDEF +#undef __U16_TYPEDEF +#undef __S32_TYPEDEF +#undef __U32_TYPEDEF +#undef __S64_TYPEDEF +#undef __U64_TYPEDEF + +#endif /* _*_TYPES_H */ + +#include + +/* endian checking stuff */ +#ifndef EXT2_ENDIAN_H_ +#define EXT2_ENDIAN_H_ + +#ifdef __CHECKER__ +# ifndef __bitwise +# define __bitwise __attribute__((bitwise)) +# endif +#define __force __attribute__((force)) +#else +# ifndef __bitwise +# define __bitwise +# endif +#define __force +#endif + +typedef __u16 __bitwise __le16; +typedef __u32 __bitwise __le32; +typedef __u64 __bitwise __le64; +typedef __u16 __bitwise __be16; +typedef __u32 __bitwise __be32; +typedef __u64 __bitwise __be64; + +#endif /* EXT2_ENDIAN_H_ */ + +/* These defines are needed for the public ext2fs.h header file */ +#define HAVE_SYS_TYPES_H 1 +#undef WORDS_BIGENDIAN diff --git a/src/ext2fs/ext2fs.h b/src/ext2fs/ext2fs.h new file mode 100644 index 00000000..6f36259a --- /dev/null +++ b/src/ext2fs/ext2fs.h @@ -0,0 +1,2036 @@ +/* + * ext2fs.h --- ext2fs + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _EXT2FS_EXT2FS_H +#define _EXT2FS_EXT2FS_H + +#ifdef __GNUC__ +#define EXT2FS_ATTR(x) __attribute__(x) +#else +#define EXT2FS_ATTR(x) +#endif + +#ifdef CONFIG_TDB +#define EXT2FS_NO_TDB_UNUSED +#else +#define EXT2FS_NO_TDB_UNUSED EXT2FS_ATTR((unused)) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Non-GNU C compilers won't necessarily understand inline + */ +#if (!defined(__GNUC__) && !defined(__WATCOMC__)) +#define NO_INLINE_FUNCS +#endif + +/* + * Where the master copy of the superblock is located, and how big + * superblocks are supposed to be. We define SUPERBLOCK_SIZE because + * the size of the superblock structure is not necessarily trustworthy + * (some versions have the padding set up so that the superblock is + * 1032 bytes long). + */ +#define SUPERBLOCK_OFFSET 1024 +#define SUPERBLOCK_SIZE 1024 + +#define UUID_STR_SIZE 37 + +/* + * The last ext2fs revision level that this version of the library is + * able to support. + */ +#define EXT2_LIB_CURRENT_REV EXT2_DYNAMIC_REV + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef EXT2_FLAT_INCLUDES +#include "ext2_types.h" +#include "ext2_fs.h" +#include "ext3_extents.h" +#else +#include +#include +#include +#endif /* EXT2_FLAT_INCLUDES */ + +typedef __u32 __bitwise ext2_ino_t; +typedef __u32 __bitwise blk_t; +typedef __u64 __bitwise blk64_t; +typedef __u32 __bitwise dgrp_t; +typedef __u32 __bitwise ext2_off_t; +typedef __u64 __bitwise ext2_off64_t; +typedef __s64 __bitwise e2_blkcnt_t; +typedef __u32 __bitwise ext2_dirhash_t; + +#ifdef EXT2_FLAT_INCLUDES +#include "com_err.h" +#include "ext2_io.h" +#include "ext2_err.h" +#include "ext2_ext_attr.h" +#else +#include +#include +#include +#include +#endif + +#define EXT2_QSORT_TYPE int + +typedef struct struct_ext2_filsys *ext2_filsys; + +#define EXT2FS_MARK_ERROR 0 +#define EXT2FS_UNMARK_ERROR 1 +#define EXT2FS_TEST_ERROR 2 + +typedef struct ext2fs_struct_generic_bitmap *ext2fs_generic_bitmap; +typedef struct ext2fs_struct_generic_bitmap *ext2fs_inode_bitmap; +typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap; + +#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s) + + +/* + * Badblocks list definitions + */ + +typedef struct ext2_struct_u32_list *ext2_badblocks_list; +typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate; + +typedef struct ext2_struct_u32_list *ext2_u32_list; +typedef struct ext2_struct_u32_iterate *ext2_u32_iterate; + +/* old */ +typedef struct ext2_struct_u32_list *badblocks_list; +typedef struct ext2_struct_u32_iterate *badblocks_iterate; + +#define BADBLOCKS_FLAG_DIRTY 1 + +/* + * ext2_dblist structure and abstractions (see dblist.c) + */ +struct ext2_db_entry2 { + ext2_ino_t ino; + blk64_t blk; + e2_blkcnt_t blockcnt; +}; + +/* Ye Olde 32-bit version */ +struct ext2_db_entry { + ext2_ino_t ino; + blk_t blk; + int blockcnt; +}; + +typedef struct ext2_struct_dblist *ext2_dblist; + +#define DBLIST_ABORT 1 + +/* + * ext2_fileio definitions + */ + +#define EXT2_FILE_WRITE 0x0001 +#define EXT2_FILE_CREATE 0x0002 + +#define EXT2_FILE_MASK 0x00FF + +#define EXT2_FILE_BUF_DIRTY 0x4000 +#define EXT2_FILE_BUF_VALID 0x2000 + +typedef struct ext2_file *ext2_file_t; + +#define EXT2_SEEK_SET 0 +#define EXT2_SEEK_CUR 1 +#define EXT2_SEEK_END 2 + +/* + * Flags for the ext2_filsys structure and for ext2fs_open() + */ +#define EXT2_FLAG_RW 0x01 +#define EXT2_FLAG_CHANGED 0x02 +#define EXT2_FLAG_DIRTY 0x04 +#define EXT2_FLAG_VALID 0x08 +#define EXT2_FLAG_IB_DIRTY 0x10 +#define EXT2_FLAG_BB_DIRTY 0x20 +#define EXT2_FLAG_SWAP_BYTES 0x40 +#define EXT2_FLAG_SWAP_BYTES_READ 0x80 +#define EXT2_FLAG_SWAP_BYTES_WRITE 0x100 +#define EXT2_FLAG_MASTER_SB_ONLY 0x200 +#define EXT2_FLAG_FORCE 0x400 +#define EXT2_FLAG_SUPER_ONLY 0x800 +#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000 +#define EXT2_FLAG_IMAGE_FILE 0x2000 +#define EXT2_FLAG_EXCLUSIVE 0x4000 +#define EXT2_FLAG_SOFTSUPP_FEATURES 0x8000 +#define EXT2_FLAG_NOFREE_ON_ERROR 0x10000 +#define EXT2_FLAG_64BITS 0x20000 +#define EXT2_FLAG_PRINT_PROGRESS 0x40000 +#define EXT2_FLAG_DIRECT_IO 0x80000 +#define EXT2_FLAG_SKIP_MMP 0x100000 +#define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000 + +/* + * Special flag in the ext2 inode i_flag field that means that this is + * a new inode. (So that ext2_write_inode() can clear extra fields.) + */ +#define EXT2_NEW_INODE_FL 0x80000000 + +/* + * Flags for mkjournal + */ +#define EXT2_MKJOURNAL_V1_SUPER 0x0000001 /* create V1 superblock (deprecated) */ +#define EXT2_MKJOURNAL_LAZYINIT 0x0000002 /* don't zero journal inode before use*/ +#define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */ + +struct blk_alloc_ctx; +struct opaque_ext2_group_desc; + +struct struct_ext2_filsys { + errcode_t magic; + io_channel io; + int flags; + char * device_name; + struct ext2_super_block * super; + unsigned int blocksize; + int fragsize; + dgrp_t group_desc_count; + unsigned long desc_blocks; + struct opaque_ext2_group_desc * group_desc; + unsigned int inode_blocks_per_group; + ext2fs_inode_bitmap inode_map; + ext2fs_block_bitmap block_map; + /* XXX FIXME-64: not 64-bit safe, but not used? */ + errcode_t (*get_blocks)(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); + errcode_t (*check_directory)(ext2_filsys fs, ext2_ino_t ino); + errcode_t (*write_bitmaps)(ext2_filsys fs); + errcode_t (*read_inode)(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); + errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); + ext2_badblocks_list badblocks; + ext2_dblist dblist; + __u32 stride; /* for mke2fs */ + struct ext2_super_block * orig_super; + struct ext2_image_hdr * image_header; + __u32 umask; + time_t now; + int cluster_ratio_bits; + __u16 default_bitmap_type; + __u16 pad; + /* + * Reserved for future expansion + */ + __u32 reserved[5]; + + /* + * Reserved for the use of the calling application. + */ + void * priv_data; + + /* + * Inode cache + */ + struct ext2_inode_cache *icache; + io_channel image_io; + + /* + * More callback functions + */ + errcode_t (*get_alloc_block)(ext2_filsys fs, blk64_t goal, + blk64_t *ret); + errcode_t (*get_alloc_block2)(ext2_filsys fs, blk64_t goal, + blk64_t *ret, struct blk_alloc_ctx *ctx); + void (*block_alloc_stats)(ext2_filsys fs, blk64_t blk, int inuse); + + /* + * Buffers for Multiple mount protection(MMP) block. + */ + void *mmp_buf; + void *mmp_cmp; + int mmp_fd; + + /* + * Time at which e2fsck last updated the MMP block. + */ + long mmp_last_written; + + /* progress operation functions */ + struct ext2fs_progress_ops *progress_ops; + + /* Precomputed FS UUID checksum for seeding other checksums */ + __u32 csum_seed; + + io_channel journal_io; + char *journal_name; + + /* New block range allocation hooks */ + errcode_t (*new_range)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen); + void (*block_alloc_stats_range)(ext2_filsys fs, blk64_t blk, blk_t num, + int inuse); +}; + +#ifdef EXT2_FLAT_INCLUDES +#include "bitops.h" +#else +#include +#endif + +/* + * 64-bit bitmap backend types + */ +#define EXT2FS_BMAP64_BITARRAY 1 +#define EXT2FS_BMAP64_RBTREE 2 +#define EXT2FS_BMAP64_AUTODIR 3 + +/* + * Return flags for the block iterator functions + */ +#define BLOCK_CHANGED 1 +#define BLOCK_ABORT 2 +#define BLOCK_ERROR 4 +#define BLOCK_INLINE_DATA_CHANGED 8 + +/* + * Block interate flags + * + * BLOCK_FLAG_APPEND, or BLOCK_FLAG_HOLE, indicates that the interator + * function should be called on blocks where the block number is zero. + * This is used by ext2fs_expand_dir() to be able to add a new block + * to an inode. It can also be used for programs that want to be able + * to deal with files that contain "holes". + * + * BLOCK_FLAG_DEPTH_TRAVERSE indicates that the iterator function for + * the indirect, doubly indirect, etc. blocks should be called after + * all of the blocks contained in the indirect blocks are processed. + * This is useful if you are going to be deallocating blocks from an + * inode. + * + * BLOCK_FLAG_DATA_ONLY indicates that the iterator function should be + * called for data blocks only. + * + * BLOCK_FLAG_READ_ONLY is a promise by the caller that it will not + * modify returned block number. + * + * BLOCK_FLAG_NO_LARGE is for internal use only. It informs + * ext2fs_block_iterate2 that large files won't be accepted. + */ +#define BLOCK_FLAG_APPEND 1 +#define BLOCK_FLAG_HOLE 1 +#define BLOCK_FLAG_DEPTH_TRAVERSE 2 +#define BLOCK_FLAG_DATA_ONLY 4 +#define BLOCK_FLAG_READ_ONLY 8 + +#define BLOCK_FLAG_NO_LARGE 0x1000 + +/* + * Magic "block count" return values for the block iterator function. + */ +#define BLOCK_COUNT_IND (-1) +#define BLOCK_COUNT_DIND (-2) +#define BLOCK_COUNT_TIND (-3) +#define BLOCK_COUNT_TRANSLATOR (-4) + +#define BLOCK_ALLOC_UNKNOWN 0 +#define BLOCK_ALLOC_DATA 1 +#define BLOCK_ALLOC_METADATA 2 + +struct blk_alloc_ctx { + ext2_ino_t ino; + struct ext2_inode *inode; + blk64_t lblk; + int flags; +}; + +#if 0 +/* + * Flags for ext2fs_move_blocks + */ +#define EXT2_BMOVE_GET_DBLIST 0x0001 +#define EXT2_BMOVE_DEBUG 0x0002 +#endif + +/* + * Generic (non-filesystem layout specific) extents structure + */ + +#define EXT2_EXTENT_FLAGS_LEAF 0x0001 +#define EXT2_EXTENT_FLAGS_UNINIT 0x0002 +#define EXT2_EXTENT_FLAGS_SECOND_VISIT 0x0004 + +struct ext2fs_extent { + blk64_t e_pblk; /* first physical block */ + blk64_t e_lblk; /* first logical block extent covers */ + __u32 e_len; /* number of blocks covered by extent */ + __u32 e_flags; /* extent flags */ +}; + +typedef struct ext2_extent_handle *ext2_extent_handle_t; +typedef struct ext2_extent_path *ext2_extent_path_t; + +/* + * Flags used by ext2fs_extent_get() + */ +#define EXT2_EXTENT_CURRENT 0x0000 +#define EXT2_EXTENT_MOVE_MASK 0x000F +#define EXT2_EXTENT_ROOT 0x0001 +#define EXT2_EXTENT_LAST_LEAF 0x0002 +#define EXT2_EXTENT_FIRST_SIB 0x0003 +#define EXT2_EXTENT_LAST_SIB 0x0004 +#define EXT2_EXTENT_NEXT_SIB 0x0005 +#define EXT2_EXTENT_PREV_SIB 0x0006 +#define EXT2_EXTENT_NEXT_LEAF 0x0007 +#define EXT2_EXTENT_PREV_LEAF 0x0008 +#define EXT2_EXTENT_NEXT 0x0009 +#define EXT2_EXTENT_PREV 0x000A +#define EXT2_EXTENT_UP 0x000B +#define EXT2_EXTENT_DOWN 0x000C +#define EXT2_EXTENT_DOWN_AND_LAST 0x000D + +/* + * Flags used by ext2fs_extent_insert() + */ +#define EXT2_EXTENT_INSERT_AFTER 0x0001 /* insert after handle loc'n */ +#define EXT2_EXTENT_INSERT_NOSPLIT 0x0002 /* insert may not cause split */ + +/* + * Flags used by ext2fs_extent_delete() + */ +#define EXT2_EXTENT_DELETE_KEEP_EMPTY 0x001 /* keep node if last extent gone */ + +/* + * Flags used by ext2fs_extent_set_bmap() + */ +#define EXT2_EXTENT_SET_BMAP_UNINIT 0x0001 + +/* + * Data structure returned by ext2fs_extent_get_info() + */ +struct ext2_extent_info { + int curr_entry; + int curr_level; + int num_entries; + int max_entries; + int max_depth; + int bytes_avail; + blk64_t max_lblk; + blk64_t max_pblk; + __u32 max_len; + __u32 max_uninit_len; +}; + +/* + * Flags for directory block reading and writing functions + */ +#define EXT2_DIRBLOCK_V2_STRUCT 0x0001 + +/* + * Return flags for the directory iterator functions + */ +#define DIRENT_CHANGED 1 +#define DIRENT_ABORT 2 +#define DIRENT_ERROR 3 + +/* + * Directory iterator flags + */ + +#define DIRENT_FLAG_INCLUDE_EMPTY 1 +#define DIRENT_FLAG_INCLUDE_REMOVED 2 +#define DIRENT_FLAG_INCLUDE_CSUM 4 +#define DIRENT_FLAG_INCLUDE_INLINE_DATA 8 + +#define DIRENT_DOT_FILE 1 +#define DIRENT_DOT_DOT_FILE 2 +#define DIRENT_OTHER_FILE 3 +#define DIRENT_DELETED_FILE 4 +#define DIRENT_CHECKSUM 5 + +/* + * Inode scan definitions + */ +typedef struct ext2_struct_inode_scan *ext2_inode_scan; + +/* + * ext2fs_scan flags + */ +#define EXT2_SF_CHK_BADBLOCKS 0x0001 +#define EXT2_SF_BAD_INODE_BLK 0x0002 +#define EXT2_SF_BAD_EXTRA_BYTES 0x0004 +#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008 +#define EXT2_SF_DO_LAZY 0x0010 +#define EXT2_SF_WARN_GARBAGE_INODES 0x0020 + +/* + * ext2fs_check_if_mounted flags + */ +#define EXT2_MF_MOUNTED 1 +#define EXT2_MF_ISROOT 2 +#define EXT2_MF_READONLY 4 +#define EXT2_MF_SWAP 8 +#define EXT2_MF_BUSY 16 + +/* + * Ext2/linux mode flags. We define them here so that we don't need + * to depend on the OS's sys/stat.h, since we may be compiling on a + * non-Linux system. + */ +#define LINUX_S_IFMT 00170000 +#define LINUX_S_IFSOCK 0140000 +#define LINUX_S_IFLNK 0120000 +#define LINUX_S_IFREG 0100000 +#define LINUX_S_IFBLK 0060000 +#define LINUX_S_IFDIR 0040000 +#define LINUX_S_IFCHR 0020000 +#define LINUX_S_IFIFO 0010000 +#define LINUX_S_ISUID 0004000 +#define LINUX_S_ISGID 0002000 +#define LINUX_S_ISVTX 0001000 + +#define LINUX_S_IRWXU 00700 +#define LINUX_S_IRUSR 00400 +#define LINUX_S_IWUSR 00200 +#define LINUX_S_IXUSR 00100 + +#define LINUX_S_IRWXG 00070 +#define LINUX_S_IRGRP 00040 +#define LINUX_S_IWGRP 00020 +#define LINUX_S_IXGRP 00010 + +#define LINUX_S_IRWXO 00007 +#define LINUX_S_IROTH 00004 +#define LINUX_S_IWOTH 00002 +#define LINUX_S_IXOTH 00001 + +#define LINUX_S_ISLNK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK) +#define LINUX_S_ISREG(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFREG) +#define LINUX_S_ISDIR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR) +#define LINUX_S_ISCHR(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR) +#define LINUX_S_ISBLK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK) +#define LINUX_S_ISFIFO(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO) +#define LINUX_S_ISSOCK(m) (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK) + +/* + * ext2 size of an inode + */ +#define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32)) + +/* + * ext2_icount_t abstraction + */ +#define EXT2_ICOUNT_OPT_INCREMENT 0x01 +#define EXT2_ICOUNT_OPT_FULLMAP 0x02 + +typedef struct ext2_icount *ext2_icount_t; + +/* + * Flags for ext2fs_bmap + */ +#define BMAP_ALLOC 0x0001 +#define BMAP_SET 0x0002 +#define BMAP_UNINIT 0x0004 +#define BMAP_ZERO 0x0008 + +/* + * Returned flags from ext2fs_bmap + */ +#define BMAP_RET_UNINIT 0x0001 + +/* + * Flags for imager.c functions + */ +#define IMAGER_FLAG_INODEMAP 1 +#define IMAGER_FLAG_SPARSEWRITE 2 + +/* + * For checking structure magic numbers... + */ + +#define EXT2_CHECK_MAGIC(struct, code) \ + if ((struct)->magic != (code)) return (code) + +/* + * Features supported by this version of the library + */ +#define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\ + EXT2_FEATURE_COMPAT_IMAGIC_INODES|\ + EXT3_FEATURE_COMPAT_HAS_JOURNAL|\ + EXT2_FEATURE_COMPAT_RESIZE_INODE|\ + EXT2_FEATURE_COMPAT_DIR_INDEX|\ + EXT2_FEATURE_COMPAT_EXT_ATTR|\ + EXT4_FEATURE_COMPAT_SPARSE_SUPER2) + +#ifdef CONFIG_MMP +#define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP +#else +#define EXT4_LIB_INCOMPAT_MMP (0) +#endif + +#define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ + EXT2_FEATURE_INCOMPAT_META_BG|\ + EXT3_FEATURE_INCOMPAT_RECOVER|\ + EXT3_FEATURE_INCOMPAT_EXTENTS|\ + EXT4_FEATURE_INCOMPAT_FLEX_BG|\ + EXT4_FEATURE_INCOMPAT_EA_INODE|\ + EXT4_LIB_INCOMPAT_MMP|\ + EXT4_FEATURE_INCOMPAT_64BIT|\ + EXT4_FEATURE_INCOMPAT_INLINE_DATA|\ + EXT4_FEATURE_INCOMPAT_ENCRYPT|\ + EXT4_FEATURE_INCOMPAT_CSUM_SEED|\ + EXT4_FEATURE_INCOMPAT_LARGEDIR) + +#define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ + EXT4_FEATURE_RO_COMPAT_HUGE_FILE|\ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ + EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ + EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ + EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ + EXT4_FEATURE_RO_COMPAT_BIGALLOC|\ + EXT4_FEATURE_RO_COMPAT_QUOTA|\ + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ + EXT4_FEATURE_RO_COMPAT_READONLY |\ + EXT4_FEATURE_RO_COMPAT_PROJECT) + +/* + * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed + * to ext2fs_openfs() + */ +#define EXT2_LIB_SOFTSUPP_INCOMPAT (0) +#define EXT2_LIB_SOFTSUPP_RO_COMPAT (EXT4_FEATURE_RO_COMPAT_REPLICA) + + +/* Translate a block number to a cluster number */ +#define EXT2FS_CLUSTER_RATIO(fs) (1ULL << (fs)->cluster_ratio_bits) +#define EXT2FS_CLUSTER_MASK(fs) (EXT2FS_CLUSTER_RATIO(fs) - 1) +#define EXT2FS_B2C(fs, blk) ((blk) >> (fs)->cluster_ratio_bits) +/* Translate a cluster number to a block number */ +#define EXT2FS_C2B(fs, cluster) ((cluster) << (fs)->cluster_ratio_bits) +/* Translate # of blks to # of clusters */ +#define EXT2FS_NUM_B2C(fs, blks) (((blks) + EXT2FS_CLUSTER_MASK(fs)) >> \ + (fs)->cluster_ratio_bits) + +#if defined(HAVE_FSTAT64) && !defined(__OSX_AVAILABLE_BUT_DEPRECATED) +typedef struct stat64 ext2fs_struct_stat; +#else +typedef struct stat ext2fs_struct_stat; +#endif + +/* + * For ext2fs_close2() and ext2fs_flush2(), this flag allows you to + * avoid the fsync call. + */ +#define EXT2_FLAG_FLUSH_NO_SYNC 1 + +/* + * Modify and iterate extended attributes + */ +struct ext2_xattr_handle; +#define XATTR_ABORT 1 +#define XATTR_CHANGED 2 + +/* + * function prototypes + */ +static inline int ext2fs_has_group_desc_csum(ext2_filsys fs) +{ + return ext2fs_has_feature_metadata_csum(fs->super) || + ext2fs_has_feature_gdt_csum(fs->super); +} + +/* The LARGE_FILE feature should be set if we have stored files 2GB+ in size */ +static inline int ext2fs_needs_large_file_feature(unsigned long long file_size) +{ + return file_size >= 0x80000000ULL; +} + +/* alloc.c */ +extern void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group); +extern errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir, int mode, + ext2fs_inode_bitmap map, ext2_ino_t *ret); +extern errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal, + ext2fs_block_bitmap map, blk_t *ret); +extern errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret); +extern errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal, + ext2fs_block_bitmap map, blk64_t *ret, + struct blk_alloc_ctx *ctx); +extern errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, + blk_t finish, int num, + ext2fs_block_bitmap map, + blk_t *ret); +extern errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, + blk64_t finish, int num, + ext2fs_block_bitmap map, + blk64_t *ret); +extern errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal, + char *block_buf, blk_t *ret); +extern errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret); +extern errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, + char *block_buf, blk64_t *ret, + struct blk_alloc_ctx *ctx); + +extern void ext2fs_set_alloc_block_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret), + errcode_t (**old)(ext2_filsys fs, + blk64_t goal, + blk64_t *ret)); +blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk); +extern void ext2fs_set_new_range_callback(ext2_filsys fs, + errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen), + errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, blk64_t *pblk, blk64_t *plen)); +extern void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse), + void (**old)(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse)); +#define EXT2_NEWRANGE_FIXED_GOAL (0x1) +#define EXT2_NEWRANGE_MIN_LENGTH (0x2) +#define EXT2_NEWRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal, + blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk, + blk64_t *plen); +#define EXT2_ALLOCRANGE_FIXED_GOAL (0x1) +#define EXT2_ALLOCRANGE_ZERO_BLOCKS (0x2) +#define EXT2_ALLOCRANGE_ALL_FLAGS (0x3) +errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal, + blk_t len, blk64_t *ret); + +/* alloc_sb.c */ +extern int ext2fs_reserve_super_and_bgd(ext2_filsys fs, + dgrp_t group, + ext2fs_block_bitmap bmap); +extern void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs, + void (*func)(ext2_filsys fs, + blk64_t blk, + int inuse), + void (**old)(ext2_filsys fs, + blk64_t blk, + int inuse)); + +/* alloc_stats.c */ +void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse); +void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino, + int inuse, int isdir); +void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse); +void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse); +void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, + blk_t num, int inuse); + +/* alloc_tables.c */ +extern errcode_t ext2fs_allocate_tables(ext2_filsys fs); +extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, + ext2fs_block_bitmap bmap); + +/* badblocks.c */ +extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size); +extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk); +extern int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk); +extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk); +extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb, + ext2_u32_iterate *ret); +extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk); +extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter); +extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest); +extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2); + +extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, + int size); +extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, + blk_t blk); +extern int ext2fs_badblocks_list_test(ext2_badblocks_list bb, + blk_t blk); +extern int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk); +extern void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk); +extern errcode_t + ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb, + ext2_badblocks_iterate *ret); +extern int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, + blk_t *blk); +extern void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter); +extern errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src, + ext2_badblocks_list *dest); +extern int ext2fs_badblocks_equal(ext2_badblocks_list bb1, + ext2_badblocks_list bb2); +extern int ext2fs_u32_list_count(ext2_u32_list bb); + +/* bb_compat */ +extern errcode_t badblocks_list_create(badblocks_list *ret, int size); +extern errcode_t badblocks_list_add(badblocks_list bb, blk_t blk); +extern int badblocks_list_test(badblocks_list bb, blk_t blk); +extern errcode_t badblocks_list_iterate_begin(badblocks_list bb, + badblocks_iterate *ret); +extern int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk); +extern void badblocks_list_iterate_end(badblocks_iterate iter); +extern void badblocks_list_free(badblocks_list bb); + +/* bb_inode.c */ +extern errcode_t ext2fs_update_bb_inode(ext2_filsys fs, + ext2_badblocks_list bb_list); + +/* bitmaps.c */ +extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap); +extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap); +extern errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +extern errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_write_block_bitmap (ext2_filsys fs); +extern errcode_t ext2fs_read_inode_bitmap (ext2_filsys fs); +extern errcode_t ext2fs_read_block_bitmap(ext2_filsys fs); +extern errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret); +extern errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret); +extern int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap); +extern errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_inode_bitmap *ret); +extern errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap, + ext2_ino_t end, ext2_ino_t *oend); +extern errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap, + blk_t end, blk_t *oend); +extern errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap, + blk64_t end, blk64_t *oend); +extern void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap); +extern void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap); +extern errcode_t ext2fs_read_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_write_bitmaps(ext2_filsys fs); +extern errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_inode_bitmap bmap); +extern errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, + __u64 new_real_end, + ext2fs_inode_bitmap bmap); +extern errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, + ext2fs_block_bitmap bmap); +extern errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, + __u64 new_real_end, + ext2fs_block_bitmap bmap); +extern errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1, + ext2fs_block_bitmap bm2); +extern errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, + ext2fs_inode_bitmap bm2); +extern errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *in); +extern errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *in); +extern errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap, + ext2_ino_t start, unsigned int num, + void *out); +extern errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap, + __u64 start, size_t num, + void *out); +extern errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *in); +extern errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *in); +extern errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap, + blk_t start, unsigned int num, + void *out); +extern errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t start, size_t num, + void *out); + +/* blknum.c */ +extern __u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group); +extern __u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group); +extern dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t); +extern blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group); +extern int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, + struct ext2_inode *inode); +extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, + struct ext2_inode *inode); +extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super); +extern void ext2fs_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +extern blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super); +extern void ext2fs_r_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_r_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +extern blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super); +extern void ext2fs_free_blocks_count_set(struct ext2_super_block *super, + blk64_t blk); +extern void ext2fs_free_blocks_count_add(struct ext2_super_block *super, + blk64_t blk); +/* Block group descriptor accessor functions */ +extern struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, + struct opaque_ext2_group_desc *gdp, + dgrp_t group); +extern blk64_t ext2fs_block_bitmap_csum(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern __u32 ext2fs_inode_bitmap_csum(ext2_filsys fs, dgrp_t group); +extern blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group); +extern void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, + blk64_t blk); +extern __u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, + __u32 n); +extern __u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group); +extern int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag); +extern void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags); +extern void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags); +extern __u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group); +extern void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum); +extern blk64_t ext2fs_file_acl_block(ext2_filsys fs, + const struct ext2_inode *inode); +extern void ext2fs_file_acl_block_set(ext2_filsys fs, + struct ext2_inode *inode, blk64_t blk); +extern errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode, + ext2_off64_t size); + +/* block.c */ +extern errcode_t ext2fs_block_iterate(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + int blockcnt, + void *priv_data), + void *priv_data); +errcode_t ext2fs_block_iterate2(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data); +errcode_t ext2fs_block_iterate3(ext2_filsys fs, + ext2_ino_t ino, + int flags, + char *block_buf, + int (*func)(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_blk, + int ref_offset, + void *priv_data), + void *priv_data); + +/* bmap.c */ +extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, + blk_t block, blk_t *phys_blk); +extern errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, int bmap_flags, blk64_t block, + int *ret_flags, blk64_t *phys_blk); +errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t lblk, + blk64_t *pblk); + +#if 0 +/* bmove.c */ +extern errcode_t ext2fs_move_blocks(ext2_filsys fs, + ext2fs_block_bitmap reserve, + ext2fs_block_bitmap alloc_map, + int flags); +#endif + +/* check_desc.c */ +extern errcode_t ext2fs_check_desc(ext2_filsys fs); + +/* closefs.c */ +extern errcode_t ext2fs_close(ext2_filsys fs); +extern errcode_t ext2fs_close2(ext2_filsys fs, int flags); +extern errcode_t ext2fs_close_free(ext2_filsys *fs); +extern errcode_t ext2fs_flush(ext2_filsys fs); +extern errcode_t ext2fs_flush2(ext2_filsys fs, int flags); +extern int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group_block); +extern errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, + dgrp_t group, + blk64_t *ret_super_blk, + blk64_t *ret_old_desc_blk, + blk64_t *ret_new_desc_blk, + blk_t *ret_used_blks); +extern int ext2fs_super_and_bgd_loc(ext2_filsys fs, + dgrp_t group, + blk_t *ret_super_blk, + blk_t *ret_old_desc_blk, + blk_t *ret_new_desc_blk, + int *ret_meta_bg); +extern void ext2fs_update_dynamic_rev(ext2_filsys fs); + +/* crc32c.c */ +extern __u32 ext2fs_crc32_be(__u32 crc, unsigned char const *p, size_t len); +extern __u32 ext2fs_crc32c_le(__u32 crc, unsigned char const *p, size_t len); + +/* csum.c */ +extern void ext2fs_init_csum_seed(ext2_filsys fs); +extern errcode_t ext2fs_mmp_csum_set(ext2_filsys fs, struct mmp_struct *mmp); +extern int ext2fs_mmp_csum_verify(ext2_filsys, struct mmp_struct *mmp); +extern int ext2fs_verify_csum_type(ext2_filsys fs, struct ext2_super_block *sb); +extern errcode_t ext2fs_superblock_csum_set(ext2_filsys fs, + struct ext2_super_block *sb); +extern int ext2fs_superblock_csum_verify(ext2_filsys fs, + struct ext2_super_block *sb); +extern errcode_t ext2fs_ext_attr_block_csum_set(ext2_filsys fs, + ext2_ino_t inum, blk64_t block, + struct ext2_ext_attr_header *hdr); +extern int ext2fs_ext_attr_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + blk64_t block, + struct ext2_ext_attr_header *hdr); +#define EXT2_DIRENT_TAIL(block, blocksize) \ + ((struct ext2_dir_entry_tail *)(((char *)(block)) + \ + (blocksize) - sizeof(struct ext2_dir_entry_tail))) + +extern void ext2fs_initialize_dirent_tail(ext2_filsys fs, + struct ext2_dir_entry_tail *t); +extern int ext2fs_dirent_has_tail(ext2_filsys fs, + struct ext2_dir_entry *dirent); +extern int ext2fs_dirent_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern int ext2fs_dir_block_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_dir_block_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, + struct ext2_dir_entry *dirent, + struct ext2_dx_countlimit **cc, + int *offset); +extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, + ext2_ino_t inum, + struct ext3_extent_header *eh); +extern int ext2fs_extent_block_csum_verify(ext2_filsys fs, + ext2_ino_t inum, + struct ext3_extent_header *eh); +extern errcode_t ext2fs_block_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern int ext2fs_block_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern errcode_t ext2fs_inode_bitmap_csum_set(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern int ext2fs_inode_bitmap_csum_verify(ext2_filsys fs, dgrp_t group, + char *bitmap, int size); +extern errcode_t ext2fs_inode_csum_set(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode); +extern int ext2fs_inode_csum_verify(ext2_filsys fs, ext2_ino_t inum, + struct ext2_inode_large *inode); +extern void ext2fs_group_desc_csum_set(ext2_filsys fs, dgrp_t group); +extern int ext2fs_group_desc_csum_verify(ext2_filsys fs, dgrp_t group); +extern errcode_t ext2fs_set_gdt_csum(ext2_filsys fs); +extern __u16 ext2fs_group_desc_csum(ext2_filsys fs, dgrp_t group); + +/* dblist.c */ +extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist); +extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, + blk_t blk, int blockcnt); +extern errcode_t ext2fs_add_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt); +extern void ext2fs_dblist_sort(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)); +extern void ext2fs_dblist_sort2(ext2_dblist dblist, + EXT2_QSORT_TYPE (*sortfunc)(const void *, + const void *)); +extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist, + int (*func)(ext2_filsys fs, struct ext2_db_entry2 *db_info, + void *priv_data), + unsigned long long start, + unsigned long long count, + void *priv_data); +extern errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, + blk_t blk, int blockcnt); +extern errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino, + blk64_t blk, e2_blkcnt_t blockcnt); +extern errcode_t ext2fs_copy_dblist(ext2_dblist src, + ext2_dblist *dest); +extern int ext2fs_dblist_count(ext2_dblist dblist); +extern blk64_t ext2fs_dblist_count2(ext2_dblist dblist); +extern errcode_t ext2fs_dblist_get_last(ext2_dblist dblist, + struct ext2_db_entry **entry); +extern errcode_t ext2fs_dblist_get_last2(ext2_dblist dblist, + struct ext2_db_entry2 **entry); +extern errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist); + +/* dblist_dir.c */ +extern errcode_t + ext2fs_dblist_dir_iterate(ext2_dblist dblist, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); + +#if 0 +/* digest_encode.c */ +#define EXT2FS_DIGEST_SIZE EXT2FS_SHA256_LENGTH +extern int ext2fs_digest_encode(const char *src, int len, char *dst); +extern int ext2fs_digest_decode(const char *src, int len, char *dst); +#endif + +/* dirblock.c */ +extern errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags); +extern errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags); +extern errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); +extern errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block, + void *buf, int flags); +extern errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block, + void *buf, int flags); +extern errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block, + void *buf, int flags, ext2_ino_t ino); + +/* dirhash.c */ +extern errcode_t ext2fs_dirhash(int version, const char *name, int len, + const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash); + + +/* dir_iterate.c */ +extern errcode_t ext2fs_get_rec_len(ext2_filsys fs, + struct ext2_dir_entry *dirent, + unsigned int *rec_len); +extern errcode_t ext2fs_set_rec_len(ext2_filsys fs, + unsigned int len, + struct ext2_dir_entry *dirent); +extern errcode_t ext2fs_dir_iterate(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); +extern errcode_t ext2fs_dir_iterate2(ext2_filsys fs, + ext2_ino_t dir, + int flags, + char *block_buf, + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data), + void *priv_data); + +/* dupfs.c */ +extern errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest); + +/* expanddir.c */ +extern errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir); + +/* ext_attr.c */ +extern __u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, + void *data); +extern errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs, + struct ext2_ext_attr_entry *entry, + void *data, __u32 *hash); +extern errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf); +extern errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, + void *buf); +extern errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, + void *buf, ext2_ino_t inum); +extern errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, + void *buf); +extern errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, + void *buf); +extern errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, + void *buf, ext2_ino_t inum); +extern errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, + char *block_buf, + int adjust, __u32 *newcount); +extern errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk, + char *block_buf, + int adjust, __u32 *newcount); +extern errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk, + char *block_buf, + int adjust, __u32 *newcount, + ext2_ino_t inum); +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle); +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle); +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h, + int (*func)(char *name, char *value, + size_t value_len, void *data), + void *data); +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key, + void **value, size_t *value_len); +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *handle, + const char *key, + const void *value, + size_t value_len); +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle, + const char *key); +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino, + struct ext2_xattr_handle **handle); +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle); +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode); +errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count); +errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size); +#define XATTR_HANDLE_FLAG_RAW 0x0001 +errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, + unsigned int *new_flags, unsigned int *old_flags); +extern void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, + struct ext2_ext_attr_entry *end); +extern __u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash); +extern __u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode); +extern void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count); + +/* extent.c */ +extern errcode_t ext2fs_extent_header_verify(void *ptr, int size); +extern errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, + ext2_extent_handle_t *handle); +extern errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t *ret_handle); +extern void ext2fs_extent_free(ext2_extent_handle_t handle); +extern errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, + int flags, struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle); +extern errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent); +extern errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, + blk64_t logical, blk64_t physical, + int flags); +extern errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags); +extern errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, + struct ext2_extent_info *info); +extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, + blk64_t blk); +extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, + int leaf_level, blk64_t blk); +extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); +size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); + +/* fallocate.c */ +#define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) +#define EXT2_FALLOCATE_FORCE_INIT (0x2) +#define EXT2_FALLOCATE_FORCE_UNINIT (0x4) +#define EXT2_FALLOCATE_INIT_BEYOND_EOF (0x8) +#define EXT2_FALLOCATE_ALL_FLAGS (0xF) +errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, + struct ext2_inode *inode, blk64_t goal, + blk64_t start, blk64_t len); + +/* fileio.c */ +extern errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + int flags, ext2_file_t *ret); +extern errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, + int flags, ext2_file_t *ret); +extern ext2_filsys ext2fs_file_get_fs(ext2_file_t file); +struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file); +extern ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file); +extern errcode_t ext2fs_file_close(ext2_file_t file); +extern errcode_t ext2fs_file_flush(ext2_file_t file); +extern errcode_t ext2fs_file_read(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got); +extern errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written); +extern errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, + int whence, __u64 *ret_pos); +extern errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos); +errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size); +extern ext2_off_t ext2fs_file_get_size(ext2_file_t file); +extern errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size); +extern errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size); + +/* finddev.c */ +extern char *ext2fs_find_block_device(dev_t device); + +/* flushb.c */ +extern errcode_t ext2fs_sync_device(int fd, int flushb); + +/* freefs.c */ +extern void ext2fs_free(ext2_filsys fs); +extern void ext2fs_free_dblist(ext2_dblist dblist); +extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb); +extern void ext2fs_u32_list_free(ext2_u32_list bb); + +/* gen_bitmap.c */ +extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap); +extern errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, + __u32 start, __u32 end, + __u32 real_end, + const char *descr, char *init_map, + ext2fs_generic_bitmap *ret); +extern errcode_t ext2fs_allocate_generic_bitmap(__u32 start, + __u32 end, + __u32 real_end, + const char *descr, + ext2fs_generic_bitmap *ret); +extern errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +extern void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap); +extern errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap, + errcode_t magic, + errcode_t neq, + ext2_ino_t end, + ext2_ino_t *oend); +extern void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map); +extern errcode_t ext2fs_resize_generic_bitmap(errcode_t magic, + __u32 new_end, + __u32 new_real_end, + ext2fs_generic_bitmap bmap); +extern errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +extern errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *out); +extern errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *in); +extern errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out); +extern errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out); + +/* gen_bitmap64.c */ +void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap); +errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char *descr, + ext2fs_generic_bitmap *ret); +errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); +void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap); +errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend); +void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap); +errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end); +errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2); +errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *out); +errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *in); +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap); + +/* get_num_dirs.c */ +extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); + +/* getsize.c */ +extern errcode_t ext2fs_get_device_size(const char *file, int blocksize, + blk64_t *retblocks); +extern errcode_t ext2fs_get_device_size2(const char *file, int blocksize, + blk64_t *retblocks); + +/* getsectsize.c */ +extern int ext2fs_get_dio_alignment(int fd); +errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize); +errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize); + +/* i_block.c */ +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks); +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks); +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b); + +/* imager.c */ +extern errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags); +extern errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags); + +/* ind_block.c */ +errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf); +errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf); + +/* initialize.c */ +extern errcode_t ext2fs_initialize(const char *name, int flags, + struct ext2_super_block *param, + io_manager manager, ext2_filsys *ret_fs); + +/* icount.c */ +extern void ext2fs_free_icount(ext2_icount_t icount); +extern errcode_t ext2fs_create_icount_tdb(ext2_filsys fs, char *tdb_dir, + int flags, ext2_icount_t *ret); +extern errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, + unsigned int size, + ext2_icount_t hint, ext2_icount_t *ret); +extern errcode_t ext2fs_create_icount(ext2_filsys fs, int flags, + unsigned int size, + ext2_icount_t *ret); +extern errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino, + __u16 *ret); +extern errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino, + __u16 count); +extern ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount); +errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *); + +/* inline.c */ + +extern errcode_t ext2fs_get_memalign(unsigned long size, + unsigned long align, void *ptr); + +/* inline_data.c */ +extern errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino); +extern errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size); +extern errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t *size); +extern errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t size); + +/* inode.c */ +extern errcode_t ext2fs_create_inode_cache(ext2_filsys fs, + unsigned int cache_size); +extern void ext2fs_free_inode_cache(struct ext2_inode_cache *icache); +extern errcode_t ext2fs_flush_icache(ext2_filsys fs); +extern errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, + ext2_ino_t *ino, + struct ext2_inode *inode, + int bufsize); +#define EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS 8 +extern errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, + ext2_inode_scan *ret_scan); +extern void ext2fs_close_inode_scan(ext2_inode_scan scan); +extern errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode); +extern errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, + int group); +extern void ext2fs_set_inode_callback + (ext2_inode_scan scan, + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data), + void *done_group_data); +extern int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, + int clear_flags); +extern errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize); +extern errcode_t ext2fs_read_inode (ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, + int bufsize); +extern errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode); +extern errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks); +extern errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino); + +/* inode_io.c */ +extern io_manager inode_io_manager; +extern errcode_t ext2fs_inode_io_intern(ext2_filsys fs, ext2_ino_t ino, + char **name); +extern errcode_t ext2fs_inode_io_intern2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char **name); + +/* ismounted.c */ +extern errcode_t ext2fs_check_if_mounted(const char *file, int *mount_flags); +extern errcode_t ext2fs_check_mount_point(const char *device, int *mount_flags, + char *mtpt, int mtlen); + +/* punch.c */ +/* + * NOTE: This function removes from an inode the blocks "start", "end", and + * every block in between. + */ +extern errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, blk64_t start, + blk64_t end); + +/* namei.c */ +extern errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, + int namelen, char *buf, ext2_ino_t *inode); +extern errcode_t ext2fs_namei(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode); +errcode_t ext2fs_namei_follow(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + const char *name, ext2_ino_t *inode); +extern errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, + ext2_ino_t inode, ext2_ino_t *res_inode); + +/* native.c */ +int ext2fs_native_flag(void); + +/* newdir.c */ +extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, char **block); +extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, __u32 *iblock); + +/* mkdir.c */ +extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, + const char *name); + +/* mkjournal.c */ +extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, + blk_t *ret_blk, int *ret_count); +extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count); +extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, + __u32 num_blocks, int flags, + char **ret_jsb); +extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, + ext2_filsys journal_dev); +extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, + int flags); +extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, + blk64_t goal, int flags); +extern int ext2fs_default_journal_size(__u64 num_blocks); +extern int ext2fs_journal_sb_start(int blocksize); + +/* openfs.c */ +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 *ret_fs); +/* + * The dgrp_t argument to these two functions is not actually a group number + * but a block number offset within a group table! Convert with the formula + * (group_number / groups_per_block). + */ +extern blk64_t ext2fs_descriptor_block_loc2(ext2_filsys fs, + blk64_t group_block, dgrp_t i); +extern blk_t ext2fs_descriptor_block_loc(ext2_filsys fs, blk_t group_block, + dgrp_t i); +errcode_t ext2fs_get_data_io(ext2_filsys fs, io_channel *old_io); +errcode_t ext2fs_set_data_io(ext2_filsys fs, io_channel new_io); +errcode_t ext2fs_rewrite_to_io(ext2_filsys fs, io_channel new_io); + +/* get_pathname.c */ +extern errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, + char **name); + +/* link.c */ +errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags); +errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags); + +/* symlink.c */ +errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, + const char *name, const char *target); +int ext2fs_is_fast_symlink(struct ext2_inode *inode); + +/* mmp.c */ +errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf); +errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf); +errcode_t ext2fs_mmp_clear(ext2_filsys fs); +errcode_t ext2fs_mmp_init(ext2_filsys fs); +errcode_t ext2fs_mmp_start(ext2_filsys fs); +errcode_t ext2fs_mmp_update(ext2_filsys fs); +errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately); +errcode_t ext2fs_mmp_stop(ext2_filsys fs); +unsigned ext2fs_mmp_new_seq(void); + +/* read_bb.c */ +extern errcode_t ext2fs_read_bb_inode(ext2_filsys fs, + ext2_badblocks_list *bb_list); + +/* read_bb_file.c */ +extern errcode_t ext2fs_read_bb_FILE2(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void *priv_data, + void (*invalid)(ext2_filsys fs, + blk_t blk, + char *badstr, + void *priv_data)); +extern errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, + ext2_badblocks_list *bb_list, + void (*invalid)(ext2_filsys fs, + blk_t blk)); + +/* res_gdt.c */ +extern errcode_t ext2fs_create_resize_inode(ext2_filsys fs); + +/*sha256.c */ +#define EXT2FS_SHA256_LENGTH 32 +#if 0 +extern void ext2fs_sha256(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA256_LENGTH]); +#endif + +/* sha512.c */ +#define EXT2FS_SHA512_LENGTH 64 +extern void ext2fs_sha512(const unsigned char *in, unsigned long in_size, + unsigned char out[EXT2FS_SHA512_LENGTH]); + +/* swapfs.c */ +extern errcode_t ext2fs_dirent_swab_in2(ext2_filsys fs, char *buf, size_t size, + int flags); +extern errcode_t ext2fs_dirent_swab_in(ext2_filsys fs, char *buf, int flags); +extern errcode_t ext2fs_dirent_swab_out2(ext2_filsys fs, char *buf, size_t size, + int flags); +extern errcode_t ext2fs_dirent_swab_out(ext2_filsys fs, char *buf, int flags); +extern void ext2fs_swap_ext_attr(char *to, char *from, int bufsize, + int has_header); +extern void ext2fs_swap_ext_attr_header(struct ext2_ext_attr_header *to_header, + struct ext2_ext_attr_header *from_hdr); +extern void ext2fs_swap_ext_attr_entry(struct ext2_ext_attr_entry *to_entry, + struct ext2_ext_attr_entry *from_entry); +extern void ext2fs_swap_super(struct ext2_super_block * super); +extern void ext2fs_swap_group_desc(struct ext2_group_desc *gdp); +extern void ext2fs_swap_group_desc2(ext2_filsys, struct ext2_group_desc *gdp); +extern void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, + struct ext2_inode_large *f, int hostorder, + int bufsize); +extern void ext2fs_swap_inode(ext2_filsys fs,struct ext2_inode *t, + struct ext2_inode *f, int hostorder); +extern void ext2fs_swap_mmp(struct mmp_struct *mmp); + +/* unix_io.c */ +extern int ext2fs_open_file(const char *pathname, int flags, mode_t mode); +extern int ext2fs_stat(const char *path, ext2fs_struct_stat *buf); +extern int ext2fs_fstat(int fd, ext2fs_struct_stat *buf); + +/* valid_blk.c */ +extern int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode); +extern int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, + struct ext2_inode *inode); + +/* version.c */ +extern int ext2fs_parse_version_string(const char *ver_string); +extern int ext2fs_get_library_version(const char **ver_string, + const char **date_string); + +/* write_bb_file.c */ +extern errcode_t ext2fs_write_bb_FILE(ext2_badblocks_list bb_list, + unsigned int flags, + FILE *f); + + +/* inline functions */ +#ifdef NO_INLINE_FUNCS +extern errcode_t ext2fs_get_mem(unsigned long size, void *ptr); +extern errcode_t ext2fs_get_memzero(unsigned long size, void *ptr); +extern errcode_t ext2fs_get_array(unsigned long count, + unsigned long size, void *ptr); +extern errcode_t ext2fs_get_arrayzero(unsigned long count, + unsigned long size, void *ptr); +extern errcode_t ext2fs_free_mem(void *ptr); +extern errcode_t ext2fs_resize_mem(unsigned long old_size, + unsigned long size, void *ptr); +extern void ext2fs_mark_super_dirty(ext2_filsys fs); +extern void ext2fs_mark_changed(ext2_filsys fs); +extern int ext2fs_test_changed(ext2_filsys fs); +extern void ext2fs_mark_valid(ext2_filsys fs); +extern void ext2fs_unmark_valid(ext2_filsys fs); +extern int ext2fs_test_valid(ext2_filsys fs); +extern void ext2fs_mark_ib_dirty(ext2_filsys fs); +extern void ext2fs_mark_bb_dirty(ext2_filsys fs); +extern int ext2fs_test_ib_dirty(ext2_filsys fs); +extern int ext2fs_test_bb_dirty(ext2_filsys fs); +extern dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk); +extern dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino); +extern blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group); +extern blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group); +extern blk_t ext2fs_inode_data_blocks(ext2_filsys fs, + struct ext2_inode *inode); +extern unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b); +extern __u64 ext2fs_div64_ceil(__u64 a, __u64 b); +extern int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len); +extern int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry); +extern void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type); +extern struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode); +extern const struct ext2_inode *ext2fs_const_inode(const struct ext2_inode_large * large_inode); + +#endif + +/* + * The actual inlined functions definitions themselves... + * + * If NO_INLINE_FUNCS is defined, then we won't try to do inline + * functions at all! + */ +#if (defined(INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) +#ifdef INCLUDE_INLINE_FUNCS +#ifdef _MSC_VER +#define _INLINE_ __inline +#else +#define _INLINE_ extern +#endif +#else +#if (__STDC_VERSION__ >= 199901L) +#define _INLINE_ inline +#else +#ifdef __GNUC__ +#define _INLINE_ extern __inline__ +#else /* For Watcom C */ +#define _INLINE_ extern inline +#endif /* __GNUC__ */ +#endif /* __STDC_VERSION__ >= 199901L */ +#endif + +#ifndef EXT2_CUSTOM_MEMORY_ROUTINES +#include +/* + * Allocate memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_get_mem(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &pp, sizeof (pp)); + return 0; +} + +_INLINE_ errcode_t ext2fs_get_memzero(unsigned long size, void *ptr) +{ + void *pp; + + pp = malloc(size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memset(pp, 0, size); + memcpy(ptr, &pp, sizeof(pp)); + return 0; +} + +_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) +{ + if (count && (~0UL)/count < size) + return EXT2_ET_NO_MEMORY; + return ext2fs_get_mem(count*size, ptr); +} + +_INLINE_ errcode_t ext2fs_get_arrayzero(unsigned long count, + unsigned long size, void *ptr) +{ + void *pp; + + if (count && (~0UL)/count < size) + return EXT2_ET_NO_MEMORY; + pp = calloc(count, size); + if (!pp) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &pp, sizeof(pp)); + return 0; +} + +/* + * Free memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_free_mem(void *ptr) +{ + void *p; + + memcpy(&p, ptr, sizeof(p)); + free(p); + p = 0; + memcpy(ptr, &p, sizeof(p)); + return 0; +} + +/* + * Resize memory. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_size, + unsigned long size, void *ptr) +{ + void *p; + + /* Use "memcpy" for pointer assignments here to avoid problems + * with C99 strict type aliasing rules. */ + memcpy(&p, ptr, sizeof(p)); + p = realloc(p, size); + if (!p) + return EXT2_ET_NO_MEMORY; + memcpy(ptr, &p, sizeof(p)); + return 0; +} +#endif /* Custom memory routines */ + +/* + * Mark a filesystem superblock as dirty + */ +_INLINE_ void ext2fs_mark_super_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Mark a filesystem as changed + */ +_INLINE_ void ext2fs_mark_changed(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_CHANGED; +} + +/* + * Check to see if a filesystem has changed + */ +_INLINE_ int ext2fs_test_changed(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_CHANGED); +} + +/* + * Mark a filesystem as valid + */ +_INLINE_ void ext2fs_mark_valid(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_VALID; +} + +/* + * Mark a filesystem as NOT valid + */ +_INLINE_ void ext2fs_unmark_valid(ext2_filsys fs) +{ + fs->flags &= ~EXT2_FLAG_VALID; +} + +/* + * Check to see if a filesystem is valid + */ +_INLINE_ int ext2fs_test_valid(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_VALID); +} + +/* + * Mark the inode bitmap as dirty + */ +_INLINE_ void ext2fs_mark_ib_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_IB_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Mark the block bitmap as dirty + */ +_INLINE_ void ext2fs_mark_bb_dirty(ext2_filsys fs) +{ + fs->flags |= EXT2_FLAG_BB_DIRTY | EXT2_FLAG_CHANGED; +} + +/* + * Check to see if a filesystem's inode bitmap is dirty + */ +_INLINE_ int ext2fs_test_ib_dirty(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_IB_DIRTY); +} + +/* + * Check to see if a filesystem's block bitmap is dirty + */ +_INLINE_ int ext2fs_test_bb_dirty(ext2_filsys fs) +{ + return (fs->flags & EXT2_FLAG_BB_DIRTY); +} + +/* + * Return the group # of a block + */ +_INLINE_ dgrp_t ext2fs_group_of_blk(ext2_filsys fs, blk_t blk) +{ + return ext2fs_group_of_blk2(fs, blk); +} +/* + * Return the group # of an inode number + */ +_INLINE_ dgrp_t ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) +{ + return (ino - 1) / fs->super->s_inodes_per_group; +} + +/* + * Return the first block (inclusive) in a group + */ +_INLINE_ blk_t ext2fs_group_first_block(ext2_filsys fs, dgrp_t group) +{ + return (blk_t) ext2fs_group_first_block2(fs, group); +} + +/* + * Return the last block (inclusive) in a group + */ +_INLINE_ blk_t ext2fs_group_last_block(ext2_filsys fs, dgrp_t group) +{ + return (blk_t) ext2fs_group_last_block2(fs, group); +} + +_INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs, + struct ext2_inode *inode) +{ + return (blk_t) ext2fs_inode_data_blocks2(fs, inode); +} + +/* htree levels for ext4 */ +#define EXT4_HTREE_LEVEL_COMPAT 2 +#define EXT4_HTREE_LEVEL 3 + +static inline unsigned int ext2_dir_htree_level(ext2_filsys fs) +{ + if (ext2fs_has_feature_largedir(fs->super)) + return EXT4_HTREE_LEVEL; + + return EXT4_HTREE_LEVEL_COMPAT; +} + +_INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks) +{ + return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry)); +} + +/* + * This is an efficient, overflow safe way of calculating ceil((1.0 * a) / b) + */ +_INLINE_ unsigned int ext2fs_div_ceil(unsigned int a, unsigned int b) +{ + if (!a) + return 0; + return ((a - 1) / b) + 1; +} + +_INLINE_ __u64 ext2fs_div64_ceil(__u64 a, __u64 b) +{ + if (!a) + return 0; + return ((a - 1) / b) + 1; +} + +_INLINE_ int ext2fs_dirent_name_len(const struct ext2_dir_entry *entry) +{ + return entry->name_len & 0xff; +} + +_INLINE_ void ext2fs_dirent_set_name_len(struct ext2_dir_entry *entry, int len) +{ + entry->name_len = (entry->name_len & 0xff00) | (len & 0xff); +} + +_INLINE_ int ext2fs_dirent_file_type(const struct ext2_dir_entry *entry) +{ + return entry->name_len >> 8; +} + +_INLINE_ void ext2fs_dirent_set_file_type(struct ext2_dir_entry *entry, int type) +{ + entry->name_len = (entry->name_len & 0xff) | (type << 8); +} + +_INLINE_ struct ext2_inode *ext2fs_inode(struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (struct ext2_inode *) large_inode; +} + +_INLINE_ const struct ext2_inode * +ext2fs_const_inode(const struct ext2_inode_large * large_inode) +{ + /* It is always safe to convert large inode to a small inode */ + return (const struct ext2_inode *) large_inode; +} + +#undef _INLINE_ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _EXT2FS_EXT2FS_H */ diff --git a/src/ext2fs/ext2fsP.h b/src/ext2fs/ext2fsP.h new file mode 100644 index 00000000..fd5b4b1a --- /dev/null +++ b/src/ext2fs/ext2fsP.h @@ -0,0 +1,191 @@ +/* + * ext2fsP.h --- private header file for ext2 library + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#if HAVE_SYS_STAT_H +#include +#endif + +#include "ext2fs.h" + +#define EXT2FS_MAX_NESTED_LINKS 8 + +static inline int ext2fsP_is_disk_device(mode_t mode) +{ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + return S_ISBLK(mode) || S_ISCHR(mode); +#else + return S_ISBLK(mode); +#endif +} + +/* + * Badblocks list + */ +struct ext2_struct_u32_list { + int magic; + int num; + int size; + __u32 *list; + int badblocks_flags; +}; + +struct ext2_struct_u32_iterate { + int magic; + ext2_u32_list bb; + int ptr; +}; + + +/* + * Directory block iterator definition + */ +struct ext2_struct_dblist { + int magic; + ext2_filsys fs; + unsigned long long size; + unsigned long long count; + int sorted; + struct ext2_db_entry2 * list; +}; + +/* + * For directory iterators + */ +struct dir_context { + ext2_ino_t dir; + int flags; + char *buf; + unsigned int buflen; + int (*func)(ext2_ino_t dir, + int entry, + struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data); + void *priv_data; + errcode_t errcode; +}; + +/* + * Inode cache structure + */ +struct ext2_inode_cache { + void * buffer; + blk64_t buffer_blk; + int cache_last; + unsigned int cache_size; + int refcount; + struct ext2_inode_cache_ent *cache; +}; + +struct ext2_inode_cache_ent { + ext2_ino_t ino; + struct ext2_inode *inode; +}; + +/* Function prototypes */ + +extern int ext2fs_process_dir_block(ext2_filsys fs, + blk64_t *blocknr, + e2_blkcnt_t blockcnt, + blk64_t ref_block, + int ref_offset, + void *priv_data); + +extern errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino); +extern errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino); +extern int ext2fs_inline_data_dir_iterate(ext2_filsys fs, + ext2_ino_t ino, + void *priv_data); + +/* Generic numeric progress meter */ + +struct ext2fs_numeric_progress_struct { + __u64 max; + int log_max; + int skip_progress; +}; + +/* + * progress callback functions + */ +struct ext2fs_progress_ops { + void (*init)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *label, __u64 max); + void (*update)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + __u64 val); + void (*close)(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *message); +}; + +extern struct ext2fs_progress_ops ext2fs_numeric_progress_ops; + +extern void ext2fs_numeric_progress_init(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *label, __u64 max); +extern void ext2fs_numeric_progress_update(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + __u64 val); +extern void ext2fs_numeric_progress_close(ext2_filsys fs, + struct ext2fs_numeric_progress_struct * progress, + const char *message); + +/* + * 64-bit bitmap support + */ + +extern errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char * description, + ext2fs_generic_bitmap *bmap); + +extern void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap); + +extern errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest); + +extern errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end); +extern errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend); +extern int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg); +extern errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int num, + void *in); +extern errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bitmap, + __u64 start, unsigned int num, + void *out); +extern void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap,const char *func); + +extern int ext2fs_mem_is_zero(const char *mem, size_t len); + +extern int ext2fs_file_block_offset_too_big(ext2_filsys fs, + struct ext2_inode *inode, + blk64_t offset); + +/* atexit support */ +typedef void (*ext2_exit_fn)(void *); +errcode_t ext2fs_add_exit_fn(ext2_exit_fn fn, void *data); +errcode_t ext2fs_remove_exit_fn(ext2_exit_fn fn, void *data); + +#define EXT2FS_BUILD_BUG_ON(cond) ((void)sizeof(char[1 - 2*!!(cond)])) diff --git a/src/ext2fs/ext3_extents.h b/src/ext2fs/ext3_extents.h new file mode 100644 index 00000000..309fbc8c --- /dev/null +++ b/src/ext2fs/ext3_extents.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2003,2004 Cluster File Systems, Inc, info@clusterfs.com + * Written by Alex Tomas + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _LINUX_EXT3_EXTENTS +#define _LINUX_EXT3_EXTENTS + +/* + * ext3_inode has i_block array (total 60 bytes) + * first 4 bytes are used to store: + * - tree depth (0 mean there is no tree yet. all extents in the inode) + * - number of alive extents in the inode + */ + +/* + * This is extent tail on-disk structure. + * All other extent structures are 12 bytes long. It turns out that + * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which + * covers all valid ext4 block sizes. Therefore, this tail structure can be + * crammed into the end of the block without having to rebalance the tree. + */ +struct ext3_extent_tail { + __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ +}; + +/* + * this is extent on-disk structure + * it's used at the bottom of the tree + */ +struct ext3_extent { + __le32 ee_block; /* first logical block extent covers */ + __le16 ee_len; /* number of blocks covered by extent */ + __le16 ee_start_hi; /* high 16 bits of physical block */ + __le32 ee_start; /* low 32 bigs of physical block */ +}; + +/* + * this is index on-disk structure + * it's used at all the levels, but the bottom + */ +struct ext3_extent_idx { + __le32 ei_block; /* index covers logical blocks from 'block' */ + __le32 ei_leaf; /* pointer to the physical block of the next * + * level. leaf or next index could bet here */ + __le16 ei_leaf_hi; /* high 16 bits of physical block */ + __le16 ei_unused; +}; + +/* + * each block (leaves and indexes), even inode-stored has header + */ +struct ext3_extent_header { + __le16 eh_magic; /* probably will support different formats */ + __le16 eh_entries; /* number of valid entries */ + __le16 eh_max; /* capacity of store in entries */ + __le16 eh_depth; /* has tree real underlying blocks? */ + __le32 eh_generation; /* generation of the tree */ +}; + +#define EXT3_EXT_MAGIC 0xf30a + +/* + * array of ext3_ext_path contains path to some extent + * creation/lookup routines use it for traversal/splitting/etc + * truncate uses it to simulate recursive walking + */ +struct ext3_ext_path { + __u32 p_block; + __u16 p_depth; + struct ext3_extent *p_ext; + struct ext3_extent_idx *p_idx; + struct ext3_extent_header *p_hdr; + struct buffer_head *p_bh; +}; + +/* + * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an + * initialized extent. This is 2^15 and not (2^16 - 1), since we use the + * MSB of ee_len field in the extent datastructure to signify if this + * particular extent is an initialized extent or an uninitialized (i.e. + * preallocated). + * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an + * uninitialized extent. + * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an + * uninitialized one. In other words, if MSB of ee_len is set, it is an + * uninitialized extent with only one special scenario when ee_len = 0x8000. + * In this case we can not have an uninitialized extent of zero length and + * thus we make it as a special case of initialized extent with 0x8000 length. + * This way we get better extent-to-group alignment for initialized extents. + * Hence, the maximum number of blocks we can have in an *initialized* + * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). + */ +#define EXT_INIT_MAX_LEN (1UL << 15) +#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) +#define EXT_MAX_EXTENT_LBLK (((__u64) 1 << 32) - 1) +#define EXT_MAX_EXTENT_PBLK (((__u64) 1 << 48) - 1) + +#define EXT_FIRST_EXTENT(__hdr__) \ + ((struct ext3_extent *) (((char *) (__hdr__)) + \ + sizeof(struct ext3_extent_header))) +#define EXT_FIRST_INDEX(__hdr__) \ + ((struct ext3_extent_idx *) (((char *) (__hdr__)) + \ + sizeof(struct ext3_extent_header))) +#define EXT_HAS_FREE_INDEX(__path__) \ + (ext2fs_le16_to_cpu((__path__)->p_hdr->eh_entries) < \ + ext2fs_le16_to_cpu((__path__)->p_hdr->eh_max)) +#define EXT_LAST_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_LAST_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_entries) - 1) +#define EXT_MAX_EXTENT(__hdr__) \ + (EXT_FIRST_EXTENT((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_max) - 1) +#define EXT_MAX_INDEX(__hdr__) \ + (EXT_FIRST_INDEX((__hdr__)) + \ + ext2fs_le16_to_cpu((__hdr__)->eh_max) - 1) + +#endif /* _LINUX_EXT3_EXTENTS */ + diff --git a/src/ext2fs/ext4_acl.h b/src/ext2fs/ext4_acl.h new file mode 100644 index 00000000..69ff79d5 --- /dev/null +++ b/src/ext2fs/ext4_acl.h @@ -0,0 +1,55 @@ +/* + * Ext4's on-disk acl format. From linux/fs/ext4/acl.h + */ + +#define EXT4_ACL_VERSION 0x0001 + +/* 23.2.5 acl_tag_t values */ + +#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) + +/* 23.3.6 acl_type_t values */ + +#define ACL_TYPE_ACCESS (0x8000) +#define ACL_TYPE_DEFAULT (0x4000) + +/* 23.2.7 ACL qualifier constants */ + +#define ACL_UNDEFINED_ID ((id_t)-1) + +typedef struct { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; + } ext4_acl_entry; + +typedef struct { + __le16 e_tag; + __le16 e_perm; +} ext4_acl_entry_short; + +typedef struct { + __le32 a_version; +} ext4_acl_header; + + +/* Supported ACL a_version fields */ + #define POSIX_ACL_XATTR_VERSION 0x0002 + +typedef struct { + __le16 e_tag; + __le16 e_perm; + __le32 e_id; +} posix_acl_xattr_entry; + +typedef struct { + __le32 a_version; + posix_acl_xattr_entry a_entries[0]; +} posix_acl_xattr_header; + diff --git a/src/ext2fs/ext_attr.c b/src/ext2fs/ext_attr.c new file mode 100644 index 00000000..536e387e --- /dev/null +++ b/src/ext2fs/ext_attr.c @@ -0,0 +1,1716 @@ +/* + * ext_attr.c --- extended attribute blocks + * + * Copyright (C) 2001 Andreas Gruenbacher, + * + * Copyright (C) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2_ext_attr.h" +#include "ext4_acl.h" + +#include "ext2fs.h" + +static errcode_t read_ea_inode_hash(ext2_filsys fs, ext2_ino_t ino, __u32 *hash) +{ + struct ext2_inode inode; + errcode_t retval; + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + *hash = ext2fs_get_ea_inode_hash(&inode); + return 0; +} + +#define NAME_HASH_SHIFT 5 +#define VALUE_HASH_SHIFT 16 + +/* + * ext2_xattr_hash_entry() + * + * Compute the hash of an extended attribute. + */ +__u32 ext2fs_ext_attr_hash_entry(struct ext2_ext_attr_entry *entry, void *data) +{ + __u32 hash = 0; + char *name = ((char *) entry) + sizeof(struct ext2_ext_attr_entry); + int n; + + for (n = 0; n < entry->e_name_len; n++) { + hash = (hash << NAME_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ + *name++; + } + + /* The hash needs to be calculated on the data in little-endian. */ + if (entry->e_value_inum == 0 && entry->e_value_size != 0) { + __u32 *value = (__u32 *)data; + for (n = (entry->e_value_size + EXT2_EXT_ATTR_ROUND) >> + EXT2_EXT_ATTR_PAD_BITS; n; n--) { + hash = (hash << VALUE_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ + ext2fs_le32_to_cpu(*value++); + } + } + + return hash; +} + +/* + * ext2fs_ext_attr_hash_entry2() + * + * Compute the hash of an extended attribute. + * This version of the function supports hashing entries that reference + * external inodes (ea_inode feature). + */ +errcode_t ext2fs_ext_attr_hash_entry2(ext2_filsys fs, + struct ext2_ext_attr_entry *entry, + void *data, __u32 *hash) +{ + *hash = ext2fs_ext_attr_hash_entry(entry, data); + + if (entry->e_value_inum) { + __u32 ea_inode_hash; + errcode_t retval; + + retval = read_ea_inode_hash(fs, entry->e_value_inum, + &ea_inode_hash); + if (retval) + return retval; + + *hash = (*hash << VALUE_HASH_SHIFT) ^ + (*hash >> (8*sizeof(*hash) - VALUE_HASH_SHIFT)) ^ + ea_inode_hash; + } + return 0; +} + +#undef NAME_HASH_SHIFT +#undef VALUE_HASH_SHIFT + +#define BLOCK_HASH_SHIFT 16 + +/* Mirrors ext4_xattr_rehash() implementation in kernel. */ +void ext2fs_ext_attr_block_rehash(struct ext2_ext_attr_header *header, + struct ext2_ext_attr_entry *end) +{ + struct ext2_ext_attr_entry *here; + __u32 hash = 0; + + here = (struct ext2_ext_attr_entry *)(header+1); + while (here < end && !EXT2_EXT_IS_LAST_ENTRY(here)) { + if (!here->e_hash) { + /* Block is not shared if an entry's hash value == 0 */ + hash = 0; + break; + } + hash = (hash << BLOCK_HASH_SHIFT) ^ + (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ + here->e_hash; + here = EXT2_EXT_ATTR_NEXT(here); + } + header->h_hash = hash; +} + +#undef BLOCK_HASH_SHIFT + +__u32 ext2fs_get_ea_inode_hash(struct ext2_inode *inode) +{ + return inode->i_atime; +} + +void ext2fs_set_ea_inode_hash(struct ext2_inode *inode, __u32 hash) +{ + inode->i_atime = hash; +} + +__u64 ext2fs_get_ea_inode_ref(struct ext2_inode *inode) +{ + return ((__u64)inode->i_ctime << 32) | inode->osd1.linux1.l_i_version; +} + +void ext2fs_set_ea_inode_ref(struct ext2_inode *inode, __u64 ref_count) +{ + inode->i_ctime = (__u32)(ref_count >> 32); + inode->osd1.linux1.l_i_version = (__u32)ref_count; +} + +static errcode_t check_ext_attr_header(struct ext2_ext_attr_header *header) +{ + if ((header->h_magic != EXT2_EXT_ATTR_MAGIC_v1 && + header->h_magic != EXT2_EXT_ATTR_MAGIC) || + header->h_blocks != 1) + return EXT2_ET_BAD_EA_HEADER; + + return 0; +} + +errcode_t ext2fs_read_ext_attr3(ext2_filsys fs, blk64_t block, void *buf, + ext2_ino_t inum) +{ + int csum_failed = 0; + errcode_t retval; + + retval = io_channel_read_blk64(fs->io, block, 1, buf); + if (retval) + return retval; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_ext_attr_block_csum_verify(fs, inum, block, buf)) + csum_failed = 1; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_ext_attr(buf, buf, fs->blocksize, 1); +#endif + + retval = check_ext_attr_header(buf); + if (retval == 0 && csum_failed) + retval = EXT2_ET_EXT_ATTR_CSUM_INVALID; + + return retval; +} + +errcode_t ext2fs_read_ext_attr2(ext2_filsys fs, blk64_t block, void *buf) +{ + return ext2fs_read_ext_attr3(fs, block, buf, 0); +} + +errcode_t ext2fs_read_ext_attr(ext2_filsys fs, blk_t block, void *buf) +{ + return ext2fs_read_ext_attr2(fs, block, buf); +} + +errcode_t ext2fs_write_ext_attr3(ext2_filsys fs, blk64_t block, void *inbuf, + ext2_ino_t inum) +{ + errcode_t retval; + char *write_buf; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_get_mem(fs->blocksize, &write_buf); + if (retval) + return retval; + ext2fs_swap_ext_attr(write_buf, inbuf, fs->blocksize, 1); +#else + write_buf = (char *) inbuf; +#endif + + retval = ext2fs_ext_attr_block_csum_set(fs, inum, block, + (struct ext2_ext_attr_header *)write_buf); + if (retval) + return retval; + + retval = io_channel_write_blk64(fs->io, block, 1, write_buf); +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&write_buf); +#endif + if (!retval) + ext2fs_mark_changed(fs); + return retval; +} + +errcode_t ext2fs_write_ext_attr2(ext2_filsys fs, blk64_t block, void *inbuf) +{ + return ext2fs_write_ext_attr3(fs, block, inbuf, 0); +} + +errcode_t ext2fs_write_ext_attr(ext2_filsys fs, blk_t block, void *inbuf) +{ + return ext2fs_write_ext_attr2(fs, block, inbuf); +} + +/* + * This function adjusts the reference count of the EA block. + */ +errcode_t ext2fs_adjust_ea_refcount3(ext2_filsys fs, blk64_t blk, + char *block_buf, int adjust, + __u32 *newcount, ext2_ino_t inum) +{ + errcode_t retval; + struct ext2_ext_attr_header *header; + char *buf = 0; + + if ((blk >= ext2fs_blocks_count(fs->super)) || + (blk < fs->super->s_first_data_block)) + return EXT2_ET_BAD_EA_BLOCK_NUM; + + if (!block_buf) { + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + retval = ext2fs_read_ext_attr3(fs, blk, block_buf, inum); + if (retval) + goto errout; + + header = (struct ext2_ext_attr_header *) block_buf; + header->h_refcount += adjust; + if (newcount) + *newcount = header->h_refcount; + + retval = ext2fs_write_ext_attr3(fs, blk, block_buf, inum); + if (retval) + goto errout; + +errout: + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_adjust_ea_refcount2(ext2_filsys fs, blk64_t blk, + char *block_buf, int adjust, + __u32 *newcount) +{ + return ext2fs_adjust_ea_refcount3(fs, blk, block_buf, adjust, + newcount, 0); +} + +errcode_t ext2fs_adjust_ea_refcount(ext2_filsys fs, blk_t blk, + char *block_buf, int adjust, + __u32 *newcount) +{ + return ext2fs_adjust_ea_refcount2(fs, blk, block_buf, adjust, + newcount); +} + +/* Manipulate the contents of extended attribute regions */ +struct ext2_xattr { + char *name; + void *value; + unsigned int value_len; + ext2_ino_t ea_ino; +}; + +struct ext2_xattr_handle { + errcode_t magic; + ext2_filsys fs; + struct ext2_xattr *attrs; + int capacity; + int count; + int ibody_count; + ext2_ino_t ino; + unsigned int flags; +}; + +static errcode_t ext2fs_xattrs_expand(struct ext2_xattr_handle *h, + unsigned int expandby) +{ + struct ext2_xattr *new_attrs; + errcode_t err; + + err = ext2fs_get_arrayzero(h->capacity + expandby, + sizeof(struct ext2_xattr), &new_attrs); + if (err) + return err; + + memcpy(new_attrs, h->attrs, h->capacity * sizeof(struct ext2_xattr)); + ext2fs_free_mem(&h->attrs); + h->capacity += expandby; + h->attrs = new_attrs; + + return 0; +} + +struct ea_name_index { + int index; + const char *name; +}; + +/* Keep these names sorted in order of decreasing specificity. */ +static struct ea_name_index ea_names[] = { + {3, "system.posix_acl_default"}, + {2, "system.posix_acl_access"}, + {8, "system.richacl"}, + {6, "security."}, + {4, "trusted."}, + {7, "system."}, + {1, "user."}, + {0, NULL}, +}; + +static const char *find_ea_prefix(int index) +{ + struct ea_name_index *e; + + for (e = ea_names; e->name; e++) + if (e->index == index) + return e->name; + + return NULL; +} + +static int find_ea_index(const char *fullname, char **name, int *index) +{ + struct ea_name_index *e; + + for (e = ea_names; e->name; e++) { + if (strncmp(fullname, e->name, strlen(e->name)) == 0) { + *name = (char *)fullname + strlen(e->name); + *index = e->index; + return 1; + } + } + return 0; +} + +errcode_t ext2fs_free_ext_attr(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_header *header; + void *block_buf = NULL; + blk64_t blk; + errcode_t err; + struct ext2_inode_large i; + + /* Read inode? */ + if (inode == NULL) { + err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&i, + sizeof(struct ext2_inode_large)); + if (err) + return err; + inode = &i; + } + + /* Do we already have an EA block? */ + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (blk == 0) + return 0; + + /* Find block, zero it, write back */ + if ((blk < fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out2; + } + + header->h_refcount--; + err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* Erase link to block */ + ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, 0); + if (header->h_refcount == 0) + ext2fs_block_alloc_stats2(fs, blk, -1); + err = ext2fs_iblk_sub_blocks(fs, (struct ext2_inode *)inode, 1); + if (err) + goto out2; + + /* Write inode? */ + if (inode == &i) { + err = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&i, + sizeof(struct ext2_inode_large)); + if (err) + goto out2; + } + +out2: + ext2fs_free_mem(&block_buf); +out: + return err; +} + +static errcode_t prep_ea_block_for_write(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode_large *inode) +{ + struct ext2_ext_attr_header *header; + void *block_buf = NULL; + blk64_t blk, goal; + errcode_t err; + + /* Do we already have an EA block? */ + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (blk != 0) { + if ((blk < fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out2; + } + + /* Single-user block. We're done here. */ + if (header->h_refcount == 1) + goto out2; + + /* We need to CoW the block. */ + header->h_refcount--; + err = ext2fs_write_ext_attr3(fs, blk, block_buf, ino); + if (err) + goto out2; + } else { + /* No block, we must increment i_blocks */ + err = ext2fs_iblk_add_blocks(fs, (struct ext2_inode *)inode, + 1); + if (err) + goto out; + } + + /* Allocate a block */ + goal = ext2fs_find_inode_goal(fs, ino, (struct ext2_inode *)inode, 0); + err = ext2fs_alloc_block2(fs, goal, NULL, &blk); + if (err) + goto out2; + ext2fs_file_acl_block_set(fs, (struct ext2_inode *)inode, blk); +out2: + if (block_buf) + ext2fs_free_mem(&block_buf); +out: + return err; +} + + +static inline int +posix_acl_xattr_count(size_t size) +{ + if (size < sizeof(posix_acl_xattr_header)) + return -1; + size -= sizeof(posix_acl_xattr_header); + if (size % sizeof(posix_acl_xattr_entry)) + return -1; + return size / sizeof(posix_acl_xattr_entry); +} + +/* + * The lgetxattr function returns data formatted in the POSIX extended + * attribute format. The on-disk format uses a more compact encoding. + * See the ext4_acl_to_disk in fs/ext4/acl.c. + */ +static errcode_t convert_posix_acl_to_disk_buffer(const void *value, size_t size, + void *out_buf, size_t *size_out) +{ + posix_acl_xattr_header *header = (posix_acl_xattr_header*) value; + posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end; + ext4_acl_header *ext_acl; + size_t s; + char *e; + + int count; + + if (!value) + return EINVAL; + if (size < sizeof(posix_acl_xattr_header)) + return ENOMEM; + if (header->a_version != ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION)) + return EINVAL; + + count = posix_acl_xattr_count(size); + ext_acl = out_buf; + ext_acl->a_version = ext2fs_cpu_to_le32(EXT4_ACL_VERSION); + + if (count <= 0) + return EINVAL; + + e = (char *) out_buf + sizeof(ext4_acl_header); + s = sizeof(ext4_acl_header); + for (end = entry + count; entry != end;entry++) { + ext4_acl_entry *disk_entry = (ext4_acl_entry*) e; + disk_entry->e_tag = ext2fs_cpu_to_le16(entry->e_tag); + disk_entry->e_perm = ext2fs_cpu_to_le16(entry->e_perm); + + switch(entry->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + e += sizeof(ext4_acl_entry_short); + s += sizeof(ext4_acl_entry_short); + break; + case ACL_USER: + case ACL_GROUP: + disk_entry->e_id = ext2fs_cpu_to_le32(entry->e_id); + e += sizeof(ext4_acl_entry); + s += sizeof(ext4_acl_entry); + break; + } + } + *size_out = s; + return 0; +} + +static errcode_t convert_disk_buffer_to_posix_acl(const char *value, size_t size, + void **out_buf, size_t *size_out) +{ + posix_acl_xattr_header *header; + posix_acl_xattr_entry *entry; + ext4_acl_header *ext_acl = (ext4_acl_header *) value; + errcode_t err; + const char *cp; + char *out; + + if ((!value) || + (size < sizeof(ext4_acl_header)) || + (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION))) + return EINVAL; + + err = ext2fs_get_mem(size * 2, &out); + if (err) + return err; + + header = (posix_acl_xattr_header *) out; + header->a_version = ext2fs_cpu_to_le32(POSIX_ACL_XATTR_VERSION); + entry = (posix_acl_xattr_entry *) (out + sizeof(posix_acl_xattr_header)); + + cp = value + sizeof(ext4_acl_header); + size -= sizeof(ext4_acl_header); + + while (size > 0) { + const ext4_acl_entry *disk_entry = (const ext4_acl_entry *) cp; + + entry->e_tag = ext2fs_le16_to_cpu(disk_entry->e_tag); + entry->e_perm = ext2fs_le16_to_cpu(disk_entry->e_perm); + + switch(entry->e_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + entry->e_id = 0; + cp += sizeof(ext4_acl_entry_short); + size -= sizeof(ext4_acl_entry_short); + break; + case ACL_USER: + case ACL_GROUP: + entry->e_id = ext2fs_le32_to_cpu(disk_entry->e_id); + cp += sizeof(ext4_acl_entry); + size -= sizeof(ext4_acl_entry); + break; + default: + ext2fs_free_mem(&out); + return EINVAL; + break; + } + entry++; + } + *out_buf = out; + *size_out = ((char *) entry - out); + return 0; +} + +static errcode_t +write_xattrs_to_buffer(ext2_filsys fs, struct ext2_xattr *attrs, int count, + char *entries_start, unsigned int storage_size, + unsigned int value_offset_correction, int write_hash) +{ + struct ext2_xattr *x; + struct ext2_ext_attr_entry *e = (struct ext2_ext_attr_entry *) entries_start; + char *end = entries_start + storage_size; + char *shortname; + unsigned int value_size; + int idx, ret; + errcode_t err; + + memset(entries_start, 0, storage_size); + for (x = attrs; x < attrs + count; x++) { + /* Calculate index and shortname position */ + shortname = x->name; + ret = find_ea_index(x->name, &shortname, &idx); + + /* Calculate value size */ + value_size = ((x->value_len + EXT2_EXT_ATTR_PAD - 1) / + EXT2_EXT_ATTR_PAD) * EXT2_EXT_ATTR_PAD; + + /* Fill out e appropriately */ + e->e_name_len = strlen(shortname); + e->e_name_index = (ret ? idx : 0); + + e->e_value_size = x->value_len; + e->e_value_inum = x->ea_ino; + + /* Store name */ + memcpy((char *)e + sizeof(*e), shortname, e->e_name_len); + if (x->ea_ino) { + e->e_value_offs = 0; + } else { + end -= value_size; + e->e_value_offs = end - entries_start + + value_offset_correction; + memcpy(end, x->value, e->e_value_size); + } + + if (write_hash || x->ea_ino) { + err = ext2fs_ext_attr_hash_entry2(fs, e, + x->ea_ino ? 0 : end, + &e->e_hash); + if (err) + return err; + } else + e->e_hash = 0; + + e = EXT2_EXT_ATTR_NEXT(e); + *(__u32 *)e = 0; + } + return 0; +} + +errcode_t ext2fs_xattrs_write(struct ext2_xattr_handle *handle) +{ + ext2_filsys fs = handle->fs; + const int inode_size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *inode; + char *start, *block_buf = NULL; + struct ext2_ext_attr_header *header; + __u32 ea_inode_magic; + blk64_t blk; + unsigned int storage_size; + unsigned int i; + errcode_t err; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + i = inode_size; + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(fs, handle->ino, EXT2_INODE(inode), + inode_size); + if (err) + goto out; + + /* If extra_isize isn't set, we need to set it now */ + if (inode->i_extra_isize == 0 && + inode_size > EXT2_GOOD_OLD_INODE_SIZE) { + char *p = (char *)inode; + size_t extra = fs->super->s_want_extra_isize; + + if (extra == 0) + extra = sizeof(__u32); + memset(p + EXT2_GOOD_OLD_INODE_SIZE, 0, extra); + inode->i_extra_isize = extra; + } + if (inode->i_extra_isize & 3) { + err = EXT2_ET_INODE_CORRUPTED; + goto out; + } + + /* Does the inode have space for EA? */ + if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || + inode_size <= EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize + + sizeof(__u32)) + goto write_ea_block; + + /* Write the inode EA */ + ea_inode_magic = EXT2_EXT_ATTR_MAGIC; + memcpy(((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, &ea_inode_magic, sizeof(__u32)); + storage_size = inode_size - EXT2_GOOD_OLD_INODE_SIZE - + inode->i_extra_isize - sizeof(__u32); + start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + + err = write_xattrs_to_buffer(fs, handle->attrs, handle->ibody_count, + start, storage_size, 0, 0); + if (err) + goto out; +write_ea_block: + /* Are we done? */ + if (handle->ibody_count == handle->count && + !ext2fs_file_acl_block(fs, EXT2_INODE(inode))) + goto skip_ea_block; + + /* Write the EA block */ + err = ext2fs_get_memzero(fs->blocksize, &block_buf); + if (err) + goto out; + + storage_size = fs->blocksize - sizeof(struct ext2_ext_attr_header); + start = block_buf + sizeof(struct ext2_ext_attr_header); + + err = write_xattrs_to_buffer(fs, handle->attrs + handle->ibody_count, + handle->count - handle->ibody_count, start, + storage_size, start - block_buf, 1); + if (err) + goto out2; + + /* Write a header on the EA block */ + header = (struct ext2_ext_attr_header *) block_buf; + header->h_magic = EXT2_EXT_ATTR_MAGIC; + header->h_refcount = 1; + header->h_blocks = 1; + + /* Get a new block for writing */ + err = prep_ea_block_for_write(fs, handle->ino, inode); + if (err) + goto out2; + + /* Finally, write the new EA block */ + blk = ext2fs_file_acl_block(fs, EXT2_INODE(inode)); + err = ext2fs_write_ext_attr3(fs, blk, block_buf, handle->ino); + if (err) + goto out2; + +skip_ea_block: + blk = ext2fs_file_acl_block(fs, (struct ext2_inode *)inode); + if (!block_buf && blk) { + /* xattrs shrunk, free the block */ + err = ext2fs_free_ext_attr(fs, handle->ino, inode); + if (err) + goto out; + } + + /* Write the inode */ + err = ext2fs_write_inode_full(fs, handle->ino, EXT2_INODE(inode), + inode_size); + if (err) + goto out2; + +out2: + ext2fs_free_mem(&block_buf); +out: + ext2fs_free_mem(&inode); + return err; +} + +static errcode_t read_xattrs_from_buffer(struct ext2_xattr_handle *handle, + struct ext2_inode_large *inode, + struct ext2_ext_attr_entry *entries, + unsigned int storage_size, + char *value_start) +{ + struct ext2_xattr *x; + struct ext2_ext_attr_entry *entry, *end; + const char *prefix; + unsigned int remain, prefix_len; + errcode_t err; + unsigned int values_size = storage_size + + ((char *)entries - value_start); + + /* find the end */ + end = entries; + remain = storage_size; + while (remain >= sizeof(struct ext2_ext_attr_entry) && + !EXT2_EXT_IS_LAST_ENTRY(end)) { + + /* header eats this space */ + remain -= sizeof(struct ext2_ext_attr_entry); + + /* is attribute name valid? */ + if (EXT2_EXT_ATTR_SIZE(end->e_name_len) > remain) + return EXT2_ET_EA_BAD_NAME_LEN; + + /* attribute len eats this space */ + remain -= EXT2_EXT_ATTR_SIZE(end->e_name_len); + end = EXT2_EXT_ATTR_NEXT(end); + } + + entry = entries; + remain = storage_size; + while (remain >= sizeof(struct ext2_ext_attr_entry) && + !EXT2_EXT_IS_LAST_ENTRY(entry)) { + + /* Allocate space for more attrs? */ + if (handle->count == handle->capacity) { + err = ext2fs_xattrs_expand(handle, 4); + if (err) + return err; + } + + x = handle->attrs + handle->count; + + /* header eats this space */ + remain -= sizeof(struct ext2_ext_attr_entry); + + /* attribute len eats this space */ + remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); + + /* Extract name */ + prefix = find_ea_prefix(entry->e_name_index); + prefix_len = (prefix ? strlen(prefix) : 0); + err = ext2fs_get_memzero(entry->e_name_len + prefix_len + 1, + &x->name); + if (err) + return err; + if (prefix) + memcpy(x->name, prefix, prefix_len); + if (entry->e_name_len) + memcpy(x->name + prefix_len, + (char *)entry + sizeof(*entry), + entry->e_name_len); + + /* Check & copy value */ + if (!ext2fs_has_feature_ea_inode(handle->fs->super) && + entry->e_value_inum != 0) + return EXT2_ET_BAD_EA_BLOCK_NUM; + + if (entry->e_value_inum == 0) { + if (entry->e_value_size > remain) + return EXT2_ET_EA_BAD_VALUE_SIZE; + + if (entry->e_value_offs + entry->e_value_size > values_size) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + if (entry->e_value_size > 0 && + value_start + entry->e_value_offs < + (char *)end + sizeof(__u32)) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + remain -= entry->e_value_size; + + err = ext2fs_get_mem(entry->e_value_size, &x->value); + if (err) + return err; + memcpy(x->value, value_start + entry->e_value_offs, + entry->e_value_size); + } else { + struct ext2_inode *ea_inode; + ext2_file_t ea_file; + + if (entry->e_value_offs != 0) + return EXT2_ET_EA_BAD_VALUE_OFFSET; + + if (entry->e_value_size > (64 * 1024)) + return EXT2_ET_EA_BAD_VALUE_SIZE; + + err = ext2fs_get_mem(entry->e_value_size, &x->value); + if (err) + return err; + + err = ext2fs_file_open(handle->fs, entry->e_value_inum, + 0, &ea_file); + if (err) + return err; + + ea_inode = ext2fs_file_get_inode(ea_file); + if ((ea_inode->i_flags & EXT4_INLINE_DATA_FL) || + !(ea_inode->i_flags & EXT4_EA_INODE_FL) || + ea_inode->i_links_count == 0) + err = EXT2_ET_EA_INODE_CORRUPTED; + else if (ext2fs_file_get_size(ea_file) != + entry->e_value_size) + err = EXT2_ET_EA_BAD_VALUE_SIZE; + else + err = ext2fs_file_read(ea_file, x->value, + entry->e_value_size, 0); + ext2fs_file_close(ea_file); + if (err) + return err; + } + + x->ea_ino = entry->e_value_inum; + x->value_len = entry->e_value_size; + + /* e_hash may be 0 in older inode's ea */ + if (entry->e_hash != 0) { + __u32 hash; + void *data = (entry->e_value_inum != 0) ? + 0 : value_start + entry->e_value_offs; + + err = ext2fs_ext_attr_hash_entry2(handle->fs, entry, + data, &hash); + if (err) + return err; + if (entry->e_hash != hash) { + struct ext2_inode child; + + /* Check whether this is an old Lustre-style + * ea_inode reference. + */ + err = ext2fs_read_inode(handle->fs, + entry->e_value_inum, + &child); + if (err) + return err; + if (child.i_mtime != handle->ino || + child.i_generation != inode->i_generation) + return EXT2_ET_BAD_EA_HASH; + } + } + + handle->count++; + entry = EXT2_EXT_ATTR_NEXT(entry); + } + + return 0; +} + +static void xattrs_free_keys(struct ext2_xattr_handle *h) +{ + struct ext2_xattr *a = h->attrs; + int i; + + for (i = 0; i < h->capacity; i++) { + if (a[i].name) + ext2fs_free_mem(&a[i].name); + if (a[i].value) + ext2fs_free_mem(&a[i].value); + } + h->count = 0; + h->ibody_count = 0; +} + +errcode_t ext2fs_xattrs_read(struct ext2_xattr_handle *handle) +{ + struct ext2_inode_large *inode; + struct ext2_ext_attr_header *header; + __u32 ea_inode_magic; + unsigned int storage_size; + char *start, *block_buf = NULL; + blk64_t blk; + size_t i; + errcode_t err; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + i = EXT2_INODE_SIZE(handle->fs->super); + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(handle->fs, handle->ino, + (struct ext2_inode *)inode, + EXT2_INODE_SIZE(handle->fs->super)); + if (err) + goto out; + + xattrs_free_keys(handle); + + /* Does the inode have space for EA? */ + if (inode->i_extra_isize < sizeof(inode->i_extra_isize) || + EXT2_INODE_SIZE(handle->fs->super) <= EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + + sizeof(__u32)) + goto read_ea_block; + if (inode->i_extra_isize & 3) { + err = EXT2_ET_INODE_CORRUPTED; + goto out; + } + + /* Look for EA in the inode */ + memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, sizeof(__u32)); + if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) { + storage_size = EXT2_INODE_SIZE(handle->fs->super) - + EXT2_GOOD_OLD_INODE_SIZE - inode->i_extra_isize - + sizeof(__u32); + start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + + err = read_xattrs_from_buffer(handle, inode, + (struct ext2_ext_attr_entry *) start, + storage_size, start); + if (err) + goto out; + + handle->ibody_count = handle->count; + } + +read_ea_block: + /* Look for EA in a separate EA block */ + blk = ext2fs_file_acl_block(handle->fs, (struct ext2_inode *)inode); + if (blk != 0) { + if ((blk < handle->fs->super->s_first_data_block) || + (blk >= ext2fs_blocks_count(handle->fs->super))) { + err = EXT2_ET_BAD_EA_BLOCK_NUM; + goto out; + } + + err = ext2fs_get_mem(handle->fs->blocksize, &block_buf); + if (err) + goto out; + + err = ext2fs_read_ext_attr3(handle->fs, blk, block_buf, + handle->ino); + if (err) + goto out3; + + /* We only know how to deal with v2 EA blocks */ + header = (struct ext2_ext_attr_header *) block_buf; + if (header->h_magic != EXT2_EXT_ATTR_MAGIC) { + err = EXT2_ET_BAD_EA_HEADER; + goto out3; + } + + /* Read EAs */ + storage_size = handle->fs->blocksize - + sizeof(struct ext2_ext_attr_header); + start = block_buf + sizeof(struct ext2_ext_attr_header); + err = read_xattrs_from_buffer(handle, inode, + (struct ext2_ext_attr_entry *) start, + storage_size, block_buf); + if (err) + goto out3; + + ext2fs_free_mem(&block_buf); + } + + ext2fs_free_mem(&block_buf); + ext2fs_free_mem(&inode); + return 0; + +out3: + ext2fs_free_mem(&block_buf); +out: + ext2fs_free_mem(&inode); + return err; +} + +errcode_t ext2fs_xattrs_iterate(struct ext2_xattr_handle *h, + int (*func)(char *name, char *value, + size_t value_len, void *data), + void *data) +{ + struct ext2_xattr *x; + int dirty = 0; + int ret; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + for (x = h->attrs; x < h->attrs + h->count; x++) { + ret = func(x->name, x->value, x->value_len, data); + if (ret & XATTR_CHANGED) + dirty = 1; + if (ret & XATTR_ABORT) + break; + } + + if (dirty) + return ext2fs_xattrs_write(h); + return 0; +} + +errcode_t ext2fs_xattr_get(struct ext2_xattr_handle *h, const char *key, + void **value, size_t *value_len) +{ + struct ext2_xattr *x; + char *val; + errcode_t err; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + for (x = h->attrs; x < h->attrs + h->count; x++) { + if (strcmp(x->name, key)) + continue; + + if (!(h->flags & XATTR_HANDLE_FLAG_RAW) && + ((strcmp(key, "system.posix_acl_default") == 0) || + (strcmp(key, "system.posix_acl_access") == 0))) { + err = convert_disk_buffer_to_posix_acl(x->value, x->value_len, + value, value_len); + return err; + } else { + err = ext2fs_get_mem(x->value_len, &val); + if (err) + return err; + memcpy(val, x->value, x->value_len); + *value = val; + *value_len = x->value_len; + return 0; + } + } + + return EXT2_ET_EA_KEY_NOT_FOUND; +} + +errcode_t ext2fs_xattr_inode_max_size(ext2_filsys fs, ext2_ino_t ino, + size_t *size) +{ + struct ext2_ext_attr_entry *entry; + struct ext2_inode_large *inode; + __u32 ea_inode_magic; + unsigned int minoff; + char *start; + size_t i; + errcode_t err; + + i = EXT2_INODE_SIZE(fs->super); + if (i < sizeof(*inode)) + i = sizeof(*inode); + err = ext2fs_get_memzero(i, &inode); + if (err) + return err; + + err = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)inode, + EXT2_INODE_SIZE(fs->super)); + if (err) + goto out; + + /* Does the inode have size for EA? */ + if (EXT2_INODE_SIZE(fs->super) <= EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + + sizeof(__u32)) { + err = EXT2_ET_INLINE_DATA_NO_SPACE; + goto out; + } + + minoff = EXT2_INODE_SIZE(fs->super) - sizeof(*inode) - sizeof(__u32); + memcpy(&ea_inode_magic, ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize, sizeof(__u32)); + if (ea_inode_magic == EXT2_EXT_ATTR_MAGIC) { + /* has xattrs. calculate the size */ + start= ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + + inode->i_extra_isize + sizeof(__u32); + entry = (struct ext2_ext_attr_entry *) start; + while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { + if (!entry->e_value_inum && entry->e_value_size) { + unsigned int offs = entry->e_value_offs; + if (offs < minoff) + minoff = offs; + } + entry = EXT2_EXT_ATTR_NEXT(entry); + } + *size = minoff - ((char *)entry - (char *)start) - sizeof(__u32); + } else { + /* no xattr. return a maximum size */ + *size = EXT2_EXT_ATTR_SIZE(minoff - + EXT2_EXT_ATTR_LEN(strlen("data")) - + EXT2_EXT_ATTR_ROUND - sizeof(__u32)); + } + +out: + ext2fs_free_mem(&inode); + return err; +} + +static errcode_t xattr_create_ea_inode(ext2_filsys fs, const void *value, + size_t value_len, ext2_ino_t *ea_ino) +{ + struct ext2_inode inode; + ext2_ino_t ino; + ext2_file_t file; + __u32 hash; + errcode_t ret; + + ret = ext2fs_new_inode(fs, 0, 0, 0, &ino); + if (ret) + return ret; + + memset(&inode, 0, sizeof(inode)); + inode.i_flags |= EXT4_EA_INODE_FL; + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + inode.i_size = 0; + inode.i_mode = LINUX_S_IFREG | 0600; + inode.i_links_count = 1; + ret = ext2fs_write_new_inode(fs, ino, &inode); + if (ret) + return ret; + /* + * ref_count and hash utilize inode's i_*time fields. + * ext2fs_write_new_inode() call above initializes these fields with + * current time. That's why ref count and hash updates are done + * separately below. + */ + ext2fs_set_ea_inode_ref(&inode, 1); + hash = ext2fs_crc32c_le(fs->csum_seed, value, value_len); + ext2fs_set_ea_inode_hash(&inode, hash); + + ret = ext2fs_write_inode(fs, ino, &inode); + if (ret) + return ret; + + ret = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &file); + if (ret) + return ret; + ret = ext2fs_file_write(file, value, value_len, NULL); + ext2fs_file_close(file); + if (ret) + return ret; + + ext2fs_inode_alloc_stats2(fs, ino, 1 /* inuse */, 0 /* isdir */); + + *ea_ino = ino; + return 0; +} + +static errcode_t xattr_inode_dec_ref(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode_large inode; + __u64 ref_count; + errcode_t ret; + + ret = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); + if (ret) + goto out; + + ref_count = ext2fs_get_ea_inode_ref(EXT2_INODE(&inode)); + ref_count--; + ext2fs_set_ea_inode_ref(EXT2_INODE(&inode), ref_count); + + if (ref_count) + goto write_out; + + inode.i_links_count = 0; + inode.i_dtime = fs->now ? fs->now : time(0); + + ret = ext2fs_free_ext_attr(fs, ino, &inode); + if (ret) + goto write_out; + + if (ext2fs_inode_has_valid_blocks2(fs, (struct ext2_inode *)&inode)) { + ret = ext2fs_punch(fs, ino, (struct ext2_inode *)&inode, NULL, + 0, ~0ULL); + if (ret) + goto out; + } + + ext2fs_inode_alloc_stats2(fs, ino, -1 /* inuse */, 0 /* is_dir */); + +write_out: + ret = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, + sizeof(inode)); +out: + return ret; +} + +static errcode_t xattr_update_entry(ext2_filsys fs, struct ext2_xattr *x, + const char *name, const void *value, + size_t value_len, int in_inode) +{ + ext2_ino_t ea_ino = 0; + void *new_value = NULL; + char *new_name = NULL; + int name_len; + errcode_t ret; + + if (!x->name) { + name_len = strlen(name); + ret = ext2fs_get_mem(name_len + 1, &new_name); + if (ret) + goto fail; + memcpy(new_name, name, name_len + 1); + } + + ret = ext2fs_get_mem(value_len, &new_value); + if (ret) + goto fail; + memcpy(new_value, value, value_len); + + if (in_inode) { + ret = xattr_create_ea_inode(fs, value, value_len, &ea_ino); + if (ret) + goto fail; + } + + if (x->ea_ino) { + ret = xattr_inode_dec_ref(fs, x->ea_ino); + if (ret) + goto fail; + } + + if (!x->name) + x->name = new_name; + + if (x->value) + ext2fs_free_mem(&x->value); + x->value = new_value; + x->value_len = value_len; + x->ea_ino = ea_ino; + return 0; +fail: + if (new_name) + ext2fs_free_mem(&new_name); + if (new_value) + ext2fs_free_mem(&new_value); + if (ea_ino) + xattr_inode_dec_ref(fs, ea_ino); + return ret; +} + +static int xattr_find_position(struct ext2_xattr *attrs, int count, + const char *name) +{ + struct ext2_xattr *x; + int i; + char *shortname, *x_shortname; + int name_idx, x_name_idx; + int shortname_len, x_shortname_len; + + find_ea_index(name, &shortname, &name_idx); + shortname_len = strlen(shortname); + + for (i = 0, x = attrs; i < count; i++, x++) { + find_ea_index(x->name, &x_shortname, &x_name_idx); + if (name_idx < x_name_idx) + break; + if (name_idx > x_name_idx) + continue; + + x_shortname_len = strlen(x_shortname); + if (shortname_len < x_shortname_len) + break; + if (shortname_len > x_shortname_len) + continue; + + if (memcmp(shortname, x_shortname, shortname_len) <= 0) + break; + } + return i; +} + +static errcode_t xattr_array_update(struct ext2_xattr_handle *h, + const char *name, + const void *value, size_t value_len, + int ibody_free, int block_free, + int old_idx, int in_inode) +{ + struct ext2_xattr tmp; + int add_to_ibody; + int needed; + int name_len, name_idx; + char *shortname; + int new_idx; + int ret; + + find_ea_index(name, &shortname, &name_idx); + name_len = strlen(shortname); + + needed = EXT2_EXT_ATTR_LEN(name_len); + if (!in_inode) + needed += EXT2_EXT_ATTR_SIZE(value_len); + + if (old_idx >= 0 && old_idx < h->ibody_count) { + ibody_free += EXT2_EXT_ATTR_LEN(name_len); + if (!h->attrs[old_idx].ea_ino) + ibody_free += EXT2_EXT_ATTR_SIZE( + h->attrs[old_idx].value_len); + } + + if (needed <= ibody_free) { + if (old_idx < 0) { + new_idx = h->ibody_count; + add_to_ibody = 1; + goto add_new; + } + + /* Update the existing entry. */ + ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name, + value, value_len, in_inode); + if (ret) + return ret; + if (h->ibody_count <= old_idx) { + /* Move entry from block to the end of ibody. */ + tmp = h->attrs[old_idx]; + memmove(h->attrs + h->ibody_count + 1, + h->attrs + h->ibody_count, + (old_idx - h->ibody_count) * sizeof(*h->attrs)); + h->attrs[h->ibody_count] = tmp; + h->ibody_count++; + } + return 0; + } + + if (h->ibody_count <= old_idx) { + block_free += EXT2_EXT_ATTR_LEN(name_len); + if (!h->attrs[old_idx].ea_ino) + block_free += + EXT2_EXT_ATTR_SIZE(h->attrs[old_idx].value_len); + } + + if (needed > block_free) + return EXT2_ET_EA_NO_SPACE; + + if (old_idx >= 0) { + /* Update the existing entry. */ + ret = xattr_update_entry(h->fs, &h->attrs[old_idx], name, + value, value_len, in_inode); + if (ret) + return ret; + if (old_idx < h->ibody_count) { + /* + * Move entry from ibody to the block. Note that + * entries in the block are sorted. + */ + new_idx = xattr_find_position(h->attrs + h->ibody_count, + h->count - h->ibody_count, name); + new_idx += h->ibody_count - 1; + tmp = h->attrs[old_idx]; + memmove(h->attrs + old_idx, h->attrs + old_idx + 1, + (new_idx - old_idx) * sizeof(*h->attrs)); + h->attrs[new_idx] = tmp; + h->ibody_count--; + } + return 0; + } + + new_idx = xattr_find_position(h->attrs + h->ibody_count, + h->count - h->ibody_count, name); + new_idx += h->ibody_count; + add_to_ibody = 0; + +add_new: + if (h->count == h->capacity) { + ret = ext2fs_xattrs_expand(h, 4); + if (ret) + return ret; + } + + ret = xattr_update_entry(h->fs, &h->attrs[h->count], name, value, + value_len, in_inode); + if (ret) + return ret; + + tmp = h->attrs[h->count]; + memmove(h->attrs + new_idx + 1, h->attrs + new_idx, + (h->count - new_idx)*sizeof(*h->attrs)); + h->attrs[new_idx] = tmp; + if (add_to_ibody) + h->ibody_count++; + h->count++; + return 0; +} + +static int space_used(struct ext2_xattr *attrs, int count) +{ + int total = 0; + struct ext2_xattr *x; + char *shortname; + int i, len, name_idx; + + for (i = 0, x = attrs; i < count; i++, x++) { + find_ea_index(x->name, &shortname, &name_idx); + len = strlen(shortname); + total += EXT2_EXT_ATTR_LEN(len); + if (!x->ea_ino) + total += EXT2_EXT_ATTR_SIZE(x->value_len); + } + return total; +} + +/* + * The minimum size of EA value when you start storing it in an external inode + * size of block - size of header - size of 1 entry - 4 null bytes + */ +#define EXT4_XATTR_MIN_LARGE_EA_SIZE(b) \ + ((b) - EXT2_EXT_ATTR_LEN(3) - sizeof(struct ext2_ext_attr_header) - 4) + +errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *h, + const char *name, + const void *value, + size_t value_len) +{ + ext2_filsys fs = h->fs; + const int inode_size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *inode = NULL; + struct ext2_xattr *x; + char *new_value; + int ibody_free, block_free; + int in_inode = 0; + int old_idx = -1; + int extra_isize; + errcode_t ret; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + + ret = ext2fs_get_mem(value_len, &new_value); + if (ret) + return ret; + if (!(h->flags & XATTR_HANDLE_FLAG_RAW) && + ((strcmp(name, "system.posix_acl_default") == 0) || + (strcmp(name, "system.posix_acl_access") == 0))) { + ret = convert_posix_acl_to_disk_buffer(value, value_len, + new_value, &value_len); + if (ret) + goto out; + } else + memcpy(new_value, value, value_len); + + /* Imitate kernel behavior by skipping update if value is the same. */ + for (x = h->attrs; x < h->attrs + h->count; x++) { + if (!strcmp(x->name, name)) { + if (!x->ea_ino && x->value_len == value_len && + !memcmp(x->value, new_value, value_len)) { + ret = 0; + goto out; + } + old_idx = x - h->attrs; + break; + } + } + + ret = ext2fs_get_memzero(inode_size, &inode); + if (ret) + goto out; + ret = ext2fs_read_inode_full(fs, h->ino, + (struct ext2_inode *)inode, + inode_size); + if (ret) + goto out; + if (inode_size > EXT2_GOOD_OLD_INODE_SIZE) { + extra_isize = inode->i_extra_isize; + if (extra_isize == 0) { + extra_isize = fs->super->s_want_extra_isize; + if (extra_isize == 0) + extra_isize = sizeof(__u32); + } + ibody_free = inode_size - EXT2_GOOD_OLD_INODE_SIZE; + ibody_free -= extra_isize; + /* Extended attribute magic and final null entry. */ + ibody_free -= sizeof(__u32) * 2; + ibody_free -= space_used(h->attrs, h->ibody_count); + } else + ibody_free = 0; + + /* Inline data can only go to ibody. */ + if (strcmp(name, "system.data") == 0) { + if (h->ibody_count <= old_idx) { + ret = EXT2_ET_FILESYSTEM_CORRUPTED; + goto out; + } + ret = xattr_array_update(h, name, value, value_len, ibody_free, + 0 /* block_free */, old_idx, + 0 /* in_inode */); + if (ret) + goto out; + goto write_out; + } + + block_free = fs->blocksize; + block_free -= sizeof(struct ext2_ext_attr_header); + /* Final null entry. */ + block_free -= sizeof(__u32); + block_free -= space_used(h->attrs + h->ibody_count, + h->count - h->ibody_count); + + if (ext2fs_has_feature_ea_inode(fs->super) && + value_len > EXT4_XATTR_MIN_LARGE_EA_SIZE(fs->blocksize)) + in_inode = 1; + + ret = xattr_array_update(h, name, value, value_len, ibody_free, + block_free, old_idx, in_inode); + if (ret == EXT2_ET_EA_NO_SPACE && !in_inode && + ext2fs_has_feature_ea_inode(fs->super)) + ret = xattr_array_update(h, name, value, value_len, ibody_free, + block_free, old_idx, 1 /* in_inode */); + if (ret) + goto out; + +write_out: + ret = ext2fs_xattrs_write(h); +out: + if (inode) + ext2fs_free_mem(&inode); + ext2fs_free_mem(&new_value); + return ret; +} + +errcode_t ext2fs_xattr_remove(struct ext2_xattr_handle *handle, + const char *key) +{ + struct ext2_xattr *x; + struct ext2_xattr *end = handle->attrs + handle->count; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + for (x = handle->attrs; x < end; x++) { + if (strcmp(x->name, key) == 0) { + ext2fs_free_mem(&x->name); + ext2fs_free_mem(&x->value); + if (x->ea_ino) + xattr_inode_dec_ref(handle->fs, x->ea_ino); + memmove(x, x + 1, (end - x - 1)*sizeof(*x)); + memset(end - 1, 0, sizeof(*end)); + if (x < handle->attrs + handle->ibody_count) + handle->ibody_count--; + handle->count--; + return ext2fs_xattrs_write(handle); + } + } + + /* no key found, success! */ + return 0; +} + +errcode_t ext2fs_xattrs_open(ext2_filsys fs, ext2_ino_t ino, + struct ext2_xattr_handle **handle) +{ + struct ext2_xattr_handle *h; + errcode_t err; + + if (!ext2fs_has_feature_xattr(fs->super) && + !ext2fs_has_feature_inline_data(fs->super)) + return EXT2_ET_MISSING_EA_FEATURE; + + err = ext2fs_get_memzero(sizeof(*h), &h); + if (err) + return err; + + h->magic = EXT2_ET_MAGIC_EA_HANDLE; + h->capacity = 4; + err = ext2fs_get_arrayzero(h->capacity, sizeof(struct ext2_xattr), + &h->attrs); + if (err) { + ext2fs_free_mem(&h); + return err; + } + h->count = 0; + h->ino = ino; + h->fs = fs; + *handle = h; + return 0; +} + +errcode_t ext2fs_xattrs_close(struct ext2_xattr_handle **handle) +{ + struct ext2_xattr_handle *h = *handle; + + EXT2_CHECK_MAGIC(h, EXT2_ET_MAGIC_EA_HANDLE); + xattrs_free_keys(h); + ext2fs_free_mem(&h->attrs); + ext2fs_free_mem(handle); + return 0; +} + +errcode_t ext2fs_xattrs_count(struct ext2_xattr_handle *handle, size_t *count) +{ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + *count = handle->count; + return 0; +} + +errcode_t ext2fs_xattrs_flags(struct ext2_xattr_handle *handle, + unsigned int *new_flags, unsigned int *old_flags) +{ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EA_HANDLE); + if (old_flags) + *old_flags = handle->flags; + if (new_flags) + handle->flags = *new_flags; + return 0; +} diff --git a/src/ext2fs/extent.c b/src/ext2fs/extent.c new file mode 100644 index 00000000..a9cdae79 --- /dev/null +++ b/src/ext2fs/extent.c @@ -0,0 +1,1747 @@ +/* + * extent.c --- routines to implement extents support + * + * Copyright (C) 2007 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "e2image.h" + +#undef DEBUG + +/* + * Definitions to be dropped in lib/ext2fs/ext2fs.h + */ + +/* + * Private definitions + */ + +struct extent_path { + char *buf; + int entries; + int max_entries; + int left; + int visit_num; + int flags; + blk64_t end_blk; + void *curr; +}; + + +struct ext2_extent_handle { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t ino; + struct ext2_inode *inode; + struct ext2_inode inodebuf; + int type; + int level; + int max_depth; + int max_paths; + struct extent_path *path; +}; + +struct ext2_extent_path { + errcode_t magic; + int leaf_height; + blk64_t lblk; +}; + +/* + * Useful Debugging stuff + */ + +#ifdef DEBUG +static void dbg_show_header(struct ext3_extent_header *eh) +{ + printf("header: magic=%x entries=%u max=%u depth=%u generation=%u\n", + ext2fs_le16_to_cpu(eh->eh_magic), + ext2fs_le16_to_cpu(eh->eh_entries), + ext2fs_le16_to_cpu(eh->eh_max), + ext2fs_le16_to_cpu(eh->eh_depth), + ext2fs_le32_to_cpu(eh->eh_generation)); +} + +static void dbg_show_index(struct ext3_extent_idx *ix) +{ + printf("index: block=%u leaf=%u leaf_hi=%u unused=%u\n", + ext2fs_le32_to_cpu(ix->ei_block), + ext2fs_le32_to_cpu(ix->ei_leaf), + ext2fs_le16_to_cpu(ix->ei_leaf_hi), + ext2fs_le16_to_cpu(ix->ei_unused)); +} + +static void dbg_show_extent(struct ext3_extent *ex) +{ + printf("extent: block=%u-%u len=%u start=%u start_hi=%u\n", + ext2fs_le32_to_cpu(ex->ee_block), + ext2fs_le32_to_cpu(ex->ee_block) + + ext2fs_le16_to_cpu(ex->ee_len) - 1, + ext2fs_le16_to_cpu(ex->ee_len), + ext2fs_le32_to_cpu(ex->ee_start), + ext2fs_le16_to_cpu(ex->ee_start_hi)); +} + +static void dbg_print_extent(char *desc, struct ext2fs_extent *extent) +{ + if (desc) + printf("%s: ", desc); + printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", + extent->e_lblk, extent->e_lblk + extent->e_len - 1, + extent->e_len, extent->e_pblk); + if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) + fputs("LEAF ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fputs("UNINIT ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + fputs("2ND_VISIT ", stdout); + if (!extent->e_flags) + fputs("(none)", stdout); + fputc('\n', stdout); + +} + +static void dump_path(const char *tag, struct ext2_extent_handle *handle, + struct extent_path *path) +{ + struct extent_path *ppp = path; + printf("%s: level=%d\n", tag, handle->level); + + do { + printf("%s: path=%ld buf=%p entries=%d max_entries=%d left=%d " + "visit_num=%d flags=0x%x end_blk=%llu curr=%p(%ld)\n", + tag, (ppp - handle->path), ppp->buf, ppp->entries, + ppp->max_entries, ppp->left, ppp->visit_num, ppp->flags, + ppp->end_blk, ppp->curr, ppp->curr - (void *)ppp->buf); + printf(" "); + dbg_show_header((struct ext3_extent_header *)ppp->buf); + if (ppp->curr) { + printf(" "); + dbg_show_index(ppp->curr); + printf(" "); + dbg_show_extent(ppp->curr); + } + ppp--; + } while (ppp >= handle->path); + fflush(stdout); + + return; +} + +#else +#define dbg_show_header(eh) do { } while (0) +#define dbg_show_index(ix) do { } while (0) +#define dbg_show_extent(ex) do { } while (0) +#define dbg_print_extent(desc, ex) do { } while (0) +#define dump_path(tag, handle, path) do { } while (0) +#endif + +/* + * Verify the extent header as being sane + */ +errcode_t ext2fs_extent_header_verify(void *ptr, int size) +{ + int eh_max, entry_size; + struct ext3_extent_header *eh = ptr; + + dbg_show_header(eh); + if (ext2fs_le16_to_cpu(eh->eh_magic) != EXT3_EXT_MAGIC) + return EXT2_ET_EXTENT_HEADER_BAD; + if (ext2fs_le16_to_cpu(eh->eh_entries) > ext2fs_le16_to_cpu(eh->eh_max)) + return EXT2_ET_EXTENT_HEADER_BAD; + if (eh->eh_depth == 0) + entry_size = sizeof(struct ext3_extent); + else + entry_size = sizeof(struct ext3_extent_idx); + + eh_max = (size - sizeof(*eh)) / entry_size; + /* Allow two extent-sized items at the end of the block, for + * ext4_extent_tail with checksum in the future. */ + if ((ext2fs_le16_to_cpu(eh->eh_max) > eh_max) || + (ext2fs_le16_to_cpu(eh->eh_max) < (eh_max - 2))) + return EXT2_ET_EXTENT_HEADER_BAD; + + return 0; +} + + +/* + * Begin functions to handle an inode's extent information + */ +void ext2fs_extent_free(ext2_extent_handle_t handle) +{ + int i; + + if (!handle) + return; + + if (handle->path) { + for (i = 1; i < handle->max_paths; i++) { + if (handle->path[i].buf) + ext2fs_free_mem(&handle->path[i].buf); + } + ext2fs_free_mem(&handle->path); + } + ext2fs_free_mem(&handle); +} + +errcode_t ext2fs_extent_open(ext2_filsys fs, ext2_ino_t ino, + ext2_extent_handle_t *ret_handle) +{ + return ext2fs_extent_open2(fs, ino, NULL, ret_handle); +} + +errcode_t ext2fs_extent_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + ext2_extent_handle_t *ret_handle) +{ + struct ext2_extent_handle *handle; + errcode_t retval; + int i; + struct ext3_extent_header *eh; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!inode) + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + + retval = ext2fs_get_mem(sizeof(struct ext2_extent_handle), &handle); + if (retval) + return retval; + memset(handle, 0, sizeof(struct ext2_extent_handle)); + + handle->ino = ino; + handle->fs = fs; + + if (inode) { + handle->inode = inode; + } else { + handle->inode = &handle->inodebuf; + retval = ext2fs_read_inode(fs, ino, handle->inode); + if (retval) + goto errout; + } + + eh = (struct ext3_extent_header *) &handle->inode->i_block[0]; + + for (i=0; i < EXT2_N_BLOCKS; i++) + if (handle->inode->i_block[i]) + break; + if (i >= EXT2_N_BLOCKS) { + eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); + eh->eh_depth = 0; + eh->eh_entries = 0; + i = (sizeof(handle->inode->i_block) - sizeof(*eh)) / + sizeof(struct ext3_extent); + eh->eh_max = ext2fs_cpu_to_le16(i); + handle->inode->i_flags |= EXT4_EXTENTS_FL; + } + + if (!(handle->inode->i_flags & EXT4_EXTENTS_FL)) { + retval = EXT2_ET_INODE_NOT_EXTENT; + goto errout; + } + + retval = ext2fs_extent_header_verify(eh, sizeof(handle->inode->i_block)); + if (retval) + goto errout; + + handle->max_depth = ext2fs_le16_to_cpu(eh->eh_depth); + handle->type = ext2fs_le16_to_cpu(eh->eh_magic); + + handle->max_paths = handle->max_depth + 1; + retval = ext2fs_get_memzero(handle->max_paths * + sizeof(struct extent_path), + &handle->path); + handle->path[0].buf = (char *) handle->inode->i_block; + + handle->path[0].left = handle->path[0].entries = + ext2fs_le16_to_cpu(eh->eh_entries); + handle->path[0].max_entries = ext2fs_le16_to_cpu(eh->eh_max); + handle->path[0].curr = 0; + handle->path[0].end_blk = + (EXT2_I_SIZE(handle->inode) + fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(fs->super); + handle->path[0].visit_num = 1; + handle->level = 0; + handle->magic = EXT2_ET_MAGIC_EXTENT_HANDLE; + + *ret_handle = handle; + return 0; + +errout: + ext2fs_extent_free(handle); + return retval; +} + +/* + * This function is responsible for (optionally) moving through the + * extent tree and then returning the current extent + */ +errcode_t ext2fs_extent_get(ext2_extent_handle_t handle, + int flags, struct ext2fs_extent *extent) +{ + struct extent_path *path, *newpath; + struct ext3_extent_header *eh; + struct ext3_extent_idx *ix = 0; + struct ext3_extent *ex; + errcode_t retval; + blk64_t blk; + blk64_t end_blk; + int orig_op, op; + int failed_csum = 0; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + orig_op = op = flags & EXT2_EXTENT_MOVE_MASK; + +retry: + path = handle->path + handle->level; + if ((orig_op == EXT2_EXTENT_NEXT) || + (orig_op == EXT2_EXTENT_NEXT_LEAF)) { + if (handle->level < handle->max_depth) { + /* interior node */ + if (path->visit_num == 0) { + path->visit_num++; + op = EXT2_EXTENT_DOWN; + } else if (path->left > 0) + op = EXT2_EXTENT_NEXT_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_NEXT; + } else { + /* leaf node */ + if (path->left > 0) + op = EXT2_EXTENT_NEXT_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_NEXT; + } + if (op != EXT2_EXTENT_NEXT_SIB) { +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN) ? "down" : + ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); +#endif + } + } + + if ((orig_op == EXT2_EXTENT_PREV) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) { + if (handle->level < handle->max_depth) { + /* interior node */ + if (path->visit_num > 0 ) { + /* path->visit_num = 0; */ + op = EXT2_EXTENT_DOWN_AND_LAST; + } else if (path->left < path->entries-1) + op = EXT2_EXTENT_PREV_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_PREV; + } else { + /* leaf node */ + if (path->left < path->entries-1) + op = EXT2_EXTENT_PREV_SIB; + else if (handle->level > 0) + op = EXT2_EXTENT_UP; + else + return EXT2_ET_EXTENT_NO_PREV; + } + if (op != EXT2_EXTENT_PREV_SIB) { +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN_AND_LAST) ? "down/last" : + ((op == EXT2_EXTENT_UP) ? "up" : "unknown")); +#endif + } + } + + if (orig_op == EXT2_EXTENT_LAST_LEAF) { + if ((handle->level < handle->max_depth) && + (path->left == 0)) + op = EXT2_EXTENT_DOWN; + else + op = EXT2_EXTENT_LAST_SIB; +#ifdef DEBUG_GET_EXTENT + printf("<<<< OP = %s\n", + (op == EXT2_EXTENT_DOWN) ? "down" : "last_sib"); +#endif + } + + switch (op) { + case EXT2_EXTENT_CURRENT: + ix = path->curr; + break; + case EXT2_EXTENT_ROOT: + handle->level = 0; + path = handle->path + handle->level; + /* fallthrough */ + case EXT2_EXTENT_FIRST_SIB: + path->left = path->entries; + path->curr = 0; + /* fallthrough */ + case EXT2_EXTENT_NEXT_SIB: + if (path->left <= 0) + return EXT2_ET_EXTENT_NO_NEXT; + if (path->curr) { + ix = path->curr; + ix++; + } else { + eh = (struct ext3_extent_header *) path->buf; + ix = EXT_FIRST_INDEX(eh); + } + path->left--; + path->curr = ix; + path->visit_num = 0; + break; + case EXT2_EXTENT_PREV_SIB: + if (!path->curr || + path->left+1 >= path->entries) + return EXT2_ET_EXTENT_NO_PREV; + ix = path->curr; + ix--; + path->curr = ix; + path->left++; + if (handle->level < handle->max_depth) + path->visit_num = 1; + break; + case EXT2_EXTENT_LAST_SIB: + eh = (struct ext3_extent_header *) path->buf; + path->curr = EXT_LAST_EXTENT(eh); + ix = path->curr; + path->left = 0; + path->visit_num = 0; + break; + case EXT2_EXTENT_UP: + if (handle->level <= 0) + return EXT2_ET_EXTENT_NO_UP; + handle->level--; + path--; + ix = path->curr; + if ((orig_op == EXT2_EXTENT_PREV) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) + path->visit_num = 0; + break; + case EXT2_EXTENT_DOWN: + case EXT2_EXTENT_DOWN_AND_LAST: + if (!path->curr ||(handle->level >= handle->max_depth)) + return EXT2_ET_EXTENT_NO_DOWN; + + ix = path->curr; + newpath = path + 1; + if (!newpath->buf) { + retval = ext2fs_get_mem(handle->fs->blocksize, + &newpath->buf); + if (retval) + return retval; + } + blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + if ((handle->fs->flags & EXT2_FLAG_IMAGE_FILE) && + (handle->fs->io != handle->fs->image_io)) + memset(newpath->buf, 0, handle->fs->blocksize); + else { + retval = io_channel_read_blk64(handle->fs->io, + blk, 1, newpath->buf); + if (retval) + return retval; + } + handle->level++; + + eh = (struct ext3_extent_header *) newpath->buf; + + retval = ext2fs_extent_header_verify(eh, handle->fs->blocksize); + if (retval) { + handle->level--; + return retval; + } + + if (!(handle->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_extent_block_csum_verify(handle->fs, handle->ino, + eh)) + failed_csum = 1; + + newpath->left = newpath->entries = + ext2fs_le16_to_cpu(eh->eh_entries); + newpath->max_entries = ext2fs_le16_to_cpu(eh->eh_max); + + if (path->left > 0) { + ix++; + newpath->end_blk = ext2fs_le32_to_cpu(ix->ei_block); + } else + newpath->end_blk = path->end_blk; + + path = newpath; + if (op == EXT2_EXTENT_DOWN) { + ix = EXT_FIRST_INDEX((struct ext3_extent_header *) eh); + path->curr = ix; + path->left = path->entries - 1; + path->visit_num = 0; + } else { + ix = EXT_LAST_INDEX((struct ext3_extent_header *) eh); + path->curr = ix; + path->left = 0; + if (handle->level < handle->max_depth) + path->visit_num = 1; + } +#ifdef DEBUG_GET_EXTENT + printf("Down to level %d/%d, end_blk=%llu\n", + handle->level, handle->max_depth, + path->end_blk); +#endif + break; + default: + return EXT2_ET_OP_NOT_SUPPORTED; + } + + if (!ix) + return EXT2_ET_NO_CURRENT_NODE; + + extent->e_flags = 0; +#ifdef DEBUG_GET_EXTENT + printf("(Left %d)\n", path->left); +#endif + + if (handle->level == handle->max_depth) { + ex = (struct ext3_extent *) ix; + + extent->e_pblk = ext2fs_le32_to_cpu(ex->ee_start) + + ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); + extent->e_lblk = ext2fs_le32_to_cpu(ex->ee_block); + extent->e_len = ext2fs_le16_to_cpu(ex->ee_len); + extent->e_flags |= EXT2_EXTENT_FLAGS_LEAF; + if (extent->e_len > EXT_INIT_MAX_LEN) { + extent->e_len -= EXT_INIT_MAX_LEN; + extent->e_flags |= EXT2_EXTENT_FLAGS_UNINIT; + } + } else { + extent->e_pblk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + extent->e_lblk = ext2fs_le32_to_cpu(ix->ei_block); + if (path->left > 0) { + ix++; + end_blk = ext2fs_le32_to_cpu(ix->ei_block); + } else + end_blk = path->end_blk; + + extent->e_len = end_blk - extent->e_lblk; + } + if (path->visit_num) + extent->e_flags |= EXT2_EXTENT_FLAGS_SECOND_VISIT; + + if (((orig_op == EXT2_EXTENT_NEXT_LEAF) || + (orig_op == EXT2_EXTENT_PREV_LEAF)) && + (handle->level != handle->max_depth)) + goto retry; + + if ((orig_op == EXT2_EXTENT_LAST_LEAF) && + ((handle->level != handle->max_depth) || + (path->left != 0))) + goto retry; + + if (failed_csum) + return EXT2_ET_EXTENT_CSUM_INVALID; + + return 0; +} + +static errcode_t update_path(ext2_extent_handle_t handle) +{ + blk64_t blk; + errcode_t retval; + struct ext3_extent_idx *ix; + struct ext3_extent_header *eh; + + if (handle->level == 0) { + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + } else { + ix = handle->path[handle->level - 1].curr; + blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + + /* then update the checksum */ + eh = (struct ext3_extent_header *) + handle->path[handle->level].buf; + retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, + eh); + if (retval) + return retval; + + retval = io_channel_write_blk64(handle->fs->io, + blk, 1, handle->path[handle->level].buf); + } + return retval; +} + +#if 0 +errcode_t ext2fs_extent_save_path(ext2_extent_handle_t handle, + ext2_extent_path_t *ret_path) +{ + ext2_extent_path_t save_path; + struct ext2fs_extent extent; + struct ext2_extent_info info; + errcode_t retval; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + return retval; + + retval = ext2fs_extent_get_info(handle, &info); + if (retval) + return retval; + + retval = ext2fs_get_mem(sizeof(struct ext2_extent_path), &save_path); + if (retval) + return retval; + memset(save_path, 0, sizeof(struct ext2_extent_path)); + + save_path->magic = EXT2_ET_MAGIC_EXTENT_PATH; + save_path->leaf_height = info.max_depth - info.curr_level - 1; + save_path->lblk = extent.e_lblk; + + *ret_path = save_path; + return 0; +} + +errcode_t ext2fs_extent_free_path(ext2_extent_path_t path) +{ + EXT2_CHECK_MAGIC(path, EXT2_ET_MAGIC_EXTENT_PATH); + + ext2fs_free_mem(&path); + return 0; +} +#endif + +/* + * Go to the node at leaf_level which contains logical block blk. + * + * leaf_level is height from the leaf node level, i.e. + * leaf_level 0 is at leaf node, leaf_level 1 is 1 above etc. + * + * If "blk" has no mapping (hole) then handle is left at last + * extent before blk. + */ +errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, + int leaf_level, blk64_t blk) +{ + struct ext2fs_extent extent; + errcode_t retval; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); + if (retval) { + if (retval == EXT2_ET_EXTENT_NO_NEXT) + retval = EXT2_ET_EXTENT_NOT_FOUND; + return retval; + } + + if (leaf_level > handle->max_depth) { +#ifdef DEBUG + printf("leaf level %d greater than tree depth %d\n", + leaf_level, handle->max_depth); +#endif + return EXT2_ET_OP_NOT_SUPPORTED; + } + +#ifdef DEBUG + printf("goto extent ino %u, level %d, %llu\n", handle->ino, + leaf_level, blk); +#endif + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("root", &extent); +#endif + while (1) { + if (handle->max_depth - handle->level == leaf_level) { + /* block is in this &extent */ + if ((blk >= extent.e_lblk) && + (blk < extent.e_lblk + extent.e_len)) + return 0; + if (blk < extent.e_lblk) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_PREV_SIB, + &extent); + return EXT2_ET_EXTENT_NOT_FOUND; + } + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_SIB, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + return EXT2_ET_EXTENT_NOT_FOUND; + if (retval) + return retval; + continue; + } + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_SIB, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + goto go_down; + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("next", &extent); +#endif + if (blk == extent.e_lblk) + goto go_down; + if (blk > extent.e_lblk) + continue; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_SIB, + &extent); + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("prev", &extent); +#endif + + go_down: + retval = ext2fs_extent_get(handle, EXT2_EXTENT_DOWN, + &extent); + if (retval) + return retval; + +#ifdef DEBUG_GOTO_EXTENTS + dbg_print_extent("down", &extent); +#endif + } +} + +errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, + blk64_t blk) +{ + return ext2fs_extent_goto2(handle, 0, blk); +} + +/* + * Traverse back up to root fixing parents of current node as needed. + * + * If we changed start of first entry in a node, fix parent index start + * and so on. + * + * Safe to call for any position in node; if not at the first entry, + * it will simply return. + * + * Note a subtlety of this function -- if there happen to be two extents + * mapping the same lblk and someone calls fix_parents on the second of the two + * extents, the position of the extent handle after the call will be the second + * extent if nothing happened, or the first extent if something did. A caller + * in this situation must use ext2fs_extent_goto() after calling this function. + * Or simply don't map the same lblk with two extents, ever. + */ +errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle) +{ + int retval = 0; + int orig_height; + blk64_t start; + struct extent_path *path; + struct ext2fs_extent extent; + struct ext2_extent_info info; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + + /* modified node's start block */ + start = extent.e_lblk; + + if ((retval = ext2fs_extent_get_info(handle, &info))) + return retval; + orig_height = info.max_depth - info.curr_level; + + /* traverse up until index not first, or startblk matches, or top */ + while (handle->level > 0 && + (path->left == path->entries - 1)) { + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + if (retval) + goto done; + if (extent.e_lblk == start) + break; + path = handle->path + handle->level; + extent.e_len += (extent.e_lblk - start); + extent.e_lblk = start; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + update_path(handle); + } + + /* put handle back to where we started */ + retval = ext2fs_extent_goto2(handle, orig_height, start); +done: + return retval; +} + +errcode_t ext2fs_extent_replace(ext2_extent_handle_t handle, + int flags EXT2FS_ATTR((unused)), + struct ext2fs_extent *extent) +{ + struct extent_path *path; + struct ext3_extent_idx *ix; + struct ext3_extent *ex; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("extent replace: %u ", handle->ino); + dbg_print_extent(0, extent); +#endif + + if (handle->level == handle->max_depth) { + ex = path->curr; + + ex->ee_block = ext2fs_cpu_to_le32(extent->e_lblk); + ex->ee_start = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); + ex->ee_start_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) { + if (extent->e_len > EXT_UNINIT_MAX_LEN) + return EXT2_ET_EXTENT_INVALID_LENGTH; + ex->ee_len = ext2fs_cpu_to_le16(extent->e_len + + EXT_INIT_MAX_LEN); + } else { + if (extent->e_len > EXT_INIT_MAX_LEN) + return EXT2_ET_EXTENT_INVALID_LENGTH; + ex->ee_len = ext2fs_cpu_to_le16(extent->e_len); + } + } else { + ix = path->curr; + + ix->ei_leaf = ext2fs_cpu_to_le32(extent->e_pblk & 0xFFFFFFFF); + ix->ei_leaf_hi = ext2fs_cpu_to_le16(extent->e_pblk >> 32); + ix->ei_block = ext2fs_cpu_to_le32(extent->e_lblk); + ix->ei_unused = 0; + } + update_path(handle); + return 0; +} + +static int splitting_at_eof(struct ext2_extent_handle *handle, + struct extent_path *path) +{ + struct extent_path *ppp = path; + dump_path(__func__, handle, path); + + if (handle->level == 0) + return 0; + + do { + if (ppp->left) + return 0; + ppp--; + } while (ppp >= handle->path); + + return 1; +} + +/* + * allocate a new block, move half the current node to it, and update parent + * + * handle will be left pointing at original record. + */ +static errcode_t extent_node_split(ext2_extent_handle_t handle, + int expand_allowed) +{ + errcode_t retval = 0; + blk64_t new_node_pblk; + blk64_t new_node_start; + blk64_t orig_lblk; + blk64_t goal_blk = 0; + int orig_height; + char *block_buf = NULL; + struct ext2fs_extent extent; + struct extent_path *path, *newpath = 0; + struct ext3_extent_header *eh, *neweh; + int tocopy; + int new_root = 0; + struct ext2_extent_info info; + int no_balance; + + /* basic sanity */ + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("splitting node at level %d\n", handle->level); +#endif + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + + retval = ext2fs_extent_get_info(handle, &info); + if (retval) + goto done; + + /* save the position we were originally splitting... */ + orig_height = info.max_depth - info.curr_level; + orig_lblk = extent.e_lblk; + + /* Try to put the index block before the first extent */ + path = handle->path + handle->level; + eh = (struct ext3_extent_header *) path->buf; + if (handle->level == handle->max_depth) { + struct ext3_extent *ex; + + ex = EXT_FIRST_EXTENT(eh); + goal_blk = ext2fs_le32_to_cpu(ex->ee_start) + + ((__u64) ext2fs_le16_to_cpu(ex->ee_start_hi) << 32); + } else { + struct ext3_extent_idx *ix; + + ix = EXT_FIRST_INDEX(eh); + goal_blk = ext2fs_le32_to_cpu(ix->ei_leaf) + + ((__u64) ext2fs_le16_to_cpu(ix->ei_leaf_hi) << 32); + } + goal_blk -= EXT2FS_CLUSTER_RATIO(handle->fs); + goal_blk &= ~EXT2FS_CLUSTER_MASK(handle->fs); + + /* Is there room in the parent for a new entry? */ + if (handle->level && + (handle->path[handle->level - 1].entries >= + handle->path[handle->level - 1].max_entries)) { + +#ifdef DEBUG + printf("parent level %d full; splitting it too\n", + handle->level - 1); +#endif + /* split the parent */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + if (retval) + goto done; + + retval = extent_node_split(handle, expand_allowed); + if (retval) + goto done; + + /* get handle back to our original split position */ + retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk); + if (retval) + goto done; + } + + /* At this point, parent should have room for this split */ + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + /* + * Normally, we try to split a full node in half. This doesn't turn + * out so well if we're tacking extents on the end of the file because + * then we're stuck with a tree of half-full extent blocks. This of + * course doesn't apply to the root level. + */ + no_balance = expand_allowed ? splitting_at_eof(handle, path) : 0; + + /* extent header of the current node we'll split */ + eh = (struct ext3_extent_header *)path->buf; + + /* splitting root level means moving them all out */ + if (handle->level == 0) { + new_root = 1; + tocopy = ext2fs_le16_to_cpu(eh->eh_entries); + retval = ext2fs_get_memzero((handle->max_paths + 1) * + sizeof(struct extent_path), + &newpath); + if (retval) + goto done; + } else { + if (no_balance) + tocopy = 1; + else + tocopy = ext2fs_le16_to_cpu(eh->eh_entries) / 2; + } + +#ifdef DEBUG + printf("will copy out %d of %d entries at level %d\n", + tocopy, ext2fs_le16_to_cpu(eh->eh_entries), + handle->level); +#endif + + if (!tocopy && !no_balance) { +#ifdef DEBUG + printf("Nothing to copy to new block!\n"); +#endif + retval = EXT2_ET_CANT_SPLIT_EXTENT; + goto done; + } + + /* first we need a new block, or can do nothing. */ + block_buf = malloc(handle->fs->blocksize); + if (!block_buf) { + retval = ENOMEM; + goto done; + } + + if (!goal_blk) + goal_blk = ext2fs_find_inode_goal(handle->fs, handle->ino, + handle->inode, 0); + retval = ext2fs_alloc_block2(handle->fs, goal_blk, block_buf, + &new_node_pblk); + if (retval) + goto done; + +#ifdef DEBUG + printf("will copy to new node at block %lu\n", + (unsigned long) new_node_pblk); +#endif + + /* Copy data into new block buffer */ + /* First the header for the new block... */ + neweh = (struct ext3_extent_header *) block_buf; + memcpy(neweh, eh, sizeof(struct ext3_extent_header)); + neweh->eh_entries = ext2fs_cpu_to_le16(tocopy); + neweh->eh_max = ext2fs_cpu_to_le16((handle->fs->blocksize - + sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent)); + + /* then the entries for the new block... */ + memcpy(EXT_FIRST_INDEX(neweh), + EXT_FIRST_INDEX(eh) + + (ext2fs_le16_to_cpu(eh->eh_entries) - tocopy), + sizeof(struct ext3_extent_idx) * tocopy); + + new_node_start = ext2fs_le32_to_cpu(EXT_FIRST_INDEX(neweh)->ei_block); + + /* then update the checksum */ + retval = ext2fs_extent_block_csum_set(handle->fs, handle->ino, neweh); + if (retval) + goto done; + + /* ...and write the new node block out to disk. */ + retval = io_channel_write_blk64(handle->fs->io, new_node_pblk, 1, + block_buf); + + if (retval) + goto done; + + /* OK! we've created the new node; now adjust the tree */ + + /* current path now has fewer active entries, we copied some out */ + if (handle->level == 0) { + memcpy(newpath, path, + sizeof(struct extent_path) * handle->max_paths); + handle->path = newpath; + newpath = path; + path = handle->path; + path->entries = 1; + path->left = path->max_entries - 1; + handle->max_depth++; + handle->max_paths++; + eh->eh_depth = ext2fs_cpu_to_le16(handle->max_depth); + } else { + path->entries -= tocopy; + path->left -= tocopy; + } + + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + /* this writes out the node, incl. the modified header */ + retval = update_path(handle); + if (retval) + goto done; + + /* now go up and insert/replace index for new node we created */ + if (new_root) { + retval = ext2fs_extent_get(handle, EXT2_EXTENT_FIRST_SIB, &extent); + if (retval) + goto done; + + extent.e_lblk = new_node_start; + extent.e_pblk = new_node_pblk; + extent.e_len = handle->path[0].end_blk - extent.e_lblk; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + } else { + __u32 new_node_length; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, &extent); + /* will insert after this one; it's length is shorter now */ + new_node_length = new_node_start - extent.e_lblk; + extent.e_len -= new_node_length; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + + /* now set up the new extent and insert it */ + extent.e_lblk = new_node_start; + extent.e_pblk = new_node_pblk; + extent.e_len = new_node_length; + retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER, &extent); + if (retval) + goto done; + } + + /* get handle back to our original position */ + retval = ext2fs_extent_goto2(handle, orig_height, orig_lblk); + if (retval) + goto done; + + /* new node hooked in, so update inode block count (do this here?) */ + ext2fs_iblk_add_blocks(handle->fs, handle->inode, 1); + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + if (retval) + goto done; + +done: + if (newpath) + ext2fs_free_mem(&newpath); + free(block_buf); + + return retval; +} + +errcode_t ext2fs_extent_node_split(ext2_extent_handle_t handle) +{ + return extent_node_split(handle, 0); +} + +errcode_t ext2fs_extent_insert(ext2_extent_handle_t handle, int flags, + struct ext2fs_extent *extent) +{ + struct extent_path *path; + struct ext3_extent_idx *ix; + struct ext3_extent_header *eh; + errcode_t retval; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + printf("extent insert: %u ", handle->ino); + dbg_print_extent(0, extent); +#endif + + path = handle->path + handle->level; + + if (path->entries >= path->max_entries) { + if (flags & EXT2_EXTENT_INSERT_NOSPLIT) { + return EXT2_ET_CANT_INSERT_EXTENT; + } else { +#ifdef DEBUG + printf("node full (level %d) - splitting\n", + handle->level); +#endif + retval = extent_node_split(handle, 1); + if (retval) + return retval; + path = handle->path + handle->level; + } + } + + eh = (struct ext3_extent_header *) path->buf; + if (path->curr) { + ix = path->curr; + if (flags & EXT2_EXTENT_INSERT_AFTER) { + ix++; + path->left--; + } + } else { + ix = EXT_FIRST_INDEX(eh); + path->left = -1; + } + + path->curr = ix; + + if (path->left >= 0) + memmove(ix + 1, ix, + (path->left+1) * sizeof(struct ext3_extent_idx)); + path->left++; + path->entries++; + + eh = (struct ext3_extent_header *) path->buf; + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + + retval = ext2fs_extent_replace(handle, 0, extent); + if (retval) + goto errout; + + retval = update_path(handle); + if (retval) + goto errout; + + return 0; + +errout: + ext2fs_extent_delete(handle, 0); + return retval; +} + +/* + * Sets the physical block for a logical file block in the extent tree. + * + * May: map unmapped, unmap mapped, or remap mapped blocks. + * + * Mapping an unmapped block adds a single-block extent. + * + * Unmapping first or last block modifies extent in-place + * - But may need to fix parent's starts too in first-block case + * + * Mapping any unmapped block requires adding a (single-block) extent + * and inserting into proper point in tree. + * + * Modifying (unmapping or remapping) a block in the middle + * of an extent requires splitting the extent. + * - Remapping case requires new single-block extent. + * + * Remapping first or last block adds an extent. + * + * We really need extent adding to be smart about merging. + */ + +errcode_t ext2fs_extent_set_bmap(ext2_extent_handle_t handle, + blk64_t logical, blk64_t physical, int flags) +{ + errcode_t ec, retval = 0; + int mapped = 1; /* logical is mapped? */ + int orig_height; + int extent_uninit = 0; + int prev_uninit = 0; + int next_uninit = 0; + int new_uninit = 0; + int max_len = EXT_INIT_MAX_LEN; + int has_prev, has_next; + blk64_t orig_lblk; + struct extent_path *path; + struct ext2fs_extent extent, next_extent, prev_extent; + struct ext2fs_extent newextent; + struct ext2_extent_info info; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + +#ifdef DEBUG + printf("set_bmap ino %u log %lld phys %lld flags %d\n", + handle->ino, logical, physical, flags); +#endif + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + + path = handle->path + handle->level; + + if (flags & EXT2_EXTENT_SET_BMAP_UNINIT) { + new_uninit = 1; + max_len = EXT_UNINIT_MAX_LEN; + } + + /* if (re)mapping, set up new extent to insert */ + if (physical) { + newextent.e_len = 1; + newextent.e_pblk = physical; + newextent.e_lblk = logical; + newextent.e_flags = EXT2_EXTENT_FLAGS_LEAF; + if (new_uninit) + newextent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT; + } + + /* special case if the extent tree is completely empty */ + if ((handle->max_depth == 0) && (path->entries == 0)) { + retval = ext2fs_extent_insert(handle, 0, &newextent); + return retval; + } + + /* save our original location in the extent tree */ + if ((retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &extent))) { + if (retval != EXT2_ET_NO_CURRENT_NODE) + return retval; + memset(&extent, 0, sizeof(extent)); + } + if ((retval = ext2fs_extent_get_info(handle, &info))) + return retval; + orig_height = info.max_depth - info.curr_level; + orig_lblk = extent.e_lblk; + + /* go to the logical spot we want to (re/un)map */ + retval = ext2fs_extent_goto(handle, logical); + if (retval) { + if (retval == EXT2_ET_EXTENT_NOT_FOUND) { + retval = 0; + mapped = 0; + if (!physical) { +#ifdef DEBUG + printf("block %llu already unmapped\n", + logical); +#endif + goto done; + } + } else + goto done; + } + + /* + * This may be the extent *before* the requested logical, + * if it's currently unmapped. + * + * Get the previous and next leaf extents, if they are present. + */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval) + goto done; + if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + extent_uninit = 1; + retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &next_extent); + if (retval) { + has_next = 0; + if (retval != EXT2_ET_EXTENT_NO_NEXT) + goto done; + } else { + dbg_print_extent("set_bmap: next_extent", + &next_extent); + has_next = 1; + if (next_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + next_uninit = 1; + } + retval = ext2fs_extent_goto(handle, logical); + if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND) + goto done; + retval = ext2fs_extent_get(handle, EXT2_EXTENT_PREV_LEAF, &prev_extent); + if (retval) { + has_prev = 0; + if (retval != EXT2_ET_EXTENT_NO_PREV) + goto done; + } else { + has_prev = 1; + dbg_print_extent("set_bmap: prev_extent", + &prev_extent); + if (prev_extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) + prev_uninit = 1; + } + retval = ext2fs_extent_goto(handle, logical); + if (retval && retval != EXT2_ET_EXTENT_NOT_FOUND) + goto done; + + /* check if already pointing to the requested physical */ + if (mapped && (new_uninit == extent_uninit) && + (extent.e_pblk + (logical - extent.e_lblk) == physical)) { +#ifdef DEBUG + printf("physical block (at %llu) unchanged\n", logical); +#endif + goto done; + } + + if (!mapped) { +#ifdef DEBUG + printf("mapping unmapped logical block %llu\n", logical); +#endif + if ((logical == extent.e_lblk + extent.e_len) && + (physical == extent.e_pblk + extent.e_len) && + (new_uninit == extent_uninit) && + ((int) extent.e_len < max_len-1)) { + extent.e_len++; + retval = ext2fs_extent_replace(handle, 0, &extent); + } else if ((logical == extent.e_lblk - 1) && + (physical == extent.e_pblk - 1) && + (new_uninit == extent_uninit) && + ((int) extent.e_len < max_len - 1)) { + extent.e_len++; + extent.e_lblk--; + extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, &extent); + } else if (has_next && + (logical == next_extent.e_lblk - 1) && + (physical == next_extent.e_pblk - 1) && + (new_uninit == next_uninit) && + ((int) next_extent.e_len < max_len - 1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &next_extent); + if (retval) + goto done; + next_extent.e_len++; + next_extent.e_lblk--; + next_extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, &next_extent); + } else if (logical < extent.e_lblk) + retval = ext2fs_extent_insert(handle, 0, &newextent); + else + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + } else if ((logical == extent.e_lblk) && (extent.e_len == 1)) { +#ifdef DEBUG + printf("(re/un)mapping only block in extent\n"); +#endif + if (physical) { + retval = ext2fs_extent_replace(handle, 0, &newextent); + } else { + retval = ext2fs_extent_delete(handle, 0); + if (retval) + goto done; + ec = ext2fs_extent_fix_parents(handle); + if (ec != EXT2_ET_NO_CURRENT_NODE) + retval = ec; + } + + if (retval) + goto done; + } else if (logical == extent.e_lblk + extent.e_len - 1) { +#ifdef DEBUG + printf("(re/un)mapping last block in extent\n"); +#endif + if (physical) { + if (has_next && + (logical == (next_extent.e_lblk - 1)) && + (physical == (next_extent.e_pblk - 1)) && + (new_uninit == next_uninit) && + ((int) next_extent.e_len < max_len - 1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, &next_extent); + if (retval) + goto done; + next_extent.e_len++; + next_extent.e_lblk--; + next_extent.e_pblk--; + retval = ext2fs_extent_replace(handle, 0, + &next_extent); + if (retval) + goto done; + } else + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + /* + * Now pointing at inserted extent; move back to prev. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, logical); + if (retval) + goto done; + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_CURRENT, + &extent); + if (retval) + goto done; + } + extent.e_len--; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + } else if (logical == extent.e_lblk) { +#ifdef DEBUG + printf("(re/un)mapping first block in extent\n"); +#endif + if (physical) { + if (has_prev && + (logical == (prev_extent.e_lblk + + prev_extent.e_len)) && + (physical == (prev_extent.e_pblk + + prev_extent.e_len)) && + (new_uninit == prev_uninit) && + ((int) prev_extent.e_len < max_len-1)) { + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_PREV_LEAF, &prev_extent); + if (retval) + goto done; + prev_extent.e_len++; + retval = ext2fs_extent_replace(handle, 0, + &prev_extent); + } else + retval = ext2fs_extent_insert(handle, + 0, &newextent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &extent); + if (retval) + goto done; + } + extent.e_pblk++; + extent.e_lblk++; + extent.e_len--; + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto done; + } else { + __u32 save_length; + blk64_t save_lblk; + struct ext2fs_extent save_extent; + errcode_t r2; + +#ifdef DEBUG + printf("(re/un)mapping in middle of extent\n"); +#endif + /* need to split this extent; later */ + save_lblk = extent.e_lblk; + save_length = extent.e_len; + save_extent = extent; + + /* shorten pre-split extent */ + extent.e_len = (logical - extent.e_lblk); + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto done; + /* insert our new extent, if any */ + if (physical) { + /* insert new extent after current */ + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newextent); + if (retval) { + r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) + (void)ext2fs_extent_replace(handle, 0, + &save_extent); + goto done; + } + } + /* add post-split extent */ + extent.e_pblk += extent.e_len + 1; + extent.e_lblk += extent.e_len + 1; + extent.e_len = save_length - extent.e_len - 1; + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &extent); + if (retval) { + if (physical) { + r2 = ext2fs_extent_goto(handle, + newextent.e_lblk); + if (r2 == 0) + (void)ext2fs_extent_delete(handle, 0); + } + r2 = ext2fs_extent_goto(handle, save_lblk); + if (r2 == 0) + (void)ext2fs_extent_replace(handle, 0, + &save_extent); + goto done; + } + } + +done: + /* get handle back to its position */ + if (orig_height > handle->max_depth) + orig_height = handle->max_depth; /* In case we shortened the tree */ + ext2fs_extent_goto2(handle, orig_height, orig_lblk); + return retval; +} + +errcode_t ext2fs_extent_delete(ext2_extent_handle_t handle, int flags) +{ + struct extent_path *path; + char *cp; + struct ext3_extent_header *eh; + errcode_t retval = 0; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + if (!(handle->fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + if (!handle->path) + return EXT2_ET_NO_CURRENT_NODE; + +#ifdef DEBUG + { + struct ext2fs_extent extent; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &extent); + if (retval == 0) { + printf("extent delete %u ", handle->ino); + dbg_print_extent(0, &extent); + } + } +#endif + + path = handle->path + handle->level; + if (!path->curr) + return EXT2_ET_NO_CURRENT_NODE; + + cp = path->curr; + + if (path->left) { + memmove(cp, cp + sizeof(struct ext3_extent_idx), + path->left * sizeof(struct ext3_extent_idx)); + path->left--; + } else { + struct ext3_extent_idx *ix = path->curr; + ix--; + path->curr = ix; + } + if (--path->entries == 0) + path->curr = 0; + + /* if non-root node has no entries left, remove it & parent ptr to it */ + if (path->entries == 0 && handle->level) { + if (!(flags & EXT2_EXTENT_DELETE_KEEP_EMPTY)) { + struct ext2fs_extent extent; + + retval = ext2fs_extent_get(handle, EXT2_EXTENT_UP, + &extent); + if (retval) + return retval; + + retval = ext2fs_extent_delete(handle, flags); + handle->inode->i_blocks -= + (handle->fs->blocksize * + EXT2FS_CLUSTER_RATIO(handle->fs)) / 512; + retval = ext2fs_write_inode(handle->fs, handle->ino, + handle->inode); + ext2fs_block_alloc_stats2(handle->fs, + extent.e_pblk, -1); + } + } else { + eh = (struct ext3_extent_header *) path->buf; + eh->eh_entries = ext2fs_cpu_to_le16(path->entries); + if ((path->entries == 0) && (handle->level == 0)) { + eh->eh_depth = 0; + handle->max_depth = 0; + } + retval = update_path(handle); + } + return retval; +} + +errcode_t ext2fs_extent_get_info(ext2_extent_handle_t handle, + struct ext2_extent_info *info) +{ + struct extent_path *path; + + EXT2_CHECK_MAGIC(handle, EXT2_ET_MAGIC_EXTENT_HANDLE); + + memset(info, 0, sizeof(struct ext2_extent_info)); + + path = handle->path + handle->level; + if (path) { + if (path->curr) + info->curr_entry = ((char *) path->curr - path->buf) / + sizeof(struct ext3_extent_idx); + else + info->curr_entry = 0; + info->num_entries = path->entries; + info->max_entries = path->max_entries; + info->bytes_avail = (path->max_entries - path->entries) * + sizeof(struct ext3_extent); + } + + info->curr_level = handle->level; + info->max_depth = handle->max_depth; + info->max_lblk = EXT_MAX_EXTENT_LBLK; + info->max_pblk = EXT_MAX_EXTENT_PBLK; + info->max_len = EXT_INIT_MAX_LEN; + info->max_uninit_len = EXT_UNINIT_MAX_LEN; + + return 0; +} + +static int ul_log2(unsigned long arg) +{ + int l = 0; + + arg >>= 1; + while (arg) { + l++; + arg >>= 1; + } + return l; +} + +size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle) +{ + size_t iblock_sz = sizeof(((struct ext2_inode *)NULL)->i_block); + size_t iblock_extents = (iblock_sz - sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent); + size_t extents_per_block = (handle->fs->blocksize - + sizeof(struct ext3_extent_header)) / + sizeof(struct ext3_extent); + static unsigned int last_blocksize = 0; + static size_t last_result = 0; + + if (last_blocksize && last_blocksize == handle->fs->blocksize) + return last_result; + + last_result = 1 + ((ul_log2(EXT_MAX_EXTENT_LBLK) - ul_log2(iblock_extents)) / + ul_log2(extents_per_block)); + last_blocksize = handle->fs->blocksize; + return last_result; +} + +#ifdef DEBUG +/* + * Override debugfs's prompt + */ +const char *debug_prog_name = "tst_extents"; + +#endif + diff --git a/src/ext2fs/fileio.c b/src/ext2fs/fileio.c new file mode 100644 index 00000000..810a7fd8 --- /dev/null +++ b/src/ext2fs/fileio.c @@ -0,0 +1,615 @@ +/* + * fileio.c --- Simple file I/O routines + * + * Copyright (C) 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +struct ext2_file { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t ino; + struct ext2_inode inode; + int flags; + __u64 pos; + blk64_t blockno; + blk64_t physblock; + char *buf; +}; + +#define BMAP_BUFFER (file->buf + fs->blocksize) + +errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + int flags, ext2_file_t *ret) +{ + ext2_file_t file; + errcode_t retval; + + /* + * Don't let caller create or open a file for writing if the + * filesystem is read-only. + */ + if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) && + !(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + retval = ext2fs_get_mem(sizeof(struct ext2_file), &file); + if (retval) + return retval; + + memset(file, 0, sizeof(struct ext2_file)); + file->magic = EXT2_ET_MAGIC_EXT2_FILE; + file->fs = fs; + file->ino = ino; + file->flags = flags & EXT2_FILE_MASK; + + if (inode) { + memcpy(&file->inode, inode, sizeof(struct ext2_inode)); + } else { + retval = ext2fs_read_inode(fs, ino, &file->inode); + if (retval) + goto fail; + } + + retval = ext2fs_get_array(3, fs->blocksize, &file->buf); + if (retval) + goto fail; + + *ret = file; + return 0; + +fail: + if (file->buf) + ext2fs_free_mem(&file->buf); + ext2fs_free_mem(&file); + return retval; +} + +errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino, + int flags, ext2_file_t *ret) +{ + return ext2fs_file_open2(fs, ino, NULL, flags, ret); +} + +/* + * This function returns the filesystem handle of a file from the structure + */ +ext2_filsys ext2fs_file_get_fs(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return 0; + return file->fs; +} + +/* + * This function returns the pointer to the inode of a file from the structure + */ +struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return NULL; + return &file->inode; +} + +/* This function returns the inode number from the structure */ +ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return 0; + return file->ino; +} + +/* + * This function flushes the dirty block buffer out to disk if + * necessary. + */ +errcode_t ext2fs_file_flush(ext2_file_t file) +{ + errcode_t retval; + ext2_filsys fs; + int ret_flags; + blk64_t dontcare; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + if (!(file->flags & EXT2_FILE_BUF_VALID) || + !(file->flags & EXT2_FILE_BUF_DIRTY)) + return 0; + + /* Is this an uninit block? */ + if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER, + 0, file->blockno, &ret_flags, &dontcare); + if (retval) + return retval; + if (ret_flags & BMAP_RET_UNINIT) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, BMAP_SET, + file->blockno, 0, + &file->physblock); + if (retval) + return retval; + } + } + + /* + * OK, the physical block hasn't been allocated yet. + * Allocate it. + */ + if (!file->physblock) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0, + file->blockno, 0, &file->physblock); + if (retval) + return retval; + } + + retval = io_channel_write_blk64(fs->io, file->physblock, 1, file->buf); + if (retval) + return retval; + + file->flags &= ~EXT2_FILE_BUF_DIRTY; + + return retval; +} + +/* + * This function synchronizes the file's block buffer and the current + * file position, possibly invalidating block buffer if necessary + */ +static errcode_t sync_buffer_position(ext2_file_t file) +{ + blk64_t b; + errcode_t retval; + + b = file->pos / file->fs->blocksize; + if (b != file->blockno) { + retval = ext2fs_file_flush(file); + if (retval) + return retval; + file->flags &= ~EXT2_FILE_BUF_VALID; + } + file->blockno = b; + return 0; +} + +/* + * This function loads the file's block buffer with valid data from + * the disk as necessary. + * + * If dontfill is true, then skip initializing the buffer since we're + * going to be replacing its entire contents anyway. If set, then the + * function basically only sets file->physblock and EXT2_FILE_BUF_VALID + */ +#define DONTFILL 1 +static errcode_t load_buffer(ext2_file_t file, int dontfill) +{ + ext2_filsys fs = file->fs; + errcode_t retval; + int ret_flags; + + if (!(file->flags & EXT2_FILE_BUF_VALID)) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, 0, file->blockno, &ret_flags, + &file->physblock); + if (retval) + return retval; + if (!dontfill) { + if (file->physblock && + !(ret_flags & BMAP_RET_UNINIT)) { + retval = io_channel_read_blk64(fs->io, + file->physblock, + 1, file->buf); + if (retval) + return retval; + } else + memset(file->buf, 0, fs->blocksize); + } + file->flags |= EXT2_FILE_BUF_VALID; + } + return 0; +} + + +errcode_t ext2fs_file_close(ext2_file_t file) +{ + errcode_t retval; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + retval = ext2fs_file_flush(file); + + if (file->buf) + ext2fs_free_mem(&file->buf); + ext2fs_free_mem(&file); + + return retval; +} + + +static errcode_t +ext2fs_file_read_inline_data(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got) +{ + ext2_filsys fs; + errcode_t retval; + unsigned int count = 0; + size_t size; + + fs = file->fs; + retval = ext2fs_inline_data_get(fs, file->ino, &file->inode, + file->buf, &size); + if (retval) + return retval; + + if (file->pos >= size) + goto out; + + count = size - file->pos; + if (count > wanted) + count = wanted; + memcpy(buf, file->buf + file->pos, count); + file->pos += count; + buf = (char *) buf + count; + +out: + if (got) + *got = count; + return retval; +} + + +errcode_t ext2fs_file_read(ext2_file_t file, void *buf, + unsigned int wanted, unsigned int *got) +{ + ext2_filsys fs; + errcode_t retval = 0; + unsigned int start, c, count = 0; + __u64 left; + char *ptr = (char *) buf; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + /* If an inode has inline data, things get complicated. */ + if (file->inode.i_flags & EXT4_INLINE_DATA_FL) + return ext2fs_file_read_inline_data(file, buf, wanted, got); + + while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) { + retval = sync_buffer_position(file); + if (retval) + goto fail; + retval = load_buffer(file, 0); + if (retval) + goto fail; + + start = file->pos % fs->blocksize; + c = fs->blocksize - start; + if (c > wanted) + c = wanted; + left = EXT2_I_SIZE(&file->inode) - file->pos ; + if (c > left) + c = left; + + memcpy(ptr, file->buf+start, c); + file->pos += c; + ptr += c; + count += c; + wanted -= c; + } + +fail: + if (got) + *got = count; + return retval; +} + + +static errcode_t +ext2fs_file_write_inline_data(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written) +{ + ext2_filsys fs; + errcode_t retval; + unsigned int count = 0; + size_t size; + + fs = file->fs; + retval = ext2fs_inline_data_get(fs, file->ino, &file->inode, + file->buf, &size); + if (retval) + return retval; + + if (file->pos < size) { + count = nbytes - file->pos; + memcpy(file->buf + file->pos, buf, count); + + retval = ext2fs_inline_data_set(fs, file->ino, &file->inode, + file->buf, count); + if (retval == EXT2_ET_INLINE_DATA_NO_SPACE) + goto expand; + if (retval) + return retval; + + file->pos += count; + + /* Update inode size */ + if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) { + errcode_t rc; + + rc = ext2fs_file_set_size2(file, file->pos); + if (retval == 0) + retval = rc; + } + + if (written) + *written = count; + return 0; + } + +expand: + retval = ext2fs_inline_data_expand(fs, file->ino); + if (retval) + return retval; + /* + * reload inode and return no space error + * + * XXX: file->inode could be copied from the outside + * in ext2fs_file_open2(). We have no way to modify + * the outside inode. + */ + retval = ext2fs_read_inode(fs, file->ino, &file->inode); + if (retval) + return retval; + return EXT2_ET_INLINE_DATA_NO_SPACE; +} + + +errcode_t ext2fs_file_write(ext2_file_t file, const void *buf, + unsigned int nbytes, unsigned int *written) +{ + ext2_filsys fs; + errcode_t retval = 0; + unsigned int start, c, count = 0; + const char *ptr = (const char *) buf; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + fs = file->fs; + + if (!(file->flags & EXT2_FILE_WRITE)) + return EXT2_ET_FILE_RO; + + /* If an inode has inline data, things get complicated. */ + if (file->inode.i_flags & EXT4_INLINE_DATA_FL) { + retval = ext2fs_file_write_inline_data(file, buf, nbytes, + written); + if (retval != EXT2_ET_INLINE_DATA_NO_SPACE) + return retval; + /* fall through to read data from the block */ + retval = 0; + } + + while (nbytes > 0) { + retval = sync_buffer_position(file); + if (retval) + goto fail; + + start = file->pos % fs->blocksize; + c = fs->blocksize - start; + if (c > nbytes) + c = nbytes; + + /* + * We only need to do a read-modify-update cycle if + * we're doing a partial write. + */ + retval = load_buffer(file, (c == fs->blocksize)); + if (retval) + goto fail; + + /* + * OK, the physical block hasn't been allocated yet. + * Allocate it. + */ + if (!file->physblock) { + retval = ext2fs_bmap2(fs, file->ino, &file->inode, + BMAP_BUFFER, + file->ino ? BMAP_ALLOC : 0, + file->blockno, 0, + &file->physblock); + if (retval) + goto fail; + } + + file->flags |= EXT2_FILE_BUF_DIRTY; + memcpy(file->buf+start, ptr, c); + file->pos += c; + ptr += c; + count += c; + nbytes -= c; + } + +fail: + /* Update inode size */ + if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) { + errcode_t rc; + + rc = ext2fs_file_set_size2(file, file->pos); + if (retval == 0) + retval = rc; + } + + if (written) + *written = count; + return retval; +} + +errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset, + int whence, __u64 *ret_pos) +{ + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + if (whence == EXT2_SEEK_SET) + file->pos = offset; + else if (whence == EXT2_SEEK_CUR) + file->pos += offset; + else if (whence == EXT2_SEEK_END) + file->pos = EXT2_I_SIZE(&file->inode) + offset; + else + return EXT2_ET_INVALID_ARGUMENT; + + if (ret_pos) + *ret_pos = file->pos; + + return 0; +} + +errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset, + int whence, ext2_off_t *ret_pos) +{ + __u64 loffset, ret_loffset = 0; + errcode_t retval; + + loffset = offset; + retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset); + if (ret_pos) + *ret_pos = (ext2_off_t) ret_loffset; + return retval; +} + + +/* + * This function returns the size of the file, according to the inode + */ +errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size) +{ + if (file->magic != EXT2_ET_MAGIC_EXT2_FILE) + return EXT2_ET_MAGIC_EXT2_FILE; + *ret_size = EXT2_I_SIZE(&file->inode); + return 0; +} + +/* + * This function returns the size of the file, according to the inode + */ +ext2_off_t ext2fs_file_get_size(ext2_file_t file) +{ + __u64 size; + + if (ext2fs_file_get_lsize(file, &size)) + return 0; + if ((size >> 32) != 0) + return 0; + return size; +} + +/* Zero the parts of the last block that are past EOF. */ +static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file, + ext2_off64_t offset) +{ + ext2_filsys fs = file->fs; + char *b = NULL; + ext2_off64_t off = offset % fs->blocksize; + blk64_t blk; + int ret_flags; + errcode_t retval; + + if (off == 0) + return 0; + + retval = sync_buffer_position(file); + if (retval) + return retval; + + /* Is there an initialized block at the end? */ + retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0, + offset / fs->blocksize, &ret_flags, &blk); + if (retval) + return retval; + if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT)) + return 0; + + /* Zero to the end of the block */ + retval = ext2fs_get_mem(fs->blocksize, &b); + if (retval) + return retval; + + /* Read/zero/write block */ + retval = io_channel_read_blk64(fs->io, blk, 1, b); + if (retval) + goto out; + + memset(b + off, 0, fs->blocksize - off); + + retval = io_channel_write_blk64(fs->io, blk, 1, b); + if (retval) + goto out; + +out: + ext2fs_free_mem(&b); + return retval; +} + +/* + * This function sets the size of the file, truncating it if necessary + * + */ +errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size) +{ + ext2_off64_t old_size; + errcode_t retval; + blk64_t old_truncate, truncate_block; + + EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE); + + if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode, + (size - 1) / file->fs->blocksize)) + return EXT2_ET_FILE_TOO_BIG; + truncate_block = ((size + file->fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(file->fs->super)); + old_size = EXT2_I_SIZE(&file->inode); + old_truncate = ((old_size + file->fs->blocksize - 1) >> + EXT2_BLOCK_SIZE_BITS(file->fs->super)); + + retval = ext2fs_inode_size_set(file->fs, &file->inode, size); + if (retval) + return retval; + + if (file->ino) { + retval = ext2fs_write_inode(file->fs, file->ino, &file->inode); + if (retval) + return retval; + } + + retval = ext2fs_file_zero_past_offset(file, size); + if (retval) + return retval; + + if (truncate_block >= old_truncate) + return 0; + + return ext2fs_punch(file->fs, file->ino, &file->inode, 0, + truncate_block, ~0ULL); +} + +errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size) +{ + return ext2fs_file_set_size2(file, size); +} diff --git a/src/ext2fs/freefs.c b/src/ext2fs/freefs.c new file mode 100644 index 00000000..ea9742ef --- /dev/null +++ b/src/ext2fs/freefs.c @@ -0,0 +1,104 @@ +/* + * freefs.c --- free an ext2 filesystem + * + * Copyright (C) 1993, 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +void ext2fs_free(ext2_filsys fs) +{ + if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)) + return; + if (fs->image_io != fs->io) { + if (fs->image_io) + io_channel_close(fs->image_io); + } + if (fs->io) { + io_channel_close(fs->io); + } + if (fs->device_name) + ext2fs_free_mem(&fs->device_name); + if (fs->super) + ext2fs_free_mem(&fs->super); + if (fs->orig_super) + ext2fs_free_mem(&fs->orig_super); + if (fs->group_desc) + ext2fs_free_mem(&fs->group_desc); + if (fs->block_map) + ext2fs_free_block_bitmap(fs->block_map); + if (fs->inode_map) + ext2fs_free_inode_bitmap(fs->inode_map); + if (fs->image_header) + ext2fs_free_mem(&fs->image_header); + + if (fs->badblocks) + ext2fs_badblocks_list_free(fs->badblocks); + fs->badblocks = 0; + + if (fs->dblist) + ext2fs_free_dblist(fs->dblist); + + if (fs->icache) + ext2fs_free_inode_cache(fs->icache); + + if (fs->mmp_buf) + ext2fs_free_mem(&fs->mmp_buf); + if (fs->mmp_cmp) + ext2fs_free_mem(&fs->mmp_cmp); + + fs->magic = 0; + + ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL); + ext2fs_free_mem(&fs); +} + +/* + * This procedure frees a badblocks list. + */ +void ext2fs_u32_list_free(ext2_u32_list bb) +{ + if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST) + return; + + if (bb->list) + ext2fs_free_mem(&bb->list); + bb->list = 0; + ext2fs_free_mem(&bb); +} + +void ext2fs_badblocks_list_free(ext2_badblocks_list bb) +{ + ext2fs_u32_list_free((ext2_u32_list) bb); +} + + +/* + * Free a directory block list + */ +void ext2fs_free_dblist(ext2_dblist dblist) +{ + if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST)) + return; + + if (dblist->list) + ext2fs_free_mem(&dblist->list); + dblist->list = 0; + if (dblist->fs && dblist->fs->dblist == dblist) + dblist->fs->dblist = 0; + dblist->magic = 0; + ext2fs_free_mem(&dblist); +} + diff --git a/src/ext2fs/gen_bitmap.c b/src/ext2fs/gen_bitmap.c new file mode 100644 index 00000000..d0061b82 --- /dev/null +++ b/src/ext2fs/gen_bitmap.c @@ -0,0 +1,607 @@ +/* + * gen_bitmap.c --- Generic (32-bit) bitmap routines + * + * Copyright (C) 2001 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" + +struct ext2fs_struct_generic_bitmap { + errcode_t magic; + ext2_filsys fs; + __u32 start, end; + __u32 real_end; + char * description; + char * bitmap; + errcode_t base_error_code; + __u32 reserved[7]; +}; + +#define EXT2FS_IS_32_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP)) + +#define EXT2FS_IS_64_BITMAP(bmap) \ + (((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \ + ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64)) + +/* + * Used by previously inlined function, so we have to export this and + * not change the function signature + */ +void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, + int code, unsigned long arg) +{ +#ifndef OMIT_COM_ERR + if (bitmap->description) + com_err(0, bitmap->base_error_code+code, + "#%lu for %s", arg, bitmap->description); + else + com_err(0, bitmap->base_error_code + code, "#%lu", arg); +#endif +} + +static errcode_t check_magic(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap || !((bitmap->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || + (bitmap->magic == EXT2_ET_MAGIC_INODE_BITMAP) || + (bitmap->magic == EXT2_ET_MAGIC_BLOCK_BITMAP))) + return EXT2_ET_MAGIC_GENERIC_BITMAP; + return 0; +} + +errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs, + __u32 start, __u32 end, __u32 real_end, + const char *descr, char *init_map, + ext2fs_generic_bitmap *ret) +{ + ext2fs_generic_bitmap bitmap; + errcode_t retval; + size_t size; + + retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), + &bitmap); + if (retval) + return retval; + + bitmap->magic = magic; + bitmap->fs = fs; + bitmap->start = start; + bitmap->end = end; + bitmap->real_end = real_end; + switch (magic) { + case EXT2_ET_MAGIC_INODE_BITMAP: + bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; + break; + case EXT2_ET_MAGIC_BLOCK_BITMAP: + bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; + break; + default: + bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; + } + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); + if (retval) { + ext2fs_free_mem(&bitmap); + return retval; + } + strcpy(bitmap->description, descr); + } else + bitmap->description = 0; + + size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1); + /* Round up to allow for the BT x86 instruction */ + size = (size + 7) & ~3; + retval = ext2fs_get_mem(size, &bitmap->bitmap); + if (retval) { + ext2fs_free_mem(&bitmap->description); + ext2fs_free_mem(&bitmap); + return retval; + } + + if (init_map) + memcpy(bitmap->bitmap, init_map, size); + else + memset(bitmap->bitmap, 0, size); + *ret = bitmap; + return 0; +} + +errcode_t ext2fs_allocate_generic_bitmap(__u32 start, + __u32 end, + __u32 real_end, + const char *descr, + ext2fs_generic_bitmap *ret) +{ + return ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_GENERIC_BITMAP, 0, + start, end, real_end, descr, 0, ret); +} + +errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + return (ext2fs_make_generic_bitmap(src->magic, src->fs, + src->start, src->end, + src->real_end, + src->description, src->bitmap, + dest)); +} + +void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap) +{ + if (check_magic(bitmap)) + return; + + bitmap->magic = 0; + if (bitmap->description) { + ext2fs_free_mem(&bitmap->description); + bitmap->description = 0; + } + if (bitmap->bitmap) { + ext2fs_free_mem(&bitmap->bitmap); + bitmap->bitmap = 0; + } + ext2fs_free_mem(&bitmap); +} + +int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_test_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "test_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno); + return 0; + } + return ext2fs_test_bit(bitno - bitmap->start, bitmap->bitmap); +} + +int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_mark_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "mark_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno); + return 0; + } + return ext2fs_set_bit(bitno - bitmap->start, bitmap->bitmap); +} + +int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap, + blk_t bitno) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_unmark_generic_bmap(bitmap, bitno); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "mark_bitmap(%lu)", (unsigned long) bitno); +#endif + return 0; + } + + if ((bitno < bitmap->start) || (bitno > bitmap->end)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno); + return 0; + } + return ext2fs_clear_bit(bitno - bitmap->start, bitmap->bitmap); +} + +__u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_get_generic_bmap_start(bitmap); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "get_bitmap_start"); +#endif + return 0; + } + + return bitmap->start; +} + +__u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + return ext2fs_get_generic_bmap_end(bitmap); + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "get_bitmap_end"); +#endif + return 0; + } + return bitmap->end; +} + +void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap) +{ + if (!EXT2FS_IS_32_BITMAP(bitmap)) { + if (EXT2FS_IS_64_BITMAP(bitmap)) { + ext2fs_warn_bitmap32(bitmap, __func__); + ext2fs_clear_generic_bmap(bitmap); + return; + } +#ifndef OMIT_COM_ERR + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "clear_generic_bitmap"); +#endif + return; + } + + memset(bitmap->bitmap, 0, + (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1)); +} + +errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap bitmap, + errcode_t magic, errcode_t neq, + ext2_ino_t end, ext2_ino_t *oend) +{ + EXT2_CHECK_MAGIC(bitmap, magic); + + if (end > bitmap->real_end) + return neq; + if (oend) + *oend = bitmap->end; + bitmap->end = end; + return 0; +} + +errcode_t ext2fs_resize_generic_bitmap(errcode_t magic, + __u32 new_end, __u32 new_real_end, + ext2fs_generic_bitmap bmap) +{ + errcode_t retval; + size_t size, new_size; + __u32 bitno; + + if (!bmap || (bmap->magic != magic)) + return magic; + + /* + * If we're expanding the bitmap, make sure all of the new + * parts of the bitmap are zero. + */ + if (new_end > bmap->end) { + bitno = bmap->real_end; + if (bitno > new_end) + bitno = new_end; + for (; bitno > bmap->end; bitno--) + ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap); + } + if (new_real_end == bmap->real_end) { + bmap->end = new_end; + return 0; + } + + size = ((bmap->real_end - bmap->start) / 8) + 1; + new_size = ((new_real_end - bmap->start) / 8) + 1; + + if (size != new_size) { + retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap); + if (retval) + return retval; + } + if (new_size > size) + memset(bmap->bitmap + size, 0, new_size - size); + + bmap->end = new_end; + bmap->real_end = new_real_end; + return 0; +} + +errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2) +{ + blk_t i; + + if (!bm1 || bm1->magic != magic) + return magic; + if (!bm2 || bm2->magic != magic) + return magic; + + if ((bm1->start != bm2->start) || + (bm1->end != bm2->end) || + (memcmp(bm1->bitmap, bm2->bitmap, + (size_t) (bm1->end - bm1->start)/8))) + return neq; + + for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) + if (ext2fs_fast_test_block_bitmap(bm1, i) != + ext2fs_fast_test_block_bitmap(bm2, i)) + return neq; + + return 0; +} + +void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap map) +{ + __u32 i, j; + + /* Protect loop from wrap-around if map->real_end is maxed */ + for (i=map->end+1, j = i - map->start; + i <= map->real_end && i > map->end; + i++, j++) + ext2fs_set_bit(j, map->bitmap); +} + +errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *out) +{ + if (!bmap || (bmap->magic != magic)) + return magic; + + if ((start < bmap->start) || (start+num-1 > bmap->real_end)) + return EXT2_ET_INVALID_ARGUMENT; + + memcpy(out, bmap->bitmap + (start >> 3), (num+7) >> 3); + return 0; +} + +errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap bmap, + errcode_t magic, + __u32 start, __u32 num, + void *in) +{ + if (!bmap || (bmap->magic != magic)) + return magic; + + if ((start < bmap->start) || (start+num-1 > bmap->real_end)) + return EXT2_ET_INVALID_ARGUMENT; + + memcpy(bmap->bitmap + (start >> 3), in, (num+7) >> 3); + return 0; +} + +/* + * Compare @mem to zero buffer by 256 bytes. + * Return 1 if @mem is zeroed memory, otherwise return 0. + */ +int ext2fs_mem_is_zero(const char *mem, size_t len) +{ + static const char zero_buf[256]; + + while (len >= sizeof(zero_buf)) { + if (memcmp(mem, zero_buf, sizeof(zero_buf))) + return 0; + len -= sizeof(zero_buf); + mem += sizeof(zero_buf); + } + /* Deal with leftover bytes. */ + if (len) + return !memcmp(mem, zero_buf, len); + return 1; +} + +/* + * Return true if all of the bits in a specified range are clear + */ +static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap bitmap, + unsigned int start, + unsigned int len) +{ + size_t start_byte, len_byte = len >> 3; + unsigned int start_bit, len_bit = len % 8; + int first_bit = 0; + int last_bit = 0; + int mark_count = 0; + int mark_bit = 0; + int i; + const char *ADDR = bitmap->bitmap; + + start -= bitmap->start; + start_byte = start >> 3; + start_bit = start % 8; + + if (start_bit != 0) { + /* + * The compared start block number or start inode number + * is not the first bit in a byte. + */ + mark_count = 8 - start_bit; + if (len < 8 - start_bit) { + mark_count = (int)len; + mark_bit = len + start_bit - 1; + } else + mark_bit = 7; + + for (i = mark_count; i > 0; i--, mark_bit--) + first_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the first byte. + * If there is any marked bit, this function returns 0. + */ + if (first_bit & ADDR[start_byte]) + return 0; + else if (len <= 8 - start_bit) + return 1; + + start_byte++; + len_bit = (len - mark_count) % 8; + len_byte = (len - mark_count) >> 3; + } + + /* + * The compared start block number or start inode number is + * the first bit in a byte. + */ + if (len_bit != 0) { + /* + * The compared end block number or end inode number is + * not the last bit in a byte. + */ + for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--) + last_bit |= 1 << mark_bit; + + /* + * Compare blocks or inodes in the last byte. + * If there is any marked bit, this function returns 0. + */ + if (last_bit & ADDR[start_byte + len_byte]) + return 0; + else if (len_byte == 0) + return 1; + } + + /* Check whether all bytes are 0 */ + return ext2fs_mem_is_zero(ADDR + start_byte, len_byte); +} + +errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out) +{ + blk_t b; + + if (start < bitmap->start || end > bitmap->end || start > end) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + while (start <= end) { + b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap); + if (!b) { + *out = start; + return 0; + } + start++; + } + + return ENOENT; +} + +errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap bitmap, + __u32 start, __u32 end, + __u32 *out) +{ + blk_t b; + + if (start < bitmap->start || end > bitmap->end || start > end) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + while (start <= end) { + b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap); + if (b) { + *out = start; + return 0; + } + start++; + } + + return ENOENT; +} + +int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP); + if ((block < bitmap->start) || (block+num-1 > bitmap->real_end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, + block, bitmap->description); + return 0; + } + return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap) + bitmap, block, num); +} + +int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap, + ext2_ino_t inode, int num) +{ + EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP); + if ((inode < bitmap->start) || (inode+num-1 > bitmap->real_end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST, + inode, bitmap->description); + return 0; + } + return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap) + bitmap, inode, num); +} + +void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + int i; + + if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, + bitmap->description); + return; + } + for (i=0; i < num; i++) + ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap); +} + +void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num) +{ + int i; + + if ((block < bitmap->start) || (block+num-1 > bitmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, + bitmap->description); + return; + } + for (i=0; i < num; i++) + ext2fs_fast_clear_bit(block + i - bitmap->start, + bitmap->bitmap); +} + diff --git a/src/ext2fs/gen_bitmap64.c b/src/ext2fs/gen_bitmap64.c new file mode 100644 index 00000000..3fc73498 --- /dev/null +++ b/src/ext2fs/gen_bitmap64.c @@ -0,0 +1,907 @@ +/* + * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and + * block bitmaps. + * + * Copyright (C) 2007, 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "bmap64.h" + +/* + * Design of 64-bit bitmaps + * + * In order maintain ABI compatibility with programs that don't + * understand about 64-bit blocks/inodes, + * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() + * will create old-style bitmaps unless the application passes the + * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is + * passed, then we know the application has been recompiled, so we can + * use the new-style bitmaps. If it is not passed, we have to return + * an error if trying to open a filesystem which needs 64-bit bitmaps. + * + * The new bitmaps use a new set of structure magic numbers, so that + * both the old-style and new-style interfaces can identify which + * version of the data structure was used. Both the old-style and + * new-style interfaces will support either type of bitmap, although + * of course 64-bit operation will only be possible when both the + * new-style interface and the new-style bitmap are used. + * + * For example, the new bitmap interfaces will check the structure + * magic numbers and so will be able to detect old-stype bitmap. If + * they see an old-style bitmap, they will pass it to the gen_bitmap.c + * functions for handling. The same will be true for the old + * interfaces as well. + * + * The new-style interfaces will have several different back-end + * implementations, so we can support different encodings that are + * appropriate for different applications. In general the default + * should be whatever makes sense, and what the application/library + * will use. However, e2fsck may need specialized implementations for + * its own uses. For example, when doing parent directory pointer + * loop detections in pass 3, the bitmap will *always* be sparse, so + * e2fsck can request an encoding which is optimized for that. + */ + +static void warn_bitmap(ext2fs_generic_bitmap bitmap, + int code, __u64 arg) +{ +#ifndef OMIT_COM_ERR + if (bitmap->description) + com_err(0, bitmap->base_error_code+code, + "#%llu for %s", arg, bitmap->description); + else + com_err(0, bitmap->base_error_code + code, "#%llu", arg); +#endif +} + +#ifdef ENABLE_BMAP_STATS_OPS +#define INC_STAT(map, name) map->stats.name +#else +#define INC_STAT(map, name) ;; +#endif + + +errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, + int type, __u64 start, __u64 end, + __u64 real_end, + const char *descr, + ext2fs_generic_bitmap *ret) +{ + ext2fs_generic_bitmap bitmap; + struct ext2_bitmap_ops *ops; + ext2_ino_t num_dirs; + errcode_t retval; + + if (!type) + type = EXT2FS_BMAP64_BITARRAY; + + switch (type) { + case EXT2FS_BMAP64_BITARRAY: + ops = &ext2fs_blkmap64_bitarray; + break; + case EXT2FS_BMAP64_RBTREE: + ops = &ext2fs_blkmap64_rbtree; + break; + case EXT2FS_BMAP64_AUTODIR: + retval = ext2fs_get_num_dirs(fs, &num_dirs); + if (retval || num_dirs > (fs->super->s_inodes_count / 320)) + ops = &ext2fs_blkmap64_bitarray; + else + ops = &ext2fs_blkmap64_rbtree; + break; + default: + return EINVAL; + } + + retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), + &bitmap); + if (retval) + return retval; + +#ifdef ENABLE_BMAP_STATS + if (gettimeofday(&bitmap->stats.created, + (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + ext2fs_free_mem(&bitmap); + return 1; + } + bitmap->stats.type = type; +#endif + + /* XXX factor out, repeated in copy_bmap */ + bitmap->magic = magic; + bitmap->fs = fs; + bitmap->start = start; + bitmap->end = end; + bitmap->real_end = real_end; + bitmap->bitmap_ops = ops; + bitmap->cluster_bits = 0; + switch (magic) { + case EXT2_ET_MAGIC_INODE_BITMAP64: + bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; + break; + case EXT2_ET_MAGIC_BLOCK_BITMAP64: + bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; + bitmap->cluster_bits = fs->cluster_ratio_bits; + break; + default: + bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; + } + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); + if (retval) { + ext2fs_free_mem(&bitmap); + return retval; + } + strcpy(bitmap->description, descr); + } else + bitmap->description = 0; + + retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); + if (retval) { + ext2fs_free_mem(&bitmap->description); + ext2fs_free_mem(&bitmap); + return retval; + } + + *ret = bitmap; + return 0; +} + +#ifdef ENABLE_BMAP_STATS +static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap) +{ + struct ext2_bmap_statistics *stats = &bitmap->stats; +#ifdef ENABLE_BMAP_STATS_OPS + float mark_seq_perc = 0.0, test_seq_perc = 0.0; + float mark_back_perc = 0.0, test_back_perc = 0.0; +#endif + double inuse; + struct timeval now; + +#ifdef ENABLE_BMAP_STATS_OPS + if (stats->test_count) { + test_seq_perc = ((float)stats->test_seq / + stats->test_count) * 100; + test_back_perc = ((float)stats->test_back / + stats->test_count) * 100; + } + + if (stats->mark_count) { + mark_seq_perc = ((float)stats->mark_seq / + stats->mark_count) * 100; + mark_back_perc = ((float)stats->mark_back / + stats->mark_count) * 100; + } +#endif + + if (gettimeofday(&now, (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + return; + } + + inuse = (double) now.tv_sec + \ + (((double) now.tv_usec) * 0.000001); + inuse -= (double) stats->created.tv_sec + \ + (((double) stats->created.tv_usec) * 0.000001); + + fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description, + stats->type); + fprintf(stderr, "=================================================\n"); +#ifdef ENABLE_BMAP_STATS_OPS + fprintf(stderr, "%16llu bits long\n", + bitmap->real_end - bitmap->start); + fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n", + stats->copy_count, stats->resize_count); + fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n", + stats->mark_count, stats->unmark_count); + fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n", + stats->test_count, stats->mark_ext_count); + fprintf(stderr, "%16lu unmark_bmap_extent\n" + "%16lu test_clear_bmap_extent\n", + stats->unmark_ext_count, stats->test_ext_count); + fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n", + stats->set_range_count, stats->get_range_count); + fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n", + stats->clear_count, stats->test_seq, test_seq_perc); + fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n" + "%16llu bits tested backwards (%.2f%%)\n", + stats->mark_seq, mark_seq_perc, + stats->test_back, test_back_perc); + fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n" + "%16.2f seconds in use\n", + stats->mark_back, mark_back_perc, inuse); +#endif /* ENABLE_BMAP_STATS_OPS */ +} +#endif + +void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) +{ + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + ext2fs_free_generic_bitmap(bmap); + return; + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + +#ifdef ENABLE_BMAP_STATS + if (getenv("E2FSPROGS_BITMAP_STATS")) { + ext2fs_print_bmap_statistics(bmap); + bmap->bitmap_ops->print_stats(bmap); + } +#endif + + bmap->bitmap_ops->free_bmap(bmap); + + if (bmap->description) { + ext2fs_free_mem(&bmap->description); + bmap->description = 0; + } + bmap->magic = 0; + ext2fs_free_mem(&bmap); +} + +errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, + ext2fs_generic_bitmap *dest) +{ + char *descr, *new_descr; + ext2fs_generic_bitmap new_bmap; + errcode_t retval; + + if (!src) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(src)) + return ext2fs_copy_generic_bitmap(src, dest); + + if (!EXT2FS_IS_64_BITMAP(src)) + return EINVAL; + + /* Allocate a new bitmap struct */ + retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), + &new_bmap); + if (retval) + return retval; + + +#ifdef ENABLE_BMAP_STATS_OPS + src->stats.copy_count++; +#endif +#ifdef ENABLE_BMAP_STATS + if (gettimeofday(&new_bmap->stats.created, + (struct timezone *) NULL) == -1) { + perror("gettimeofday"); + ext2fs_free_mem(&new_bmap); + return 1; + } + new_bmap->stats.type = src->stats.type; +#endif + + /* Copy all the high-level parts over */ + new_bmap->magic = src->magic; + new_bmap->fs = src->fs; + new_bmap->start = src->start; + new_bmap->end = src->end; + new_bmap->real_end = src->real_end; + new_bmap->bitmap_ops = src->bitmap_ops; + new_bmap->base_error_code = src->base_error_code; + new_bmap->cluster_bits = src->cluster_bits; + + descr = src->description; + if (descr) { + retval = ext2fs_get_mem(strlen(descr)+10, &new_descr); + if (retval) { + ext2fs_free_mem(&new_bmap); + return retval; + } + strcpy(new_descr, "copy of "); + strcat(new_descr, descr); + new_bmap->description = new_descr; + } + + retval = src->bitmap_ops->copy_bmap(src, new_bmap); + if (retval) { + ext2fs_free_mem(&new_bmap->description); + ext2fs_free_mem(&new_bmap); + return retval; + } + + *dest = new_bmap; + + return 0; +} + +errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, + __u64 new_end, + __u64 new_real_end) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) + return ext2fs_resize_generic_bitmap(bmap->magic, new_end, + new_real_end, bmap); + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, resize_count); + + return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); +} + +errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, + errcode_t neq, + __u64 end, __u64 *oend) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + ext2_ino_t tmp_oend; + int retval; + + retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, + neq, end, &tmp_oend); + if (oend) + *oend = tmp_oend; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + if (end > bitmap->real_end) + return neq; + if (oend) + *oend = bitmap->end; + bitmap->end = end; + return 0; +} + +__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) + return ext2fs_get_generic_bitmap_start(bitmap); + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + return bitmap->start; +} + +__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) +{ + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) + return ext2fs_get_generic_bitmap_end(bitmap); + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + return bitmap->end; +} + +void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) +{ + if (EXT2FS_IS_32_BITMAP(bitmap)) + ext2fs_clear_generic_bitmap(bitmap); + else + bitmap->bitmap_ops->clear_bmap (bitmap); +} + +int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, + EXT2FS_MARK_ERROR, 0xffffffff); + return 0; + } + return ext2fs_mark_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + +#ifdef ENABLE_BMAP_STATS_OPS + if (arg == bitmap->stats.last_marked + 1) + bitmap->stats.mark_seq++; + if (arg < bitmap->stats.last_marked) + bitmap->stats.mark_back++; + bitmap->stats.last_marked = arg; + bitmap->stats.mark_count++; +#endif + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->mark_bmap(bitmap, arg); +} + +int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, + 0xffffffff); + return 0; + } + return ext2fs_unmark_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + + INC_STAT(bitmap, unmark_count); + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); +} + +int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 arg) +{ + if (!bitmap) + return 0; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + if (arg & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, + 0xffffffff); + return 0; + } + return ext2fs_test_generic_bitmap(bitmap, arg); + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return 0; + + arg >>= bitmap->cluster_bits; + +#ifdef ENABLE_BMAP_STATS_OPS + bitmap->stats.test_count++; + if (arg == bitmap->stats.last_tested + 1) + bitmap->stats.test_seq++; + if (arg < bitmap->stats.last_tested) + bitmap->stats.test_back++; + bitmap->stats.last_tested = arg; +#endif + + if ((arg < bitmap->start) || (arg > bitmap->end)) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); + return 0; + } + + return bitmap->bitmap_ops->test_bmap(bitmap, arg); +} + +errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *in) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((start+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, + 0xffffffff); + return EINVAL; + } + return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, + start, num, in); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, set_range_count); + + return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); +} + +errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, + __u64 start, unsigned int num, + void *out) +{ + if (!bmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((start+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2(bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return EINVAL; + } + return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, + start, num, out); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, get_range_count); + + return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); +} + +errcode_t ext2fs_compare_generic_bmap(errcode_t neq, + ext2fs_generic_bitmap bm1, + ext2fs_generic_bitmap bm2) +{ + blk64_t i; + + if (!bm1 || !bm2) + return EINVAL; + if (bm1->magic != bm2->magic) + return EINVAL; + + /* Now we know both bitmaps have the same magic */ + if (EXT2FS_IS_32_BITMAP(bm1)) + return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); + + if (!EXT2FS_IS_64_BITMAP(bm1)) + return EINVAL; + + if ((bm1->start != bm2->start) || + (bm1->end != bm2->end)) + return neq; + + for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) + if (ext2fs_test_generic_bmap(bm1, i) != + ext2fs_test_generic_bmap(bm2, i)) + return neq; + + return 0; +} + +void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) +{ + __u64 start, num; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + ext2fs_set_generic_bitmap_padding(bmap); + return; + } + + start = bmap->end + 1; + num = bmap->real_end - bmap->end; + bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); + /* XXX ought to warn on error */ +} + +int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return EINVAL; + + if (num == 1) + return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) + bmap, block); + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return EINVAL; + } + return ext2fs_test_block_bitmap_range( + (ext2fs_generic_bitmap) bmap, block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return EINVAL; + + INC_STAT(bmap, test_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block, + bmap->description); + return EINVAL; + } + + return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); +} + +void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return; + } + ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, + block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + + INC_STAT(bmap, mark_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, + bmap->description); + return; + } + + bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); +} + +void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, + blk64_t block, unsigned int num) +{ + __u64 end = block + num; + + if (!bmap) + return; + + if (EXT2FS_IS_32_BITMAP(bmap)) { + if ((block+num-1) & ~0xffffffffULL) { + ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, + EXT2FS_UNMARK_ERROR, 0xffffffff); + return; + } + ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, + block, num); + } + + if (!EXT2FS_IS_64_BITMAP(bmap)) + return; + + INC_STAT(bmap, unmark_ext_count); + + /* convert to clusters if necessary */ + block >>= bmap->cluster_bits; + end += (1 << bmap->cluster_bits) - 1; + end >>= bmap->cluster_bits; + num = end - block; + + if ((block < bmap->start) || (block+num-1 > bmap->end)) { + ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, + bmap->description); + return; + } + + bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); +} + +void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) +{ +#ifndef OMIT_COM_ERR + if (bitmap && bitmap->description) + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "called %s with 64-bit bitmap for %s", func, + bitmap->description); + else + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "called %s with 64-bit bitmap", func); +#endif +} + +errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap *bitmap) +{ + ext2fs_block_bitmap cmap, bmap; + errcode_t retval; + blk64_t i, b_end, c_end; + int n, ratio; + + bmap = *bitmap; + + if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) + return 0; /* Nothing to do */ + + retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", + &cmap); + if (retval) + return retval; + + i = bmap->start; + b_end = bmap->end; + bmap->end = bmap->real_end; + c_end = cmap->end; + cmap->end = cmap->real_end; + n = 0; + ratio = 1 << fs->cluster_ratio_bits; + while (i < bmap->real_end) { + if (ext2fs_test_block_bitmap2(bmap, i)) { + ext2fs_mark_block_bitmap2(cmap, i); + i += ratio - n; + n = 0; + continue; + } + i++; n++; + if (n >= ratio) + n = 0; + } + bmap->end = b_end; + cmap->end = c_end; + ext2fs_free_block_bitmap(bmap); + *bitmap = cmap; + return 0; +} + +errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + __u64 cstart, cend, cout; + errcode_t retval; + + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + blk_t blk = 0; + + if (((start) & ~0xffffffffULL) || + ((end) & ~0xffffffffULL)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start, + end, &blk); + if (retval == 0) + *out = blk; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + cstart = start >> bitmap->cluster_bits; + cend = end >> bitmap->cluster_bits; + + if (cstart < bitmap->start || cend > bitmap->end || start > end) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + if (bitmap->bitmap_ops->find_first_zero) { + retval = bitmap->bitmap_ops->find_first_zero(bitmap, cstart, + cend, &cout); + if (retval) + return retval; + found: + cout <<= bitmap->cluster_bits; + *out = (cout >= start) ? cout : start; + return 0; + } + + for (cout = cstart; cout <= cend; cout++) + if (!bitmap->bitmap_ops->test_bmap(bitmap, cout)) + goto found; + + return ENOENT; +} + +errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, + __u64 start, __u64 end, __u64 *out) +{ + __u64 cstart, cend, cout; + errcode_t retval; + + if (!bitmap) + return EINVAL; + + if (EXT2FS_IS_32_BITMAP(bitmap)) { + blk_t blk = 0; + + if (((start) & ~0xffffffffULL) || + ((end) & ~0xffffffffULL)) { + ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + retval = ext2fs_find_first_set_generic_bitmap(bitmap, start, + end, &blk); + if (retval == 0) + *out = blk; + return retval; + } + + if (!EXT2FS_IS_64_BITMAP(bitmap)) + return EINVAL; + + cstart = start >> bitmap->cluster_bits; + cend = end >> bitmap->cluster_bits; + + if (cstart < bitmap->start || cend > bitmap->end || start > end) { + warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start); + return EINVAL; + } + + if (bitmap->bitmap_ops->find_first_set) { + retval = bitmap->bitmap_ops->find_first_set(bitmap, cstart, + cend, &cout); + if (retval) + return retval; + found: + cout <<= bitmap->cluster_bits; + *out = (cout >= start) ? cout : start; + return 0; + } + + for (cout = cstart; cout <= cend; cout++) + if (bitmap->bitmap_ops->test_bmap(bitmap, cout)) + goto found; + + return ENOENT; +} diff --git a/src/ext2fs/get_num_dirs.c b/src/ext2fs/get_num_dirs.c new file mode 100644 index 00000000..f5644f8e --- /dev/null +++ b/src/ext2fs/get_num_dirs.c @@ -0,0 +1,50 @@ +/* + * get_num_dirs.c -- calculate number of directories + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fsP.h" + +/* + * Returns the number of directories in the filesystem as reported by + * the group descriptors. Of course, the group descriptors could be + * wrong! + */ +errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs) +{ + dgrp_t i; + ext2_ino_t num_dirs, max_dirs; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + num_dirs = 0; + max_dirs = fs->super->s_inodes_per_group; + for (i = 0; i < fs->group_desc_count; i++) { + if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs) + num_dirs += max_dirs / 8; + else + num_dirs += ext2fs_bg_used_dirs_count(fs, i); + } + if (num_dirs > fs->super->s_inodes_count) + num_dirs = fs->super->s_inodes_count; + + *ret_num_dirs = num_dirs; + + return 0; +} + diff --git a/src/ext2fs/i_block.c b/src/ext2fs/i_block.c new file mode 100644 index 00000000..2eecf02f --- /dev/null +++ b/src/ext2fs/i_block.c @@ -0,0 +1,90 @@ +/* + * i_block.c --- Manage the i_block field for i_blocks + * + * Copyright (C) 2008 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks) +{ + unsigned long long b = inode->i_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; + + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + num_blocks *= fs->blocksize / 512; + num_blocks *= EXT2FS_CLUSTER_RATIO(fs); + + b += num_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + else if (b > 0xFFFFFFFF) + return EOVERFLOW; + inode->i_blocks = b & 0xFFFFFFFF; + return 0; +} + +errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode, + blk64_t num_blocks) +{ + unsigned long long b = inode->i_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; + + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + num_blocks *= fs->blocksize / 512; + num_blocks *= EXT2FS_CLUSTER_RATIO(fs); + + if (num_blocks > b) + return EOVERFLOW; + + b -= num_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + inode->i_blocks = b & 0xFFFFFFFF; + return 0; +} + +errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b) +{ + if (!ext2fs_has_feature_huge_file(fs->super) || + !(inode->i_flags & EXT4_HUGE_FILE_FL)) + b *= fs->blocksize / 512; + b *= EXT2FS_CLUSTER_RATIO(fs); + + inode->i_blocks = b & 0xFFFFFFFF; + if (ext2fs_has_feature_huge_file(fs->super)) + inode->osd2.linux2.l_i_blocks_hi = b >> 32; + else if (b >> 32) + return EOVERFLOW; + return 0; +} diff --git a/src/ext2fs/ind_block.c b/src/ext2fs/ind_block.c new file mode 100644 index 00000000..aa82ae6b --- /dev/null +++ b/src/ext2fs/ind_block.c @@ -0,0 +1,67 @@ +/* + * ind_block.c --- indirect block I/O routines + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf) +{ + errcode_t retval; +#ifdef WORDS_BIGENDIAN + blk_t *block_nr; + int i; + int limit = fs->blocksize >> 2; +#endif + + if ((fs->flags & EXT2_FLAG_IMAGE_FILE) && + (fs->io != fs->image_io)) + memset(buf, 0, fs->blocksize); + else { + retval = io_channel_read_blk(fs->io, blk, 1, buf); + if (retval) + return retval; + } +#ifdef WORDS_BIGENDIAN + block_nr = (blk_t *) buf; + for (i = 0; i < limit; i++, block_nr++) + *block_nr = ext2fs_swab32(*block_nr); +#endif + return 0; +} + +errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf) +{ +#ifdef WORDS_BIGENDIAN + blk_t *block_nr; + int i; + int limit = fs->blocksize >> 2; +#endif + + if (fs->flags & EXT2_FLAG_IMAGE_FILE) + return 0; + +#ifdef WORDS_BIGENDIAN + block_nr = (blk_t *) buf; + for (i = 0; i < limit; i++, block_nr++) + *block_nr = ext2fs_swab32(*block_nr); +#endif + return io_channel_write_blk(fs->io, blk, 1, buf); +} + + diff --git a/src/ext2fs/initialize.c b/src/ext2fs/initialize.c new file mode 100644 index 00000000..a69becdc --- /dev/null +++ b/src/ext2fs/initialize.c @@ -0,0 +1,575 @@ +/* + * initialize.c --- initialize a filesystem handle given superblock + * parameters. Used by mke2fs when initializing a filesystem. + * + * Copyright (C) 1994, 1995, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#if defined(__linux__) && defined(EXT2_OS_LINUX) +#define CREATOR_OS EXT2_OS_LINUX +#else +#if defined(__GNU__) && defined(EXT2_OS_HURD) +#define CREATOR_OS EXT2_OS_HURD +#else +#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) +#define CREATOR_OS EXT2_OS_FREEBSD +#else +#if defined(LITES) && defined(EXT2_OS_LITES) +#define CREATOR_OS EXT2_OS_LITES +#else +#define CREATOR_OS EXT2_OS_LINUX /* by default */ +#endif /* defined(LITES) && defined(EXT2_OS_LITES) */ +#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */ +#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */ +#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */ + +/* + * Calculate the number of GDT blocks to reserve for online filesystem growth. + * The absolute maximum number of GDT blocks we can reserve is determined by + * the number of block pointers that can fit into a single block. + */ +static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs) +{ + struct ext2_super_block *sb = fs->super; + unsigned long bpg = sb->s_blocks_per_group; + unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb); + unsigned long max_blocks = 0xffffffff; + unsigned long rsv_groups; + unsigned int rsv_gdb; + + /* We set it at 1024x the current filesystem size, or + * the upper block count limit (2^32), whichever is lower. + */ + if (ext2fs_blocks_count(sb) < max_blocks / 1024) + max_blocks = ext2fs_blocks_count(sb) * 1024; + /* + * ext2fs_div64_ceil() is unnecessary because max_blocks is + * max _GDT_ blocks, which is limited to 32 bits. + */ + rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg); + rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks; + if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb)) + rsv_gdb = EXT2_ADDR_PER_BLOCK(sb); +#ifdef RES_GDT_DEBUG + printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n", + max_blocks, rsv_groups, rsv_gdb); +#endif + + return rsv_gdb; +} + +errcode_t ext2fs_initialize(const char *name, int flags, + struct ext2_super_block *param, + io_manager manager, ext2_filsys *ret_fs) +{ + ext2_filsys fs; + errcode_t retval; + struct ext2_super_block *super; + unsigned int rem; + unsigned int overhead = 0; + unsigned int ipg; + dgrp_t i; + blk64_t free_blocks; + blk_t numblocks; + int rsv_gdt; + int csum_flag; + int bigalloc_flag; + int io_flags; + int has_bg; + unsigned reserved_inos; + char *buf = 0; + char c; + double reserved_ratio; + char *time_env; + + if (!name || !param || !ext2fs_blocks_count(param)) { + com_err("ext2fs_initialize", EXT2_ET_INVALID_ARGUMENT, "invalid argument"); + return EXT2_ET_INVALID_ARGUMENT; + } + + if (!name || !param || !ext2fs_blocks_count(param)) { + com_err("ext2fs_initialize", EXT2_ET_INVALID_ARGUMENT, "invalid argument"); + return EXT2_ET_INVALID_ARGUMENT; + } + + retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs); + if (retval) + return retval; + + memset(fs, 0, sizeof(struct struct_ext2_filsys)); + fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS; + fs->flags = flags | EXT2_FLAG_RW; + fs->umask = 022; + fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; +#ifdef WORDS_BIGENDIAN + fs->flags |= EXT2_FLAG_SWAP_BYTES; +#endif + + time_env = getenv("E2FSPROGS_FAKE_TIME"); + if (time_env) + fs->now = strtoul(time_env, NULL, 0); + + io_flags = IO_FLAG_RW; + if (flags & EXT2_FLAG_EXCLUSIVE) + io_flags |= IO_FLAG_EXCLUSIVE; + if (flags & EXT2_FLAG_DIRECT_IO) + io_flags |= IO_FLAG_DIRECT_IO; + io_flags |= O_BINARY; + retval = manager->open(name, io_flags, &fs->io); + if (retval) + goto cleanup; + fs->image_io = fs->io; + fs->io->app_data = fs; + retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name); + if (retval) + goto cleanup; + + strcpy(fs->device_name, name); + retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super); + if (retval) + goto cleanup; + fs->super = super; + + memset(super, 0, SUPERBLOCK_SIZE); + +#define set_field(field, default) (super->field = param->field ? \ + param->field : (default)) +#define assign_field(field) (super->field = param->field) + + super->s_magic = EXT2_SUPER_MAGIC; + super->s_state = EXT2_VALID_FS; + + bigalloc_flag = ext2fs_has_feature_bigalloc(param); + + assign_field(s_log_block_size); + + if (bigalloc_flag) { + set_field(s_log_cluster_size, super->s_log_block_size+4); + if (super->s_log_block_size > super->s_log_cluster_size) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + } else + super->s_log_cluster_size = super->s_log_block_size; + + set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1); + set_field(s_max_mnt_count, 0); + set_field(s_errors, EXT2_ERRORS_DEFAULT); + set_field(s_feature_compat, 0); + set_field(s_feature_incompat, 0); + set_field(s_feature_ro_compat, 0); + set_field(s_default_mount_opts, 0); + set_field(s_first_meta_bg, 0); + set_field(s_raid_stride, 0); /* default stride size: 0 */ + set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */ + set_field(s_log_groups_per_flex, 0); + set_field(s_flags, 0); + assign_field(s_backup_bgs[0]); + assign_field(s_backup_bgs[1]); + if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { + retval = EXT2_ET_UNSUPP_FEATURE; + goto cleanup; + } + if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) { + retval = EXT2_ET_RO_UNSUPP_FEATURE; + goto cleanup; + } + + set_field(s_rev_level, EXT2_GOOD_OLD_REV); + if (super->s_rev_level >= EXT2_DYNAMIC_REV) { + set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO); + set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE); + if (super->s_inode_size >= sizeof(struct ext2_inode_large)) { + int extra_isize = sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE; + set_field(s_min_extra_isize, extra_isize); + set_field(s_want_extra_isize, extra_isize); + } + } else { + super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO; + super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + } + + set_field(s_checkinterval, 0); + super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL); + + super->s_creator_os = CREATOR_OS; + + fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super); + fs->cluster_ratio_bits = super->s_log_cluster_size - + super->s_log_block_size; + + if (bigalloc_flag) { + unsigned long long bpg; + + if (param->s_blocks_per_group && + param->s_clusters_per_group && + ((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) != + param->s_blocks_per_group)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + if (param->s_clusters_per_group) + assign_field(s_clusters_per_group); + else if (param->s_blocks_per_group) + super->s_clusters_per_group = + param->s_blocks_per_group / + EXT2FS_CLUSTER_RATIO(fs); + else if (super->s_log_cluster_size + 15 < 32) + super->s_clusters_per_group = fs->blocksize * 8; + else + super->s_clusters_per_group = (fs->blocksize - 1) * 8; + if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super)) + super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super); + bpg = EXT2FS_C2B(fs, + (unsigned long long) super->s_clusters_per_group); + if (bpg >= (((unsigned long long) 1) << 32)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + super->s_blocks_per_group = bpg; + } else { + set_field(s_blocks_per_group, fs->blocksize * 8); + if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super)) + super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super); + super->s_clusters_per_group = super->s_blocks_per_group; + } + + ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) & + ~((blk64_t) EXT2FS_CLUSTER_MASK(fs))); + ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param)); + if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + + set_field(s_mmp_update_interval, 0); + + /* + * If we're creating an external journal device, we don't need + * to bother with the rest. + */ + if (ext2fs_has_feature_journal_dev(super)) { + fs->group_desc_count = 0; + ext2fs_mark_super_dirty(fs); + *ret_fs = fs; + return 0; + } + +retry: + fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil( + ext2fs_blocks_count(super) - super->s_first_data_block, + EXT2_BLOCKS_PER_GROUP(super)); + if (fs->group_desc_count == 0) { + retval = EXT2_ET_TOOSMALL; + goto cleanup; + } + + set_field(s_desc_size, + ext2fs_has_feature_64bit(super) ? + EXT2_MIN_DESC_SIZE_64BIT : 0); + + fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, + EXT2_DESC_PER_BLOCK(super)); + + i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize; + + if (ext2fs_has_feature_64bit(super) && + (ext2fs_blocks_count(super) / i) > (1ULL << 32)) + set_field(s_inodes_count, ~0U); + else + set_field(s_inodes_count, ext2fs_blocks_count(super) / i); + + /* + * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so + * that we have enough inodes for the filesystem(!) + */ + if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1) + super->s_inodes_count = EXT2_FIRST_INODE(super)+1; + + /* + * There should be at least as many inodes as the user + * requested. Figure out how many inodes per group that + * should be. But make sure that we don't allocate more than + * one bitmap's worth of inodes each group. + */ + ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count); + if (ipg > fs->blocksize * 8) { + if (!bigalloc_flag && super->s_blocks_per_group >= 256) { + /* Try again with slightly different parameters */ + super->s_blocks_per_group -= 8; + ext2fs_blocks_count_set(super, + ext2fs_blocks_count(param)); + super->s_clusters_per_group = super->s_blocks_per_group; + goto retry; + } else { + retval = EXT2_ET_TOO_MANY_INODES; + goto cleanup; + } + } + + if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super)) + ipg = EXT2_MAX_INODES_PER_GROUP(super); + +ipg_retry: + super->s_inodes_per_group = ipg; + + /* + * Make sure the number of inodes per group completely fills + * the inode table blocks in the descriptor. If not, add some + * additional inodes/group. Waste not, want not... + */ + fs->inode_blocks_per_group = (((super->s_inodes_per_group * + EXT2_INODE_SIZE(super)) + + EXT2_BLOCK_SIZE(super) - 1) / + EXT2_BLOCK_SIZE(super)); + super->s_inodes_per_group = ((fs->inode_blocks_per_group * + EXT2_BLOCK_SIZE(super)) / + EXT2_INODE_SIZE(super)); + /* + * Finally, make sure the number of inodes per group is a + * multiple of 8. This is needed to simplify the bitmap + * splicing code. + */ + if (super->s_inodes_per_group < 8) + super->s_inodes_per_group = 8; + super->s_inodes_per_group &= ~7; + fs->inode_blocks_per_group = (((super->s_inodes_per_group * + EXT2_INODE_SIZE(super)) + + EXT2_BLOCK_SIZE(super) - 1) / + EXT2_BLOCK_SIZE(super)); + + /* + * adjust inode count to reflect the adjusted inodes_per_group + */ + if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) { + ipg--; + goto ipg_retry; + } + super->s_inodes_count = super->s_inodes_per_group * + fs->group_desc_count; + super->s_free_inodes_count = super->s_inodes_count; + + /* + * check the number of reserved group descriptor table blocks + */ + if (ext2fs_has_feature_resize_inode(super)) + rsv_gdt = calc_reserved_gdt_blocks(fs); + else + rsv_gdt = 0; + set_field(s_reserved_gdt_blocks, rsv_gdt); + if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) { + retval = EXT2_ET_RES_GDT_BLOCKS; + goto cleanup; + } + + /* + * Calculate the maximum number of bookkeeping blocks per + * group. It includes the superblock, the block group + * descriptors, the block bitmap, the inode bitmap, the inode + * table, and the reserved gdt blocks. + */ + overhead = (int) (3 + fs->inode_blocks_per_group + + super->s_reserved_gdt_blocks); + + /* Enable meta_bg if we'd lose more than 3/4 of a BG to GDT blocks. */ + if (super->s_reserved_gdt_blocks + fs->desc_blocks > + super->s_blocks_per_group * 3 / 4) + ext2fs_set_feature_meta_bg(fs->super); + + if (ext2fs_has_feature_meta_bg(fs->super)) + overhead++; + else + overhead += fs->desc_blocks; + + /* This can only happen if the user requested too many inodes */ + if (overhead > super->s_blocks_per_group) { + retval = EXT2_ET_TOO_MANY_INODES; + goto cleanup; + } + + /* + * See if the last group is big enough to support the + * necessary data structures. If not, we need to get rid of + * it. We need to recalculate the overhead for the last block + * group, since it might or might not have a superblock + * backup. + */ + overhead = (int) (2 + fs->inode_blocks_per_group); + has_bg = 0; + if (ext2fs_has_feature_sparse_super2(super)) { + /* + * We have to do this manually since + * super->s_backup_bgs hasn't been set up yet. + */ + if (fs->group_desc_count == 2) + has_bg = param->s_backup_bgs[0] != 0; + else + has_bg = param->s_backup_bgs[1] != 0; + } else + has_bg = ext2fs_bg_has_super(fs, fs->group_desc_count - 1); + if (has_bg) + overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks; + rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) % + super->s_blocks_per_group); + if ((fs->group_desc_count == 1) && rem && (rem < overhead)) { + retval = EXT2_ET_TOOSMALL; + goto cleanup; + } + if (rem && (rem < overhead+50)) { + ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) - + rem); + /* + * If blocks count is changed, we need to recalculate + * reserved blocks count not to exceed 50%. + */ + reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) / + ext2fs_blocks_count(param); + ext2fs_r_blocks_count_set(super, reserved_ratio * + ext2fs_blocks_count(super) / 100.0); + + goto retry; + } + + /* + * At this point we know how big the filesystem will be. So + * we can do any and all allocations that depend on the block + * count. + */ + + /* Set up the locations of the backup superblocks */ + if (ext2fs_has_feature_sparse_super2(super)) { + if (super->s_backup_bgs[0] >= fs->group_desc_count) + super->s_backup_bgs[0] = fs->group_desc_count - 1; + if (super->s_backup_bgs[1] >= fs->group_desc_count) + super->s_backup_bgs[1] = fs->group_desc_count - 1; + if (super->s_backup_bgs[0] == super->s_backup_bgs[1]) + super->s_backup_bgs[1] = 0; + if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) { + __u32 t = super->s_backup_bgs[0]; + super->s_backup_bgs[0] = super->s_backup_bgs[1]; + super->s_backup_bgs[1] = t; + } + } + + retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); + if (retval) + goto cleanup; + + strcpy(buf, "block bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map); + if (retval) + goto cleanup; + + strcpy(buf, "inode bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); + if (retval) + goto cleanup; + + ext2fs_free_mem(&buf); + + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &fs->group_desc); + if (retval) + goto cleanup; + + memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize); + + /* + * Reserve the superblock and group descriptors for each + * group, and fill in the correct group statistics for group. + * Note that although the block bitmap, inode bitmap, and + * inode table have not been allocated (and in fact won't be + * by this routine), they are accounted for nevertheless. + * + * If FLEX_BG meta-data grouping is used, only account for the + * superblock and group descriptors (the inode tables and + * bitmaps will be accounted for when allocated). + */ + free_blocks = 0; + csum_flag = ext2fs_has_group_desc_csum(fs); + reserved_inos = super->s_first_ino; + for (i = 0; i < fs->group_desc_count; i++) { + /* + * Don't set the BLOCK_UNINIT group for the last group + * because the block bitmap needs to be padded. + */ + if (csum_flag) { + if (i != fs->group_desc_count - 1) + ext2fs_bg_flags_set(fs, i, + EXT2_BG_BLOCK_UNINIT); + ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT); + numblocks = super->s_inodes_per_group; + if (reserved_inos) { + if (numblocks > reserved_inos) { + numblocks -= reserved_inos; + reserved_inos = 0; + } else { + reserved_inos -= numblocks; + numblocks = 0; + } + } + ext2fs_bg_itable_unused_set(fs, i, numblocks); + } + numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map); + if (fs->super->s_log_groups_per_flex) + numblocks += 2 + fs->inode_blocks_per_group; + + free_blocks += numblocks; + ext2fs_bg_free_blocks_count_set(fs, i, numblocks); + ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group); + ext2fs_bg_used_dirs_count_set(fs, i, 0); + ext2fs_group_desc_csum_set(fs, i); + } + free_blocks &= ~EXT2FS_CLUSTER_MASK(fs); + ext2fs_free_blocks_count_set(super, free_blocks); + + c = (char) 255; + if (((int) c) == -1) { + super->s_flags |= EXT2_FLAGS_SIGNED_HASH; + } else { + super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH; + } + + ext2fs_mark_super_dirty(fs); + ext2fs_mark_bb_dirty(fs); + ext2fs_mark_ib_dirty(fs); + + io_channel_set_blksize(fs->io, fs->blocksize); + + *ret_fs = fs; + return 0; +cleanup: + free(buf); + ext2fs_free(fs); + return retval; +} diff --git a/src/ext2fs/inline.c b/src/ext2fs/inline.c new file mode 100644 index 00000000..ae2ae6e4 --- /dev/null +++ b/src/ext2fs/inline.c @@ -0,0 +1,118 @@ +/* + * inline.c --- Includes the inlined functions defined in the header + * files as standalone functions, in case the application program + * is compiled with inlining turned off. + * + * Copyright (C) 1993, 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 600 /* for posix_memalign() */ +#endif + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif +#if HAVE_MALLOC_H +#include +#endif + +#include "ext2_fs.h" +#define INCLUDE_INLINE_FUNCS +#include "ext2fs.h" + +/* + * We used to define this as an inline, but since we are now using + * autoconf-defined #ifdef's, we need to export this as a + * library-provided function exclusively. + */ +errcode_t ext2fs_get_memalign(unsigned long size, + unsigned long align, void *ptr) +{ + errcode_t retval = 0; + void **p = ptr; + + if (align < 8) + align = 8; +#ifdef HAVE_POSIX_MEMALIGN + retval = posix_memalign(p, align, size); + if (retval == ENOMEM) + return EXT2_ET_NO_MEMORY; +#else /* !HAVE_POSIX_MEMALIGN */ +#ifdef HAVE_MEMALIGN + *p = memalign(align, size); + if (*p == NULL) { + if (errno) + return errno; + else + return EXT2_ET_NO_MEMORY; + } +#else /* !HAVE_MEMALIGN */ +#ifdef HAVE_VALLOC + if (align > sizeof(long long)) + *p = valloc(size); + else +#endif + *p = malloc(size); + if ((uintptr_t) *p & (align - 1)) { + free(*p); + *p = 0; + } + if (*p == 0) + return EXT2_ET_NO_MEMORY; +#endif /* HAVE_MEMALIGN */ +#endif /* HAVE_POSIX_MEMALIGN */ + return retval; +} + +#ifdef DEBUG +static int isaligned(void *ptr, unsigned long align) +{ + return (((unsigned long) ptr & (align - 1)) == 0); +} + +static errcode_t test_memalign(unsigned long align) +{ + void *ptr = 0; + errcode_t retval; + + retval = ext2fs_get_memalign(32, align, &ptr); + if (!retval && !isaligned(ptr, align)) + retval = EINVAL; + free(ptr); + printf("tst_memalign(%lu) is %s\n", align, + retval ? error_message(retval) : "OK"); + return retval; +} + +int main(int argc, char **argv) +{ + int err = 0; + + if (test_memalign(4)) + err++; + if (test_memalign(32)) + err++; + if (test_memalign(1024)) + err++; + if (test_memalign(4096)) + err++; + return err; +} +#endif diff --git a/src/ext2fs/inline_data.c b/src/ext2fs/inline_data.c new file mode 100644 index 00000000..b62fb676 --- /dev/null +++ b/src/ext2fs/inline_data.c @@ -0,0 +1,842 @@ +/* + * inline_data.c --- data in inode + * + * Copyright (C) 2012 Zheng Liu + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include /* for PATH_MAX */ + +#include "ext2_fs.h" +#include "ext2_ext_attr.h" + +#include "ext2fs.h" +#include "ext2fsP.h" + +struct ext2_inline_data { + ext2_filsys fs; + ext2_ino_t ino; + size_t ea_size; /* the size of inline data in ea area */ + void *ea_data; +}; + +static errcode_t ext2fs_inline_data_ea_set(struct ext2_inline_data *data) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_set(handle, "system.data", + data->ea_data, data->ea_size); +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +static errcode_t ext2fs_inline_data_ea_get(struct ext2_inline_data *data) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + data->ea_size = 0; + data->ea_data = 0; + + retval = ext2fs_xattrs_open(data->fs, data->ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_get(handle, "system.data", + (void **)&data->ea_data, &data->ea_size); + if (retval == EXT2_ET_EA_KEY_NOT_FOUND) { + data->ea_size = 0; + data->ea_data = NULL; + retval = 0; + } else if (retval) + goto err; + +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +errcode_t ext2fs_inline_data_init(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inline_data data; + char empty[1] = { '\0' }; + + data.fs = fs; + data.ino = ino; + data.ea_size = 0; + data.ea_data = empty; + return ext2fs_inline_data_ea_set(&data); +} + +errcode_t ext2fs_inline_data_size(ext2_filsys fs, ext2_ino_t ino, size_t *size) +{ + struct ext2_inode inode; + struct ext2_inline_data data; + errcode_t retval; + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) + return EXT2_ET_NO_INLINE_DATA; + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + + *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; + return ext2fs_free_mem(&data.ea_data); +} + +int ext2fs_inline_data_dir_iterate(ext2_filsys fs, ext2_ino_t ino, + void *priv_data) +{ + struct dir_context *ctx; + struct ext2_inode inode; + struct ext2_dir_entry dirent; + struct ext2_inline_data data; + int ret = BLOCK_ABORT; + e2_blkcnt_t blockcnt = 0; + char *old_buf; + unsigned int old_buflen; + int old_flags; + + ctx = (struct dir_context *)priv_data; + old_buf = ctx->buf; + old_buflen = ctx->buflen; + old_flags = ctx->flags; + ctx->flags |= DIRENT_FLAG_INCLUDE_INLINE_DATA; + + ctx->errcode = ext2fs_read_inode(fs, ino, &inode); + if (ctx->errcode) + goto out; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) { + ctx->errcode = EXT2_ET_NO_INLINE_DATA; + goto out; + } + + if (!LINUX_S_ISDIR(inode.i_mode)) { + ctx->errcode = EXT2_ET_NO_DIRECTORY; + goto out; + } + ret = 0; + + /* we first check '.' and '..' dir */ + dirent.inode = ino; + dirent.name_len = 1; + ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(2), &dirent); + dirent.name[0] = '.'; + dirent.name[1] = '\0'; + ctx->buf = (char *)&dirent; + ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_ABORT) + goto out; + + dirent.inode = ext2fs_le32_to_cpu(inode.i_block[0]); + dirent.name_len = 2; + ext2fs_set_rec_len(fs, EXT2_DIR_REC_LEN(3), &dirent); + dirent.name[0] = '.'; + dirent.name[1] = '.'; + dirent.name[2] = '\0'; + ctx->buf = (char *)&dirent; + ext2fs_get_rec_len(fs, &dirent, &ctx->buflen); + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { + errcode_t err; + + inode.i_block[0] = ext2fs_cpu_to_le32(dirent.inode); + err = ext2fs_write_inode(fs, ino, &inode); + if (err) + goto out; + ret &= ~BLOCK_INLINE_DATA_CHANGED; + } + if (ret & BLOCK_ABORT) + goto out; + + ctx->buf = (char *)inode.i_block + EXT4_INLINE_DATA_DOTDOT_SIZE; + ctx->buflen = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } +#endif + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, + ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } +#endif + ctx->errcode = ext2fs_write_inode(fs, ino, &inode); + if (ctx->errcode) + ret |= BLOCK_ABORT; + ret &= ~BLOCK_INLINE_DATA_CHANGED; + } + if (ret & BLOCK_ABORT) + goto out; + + data.fs = fs; + data.ino = ino; + ctx->errcode = ext2fs_inline_data_ea_get(&data); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out; + } + if (data.ea_size <= 0) + goto out1; + + ctx->buf = data.ea_data; + ctx->buflen = data.ea_size; +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_in2(fs, ctx->buf, ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out1; + } +#endif + + ret |= ext2fs_process_dir_block(fs, 0, blockcnt++, 0, 0, priv_data); + if (ret & BLOCK_INLINE_DATA_CHANGED) { +#ifdef WORDS_BIGENDIAN + ctx->errcode = ext2fs_dirent_swab_out2(fs, ctx->buf, + ctx->buflen, 0); + if (ctx->errcode) { + ret |= BLOCK_ABORT; + goto out1; + } +#endif + ctx->errcode = ext2fs_inline_data_ea_set(&data); + if (ctx->errcode) + ret |= BLOCK_ABORT; + } + +out1: + ext2fs_free_mem(&data.ea_data); +out: + ctx->buf = old_buf; + ctx->buflen = old_buflen; + ctx->flags = old_flags; + ret &= ~(BLOCK_ABORT | BLOCK_INLINE_DATA_CHANGED); + return ret; +} + +errcode_t ext2fs_inline_data_ea_remove(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_xattr_handle *handle; + errcode_t retval; + + retval = ext2fs_xattrs_open(fs, ino, &handle); + if (retval) + return retval; + + retval = ext2fs_xattrs_read(handle); + if (retval) + goto err; + + retval = ext2fs_xattr_remove(handle, "system.data"); +err: + (void) ext2fs_xattrs_close(&handle); + return retval; +} + +static errcode_t ext2fs_inline_data_convert_dir(ext2_filsys fs, ext2_ino_t ino, + char *bbuf, char *ibuf, int size) +{ + struct ext2_dir_entry *dir, *dir2; + struct ext2_dir_entry_tail *t; + errcode_t retval; + int offset; + unsigned int rec_len; + int csum_size = 0; + int filetype = 0; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + /* Create '.' and '..' */ + if (ext2fs_has_feature_filetype(fs->super)) + filetype = EXT2_FT_DIR; + + /* + * Set up entry for '.' + */ + dir = (struct ext2_dir_entry *) bbuf; + dir->inode = ino; + ext2fs_dirent_set_name_len(dir, 1); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); + dir->rec_len = EXT2_DIR_REC_LEN(1); + + /* + * Set up entry for '..' + */ + dir = (struct ext2_dir_entry *) (bbuf + dir->rec_len); + dir->rec_len = EXT2_DIR_REC_LEN(2); + dir->inode = ext2fs_le32_to_cpu(((__u32 *)ibuf)[0]); + ext2fs_dirent_set_name_len(dir, 2); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + dir->name[1] = '.'; + + /* + * Adjust the last rec_len + */ + offset = EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2); + dir = (struct ext2_dir_entry *) (bbuf + offset); + memcpy(bbuf + offset, ibuf + EXT4_INLINE_DATA_DOTDOT_SIZE, + size - EXT4_INLINE_DATA_DOTDOT_SIZE); + size += EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) - + EXT4_INLINE_DATA_DOTDOT_SIZE; + + do { + dir2 = dir; + retval = ext2fs_get_rec_len(fs, dir, &rec_len); + if (retval) + goto err; + offset += rec_len; + dir = (struct ext2_dir_entry *) (bbuf + offset); + } while (offset < size); + rec_len += fs->blocksize - csum_size - offset; + retval = ext2fs_set_rec_len(fs, rec_len, dir2); + if (retval) + goto err; + + if (csum_size) { + t = EXT2_DIRENT_TAIL(bbuf, fs->blocksize); + ext2fs_initialize_dirent_tail(fs, t); + } + +err: + return retval; +} + +static errcode_t +ext2fs_inline_data_dir_expand(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, char *buf, size_t size) +{ + errcode_t retval; + blk64_t blk; + char *blk_buf; + + retval = ext2fs_get_memzero(fs->blocksize, &blk_buf); + if (retval) + return retval; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_in2(fs, buf + EXT4_INLINE_DATA_DOTDOT_SIZE, + size, 0); + if (retval) + goto errout; +#endif + + /* Adjust the rec_len */ + retval = ext2fs_inline_data_convert_dir(fs, ino, blk_buf, buf, size); + if (retval) + goto errout; + /* Allocate a new block */ + retval = ext2fs_new_block2(fs, 0, 0, &blk); + if (retval) + goto errout; + retval = ext2fs_write_dir_block4(fs, blk, blk_buf, 0, ino); + if (retval) + goto errout; + + /* Update inode */ + if (ext2fs_has_feature_extents(fs->super)) + inode->i_flags |= EXT4_EXTENTS_FL; + inode->i_flags &= ~EXT4_INLINE_DATA_FL; + retval = ext2fs_iblk_add_blocks(fs, inode, 1); + if (retval) + goto errout; + inode->i_size = fs->blocksize; + retval = ext2fs_bmap2(fs, ino, inode, 0, BMAP_SET, 0, 0, &blk); + if (retval) + goto errout; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + goto errout; + ext2fs_block_alloc_stats(fs, blk, +1); + +errout: + ext2fs_free_mem(&blk_buf); + return retval; +} + +static errcode_t +ext2fs_inline_data_file_expand(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, char *buf, size_t size) +{ + ext2_file_t e2_file; + errcode_t retval; + + /* Update inode */ + memset(inode->i_block, 0, sizeof(inode->i_block)); + if (ext2fs_has_feature_extents(fs->super)) { + ext2_extent_handle_t handle; + + inode->i_flags &= ~EXT4_EXTENTS_FL; + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + return retval; + ext2fs_extent_free(handle); + } + inode->i_flags &= ~EXT4_INLINE_DATA_FL; + inode->i_size = 0; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + + /* Write out the block buffer */ + retval = ext2fs_file_open(fs, ino, EXT2_FILE_WRITE, &e2_file); + if (retval) + return retval; + retval = ext2fs_file_write(e2_file, buf, size, 0); + ext2fs_file_close(e2_file); + return retval; +} + +errcode_t ext2fs_inline_data_expand(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + struct ext2_inline_data data; + errcode_t retval; + size_t inline_size; + char *inline_buf = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + + if (!(inode.i_flags & EXT4_INLINE_DATA_FL)) + return EXT2_ET_NO_INLINE_DATA; + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + inline_size = data.ea_size + EXT4_MIN_INLINE_DATA_SIZE; + retval = ext2fs_get_mem(inline_size, &inline_buf); + if (retval) + goto errout; + + memcpy(inline_buf, (void *)inode.i_block, EXT4_MIN_INLINE_DATA_SIZE); + if (data.ea_size > 0) { + memcpy(inline_buf + EXT4_MIN_INLINE_DATA_SIZE, + data.ea_data, data.ea_size); + } + + memset((void *)inode.i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + /* + * NOTE: We must do this write -> ea_remove -> read cycle here because + * removing the inline data EA can free the EA block, which is a change + * that our stack copy of the inode will never see. If that happens, + * we can end up with the EA block and lblk 0 pointing to the same + * pblk, which is bad news. + */ + retval = ext2fs_write_inode(fs, ino, &inode); + if (retval) + goto errout; + retval = ext2fs_inline_data_ea_remove(fs, ino); + if (retval) + goto errout; + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + goto errout; + + if (LINUX_S_ISDIR(inode.i_mode)) { + retval = ext2fs_inline_data_dir_expand(fs, ino, &inode, + inline_buf, inline_size); + } else { + retval = ext2fs_inline_data_file_expand(fs, ino, &inode, + inline_buf, inline_size); + } + +errout: + if (inline_buf) + ext2fs_free_mem(&inline_buf); + ext2fs_free_mem(&data.ea_data); + return retval; +} + +/* + * When caller uses this function to retrieve the inline data, it must + * allocate a buffer which has the size of inline data. The size of + * inline data can be know by ext2fs_inline_data_get_size(). + */ +errcode_t ext2fs_inline_data_get(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t *size) +{ + struct ext2_inode inode_buf; + struct ext2_inline_data data; + errcode_t retval; + + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + + data.fs = fs; + data.ino = ino; + retval = ext2fs_inline_data_ea_get(&data); + if (retval) + return retval; + + memcpy(buf, (void *)inode->i_block, EXT4_MIN_INLINE_DATA_SIZE); + if (data.ea_size > 0) + memcpy((char *) buf + EXT4_MIN_INLINE_DATA_SIZE, + data.ea_data, data.ea_size); + + if (size) + *size = EXT4_MIN_INLINE_DATA_SIZE + data.ea_size; + ext2fs_free_mem(&data.ea_data); + return 0; +} + +errcode_t ext2fs_inline_data_set(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + void *buf, size_t size) +{ + struct ext2_inode inode_buf; + struct ext2_inline_data data = { + .fs = fs, + .ino = ino, + }; + errcode_t retval; + size_t free_ea_size, existing_size, free_inode_size; + + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + + if (size <= EXT4_MIN_INLINE_DATA_SIZE) { + memcpy((void *)inode->i_block, buf, size); + } else { + retval = ext2fs_xattr_inode_max_size(fs, ino, &free_ea_size); + if (retval) + return retval; + + retval = ext2fs_inline_data_size(fs, ino, &existing_size); + if (retval) + return retval; + + if (existing_size < EXT4_MIN_INLINE_DATA_SIZE) { + free_inode_size = EXT4_MIN_INLINE_DATA_SIZE - + existing_size; + } else { + free_inode_size = 0; + } + + if (size != existing_size && + size > existing_size + free_ea_size + free_inode_size) + return EXT2_ET_INLINE_DATA_NO_SPACE; + + memcpy((void *)inode->i_block, buf, EXT4_MIN_INLINE_DATA_SIZE); + if (size > EXT4_MIN_INLINE_DATA_SIZE) + data.ea_size = size - EXT4_MIN_INLINE_DATA_SIZE; + data.ea_data = (char *) buf + EXT4_MIN_INLINE_DATA_SIZE; + } + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + return ext2fs_inline_data_ea_set(&data); +} + +#ifdef DEBUG +#include "e2p/e2p.h" + +/* + * The length of buffer is set to 64 because in inode's i_block member it only + * can save 60 bytes. Thus this value can let the data being saved in extra + * space. + */ +#define BUFF_SIZE (64) + +static errcode_t file_test(ext2_filsys fs) +{ + struct ext2_inode inode; + ext2_ino_t newfile; + errcode_t retval; + size_t size; + char *buf = 0, *cmpbuf = 0; + + /* create a new file */ + retval = ext2fs_new_inode(fs, 2, 010755, 0, &newfile); + if (retval) { + com_err("file_test", retval, "while allocating a new inode"); + return 1; + } + + memset(&inode, 0, sizeof(inode)); + inode.i_flags |= EXT4_INLINE_DATA_FL; + inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; + inode.i_mode = LINUX_S_IFREG; + retval = ext2fs_write_new_inode(fs, newfile, &inode); + if (retval) { + com_err("file_test", retval, "while writing a new inode"); + return 1; + } + + retval = ext2fs_inline_data_init(fs, newfile); + if (retval) { + com_err("file_test", retval, "while init 'system.data'"); + return 1; + } + + retval = ext2fs_inline_data_size(fs, newfile, &size); + if (retval) { + com_err("file_test", retval, "while getting size"); + return 1; + } + + if (size != EXT4_MIN_INLINE_DATA_SIZE) { + fprintf(stderr, + "tst_inline_data: size of inline data is wrong\n"); + return 1; + } + + ext2fs_get_mem(BUFF_SIZE, &buf); + memset(buf, 'a', BUFF_SIZE); + retval = ext2fs_inline_data_set(fs, newfile, 0, buf, BUFF_SIZE); + if (retval) { + com_err("file_test", retval, + "while setting inline data %s", buf); + goto err; + } + + ext2fs_get_mem(BUFF_SIZE, &cmpbuf); + retval = ext2fs_inline_data_get(fs, newfile, 0, cmpbuf, &size); + if (retval) { + com_err("file_test", retval, "while getting inline data"); + goto err; + } + + if (size != BUFF_SIZE) { + fprintf(stderr, + "tst_inline_data: size %lu != buflen %u\n", + size, BUFF_SIZE); + retval = 1; + goto err; + } + + if (memcmp(buf, cmpbuf, BUFF_SIZE)) { + fprintf(stderr, "tst_inline_data: buf != cmpbuf\n"); + retval = 1; + goto err; + } + + retval = ext2fs_punch(fs, newfile, 0, 0, 0, ~0ULL); + if (retval) { + com_err("file_test", retval, "while truncating inode"); + goto err; + } + + /* reload inode and check isize */ + ext2fs_read_inode(fs, newfile, &inode); + if (inode.i_size != 0) { + fprintf(stderr, "tst_inline_data: i_size should be 0\n"); + retval = 1; + } + +err: + if (cmpbuf) + ext2fs_free_mem(&cmpbuf); + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +static errcode_t dir_test(ext2_filsys fs) +{ + const char *dot_name = "."; + const char *stub_name = "stub"; + const char *parent_name = "test"; + ext2_ino_t parent, dir, tmp; + errcode_t retval; + char dirname[32]; + int i; + + retval = ext2fs_mkdir(fs, 11, 11, stub_name); + if (retval) { + com_err("dir_test", retval, "while creating %s dir", stub_name); + return retval; + } + + retval = ext2fs_mkdir(fs, 11, 0, parent_name); + if (retval) { + com_err("dir_test", retval, + "while creating %s dir", parent_name); + return retval; + } + + retval = ext2fs_lookup(fs, 11, parent_name, strlen(parent_name), + 0, &parent); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + retval = ext2fs_lookup(fs, parent, dot_name, strlen(dot_name), + 0, &tmp); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + if (parent != tmp) { + fprintf(stderr, "tst_inline_data: parent (%u) != tmp (%u)\n", + parent, tmp); + return 1; + } + + for (i = 0, dir = 13; i < 4; i++, dir++) { + tmp = 0; + snprintf(dirname, sizeof(dirname), "%d", i); + retval = ext2fs_mkdir(fs, parent, 0, dirname); + if (retval) { + com_err("dir_test", retval, + "while creating %s dir", dirname); + return retval; + } + + retval = ext2fs_lookup(fs, parent, dirname, strlen(dirname), + 0, &tmp); + if (retval) { + com_err("dir_test", retval, + "while looking up %s dir", parent_name); + return retval; + } + + if (dir != tmp) { + fprintf(stderr, + "tst_inline_data: dir (%u) != tmp (%u)\n", + dir, tmp); + return 1; + } + } + + snprintf(dirname, sizeof(dirname), "%d", i); + retval = ext2fs_mkdir(fs, parent, 0, dirname); + if (retval && retval != EXT2_ET_DIR_NO_SPACE) { + com_err("dir_test", retval, "while creating %s dir", dirname); + return retval; + } + + retval = ext2fs_expand_dir(fs, parent); + if (retval) { + com_err("dir_test", retval, "while expanding %s dir", parent_name); + return retval; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + ext2_filsys fs; + struct ext2_super_block param; + errcode_t retval; + + /* setup */ + initialize_ext2_error_table(); + + memset(¶m, 0, sizeof(param)); + ext2fs_blocks_count_set(¶m, 32768); + param.s_inodes_count = 100; + + param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_INLINE_DATA; + param.s_rev_level = EXT2_DYNAMIC_REV; + param.s_inode_size = 256; + + retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m, + test_io_manager, &fs); + if (retval) { + com_err("setup", retval, + "while initializing filesystem"); + exit(1); + } + + retval = ext2fs_allocate_tables(fs); + if (retval) { + com_err("setup", retval, + "while allocating tables for test filesystem"); + exit(1); + } + + /* initialize inode cache */ + if (!fs->icache) { + ext2_ino_t first_ino = EXT2_FIRST_INO(fs->super); + int i; + + /* we just want to init inode cache. So ignore error */ + ext2fs_create_inode_cache(fs, 16); + if (!fs->icache) { + fprintf(stderr, + "tst_inline_data: init inode cache failed\n"); + exit(1); + } + + /* setup inode cache */ + for (i = 0; i < fs->icache->cache_size; i++) + fs->icache->cache[i].ino = first_ino++; + } + + /* test */ + if (file_test(fs)) { + fprintf(stderr, "tst_inline_data(FILE): FAILED\n"); + return 1; + } + printf("tst_inline_data(FILE): OK\n"); + + if (dir_test(fs)) { + fprintf(stderr, "tst_inline_data(DIR): FAILED\n"); + return 1; + } + printf("tst_inline_data(DIR): OK\n"); + ext2fs_free(fs); + + return 0; +} +#endif diff --git a/src/ext2fs/inode.c b/src/ext2fs/inode.c new file mode 100644 index 00000000..015cfe4b --- /dev/null +++ b/src/ext2fs/inode.c @@ -0,0 +1,1062 @@ +/* + * inode.c --- utility routines to read and write inodes + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fsP.h" +#include "e2image.h" + +#define IBLOCK_STATUS_CSUMS_OK 1 +#define IBLOCK_STATUS_INSANE 2 +#define SCAN_BLOCK_STATUS(scan) ((scan)->temp_buffer + (scan)->inode_size) + +struct ext2_struct_inode_scan { + errcode_t magic; + ext2_filsys fs; + ext2_ino_t current_inode; + blk64_t current_block; + dgrp_t current_group; + ext2_ino_t inodes_left; + blk_t blocks_left; + dgrp_t groups_left; + blk_t inode_buffer_blocks; + char * inode_buffer; + int inode_size; + char * ptr; + int bytes_left; + char *temp_buffer; + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data); + void * done_group_data; + int bad_block_ptr; + int scan_flags; + int reserved[6]; +}; + +/* + * This routine flushes the icache, if it exists. + */ +errcode_t ext2fs_flush_icache(ext2_filsys fs) +{ + unsigned i; + + if (!fs->icache) + return 0; + + for (i=0; i < fs->icache->cache_size; i++) + fs->icache->cache[i].ino = 0; + + fs->icache->buffer_blk = 0; + return 0; +} + +/* + * Free the inode cache structure + */ +void ext2fs_free_inode_cache(struct ext2_inode_cache *icache) +{ + unsigned i; + + if (--icache->refcount) + return; + if (icache->buffer) + ext2fs_free_mem(&icache->buffer); + for (i = 0; i < icache->cache_size; i++) + ext2fs_free_mem(&icache->cache[i].inode); + if (icache->cache) + ext2fs_free_mem(&icache->cache); + icache->buffer_blk = 0; + ext2fs_free_mem(&icache); +} + +errcode_t ext2fs_create_inode_cache(ext2_filsys fs, unsigned int cache_size) +{ + unsigned i; + errcode_t retval; + + if (fs->icache) + return 0; + retval = ext2fs_get_mem(sizeof(struct ext2_inode_cache), &fs->icache); + if (retval) + return retval; + + memset(fs->icache, 0, sizeof(struct ext2_inode_cache)); + retval = ext2fs_get_mem(fs->blocksize, &fs->icache->buffer); + if (retval) + goto errout; + + fs->icache->buffer_blk = 0; + fs->icache->cache_last = -1; + fs->icache->cache_size = cache_size; + fs->icache->refcount = 1; + retval = ext2fs_get_array(fs->icache->cache_size, + sizeof(struct ext2_inode_cache_ent), + &fs->icache->cache); + if (retval) + goto errout; + + for (i = 0; i < fs->icache->cache_size; i++) { + retval = ext2fs_get_mem(EXT2_INODE_SIZE(fs->super), + &fs->icache->cache[i].inode); + if (retval) + goto errout; + } + + ext2fs_flush_icache(fs); + return 0; +errout: + ext2fs_free_inode_cache(fs->icache); + fs->icache = 0; + return retval; +} + +errcode_t ext2fs_open_inode_scan(ext2_filsys fs, int buffer_blocks, + ext2_inode_scan *ret_scan) +{ + ext2_inode_scan scan; + errcode_t retval; + errcode_t (*save_get_blocks)(ext2_filsys f, ext2_ino_t ino, blk_t *blocks); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * If fs->badblocks isn't set, then set it --- since the inode + * scanning functions require it. + */ + if (fs->badblocks == 0) { + /* + * Temporarily save fs->get_blocks and set it to zero, + * for compatibility with old e2fsck's. + */ + save_get_blocks = fs->get_blocks; + fs->get_blocks = 0; + retval = ext2fs_read_bb_inode(fs, &fs->badblocks); + if (retval && fs->badblocks) { + ext2fs_badblocks_list_free(fs->badblocks); + fs->badblocks = 0; + } + fs->get_blocks = save_get_blocks; + } + + retval = ext2fs_get_mem(sizeof(struct ext2_struct_inode_scan), &scan); + if (retval) + return retval; + memset(scan, 0, sizeof(struct ext2_struct_inode_scan)); + + scan->magic = EXT2_ET_MAGIC_INODE_SCAN; + scan->fs = fs; + scan->inode_size = EXT2_INODE_SIZE(fs->super); + scan->bytes_left = 0; + scan->current_group = 0; + scan->groups_left = fs->group_desc_count - 1; + scan->inode_buffer_blocks = buffer_blocks ? buffer_blocks : + EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS; + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); + scan->inodes_left = EXT2_INODES_PER_GROUP(scan->fs->super); + scan->blocks_left = scan->fs->inode_blocks_per_group; + if (ext2fs_has_group_desc_csum(fs)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + retval = io_channel_alloc_buf(fs->io, scan->inode_buffer_blocks, + &scan->inode_buffer); + scan->done_group = 0; + scan->done_group_data = 0; + scan->bad_block_ptr = 0; + if (retval) { + ext2fs_free_mem(&scan); + return retval; + } + retval = ext2fs_get_mem(scan->inode_size + scan->inode_buffer_blocks, + &scan->temp_buffer); + if (retval) { + ext2fs_free_mem(&scan->inode_buffer); + ext2fs_free_mem(&scan); + return retval; + } + memset(SCAN_BLOCK_STATUS(scan), 0, scan->inode_buffer_blocks); + if (scan->fs->badblocks && scan->fs->badblocks->num) + scan->scan_flags |= EXT2_SF_CHK_BADBLOCKS; + if (ext2fs_has_group_desc_csum(fs)) + scan->scan_flags |= EXT2_SF_DO_LAZY; + *ret_scan = scan; + return 0; +} + +void ext2fs_close_inode_scan(ext2_inode_scan scan) +{ + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return; + + ext2fs_free_mem(&scan->inode_buffer); + scan->inode_buffer = NULL; + ext2fs_free_mem(&scan->temp_buffer); + scan->temp_buffer = NULL; + ext2fs_free_mem(&scan); + return; +} + +void ext2fs_set_inode_callback(ext2_inode_scan scan, + errcode_t (*done_group)(ext2_filsys fs, + ext2_inode_scan scan, + dgrp_t group, + void * priv_data), + void *done_group_data) +{ + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return; + + scan->done_group = done_group; + scan->done_group_data = done_group_data; +} + +int ext2fs_inode_scan_flags(ext2_inode_scan scan, int set_flags, + int clear_flags) +{ + int old_flags; + + if (!scan || (scan->magic != EXT2_ET_MAGIC_INODE_SCAN)) + return 0; + + old_flags = scan->scan_flags; + scan->scan_flags &= ~clear_flags; + scan->scan_flags |= set_flags; + return old_flags; +} + +/* + * This function is called by ext2fs_get_next_inode when it needs to + * get ready to read in a new blockgroup. + */ +static errcode_t get_next_blockgroup(ext2_inode_scan scan) +{ + ext2_filsys fs = scan->fs; + + scan->current_group++; + scan->groups_left--; + + scan->current_block = ext2fs_inode_table_loc(scan->fs, + scan->current_group); + scan->current_inode = scan->current_group * + EXT2_INODES_PER_GROUP(fs->super); + + scan->bytes_left = 0; + scan->inodes_left = EXT2_INODES_PER_GROUP(fs->super); + scan->blocks_left = fs->inode_blocks_per_group; + if (ext2fs_has_group_desc_csum(fs)) { + __u32 unused = ext2fs_bg_itable_unused(fs, scan->current_group); + if (scan->inodes_left > unused) + scan->inodes_left -= unused; + else + scan->inodes_left = 0; + scan->blocks_left = + (scan->inodes_left + + (fs->blocksize / scan->inode_size - 1)) * + scan->inode_size / fs->blocksize; + } + + return 0; +} + +errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, + int group) +{ + scan->current_group = group - 1; + scan->groups_left = scan->fs->group_desc_count - group; + return get_next_blockgroup(scan); +} + +/* + * This function is called by get_next_blocks() to check for bad + * blocks in the inode table. + * + * This function assumes that badblocks_list->list is sorted in + * increasing order. + */ +static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, + blk64_t *num_blocks) +{ + blk64_t blk = scan->current_block; + badblocks_list bb = scan->fs->badblocks; + + /* + * If the inode table is missing, then obviously there are no + * bad blocks. :-) + */ + if (blk == 0) + return 0; + + /* + * If the current block is greater than the bad block listed + * in the bad block list, then advance the pointer until this + * is no longer the case. If we run out of bad blocks, then + * we don't need to do any more checking! + */ + while (blk > bb->list[scan->bad_block_ptr]) { + if (++scan->bad_block_ptr >= bb->num) { + scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; + return 0; + } + } + + /* + * If the current block is equal to the bad block listed in + * the bad block list, then handle that one block specially. + * (We could try to handle runs of bad blocks, but that + * only increases CPU efficiency by a small amount, at the + * expense of a huge expense of code complexity, and for an + * uncommon case at that.) + */ + if (blk == bb->list[scan->bad_block_ptr]) { + scan->scan_flags |= EXT2_SF_BAD_INODE_BLK; + *num_blocks = 1; + if (++scan->bad_block_ptr >= bb->num) + scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; + return 0; + } + + /* + * If there is a bad block in the range that we're about to + * read in, adjust the number of blocks to read so that we we + * don't read in the bad block. (Then the next block to read + * will be the bad block, which is handled in the above case.) + */ + if ((blk + *num_blocks) > bb->list[scan->bad_block_ptr]) + *num_blocks = (int) (bb->list[scan->bad_block_ptr] - blk); + + return 0; +} + +static int block_map_looks_insane(ext2_filsys fs, + struct ext2_inode_large *inode) +{ + unsigned int i, bad; + + /* We're only interested in block mapped files, dirs, and symlinks */ + if ((inode->i_flags & EXT4_INLINE_DATA_FL) || + (inode->i_flags & EXT4_EXTENTS_FL)) + return 0; + if (!LINUX_S_ISREG(inode->i_mode) && + !LINUX_S_ISLNK(inode->i_mode) && + !LINUX_S_ISDIR(inode->i_mode)) + return 0; + if (LINUX_S_ISLNK(inode->i_mode) && + EXT2_I_SIZE(inode) <= sizeof(inode->i_block)) + return 0; + + /* Unused inodes probably aren't insane */ + if (inode->i_links_count == 0) + return 0; + + /* See if more than half the block maps are insane */ + for (i = 0, bad = 0; i < EXT2_N_BLOCKS; i++) + if (inode->i_block[i] != 0 && + (inode->i_block[i] < fs->super->s_first_data_block || + inode->i_block[i] >= ext2fs_blocks_count(fs->super))) + bad++; + return bad > EXT2_N_BLOCKS / 2; +} + +static int extent_head_looks_insane(struct ext2_inode_large *inode) +{ + if (!(inode->i_flags & EXT4_EXTENTS_FL) || + ext2fs_extent_header_verify(inode->i_block, + sizeof(inode->i_block)) == 0) + return 0; + return 1; +} + +/* + * Check all the inodes that we just read into the buffer. Record what we + * find here -- currently, we can observe that all checksums are ok; more + * than half the inodes are insane; or no conclusions at all. + */ +static void check_inode_block_sanity(ext2_inode_scan scan, blk64_t num_blocks) +{ + ext2_ino_t ino, inodes_to_scan; + unsigned int badness, checksum_failures; + unsigned int inodes_in_buf, inodes_per_block; + char *p; + struct ext2_inode_large *inode; + char *block_status; + unsigned int blk, bad_csum; + + if (!(scan->scan_flags & EXT2_SF_WARN_GARBAGE_INODES)) + return; + + inodes_to_scan = scan->inodes_left; + inodes_in_buf = num_blocks * scan->fs->blocksize / scan->inode_size; + if (inodes_to_scan > inodes_in_buf) + inodes_to_scan = inodes_in_buf; + + p = (char *) scan->inode_buffer; + ino = scan->current_inode + 1; + checksum_failures = badness = 0; + block_status = SCAN_BLOCK_STATUS(scan); + memset(block_status, 0, scan->inode_buffer_blocks); + inodes_per_block = EXT2_INODES_PER_BLOCK(scan->fs->super); + + if (inodes_per_block < 2) + return; + +#ifdef WORDS_BIGENDIAN + if (ext2fs_get_mem(EXT2_INODE_SIZE(scan->fs->super), &inode)) + return; +#endif + + while (inodes_to_scan > 0) { + blk = (p - (char *)scan->inode_buffer) / scan->fs->blocksize; + bad_csum = ext2fs_inode_csum_verify(scan->fs, ino, + (struct ext2_inode_large *) p) == 0; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) inode, + (struct ext2_inode_large *) p, + 0, EXT2_INODE_SIZE(scan->fs->super)); +#else + inode = (struct ext2_inode_large *) p; +#endif + + /* Is this inode insane? */ + if (bad_csum) { + checksum_failures++; + badness++; + } else if (extent_head_looks_insane(inode) || + block_map_looks_insane(scan->fs, inode)) + badness++; + + /* If more than half are insane, declare the whole block bad */ + if (badness > inodes_per_block / 2) { + unsigned int ino_adj; + + block_status[blk] |= IBLOCK_STATUS_INSANE; + ino_adj = inodes_per_block - + ((ino - 1) % inodes_per_block); + if (ino_adj > inodes_to_scan) + ino_adj = inodes_to_scan; + inodes_to_scan -= ino_adj; + p += scan->inode_size * ino_adj; + ino += ino_adj; + checksum_failures = badness = 0; + continue; + } + + if ((ino % inodes_per_block) == 0) { + if (checksum_failures == 0) + block_status[blk] |= IBLOCK_STATUS_CSUMS_OK; + checksum_failures = badness = 0; + } + inodes_to_scan--; + p += scan->inode_size; + ino++; + }; + +#ifdef WORDS_BIGENDIAN + ext2fs_free_mem(&inode); +#endif +} + +/* + * This function is called by ext2fs_get_next_inode when it needs to + * read in more blocks from the current blockgroup's inode table. + */ +static errcode_t get_next_blocks(ext2_inode_scan scan) +{ + blk64_t num_blocks; + errcode_t retval; + + /* + * Figure out how many blocks to read; we read at most + * inode_buffer_blocks, and perhaps less if there aren't that + * many blocks left to read. + */ + num_blocks = scan->inode_buffer_blocks; + if (num_blocks > scan->blocks_left) + num_blocks = scan->blocks_left; + + /* + * If the past block "read" was a bad block, then mark the + * left-over extra bytes as also being bad. + */ + if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) { + if (scan->bytes_left) + scan->scan_flags |= EXT2_SF_BAD_EXTRA_BYTES; + scan->scan_flags &= ~EXT2_SF_BAD_INODE_BLK; + } + + /* + * Do inode bad block processing, if necessary. + */ + if (scan->scan_flags & EXT2_SF_CHK_BADBLOCKS) { + retval = check_for_inode_bad_blocks(scan, &num_blocks); + if (retval) + return retval; + } + + if ((scan->scan_flags & EXT2_SF_BAD_INODE_BLK) || + (scan->current_block == 0)) { + memset(scan->inode_buffer, 0, + (size_t) num_blocks * scan->fs->blocksize); + } else { + retval = io_channel_read_blk64(scan->fs->io, + scan->current_block, + (int) num_blocks, + scan->inode_buffer); + if (retval) + return EXT2_ET_NEXT_INODE_READ; + } + check_inode_block_sanity(scan, num_blocks); + + scan->ptr = scan->inode_buffer; + scan->bytes_left = num_blocks * scan->fs->blocksize; + + scan->blocks_left -= num_blocks; + if (scan->current_block) + scan->current_block += num_blocks; + + return 0; +} + +#if 0 +/* + * Returns 1 if the entire inode_buffer has a non-zero size and + * contains all zeros. (Not just deleted inodes, since that means + * that part of the inode table was used at one point; we want all + * zeros, which means that the inode table is pristine.) + */ +static inline int is_empty_scan(ext2_inode_scan scan) +{ + int i; + + if (scan->bytes_left == 0) + return 0; + + for (i=0; i < scan->bytes_left; i++) + if (scan->ptr[i]) + return 0; + return 1; +} +#endif + +errcode_t ext2fs_get_next_inode_full(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode, int bufsize) +{ + errcode_t retval; + int extra_bytes = 0; + int length; + struct ext2_inode_large *iptr = (struct ext2_inode_large *)inode; + char *iblock_status; + unsigned int iblk; + + EXT2_CHECK_MAGIC(scan, EXT2_ET_MAGIC_INODE_SCAN); + length = EXT2_INODE_SIZE(scan->fs->super); + iblock_status = SCAN_BLOCK_STATUS(scan); + + /* + * Do we need to start reading a new block group? + */ + if (scan->inodes_left <= 0) { + force_new_group: + if (scan->done_group) { + retval = (scan->done_group) + (scan->fs, scan, scan->current_group, + scan->done_group_data); + if (retval) + return retval; + } + if (scan->groups_left <= 0) { + *ino = 0; + return 0; + } + retval = get_next_blockgroup(scan); + if (retval) + return retval; + } + /* + * These checks are done outside the above if statement so + * they can be done for block group #0. + */ + if ((scan->scan_flags & EXT2_SF_DO_LAZY) && + (ext2fs_bg_flags_test(scan->fs, scan->current_group, EXT2_BG_INODE_UNINIT) + )) + goto force_new_group; + if (scan->inodes_left == 0) + goto force_new_group; + if (scan->current_block == 0) { + if (scan->scan_flags & EXT2_SF_SKIP_MISSING_ITABLE) { + goto force_new_group; + } else + return EXT2_ET_MISSING_INODE_TABLE; + } + + + /* + * Have we run out of space in the inode buffer? If so, we + * need to read in more blocks. + */ + if (scan->bytes_left < scan->inode_size) { + if (scan->bytes_left) + memcpy(scan->temp_buffer, scan->ptr, scan->bytes_left); + extra_bytes = scan->bytes_left; + + retval = get_next_blocks(scan); + if (retval) + return retval; +#if 0 + /* + * XXX test Need check for used inode somehow. + * (Note: this is hard.) + */ + if (is_empty_scan(scan)) + goto force_new_group; +#endif + } + + if (bufsize < length) { + retval = ext2fs_get_mem(length, &iptr); + if (retval) + return retval; + } + + retval = 0; + iblk = scan->current_inode % EXT2_INODES_PER_GROUP(scan->fs->super) / + EXT2_INODES_PER_BLOCK(scan->fs->super) % + scan->inode_buffer_blocks; + if (extra_bytes) { + memcpy(scan->temp_buffer+extra_bytes, scan->ptr, + scan->inode_size - extra_bytes); + scan->ptr += scan->inode_size - extra_bytes; + scan->bytes_left -= scan->inode_size - extra_bytes; + + /* Verify the inode checksum. */ + if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) && + !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1, + (struct ext2_inode_large *)scan->temp_buffer)) + retval = EXT2_ET_INODE_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + memset(iptr, 0, length); + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) scan->temp_buffer, + 0, length); +#else + memcpy(iptr, scan->temp_buffer, length); +#endif + if (scan->scan_flags & EXT2_SF_BAD_EXTRA_BYTES) + retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; + scan->scan_flags &= ~EXT2_SF_BAD_EXTRA_BYTES; + } else { + /* Verify the inode checksum. */ + if (!(iblock_status[iblk] & IBLOCK_STATUS_CSUMS_OK) && + !(scan->fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_csum_verify(scan->fs, scan->current_inode + 1, + (struct ext2_inode_large *)scan->ptr)) + retval = EXT2_ET_INODE_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + memset(iptr, 0, length); + ext2fs_swap_inode_full(scan->fs, + (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) scan->ptr, + 0, length); +#else + memcpy(iptr, scan->ptr, length); +#endif + scan->ptr += scan->inode_size; + scan->bytes_left -= scan->inode_size; + if (scan->scan_flags & EXT2_SF_BAD_INODE_BLK) + retval = EXT2_ET_BAD_BLOCK_IN_INODE_TABLE; + } + if ((iblock_status[iblk] & IBLOCK_STATUS_INSANE) && + (retval == 0 || retval == EXT2_ET_INODE_CSUM_INVALID)) + retval = EXT2_ET_INODE_IS_GARBAGE; + + scan->inodes_left--; + scan->current_inode++; + *ino = scan->current_inode; + if (iptr != (struct ext2_inode_large *)inode) { + memcpy(inode, iptr, bufsize); + ext2fs_free_mem(&iptr); + } + return retval; +} + +errcode_t ext2fs_get_next_inode(ext2_inode_scan scan, ext2_ino_t *ino, + struct ext2_inode *inode) +{ + return ext2fs_get_next_inode_full(scan, ino, inode, + sizeof(struct ext2_inode)); +} + +/* + * Functions to read and write a single inode. + */ +errcode_t ext2fs_read_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, int bufsize) +{ + blk64_t block_nr; + unsigned long group, block, offset; + char *ptr; + errcode_t retval; + unsigned i; + int clen, inodes_per_block; + io_channel io; + int length = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *iptr; + int cache_slot, fail_csum; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* Check to see if user has an override function */ + if (fs->read_inode && + ((bufsize == sizeof(struct ext2_inode)) || + (EXT2_INODE_SIZE(fs->super) == sizeof(struct ext2_inode)))) { + retval = (fs->read_inode)(fs, ino, inode); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + /* Create inode cache if not present */ + if (!fs->icache) { + retval = ext2fs_create_inode_cache(fs, 4); + if (retval) + return retval; + } + /* Check to see if it's in the inode cache */ + for (i = 0; i < fs->icache->cache_size; i++) { + if (fs->icache->cache[i].ino == ino) { + memcpy(inode, fs->icache->cache[i].inode, + (bufsize > length) ? length : bufsize); + return 0; + } + } + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { + inodes_per_block = fs->blocksize / EXT2_INODE_SIZE(fs->super); + block_nr = ext2fs_le32_to_cpu(fs->image_header->offset_inode) / fs->blocksize; + block_nr += (ino - 1) / inodes_per_block; + offset = ((ino - 1) % inodes_per_block) * + EXT2_INODE_SIZE(fs->super); + io = fs->image_io; + } else { + group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); + if (group > fs->group_desc_count) + return EXT2_ET_BAD_INODE_NUM; + offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * + EXT2_INODE_SIZE(fs->super); + block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) + return EXT2_ET_MISSING_INODE_TABLE; + block_nr = ext2fs_inode_table_loc(fs, group) + + block; + io = fs->io; + } + offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); + + cache_slot = (fs->icache->cache_last + 1) % fs->icache->cache_size; + iptr = (struct ext2_inode_large *)fs->icache->cache[cache_slot].inode; + + ptr = (char *) iptr; + while (length) { + clen = length; + if ((offset + length) > fs->blocksize) + clen = fs->blocksize - offset; + + if (block_nr != fs->icache->buffer_blk) { + retval = io_channel_read_blk64(io, block_nr, 1, + fs->icache->buffer); + if (retval) + return retval; + fs->icache->buffer_blk = block_nr; + } + + memcpy(ptr, ((char *) fs->icache->buffer) + (unsigned) offset, + clen); + + offset = 0; + length -= clen; + ptr += clen; + block_nr++; + } + length = EXT2_INODE_SIZE(fs->super); + + /* Verify the inode checksum. */ + fail_csum = !ext2fs_inode_csum_verify(fs, ino, iptr); + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, (struct ext2_inode_large *) iptr, + (struct ext2_inode_large *) iptr, + 0, length); +#endif + + /* Update the inode cache bookkeeping */ + if (!fail_csum) { + fs->icache->cache_last = cache_slot; + fs->icache->cache[cache_slot].ino = ino; + } + memcpy(inode, iptr, (bufsize > length) ? length : bufsize); + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && fail_csum) + return EXT2_ET_INODE_CSUM_INVALID; + + return 0; +} + +errcode_t ext2fs_read_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode) +{ + return ext2fs_read_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); +} + +errcode_t ext2fs_write_inode_full(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode * inode, int bufsize) +{ + blk64_t block_nr; + unsigned long group, block, offset; + errcode_t retval = 0; + struct ext2_inode_large *w_inode; + char *ptr; + unsigned i; + int clen; + int length = EXT2_INODE_SIZE(fs->super); + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* Check to see if user provided an override function */ + if (fs->write_inode) { + retval = (fs->write_inode)(fs, ino, inode); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + + if ((ino == 0) || (ino > fs->super->s_inodes_count)) + return EXT2_ET_BAD_INODE_NUM; + + /* Prepare our shadow buffer for read/modify/byteswap/write */ + retval = ext2fs_get_mem(length, &w_inode); + if (retval) + return retval; + + if (bufsize < length) { + int old_flags = fs->flags; + fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; + retval = ext2fs_read_inode_full(fs, ino, + (struct ext2_inode *)w_inode, + length); + fs->flags = (old_flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | + (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); + if (retval) + goto errout; + } + + /* Check to see if the inode cache needs to be updated */ + if (fs->icache) { + for (i=0; i < fs->icache->cache_size; i++) { + if (fs->icache->cache[i].ino == ino) { + memcpy(fs->icache->cache[i].inode, inode, + (bufsize > length) ? length : bufsize); + break; + } + } + } else { + retval = ext2fs_create_inode_cache(fs, 4); + if (retval) + goto errout; + } + memcpy(w_inode, inode, (bufsize > length) ? length : bufsize); + + if (!(fs->flags & EXT2_FLAG_RW)) { + retval = EXT2_ET_RO_FILSYS; + goto errout; + } + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_inode_full(fs, w_inode, w_inode, 1, length); +#endif + + retval = ext2fs_inode_csum_set(fs, ino, w_inode); + if (retval) + goto errout; + + group = (ino - 1) / EXT2_INODES_PER_GROUP(fs->super); + offset = ((ino - 1) % EXT2_INODES_PER_GROUP(fs->super)) * + EXT2_INODE_SIZE(fs->super); + block = offset >> EXT2_BLOCK_SIZE_BITS(fs->super); + if (!ext2fs_inode_table_loc(fs, (unsigned) group)) { + retval = EXT2_ET_MISSING_INODE_TABLE; + goto errout; + } + block_nr = ext2fs_inode_table_loc(fs, (unsigned) group) + block; + + offset &= (EXT2_BLOCK_SIZE(fs->super) - 1); + + ptr = (char *) w_inode; + + while (length) { + clen = length; + if ((offset + length) > fs->blocksize) + clen = fs->blocksize - offset; + + if (fs->icache->buffer_blk != block_nr) { + retval = io_channel_read_blk64(fs->io, block_nr, 1, + fs->icache->buffer); + if (retval) + goto errout; + fs->icache->buffer_blk = block_nr; + } + + + memcpy((char *) fs->icache->buffer + (unsigned) offset, + ptr, clen); + + retval = io_channel_write_blk64(fs->io, block_nr, 1, + fs->icache->buffer); + if (retval) + goto errout; + + offset = 0; + ptr += clen; + length -= clen; + block_nr++; + } + + fs->flags |= EXT2_FLAG_CHANGED; +errout: + ext2fs_free_mem(&w_inode); + return retval; +} + +errcode_t ext2fs_write_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode) +{ + return ext2fs_write_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); +} + +/* + * This function should be called when writing a new inode. It makes + * sure that extra part of large inodes is initialized properly. + */ +errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode) +{ + struct ext2_inode *buf; + int size = EXT2_INODE_SIZE(fs->super); + struct ext2_inode_large *large_inode; + errcode_t retval; + __u32 t = fs->now ? fs->now : time(NULL); + + if (!inode->i_ctime) + inode->i_ctime = t; + if (!inode->i_mtime) + inode->i_mtime = t; + if (!inode->i_atime) + inode->i_atime = t; + + if (size == sizeof(struct ext2_inode)) + return ext2fs_write_inode_full(fs, ino, inode, + sizeof(struct ext2_inode)); + + buf = malloc(size); + if (!buf) + return ENOMEM; + + memset(buf, 0, size); + *buf = *inode; + + large_inode = (struct ext2_inode_large *) buf; + large_inode->i_extra_isize = sizeof(struct ext2_inode_large) - + EXT2_GOOD_OLD_INODE_SIZE; + if (!large_inode->i_crtime) + large_inode->i_crtime = t; + + retval = ext2fs_write_inode_full(fs, ino, buf, size); + free(buf); + return retval; +} + + +errcode_t ext2fs_get_blocks(ext2_filsys fs, ext2_ino_t ino, blk_t *blocks) +{ + struct ext2_inode inode; + int i; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (ino > fs->super->s_inodes_count) + return EXT2_ET_BAD_INODE_NUM; + + if (fs->get_blocks) { + if (!(*fs->get_blocks)(fs, ino, blocks)) + return 0; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + for (i=0; i < EXT2_N_BLOCKS; i++) + blocks[i] = inode.i_block[i]; + return 0; +} + +errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) +{ + struct ext2_inode inode; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (ino > fs->super->s_inodes_count) + return EXT2_ET_BAD_INODE_NUM; + + if (fs->check_directory) { + retval = (fs->check_directory)(fs, ino); + if (retval != EXT2_ET_CALLBACK_NOTHANDLED) + return retval; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + return retval; + if (!LINUX_S_ISDIR(inode.i_mode)) + return EXT2_ET_NO_DIRECTORY; + return 0; +} + diff --git a/src/ext2fs/io_manager.c b/src/ext2fs/io_manager.c new file mode 100644 index 00000000..c395d615 --- /dev/null +++ b/src/ext2fs/io_manager.c @@ -0,0 +1,150 @@ +/* + * io_manager.c --- the I/O manager abstraction + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +errcode_t io_channel_set_options(io_channel channel, const char *opts) +{ + errcode_t retval = 0; + char *next, *ptr, *options, *arg; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (!opts) + return 0; + + if (!channel->manager->set_option) + return EXT2_ET_INVALID_ARGUMENT; + + options = malloc(strlen(opts)+1); + if (!options) + return EXT2_ET_NO_MEMORY; + strcpy(options, opts); + ptr = options; + + while (ptr && *ptr) { + next = strchr(ptr, '&'); + if (next) + *next++ = 0; + + arg = strchr(ptr, '='); + if (arg) + *arg++ = 0; + + retval = (channel->manager->set_option)(channel, ptr, arg); + if (retval) + break; + ptr = next; + } + free(options); + return retval; +} + +errcode_t io_channel_write_byte(io_channel channel, unsigned long offset, + int count, const void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->write_byte) + return channel->manager->write_byte(channel, offset, + count, data); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_read_blk64(io_channel channel, unsigned long long block, + int count, void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->read_blk64) + return (channel->manager->read_blk64)(channel, block, + count, data); + + if ((block >> 32) != 0) + return EXT2_ET_IO_CHANNEL_NO_SUPPORT_64; + + return (channel->manager->read_blk)(channel, (unsigned long) block, + count, data); +} + +errcode_t io_channel_write_blk64(io_channel channel, unsigned long long block, + int count, const void *data) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->write_blk64) + return (channel->manager->write_blk64)(channel, block, + count, data); + + if ((block >> 32) != 0) + return EXT2_ET_IO_CHANNEL_NO_SUPPORT_64; + + return (channel->manager->write_blk)(channel, (unsigned long) block, + count, data); +} + +errcode_t io_channel_discard(io_channel channel, unsigned long long block, + unsigned long long count) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->discard) + return (channel->manager->discard)(channel, block, count); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_zeroout(io_channel channel, unsigned long long block, + unsigned long long count) +{ + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + + if (channel->manager->zeroout) + return (channel->manager->zeroout)(channel, block, count); + + return EXT2_ET_UNIMPLEMENTED; +} + +errcode_t io_channel_alloc_buf(io_channel io, int count, void *ptr) +{ + size_t size; + + if (count == 0) + size = io->block_size; + else if (count > 0) + size = io->block_size * count; + else + size = -count; + + if (io->align) + return ext2fs_get_memalign(size, io->align, ptr); + else + return ext2fs_get_mem(size, ptr); +} + +errcode_t io_channel_cache_readahead(io_channel io, unsigned long long block, + unsigned long long count) +{ + if (!io->manager->cache_readahead) + return EXT2_ET_OP_NOT_SUPPORTED; + + return io->manager->cache_readahead(io, block, count); +} diff --git a/src/ext2fs/link.c b/src/ext2fs/link.c new file mode 100644 index 00000000..65dc8877 --- /dev/null +++ b/src/ext2fs/link.c @@ -0,0 +1,201 @@ +/* + * link.c --- create links in a ext2fs directory + * + * Copyright (C) 1993, 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct link_struct { + ext2_filsys fs; + const char *name; + int namelen; + ext2_ino_t inode; + int flags; + int done; + unsigned int blocksize; + errcode_t err; + struct ext2_super_block *sb; +}; + +static int link_proc(struct ext2_dir_entry *dirent, + int offset, + int blocksize, + char *buf, + void *priv_data) +{ + struct link_struct *ls = (struct link_struct *) priv_data; + struct ext2_dir_entry *next; + unsigned int rec_len, min_rec_len, curr_rec_len; + int ret = 0; + int csum_size = 0; + struct ext2_dir_entry_tail *t; + + if (ls->done) + return DIRENT_ABORT; + + rec_len = EXT2_DIR_REC_LEN(ls->namelen); + + ls->err = ext2fs_get_rec_len(ls->fs, dirent, &curr_rec_len); + if (ls->err) + return DIRENT_ABORT; + + if (ext2fs_has_feature_metadata_csum(ls->fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + /* + * See if the following directory entry (if any) is unused; + * if so, absorb it into this one. + */ + next = (struct ext2_dir_entry *) (buf + offset + curr_rec_len); + if ((offset + (int) curr_rec_len < blocksize - (8 + csum_size)) && + (next->inode == 0) && + (offset + (int) curr_rec_len + (int) next->rec_len <= blocksize)) { + curr_rec_len += next->rec_len; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + ret = DIRENT_CHANGED; + } + + /* + * Since ext2fs_link blows away htree data, we need to be + * careful -- if metadata_csum is enabled and we're passed in + * a dirent that contains htree data, we need to create the + * fake entry at the end of the block that hides the checksum. + */ + + /* De-convert a dx_node block */ + if (csum_size && + curr_rec_len == ls->fs->blocksize && + !dirent->inode) { + curr_rec_len -= csum_size; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); + ext2fs_initialize_dirent_tail(ls->fs, t); + ret = DIRENT_CHANGED; + } + + /* De-convert a dx_root block */ + if (csum_size && + curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) && + offset == EXT2_DIR_REC_LEN(1) && + dirent->name[0] == '.' && dirent->name[1] == '.') { + curr_rec_len -= csum_size; + ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); + ext2fs_initialize_dirent_tail(ls->fs, t); + ret = DIRENT_CHANGED; + } + + /* + * If the directory entry is used, see if we can split the + * directory entry to make room for the new name. If so, + * truncate it and return. + */ + if (dirent->inode) { + min_rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(dirent)); + if (curr_rec_len < (min_rec_len + rec_len)) + return ret; + rec_len = curr_rec_len - min_rec_len; + ls->err = ext2fs_set_rec_len(ls->fs, min_rec_len, dirent); + if (ls->err) + return DIRENT_ABORT; + next = (struct ext2_dir_entry *) (buf + offset + + dirent->rec_len); + next->inode = 0; + ext2fs_dirent_set_name_len(next, 0); + ext2fs_dirent_set_file_type(next, 0); + ls->err = ext2fs_set_rec_len(ls->fs, rec_len, next); + if (ls->err) + return DIRENT_ABORT; + return DIRENT_CHANGED; + } + + /* + * If we get this far, then the directory entry is not used. + * See if we can fit the request entry in. If so, do it. + */ + if (curr_rec_len < rec_len) + return ret; + dirent->inode = ls->inode; + ext2fs_dirent_set_name_len(dirent, ls->namelen); + strncpy(dirent->name, ls->name, ls->namelen); + if (ext2fs_has_feature_filetype(ls->sb)) + ext2fs_dirent_set_file_type(dirent, ls->flags & 0x7); + + ls->done++; + return DIRENT_ABORT|DIRENT_CHANGED; +} + +/* + * Note: the low 3 bits of the flags field are used as the directory + * entry filetype. + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, + ext2_ino_t ino, int flags) +{ + errcode_t retval; + struct link_struct ls; + struct ext2_inode inode; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + ls.fs = fs; + ls.name = name; + ls.namelen = name ? strlen(name) : 0; + ls.inode = ino; + ls.flags = flags; + ls.done = 0; + ls.sb = fs->super; + ls.blocksize = fs->blocksize; + ls.err = 0; + + retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, + 0, link_proc, &ls); + if (retval) + return retval; + if (ls.err) + return ls.err; + + if (!ls.done) + return EXT2_ET_DIR_NO_SPACE; + + if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) + return retval; + + /* + * If this function changes to preserve the htree, remove the + * two hunks in link_proc that shove checksum tails into the + * former dx_root/dx_node blocks. + */ + if (inode.i_flags & EXT2_INDEX_FL) { + inode.i_flags &= ~EXT2_INDEX_FL; + if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0) + return retval; + } + + return 0; +} diff --git a/src/ext2fs/lookup.c b/src/ext2fs/lookup.c new file mode 100644 index 00000000..c1d802c0 --- /dev/null +++ b/src/ext2fs/lookup.c @@ -0,0 +1,70 @@ +/* + * lookup.c --- ext2fs directory lookup operations + * + * Copyright (C) 1993, 1994, 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct lookup_struct { + const char *name; + int len; + ext2_ino_t *inode; + int found; +}; + +#ifdef __TURBOC__ + #pragma argsused +#endif +static int lookup_proc(struct ext2_dir_entry *dirent, + int offset EXT2FS_ATTR((unused)), + int blocksize EXT2FS_ATTR((unused)), + char *buf EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct lookup_struct *ls = (struct lookup_struct *) priv_data; + + if (ls->len != ext2fs_dirent_name_len(dirent)) + return 0; + if (strncmp(ls->name, dirent->name, ext2fs_dirent_name_len(dirent))) + return 0; + *ls->inode = dirent->inode; + ls->found++; + return DIRENT_ABORT; +} + + +errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, + int namelen, char *buf, ext2_ino_t *inode) +{ + errcode_t retval; + struct lookup_struct ls; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + ls.name = name; + ls.len = namelen; + ls.inode = inode; + ls.found = 0; + + retval = ext2fs_dir_iterate(fs, dir, 0, buf, lookup_proc, &ls); + if (retval) + return retval; + + return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND; +} + + diff --git a/src/ext2fs/missing.c b/src/ext2fs/missing.c new file mode 100644 index 00000000..b132d63d --- /dev/null +++ b/src/ext2fs/missing.c @@ -0,0 +1,102 @@ +/* + * missing.c --- stuff we need from features we don't care about (journal) + * + * Copyright (C) 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include "ext2fs.h" + +/* + * Convenience function which zeros out _num_ blocks starting at + * _blk_. In case of an error, the details of the error is returned + * via _ret_blk_ and _ret_count_ if they are non-NULL pointers. + * Returns 0 on success, and an error code on an error. + * + * As a special case, if the first argument is NULL, then it will + * attempt to free the static zeroizing buffer. (This is to keep + * programs that check for memory leaks happy.) + */ +#define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize) +errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, + blk64_t *ret_blk, int *ret_count) +{ + int j, count; + static void *buf; + static int stride_length; + errcode_t retval; + + /* If fs is null, clean up the static buffer and return */ + if (!fs) { + if (buf) { + free(buf); + buf = 0; + stride_length = 0; + } + return 0; + } + + /* Deal with zeroing less than 1 block */ + if (num <= 0) + return 0; + + /* Try a zero out command, if supported */ + retval = io_channel_zeroout(fs->io, blk, num); + if (retval == 0) + return 0; + + /* Allocate the zeroizing buffer if necessary */ + if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) { + void *p; + int new_stride = num; + + if (new_stride > MAX_STRIDE_LENGTH) + new_stride = MAX_STRIDE_LENGTH; + p = realloc(buf, fs->blocksize * new_stride); + if (!p) + return EXT2_ET_NO_MEMORY; + buf = p; + stride_length = new_stride; + memset(buf, 0, fs->blocksize * stride_length); + } + /* OK, do the write loop */ + j=0; + while (j < num) { + if (blk % stride_length) { + count = stride_length - (blk % stride_length); + if (count > (num - j)) + count = num - j; + } else { + count = num - j; + if (count > stride_length) + count = stride_length; + } + retval = io_channel_write_blk64(fs->io, blk, count, buf); + if (retval) { + if (ret_count) + *ret_count = count; + if (ret_blk) + *ret_blk = blk; + return retval; + } + j += count; blk += count; + } + return 0; +} + +errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, + blk_t *ret_blk, int *ret_count) +{ + blk64_t ret_blk2; + errcode_t retval; + + retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count); + if (retval) + *ret_blk = (blk_t) ret_blk2; + return retval; +} diff --git a/src/ext2fs/mkdir.c b/src/ext2fs/mkdir.c new file mode 100644 index 00000000..2a63aad1 --- /dev/null +++ b/src/ext2fs/mkdir.c @@ -0,0 +1,192 @@ +/* + * mkdir.c --- make a directory in the filesystem + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#ifndef EXT2_FT_DIR +#define EXT2_FT_DIR 2 +#endif + +errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, + const char *name) +{ + ext2_extent_handle_t handle; + errcode_t retval; + struct ext2_inode parent_inode, inode; + ext2_ino_t ino = inum; + ext2_ino_t scratch_ino; + blk64_t blk; + char *block = 0; + int inline_data = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * Create a new dir with inline data iff this feature is enabled + * and ino >= EXT2_FIRST_INO. + */ + if ((!ino || ino >= EXT2_FIRST_INO(fs->super)) && + ext2fs_has_feature_inline_data(fs->super)) + inline_data = 1; + + /* + * Allocate an inode, if necessary + */ + if (!ino) { + retval = ext2fs_new_inode(fs, parent, LINUX_S_IFDIR | 0755, + 0, &ino); + if (retval) + goto cleanup; + } + + /* + * Allocate a data block for the directory + */ + memset(&inode, 0, sizeof(struct ext2_inode)); + if (!inline_data) { + retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, + &inode, + 0), + NULL, &blk); + if (retval) + goto cleanup; + } + + /* + * Create a scratch template for the directory + */ + if (inline_data) + retval = ext2fs_new_dir_inline_data(fs, ino, parent, + inode.i_block); + else + retval = ext2fs_new_dir_block(fs, ino, parent, &block); + if (retval) + goto cleanup; + + /* + * Get the parent's inode, if necessary + */ + if (parent != ino) { + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + } else + memset(&parent_inode, 0, sizeof(parent_inode)); + + /* + * Create the inode structure.... + */ + inode.i_mode = LINUX_S_IFDIR | (0777 & ~fs->umask); + inode.i_uid = inode.i_gid = 0; + if (inline_data) { + inode.i_flags |= EXT4_INLINE_DATA_FL; + inode.i_size = EXT4_MIN_INLINE_DATA_SIZE; + } else { + if (ext2fs_has_feature_extents(fs->super)) + inode.i_flags |= EXT4_EXTENTS_FL; + else + inode.i_block[0] = blk; + inode.i_size = fs->blocksize; + ext2fs_iblk_set(fs, &inode, 1); + } + inode.i_links_count = 2; + + /* + * Write out the inode and inode data block. The inode generation + * number is assigned by write_new_inode, which means that the call + * to write_dir_block must come after that. + */ + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + if (inline_data) { + /* init "system.data" for new dir */ + retval = ext2fs_inline_data_init(fs, ino); + } else { + retval = ext2fs_write_dir_block4(fs, blk, block, 0, ino); + if (retval) + goto cleanup; + + if (ext2fs_has_feature_extents(fs->super)) { + retval = ext2fs_extent_open2(fs, ino, &inode, &handle); + if (retval) + goto cleanup; + retval = ext2fs_extent_set_bmap(handle, 0, blk, 0); + ext2fs_extent_free(handle); + if (retval) + goto cleanup; + } + } + + /* + * Link the directory into the filesystem hierarchy + */ + if (name) { + retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, + &scratch_ino); + if (!retval) { + retval = EXT2_ET_DIR_EXISTS; + name = 0; + goto cleanup; + } + if (retval != EXT2_ET_FILE_NOT_FOUND) + goto cleanup; + retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_DIR); + if (retval) + goto cleanup; + } + + /* + * Update parent inode's counts + */ + if (parent != ino) { + /* reload parent inode due to inline data */ + retval = ext2fs_read_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + parent_inode.i_links_count++; + retval = ext2fs_write_inode(fs, parent, &parent_inode); + if (retval) + goto cleanup; + } + + /* + * Update accounting.... + */ + if (!inline_data) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 1); + +cleanup: + if (block) + ext2fs_free_mem(&block); + return retval; + +} + + diff --git a/src/ext2fs/mmp.c b/src/ext2fs/mmp.c new file mode 100644 index 00000000..5c01df71 --- /dev/null +++ b/src/ext2fs/mmp.c @@ -0,0 +1,470 @@ +/* + * Helper functions for multiple mount protection (MMP). + * + * Copyright (C) 2011 Whamcloud, Inc. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#ifndef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE /* since glibc 2.20 _SVID_SOURCE is deprecated */ +#endif + +#include "config.h" + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include + +#include "ext2fs/ext2_fs.h" +#include "ext2fs/ext2fs.h" + +#ifndef O_DIRECT +#define O_DIRECT 0 +#endif + +#ifndef _MSC_VER +#pragma GCC diagnostic push +#ifndef CONFIG_MMP +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#endif + +errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_cmp; + errcode_t retval = 0; + + if ((mmp_blk <= fs->super->s_first_data_block) || + (mmp_blk >= ext2fs_blocks_count(fs->super))) + return EXT2_ET_MMP_BAD_BLOCK; + + /* ext2fs_open() reserves fd0,1,2 to avoid stdio collision, so checking + * mmp_fd <= 0 is OK to validate that the fd is valid. This opens its + * own fd to read the MMP block to ensure that it is using O_DIRECT, + * regardless of how the io_manager is doing reads, to avoid caching of + * the MMP block by the io_manager or the VM. It needs to be fresh. */ + if (fs->mmp_fd <= 0) { + fs->mmp_fd = open(fs->device_name, O_RDWR | O_DIRECT); + if (fs->mmp_fd < 0) { + retval = EXT2_ET_MMP_OPEN_DIRECT; + goto out; + } + } + + if (fs->mmp_cmp == NULL) { + int align = ext2fs_get_dio_alignment(fs->mmp_fd); + + retval = ext2fs_get_memalign(fs->blocksize, align, + &fs->mmp_cmp); + if (retval) + return retval; + } + + if ((blk64_t) ext2fs_llseek(fs->mmp_fd, mmp_blk * fs->blocksize, + SEEK_SET) != + mmp_blk * fs->blocksize) { + retval = EXT2_ET_LLSEEK_FAILED; + goto out; + } + + if (read(fs->mmp_fd, fs->mmp_cmp, fs->blocksize) != fs->blocksize) { + retval = EXT2_ET_SHORT_READ; + goto out; + } + + mmp_cmp = fs->mmp_cmp; + + if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_mmp_csum_verify(fs, mmp_cmp)) + retval = EXT2_ET_MMP_CSUM_INVALID; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_cmp); +#endif + + if (buf != NULL && buf != fs->mmp_cmp) + memcpy(buf, fs->mmp_cmp, fs->blocksize); + + if (mmp_cmp->mmp_magic != EXT4_MMP_MAGIC) { + retval = EXT2_ET_MMP_MAGIC_INVALID; + goto out; + } + +out: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +errcode_t ext2fs_mmp_write(ext2_filsys fs, blk64_t mmp_blk, void *buf) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_s = buf; + struct timeval tv; + errcode_t retval = 0; + + gettimeofday(&tv, 0); + mmp_s->mmp_time = tv.tv_sec; + fs->mmp_last_written = tv.tv_sec; + + if (fs->super->s_mmp_block < fs->super->s_first_data_block || + fs->super->s_mmp_block > ext2fs_blocks_count(fs->super)) + return EXT2_ET_MMP_BAD_BLOCK; + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_s); +#endif + + retval = ext2fs_mmp_csum_set(fs, mmp_s); + if (retval) + return retval; + + /* I was tempted to make this use O_DIRECT and the mmp_fd, but + * this caused no end of grief, while leaving it as-is works. */ + retval = io_channel_write_blk64(fs->io, mmp_blk, -(int)sizeof(struct mmp_struct), buf); + +#ifdef WORDS_BIGENDIAN + ext2fs_swap_mmp(mmp_s); +#endif + + /* Make sure the block gets to disk quickly */ + io_channel_flush(fs->io); + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#ifdef HAVE_SRANDOM +#define srand(x) srandom(x) +#define rand() random() +#endif + +unsigned ext2fs_mmp_new_seq(void) +{ +#ifdef CONFIG_MMP + unsigned new_seq; + struct timeval tv; + + gettimeofday(&tv, 0); + srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); + + gettimeofday(&tv, 0); + /* Crank the random number generator a few times */ + for (new_seq = (tv.tv_sec ^ tv.tv_usec) & 0x1F; new_seq > 0; new_seq--) + rand(); + + do { + new_seq = rand(); + } while (new_seq > EXT4_MMP_SEQ_MAX); + + return new_seq; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#ifdef CONFIG_MMP +static errcode_t ext2fs_mmp_reset(ext2_filsys fs) +{ + struct mmp_struct *mmp_s = NULL; + errcode_t retval = 0; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto out; + } + + memset(fs->mmp_buf, 0, fs->blocksize); + mmp_s = fs->mmp_buf; + + mmp_s->mmp_magic = EXT4_MMP_MAGIC; + mmp_s->mmp_seq = EXT4_MMP_SEQ_CLEAN; + mmp_s->mmp_time = 0; +#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 + gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename)); +#else + mmp_s->mmp_nodename[0] = '\0'; +#endif + strncpy(mmp_s->mmp_bdevname, fs->device_name, + sizeof(mmp_s->mmp_bdevname)); + + mmp_s->mmp_check_interval = fs->super->s_mmp_update_interval; + if (mmp_s->mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) + mmp_s->mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; + + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); +out: + return retval; +} +#endif + +errcode_t ext2fs_mmp_update(ext2_filsys fs) +{ + return ext2fs_mmp_update2(fs, 0); +} + +errcode_t ext2fs_mmp_clear(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + errcode_t retval = 0; + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + retval = ext2fs_mmp_reset(fs); + + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +errcode_t ext2fs_mmp_init(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct ext2_super_block *sb = fs->super; + blk64_t mmp_block; + errcode_t retval; + + if (sb->s_mmp_update_interval == 0) + sb->s_mmp_update_interval = EXT4_MMP_UPDATE_INTERVAL; + /* This is probably excessively large, but who knows? */ + else if (sb->s_mmp_update_interval > EXT4_MMP_MAX_UPDATE_INTERVAL) + return EXT2_ET_INVALID_ARGUMENT; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto out; + } + + retval = ext2fs_alloc_block2(fs, 0, fs->mmp_buf, &mmp_block); + if (retval) + goto out; + + sb->s_mmp_block = mmp_block; + + retval = ext2fs_mmp_reset(fs); + if (retval) + goto out; + +out: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +/* + * Make sure that the fs is not mounted or being fsck'ed while opening the fs. + */ +errcode_t ext2fs_mmp_start(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp_s; + unsigned seq; + unsigned int mmp_check_interval; + errcode_t retval = 0; + + if (fs->mmp_buf == NULL) { + retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); + if (retval) + goto mmp_error; + } + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + mmp_s = fs->mmp_buf; + + mmp_check_interval = fs->super->s_mmp_update_interval; + if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) + mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; + + seq = mmp_s->mmp_seq; + if (seq == EXT4_MMP_SEQ_CLEAN) + goto clean_seq; + if (seq == EXT4_MMP_SEQ_FSCK) { + retval = EXT2_ET_MMP_FSCK_ON; + goto mmp_error; + } + + if (seq > EXT4_MMP_SEQ_FSCK) { + retval = EXT2_ET_MMP_UNKNOWN_SEQ; + goto mmp_error; + } + + /* + * If check_interval in MMP block is larger, use that instead of + * check_interval from the superblock. + */ + if (mmp_s->mmp_check_interval > mmp_check_interval) + mmp_check_interval = mmp_s->mmp_check_interval; + + sleep(2 * mmp_check_interval + 1); + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + if (seq != mmp_s->mmp_seq) { + retval = EXT2_ET_MMP_FAILED; + goto mmp_error; + } + +clean_seq: + if (!(fs->flags & EXT2_FLAG_RW)) + goto mmp_error; + + mmp_s->mmp_seq = seq = ext2fs_mmp_new_seq(); +#if _BSD_SOURCE || _XOPEN_SOURCE >= 500 + gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename)); +#else + strcpy(mmp_s->mmp_nodename, "unknown host"); +#endif + strncpy(mmp_s->mmp_bdevname, fs->device_name, + sizeof(mmp_s->mmp_bdevname)); + + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + sleep(2 * mmp_check_interval + 1); + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + if (seq != mmp_s->mmp_seq) { + retval = EXT2_ET_MMP_FAILED; + goto mmp_error; + } + + mmp_s->mmp_seq = EXT4_MMP_SEQ_FSCK; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + return 0; + +mmp_error: + return retval; +#else + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +/* + * Clear the MMP usage in the filesystem. If this function returns an + * error EXT2_ET_MMP_CHANGE_ABORT it means the filesystem was modified + * by some other process while in use, and changes should be dropped, or + * risk filesystem corruption. + */ +errcode_t ext2fs_mmp_stop(ext2_filsys fs) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp, *mmp_cmp; + errcode_t retval = 0; + + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + goto mmp_error; + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); + if (retval) + goto mmp_error; + + /* Check if the MMP block is not changed. */ + mmp = fs->mmp_buf; + mmp_cmp = fs->mmp_cmp; + if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) { + retval = EXT2_ET_MMP_CHANGE_ABORT; + goto mmp_error; + } + + mmp_cmp->mmp_seq = EXT4_MMP_SEQ_CLEAN; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_cmp); + +mmp_error: + if (fs->mmp_fd > 0) { + close(fs->mmp_fd); + fs->mmp_fd = -1; + } + + return retval; +#else + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} + +#define EXT2_MIN_MMP_UPDATE_INTERVAL 60 + +/* + * Update the on-disk mmp buffer, after checking that it hasn't been changed. + */ +errcode_t ext2fs_mmp_update2(ext2_filsys fs, int immediately) +{ +#ifdef CONFIG_MMP + struct mmp_struct *mmp, *mmp_cmp; + struct timeval tv; + errcode_t retval = 0; + + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + gettimeofday(&tv, 0); + if (!immediately && + tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL) + return 0; + + retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL); + if (retval) + goto mmp_error; + + mmp = fs->mmp_buf; + mmp_cmp = fs->mmp_cmp; + + if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) + return EXT2_ET_MMP_CHANGE_ABORT; + + mmp->mmp_time = tv.tv_sec; + mmp->mmp_seq = EXT4_MMP_SEQ_FSCK; + retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); + +mmp_error: + return retval; +#else + if (!ext2fs_has_feature_mmp(fs->super) || + !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) + return 0; + + return EXT2_ET_OP_NOT_SUPPORTED; +#endif +} +#ifndef _MSC_VER +#pragma GCC diagnostic pop +#endif diff --git a/src/ext2fs/newdir.c b/src/ext2fs/newdir.c new file mode 100644 index 00000000..7f472850 --- /dev/null +++ b/src/ext2fs/newdir.c @@ -0,0 +1,126 @@ +/* + * newdir.c --- create a new directory block + * + * Copyright (C) 1994, 1995 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef EXT2_FT_DIR +#define EXT2_FT_DIR 2 +#endif + +/* + * Create new directory block + */ +errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, + ext2_ino_t parent_ino, char **block) +{ + struct ext2_dir_entry *dir = NULL; + errcode_t retval; + char *buf; + int rec_len; + int filetype = 0; + struct ext2_dir_entry_tail *t; + int csum_size = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return retval; + memset(buf, 0, fs->blocksize); + dir = (struct ext2_dir_entry *) buf; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + retval = ext2fs_set_rec_len(fs, fs->blocksize - csum_size, dir); + if (retval) { + ext2fs_free_mem(&buf); + return retval; + } + + if (dir_ino) { + if (ext2fs_has_feature_filetype(fs->super)) + filetype = EXT2_FT_DIR; + /* + * Set up entry for '.' + */ + dir->inode = dir_ino; + ext2fs_dirent_set_name_len(dir, 1); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + rec_len = (fs->blocksize - csum_size) - EXT2_DIR_REC_LEN(1); + dir->rec_len = EXT2_DIR_REC_LEN(1); + + /* + * Set up entry for '..' + */ + dir = (struct ext2_dir_entry *) (buf + dir->rec_len); + retval = ext2fs_set_rec_len(fs, rec_len, dir); + if (retval) { + ext2fs_free_mem(&buf); + return retval; + } + dir->inode = parent_ino; + ext2fs_dirent_set_name_len(dir, 2); + ext2fs_dirent_set_file_type(dir, filetype); + dir->name[0] = '.'; + dir->name[1] = '.'; + + } + + if (csum_size) { + t = EXT2_DIRENT_TAIL(buf, fs->blocksize); + ext2fs_initialize_dirent_tail(fs, t); + } + *block = buf; + return 0; +} + +/* + * Create new directory on inline data + */ +errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, + ext2_ino_t dir_ino EXT2FS_ATTR((unused)), + ext2_ino_t parent_ino, __u32 *iblock) +{ + struct ext2_dir_entry *dir = NULL; + errcode_t retval; + int rec_len; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + iblock[0] = ext2fs_cpu_to_le32(parent_ino); + + dir = (struct ext2_dir_entry *)((char *)iblock + + EXT4_INLINE_DATA_DOTDOT_SIZE); + dir->inode = 0; + rec_len = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE; + retval = ext2fs_set_rec_len(fs, rec_len, dir); + if (retval) + goto errout; + +#ifdef WORDS_BIGENDIAN + retval = ext2fs_dirent_swab_out2(fs, (char *)dir, rec_len, 0); + if (retval) + goto errout; +#endif + +errout: + return retval; +} diff --git a/src/ext2fs/nt_io.c b/src/ext2fs/nt_io.c new file mode 100644 index 00000000..a6477c0e --- /dev/null +++ b/src/ext2fs/nt_io.c @@ -0,0 +1,831 @@ +/* + * nt_io.c --- This is the Nt I/O interface to the I/O manager. + * + * Implements a one-block write-through cache. + * + * Copyright (C) 1993, 1994, 1995 Theodore Ts'o. + * Copyright (C) 1998 Andrey Shedel + * Copyright (C) 2018-2019 Pete Batard + * + * %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 "config.h" +#include "ext2fs.h" +#include "rufus.h" +#include "msapi_utf8.h" + +extern char* NtStatusError(NTSTATUS Status); + +PF_TYPE_DECL(NTAPI, ULONG, RtlNtStatusToDosError, (NTSTATUS)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtOpenFile, (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtFlushBuffersFile, (HANDLE, PIO_STATUS_BLOCK)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtReadFile, (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtWriteFile, (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, PVOID, ULONG, PLARGE_INTEGER, PULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtDeviceIoControlFile, (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtFsControlFile, (HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtDelayExecution, (BOOLEAN, PLARGE_INTEGER)); + +// TODO: Sort out ASSERT and __attribute__(align) +#define ASSERT(x) + +#define ARGUMENT_PRESENT(ArgumentPointer) ((CHAR *)((ULONG_PTR)(ArgumentPointer)) != (CHAR *)(NULL)) + +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L) +#define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS)0xC0000010L) + +#define BooleanFlagOn(Flags, SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0))) + +#define EXT2_CHECK_MAGIC(struct, code) if ((struct)->magic != (code)) return (code) +#define EXT2_ET_MAGIC_NT_IO_CHANNEL 0x10ed + +// Private data block +typedef struct _NT_PRIVATE_DATA { + int magic; + HANDLE handle; + int flags; + char* buffer; + __u32 buffer_block_number; + ULONG buffer_size; + BOOLEAN read_only; + BOOLEAN written; +} NT_PRIVATE_DATA, *PNT_PRIVATE_DATA; + +// +// Standard interface prototypes +// + +static errcode_t nt_open(const char *name, int flags, io_channel *channel); +static errcode_t nt_close(io_channel channel); +static errcode_t nt_set_blksize(io_channel channel, int blksize); +static errcode_t nt_read_blk(io_channel channel, unsigned long block, int count, void *data); +static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *data); +static errcode_t nt_flush(io_channel channel); + +static struct struct_io_manager struct_nt_manager = { + .magic = EXT2_ET_MAGIC_IO_MANAGER, + .name = "NT I/O Manager", + .open = nt_open, + .close = nt_close, + .set_blksize = nt_set_blksize, + .read_blk = nt_read_blk, + .write_blk = nt_write_blk, + .flush = nt_flush +}; + +io_manager nt_io_manager(void) +{ + return &struct_nt_manager; +} + +// Convert Win32 errors to unix errno +typedef struct { + ULONG WinError; + int errnocode; +}ERROR_ENTRY; + +static ERROR_ENTRY ErrorTable[] = { + { ERROR_INVALID_FUNCTION, EINVAL }, + { ERROR_FILE_NOT_FOUND, ENOENT }, + { ERROR_PATH_NOT_FOUND, ENOENT }, + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, + { ERROR_ACCESS_DENIED, EACCES }, + { ERROR_INVALID_HANDLE, EBADF }, + { ERROR_ARENA_TRASHED, ENOMEM }, + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, + { ERROR_INVALID_BLOCK, ENOMEM }, + { ERROR_BAD_ENVIRONMENT, E2BIG }, + { ERROR_BAD_FORMAT, ENOEXEC }, + { ERROR_INVALID_ACCESS, EINVAL }, + { ERROR_INVALID_DATA, EINVAL }, + { ERROR_INVALID_DRIVE, ENOENT }, + { ERROR_CURRENT_DIRECTORY, EACCES }, + { ERROR_NOT_SAME_DEVICE, EXDEV }, + { ERROR_NO_MORE_FILES, ENOENT }, + { ERROR_LOCK_VIOLATION, EACCES }, + { ERROR_BAD_NETPATH, ENOENT }, + { ERROR_NETWORK_ACCESS_DENIED, EACCES }, + { ERROR_BAD_NET_NAME, ENOENT }, + { ERROR_FILE_EXISTS, EEXIST }, + { ERROR_CANNOT_MAKE, EACCES }, + { ERROR_FAIL_I24, EACCES }, + { ERROR_INVALID_PARAMETER, EINVAL }, + { ERROR_NO_PROC_SLOTS, EAGAIN }, + { ERROR_DRIVE_LOCKED, EACCES }, + { ERROR_BROKEN_PIPE, EPIPE }, + { ERROR_DISK_FULL, ENOSPC }, + { ERROR_INVALID_TARGET_HANDLE, EBADF }, + { ERROR_INVALID_HANDLE, EINVAL }, + { ERROR_WAIT_NO_CHILDREN, ECHILD }, + { ERROR_CHILD_NOT_COMPLETE, ECHILD }, + { ERROR_DIRECT_ACCESS_HANDLE, EBADF }, + { ERROR_NEGATIVE_SEEK, EINVAL }, + { ERROR_SEEK_ON_DEVICE, EACCES }, + { ERROR_DIR_NOT_EMPTY, ENOTEMPTY }, + { ERROR_NOT_LOCKED, EACCES }, + { ERROR_BAD_PATHNAME, ENOENT }, + { ERROR_MAX_THRDS_REACHED, EAGAIN }, + { ERROR_LOCK_FAILED, EACCES }, + { ERROR_ALREADY_EXISTS, EEXIST }, + { ERROR_FILENAME_EXCED_RANGE, ENOENT }, + { ERROR_NESTING_NOT_ALLOWED, EAGAIN }, + { ERROR_NOT_ENOUGH_QUOTA, ENOMEM } +}; + +static unsigned _MapDosError (IN ULONG WinError) +{ + int i; + + for (i = 0; i < (sizeof(ErrorTable)/sizeof(ErrorTable[0])); ++i) { + if (WinError == ErrorTable[i].WinError) { + return ErrorTable[i].errnocode; + } + } + + // Not in table. Check ranges + if ((WinError >= ERROR_WRITE_PROTECT) && (WinError <= ERROR_SHARING_BUFFER_EXCEEDED)) + return EACCES; + else if ((WinError >= ERROR_INVALID_STARTING_CODESEG) && (WinError <= ERROR_INFLOOP_IN_RELOC_CHAIN)) + return ENOEXEC; + else + return EINVAL; +} + + +// Map NT status to dos error. +static __inline unsigned _MapNtStatus(IN NTSTATUS Status) +{ + PF_INIT(RtlNtStatusToDosError, Ntdll); + return (pfRtlNtStatusToDosError == NULL) ? EFAULT: _MapDosError(pfRtlNtStatusToDosError(Status)); +} + +// +// Helper functions +// +static NTSTATUS _OpenNtName(IN PCSTR Name, IN BOOLEAN Readonly, OUT PHANDLE Handle, OUT PBOOLEAN OpenedReadonly OPTIONAL) +{ +// ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + WCHAR Buffer[512]; + NTSTATUS Status = EFAULT; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtDelayExecution, Ntdll); + PF_INIT_OR_OUT(NtOpenFile, Ntdll); + + utf8_to_wchar_no_alloc(Name, Buffer, ARRAYSIZE(Buffer)); + // Make Unicode name from input string + UnicodeString.Buffer = Buffer; + UnicodeString.Length = (USHORT) wcslen(Buffer) * 2; + UnicodeString.MaximumLength = sizeof(Buffer); // in bytes!!! + + // Initialize object + InitializeObjectAttributes(&ObjectAttributes, &UnicodeString, OBJ_CASE_INSENSITIVE, NULL, NULL ); + + // Try to open it in initial mode + if (ARGUMENT_PRESENT(OpenedReadonly)) + *OpenedReadonly = Readonly; + + Status = pfNtOpenFile(Handle, SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA), + &ObjectAttributes, &IoStatusBlock, FILE_SHARE_WRITE | FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS(Status)) { + uprintf("_OpenNtName: [%x] %s", Status, NtStatusError(Status)); + // Maybe was just mounted? wait 0.5 sec and retry. + LARGE_INTEGER Interval; + Interval.QuadPart = -5000000; // 0.5 sec. from now + if (pfNtDelayExecution != NULL) + pfNtDelayExecution(FALSE, &Interval); + else + Sleep(500); + + Status = pfNtOpenFile(Handle, SYNCHRONIZE | FILE_READ_DATA | (Readonly ? 0 : FILE_WRITE_DATA), + &ObjectAttributes, &IoStatusBlock, FILE_SHARE_WRITE | FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); + + // Try to satisfy mode + if ((Status == STATUS_ACCESS_DENIED) && !Readonly) { + if (ARGUMENT_PRESENT(OpenedReadonly)) + *OpenedReadonly = TRUE; + + Status = pfNtOpenFile(Handle, SYNCHRONIZE | FILE_READ_DATA, &ObjectAttributes, + &IoStatusBlock, FILE_SHARE_WRITE | FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); + } + } + +out: + return Status; +} + +static NTSTATUS _OpenDriveLetter(IN CHAR Letter, IN BOOLEAN ReadOnly, OUT PHANDLE Handle, OUT PBOOLEAN OpenedReadonly OPTIONAL) +{ + CHAR Buffer[100]; + sprintf(Buffer, "\\DosDevices\\%c:", Letter); + return _OpenNtName(Buffer, ReadOnly, Handle, OpenedReadonly); +} + +static __inline NTSTATUS _FlushDrive(IN HANDLE Handle) +{ + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtFlushBuffersFile, NtDll); + return (pfNtFlushBuffersFile == NULL) ? STATUS_DLL_NOT_FOUND : pfNtFlushBuffersFile(Handle, &IoStatusBlock); +} + + +static __inline NTSTATUS _LockDrive(IN HANDLE Handle) +{ + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtFsControlFile, NtDll); + return (pfNtFsControlFile == NULL) ? STATUS_DLL_NOT_FOUND : pfNtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_LOCK_VOLUME, 0, 0, 0, 0); +} + + +static __inline NTSTATUS _UnlockDrive(IN HANDLE Handle) +{ + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtFsControlFile, NtDll); + return (pfNtFsControlFile == NULL) ? STATUS_DLL_NOT_FOUND : pfNtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_UNLOCK_VOLUME, 0, 0, 0, 0); +} + +static __inline NTSTATUS _DismountDrive(IN HANDLE Handle) +{ + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtFsControlFile, NtDll); + return (pfNtFsControlFile == NULL) ? STATUS_DLL_NOT_FOUND : pfNtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0); +} + +static __inline BOOLEAN _IsMounted(IN HANDLE Handle) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status = STATUS_DLL_NOT_FOUND; + PF_INIT(NtFsControlFile, NtDll); + if (pfNtFsControlFile != NULL) + pfNtFsControlFile(Handle, 0, 0, 0, &IoStatusBlock, FSCTL_IS_VOLUME_MOUNTED, 0, 0, 0, 0); + return (BOOLEAN)(Status == STATUS_SUCCESS); +} + +static __inline NTSTATUS _CloseDisk(IN HANDLE Handle) +{ + PF_INIT(NtClose, Ntdll); + return (pfNtClose == NULL) ? STATUS_DLL_NOT_FOUND : pfNtClose(Handle); +} + +// +// Make NT name from any recognized name +// + +static PCSTR _NormalizeDeviceName(IN PCSTR Device, IN PSTR NormalizedDeviceNameBuffer) +{ + int PartitionNumber = -1; + UCHAR DiskNumber; + PSTR p; + + // Convert non NT paths to NT + if (Device[0] == '\\') { + if ((strlen(Device) < 4) || (Device[3] != '\\')) + return Device; + strcpy(NormalizedDeviceNameBuffer, Device); + if ((NormalizedDeviceNameBuffer[1] == '\\') || (NormalizedDeviceNameBuffer[1] == '.')) + NormalizedDeviceNameBuffer[1] = '?'; + if (NormalizedDeviceNameBuffer[2] == '.') + NormalizedDeviceNameBuffer[2] = '?'; + return NormalizedDeviceNameBuffer; + } + + // For now, don't allow the conversion of non absolute paths. + // Too easy to get a C:\ drive altered on a mishap otherwise... + return NULL; + + // Strip leading '/dev/' if any + if ((Device[0] == '/') && + (Device[1] == 'd') && + (Device[2] == 'e') && + (Device[3] == 'v') && + (Device[4] == '/')) { + Device = &Device[5]; + } + + if (Device[0] == '\0') { + return NULL; + } + + // forms: hda[n], sda[n], fd[n] + if (Device[1] != 'd') { + return NULL; + } + + if ((Device[0] == 'h') || (Device[0] == 's')) { + if ((Device[2] < 'a') || (Device[2] > ('a' + 9)) || + ((Device[3] != '\0') && + ((Device[4] != '\0') || + ((Device[3] < '0') || (Device[3] > '9')) + ) + ) + ) { + return NULL; + } + + DiskNumber = (UCHAR)(Device[2] - 'a'); + + if(Device[3] != '\0') { + PartitionNumber = (*(Device + 3) - '0'); + } + } else if (Device[0] == 'f') { + // 3-d letter should be a digit. + if ((Device[3] != '\0') || + (Device[2] < '0') || (Device[2] > '9')) { + return NULL; + } + + DiskNumber = (UCHAR)(*(Device + 2) - '0'); + } else { + // invalid prefix + return NULL; + } + + + // Prefix + strcpy(NormalizedDeviceNameBuffer, "\\Device\\"); + + // Media name + switch(*Device) { + case 'f': + strcat(NormalizedDeviceNameBuffer, "Floppy0"); + break; + case 'h': + strcat(NormalizedDeviceNameBuffer, "Harddisk0"); + break; + } + + p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1; + p[0] = (CHAR)(p[0] + DiskNumber); + + // Partition nr. + if (PartitionNumber >= 0) { + strcat(NormalizedDeviceNameBuffer, "\\Partition0"); + + p = NormalizedDeviceNameBuffer + strlen(NormalizedDeviceNameBuffer) - 1; + p[0] = (CHAR)(p[0] + PartitionNumber); + } + + return NormalizedDeviceNameBuffer; +} + + +static VOID _GetDeviceSize(IN HANDLE h, OUT unsigned __int64 *FsSize) +{ + PARTITION_INFORMATION_EX pi; + DISK_GEOMETRY_EX gi; + NTSTATUS Status; + IO_STATUS_BLOCK IoStatusBlock; + LARGE_INTEGER li; + + *FsSize = 0; + PF_INIT(NtDeviceIoControlFile, NtDll); + if (pfNtDeviceIoControlFile == NULL) + return; + + RtlZeroMemory(&pi, sizeof(pi)); + Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock, + IOCTL_DISK_GET_PARTITION_INFO_EX, + &pi, sizeof(pi), &pi, sizeof(pi)); + if (NT_SUCCESS(Status)) { + uprintf("Size retrieved with: IOCTL_DISK_GET_PARTITION_INFO_EX"); + *FsSize = pi.PartitionLength.QuadPart; + } else if (Status == STATUS_INVALID_DEVICE_REQUEST) { + // No partitions: Try a drive geometry request + uprintf("IOCTL_DISK_GET_PARTITION_INFO_EX failed, trying with IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); + RtlZeroMemory(&gi, sizeof(gi)); + + Status = pfNtDeviceIoControlFile(h, NULL, NULL, NULL, &IoStatusBlock, + IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, + &gi, sizeof(gi), &gi, sizeof(gi)); + + if (NT_SUCCESS(Status)) { + uprintf("Size retrieved with: IOCTL_DISK_GET_DRIVE_GEOMETRY_EX"); + *FsSize = gi.DiskSize.QuadPart; + } else { + uprintf("IOCTL_DISK_GET_DRIVE_GEOMETRY_EX: [%x] %s", Status, NtStatusError(Status)); + } + } else if (Status == STATUS_INVALID_PARAMETER) { + // Possibly a straight image file + if (GetFileSizeEx(h, &li)) + *FsSize = li.QuadPart; + } +} + +static BOOLEAN _Ext2OpenDevice(IN PCSTR Name, IN BOOLEAN ReadOnly, OUT PHANDLE Handle, OUT PBOOLEAN OpenedReadonly OPTIONAL, OUT errcode_t *Errno OPTIONAL) +{ + CHAR NormalizedDeviceName[512]; + NTSTATUS Status; + + if (Name == NULL) { + if (ARGUMENT_PRESENT(Errno)) + *Errno = ENOENT; + return FALSE; + } + + if ((((*Name) | 0x20) >= 'a') && (((*Name) | 0x20) <= 'z') && + (':' == *(Name + 1)) && ('\0' == *(Name + 2))) { + Status = _OpenDriveLetter(*Name, ReadOnly, Handle, OpenedReadonly); + } else { + Name = _NormalizeDeviceName(Name, NormalizedDeviceName); + if (Name == NULL) { + if (ARGUMENT_PRESENT(Errno)) + *Errno = ENOENT; + return FALSE; + } + + Status = _OpenNtName(Name, ReadOnly, Handle, OpenedReadonly); + } + + if (!NT_SUCCESS(Status)) { + if (ARGUMENT_PRESENT(Errno)) + *Errno = _MapNtStatus(Status); + return FALSE; + } + + return TRUE; +} + +static BOOLEAN _BlockIo(IN HANDLE Handle, IN LARGE_INTEGER Offset, IN ULONG Bytes, IN OUT PCHAR Buffer, IN BOOLEAN Read, OUT unsigned* Errno) +{ + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status = STATUS_DLL_NOT_FOUND; + PF_INIT_OR_OUT(NtReadFile, NtDll); + PF_INIT_OR_OUT(NtWriteFile, NtDll); + + // Should be aligned + ASSERT(0 == (Bytes % 512)); + ASSERT(0 == (Offset.LowPart % 512)); + + // Perform io + if(Read) { + Status = pfNtReadFile(Handle, NULL, NULL, NULL, + &IoStatusBlock, Buffer, Bytes, &Offset, NULL); + } else { + Status = pfNtWriteFile(Handle, NULL, NULL, NULL, + &IoStatusBlock, Buffer, Bytes, &Offset, NULL); + } + +out: + if (NT_SUCCESS(Status)) { + *Errno = 0; + return TRUE; + } + + *Errno = _MapNtStatus(Status); + + return FALSE; +} + + + +static BOOLEAN _RawWrite(IN HANDLE Handle, IN LARGE_INTEGER Offset, IN ULONG Bytes, OUT const CHAR* Buffer, OUT unsigned* Errno) +{ + return _BlockIo(Handle, Offset, Bytes, (PCHAR)Buffer, FALSE, Errno); +} + +static BOOLEAN _RawRead(IN HANDLE Handle, IN LARGE_INTEGER Offset, IN ULONG Bytes, IN PCHAR Buffer, OUT unsigned* Errno) +{ + return _BlockIo(Handle, Offset, Bytes, Buffer, TRUE, Errno); +} + +static BOOLEAN _SetPartType(IN HANDLE Handle, IN UCHAR Type) +{ + IO_STATUS_BLOCK IoStatusBlock; + PF_INIT(NtDeviceIoControlFile, NtDll); + if (pfNtDeviceIoControlFile == NULL) + return FALSE; + return NT_SUCCESS(pfNtDeviceIoControlFile(Handle, NULL, NULL, NULL, &IoStatusBlock, + IOCTL_DISK_SET_PARTITION_INFO, &Type, + sizeof(Type), NULL, 0)); +} + + +// +// Interface functions. +// Is_mounted is set to 1 if the device is mounted, 0 otherwise +// + +errcode_t +ext2fs_check_if_mounted(const char *file, int *mount_flags) +{ + HANDLE h; + BOOLEAN Readonly; + + *mount_flags = 0; + + if (!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL)) + return 0; + + *mount_flags &= _IsMounted(h) ? EXT2_MF_MOUNTED : 0; + _CloseDisk(h); + + return 0; +} + + + +// Returns the number of blocks in a partition +// Note: Do *NOT* be tempted to cache the device size according to the NT path as +// different removable devices (e.g. UFD) may be remounted under the same path. +errcode_t ext2fs_get_device_size(const char *file, int blocksize, blk64_t *retblocks) +{ + __int64 fs_size = 0; + HANDLE h; + BOOLEAN Readonly; + + if (!_Ext2OpenDevice(file, TRUE, &h, &Readonly, NULL)) { + uprintf("FAILED TO OPEN '%s'", file); + return EACCES; + } + + _GetDeviceSize(h, &fs_size); + _CloseDisk(h); + + *retblocks = (blk64_t)(fs_size / blocksize); + return 0; +} + + +// +// Table elements +// + +static errcode_t nt_open(const char *name, int flags, io_channel *channel) +{ + io_channel io = NULL; + PNT_PRIVATE_DATA nt_data = NULL; + errcode_t errcode = 0; + + if (name == NULL) + return EXT2_ET_BAD_DEVICE_NAME; + + // Allocate channel handle + io = (io_channel) malloc(sizeof(struct struct_io_channel)); + if (io == NULL) { + errcode = ENOMEM; + goto out; + } + + RtlZeroMemory(io, sizeof(struct struct_io_channel)); + io->magic = EXT2_ET_MAGIC_IO_CHANNEL; + + nt_data = (PNT_PRIVATE_DATA) malloc(sizeof(NT_PRIVATE_DATA)); + if (nt_data == NULL) { + errcode = ENOMEM; + goto out; + } + + io->manager = nt_io_manager(); + io->name = malloc(strlen(name) + 1); + if (io->name == NULL) { + errcode = ENOMEM; + goto out; + } + + strcpy(io->name, name); + io->private_data = nt_data; + io->block_size = 1024; + io->read_error = 0; + io->write_error = 0; + io->refcount = 1; + + // Initialize data + RtlZeroMemory(nt_data, sizeof(NT_PRIVATE_DATA)); + + nt_data->magic = EXT2_ET_MAGIC_NT_IO_CHANNEL; + nt_data->buffer_block_number = 0xffffffff; + nt_data->buffer_size = 1024; + nt_data->buffer = malloc(nt_data->buffer_size); + if (nt_data->buffer == NULL) { + errcode = ENOMEM; + goto out; + } + + // Open the device + if (!_Ext2OpenDevice(name, (BOOLEAN)!BooleanFlagOn(flags, EXT2_FLAG_RW), &nt_data->handle, &nt_data->read_only, &errcode)) + goto out; + + // Get the size +// _GetDeviceSize(nt_data->handle, &fs_size); +// strcpy(known_device, name); + + + // Lock/dismount +// if (!NT_SUCCESS(_LockDrive(nt_data->handle)) /*|| !NT_SUCCESS(_DismountDrive(NtData->Handle))*/) +// nt_data->read_only = TRUE; + + // Done + *channel = io; + +out: + if (errcode) { + if (io != NULL) { + free(io->name); + free(io); + } + + if (nt_data != NULL) { + if (nt_data->handle != NULL) { + _UnlockDrive(nt_data->handle); + _CloseDisk(nt_data->handle); + } + free(nt_data->buffer); + free(nt_data); + } + } + + return errcode; +} + +static errcode_t nt_close(io_channel channel) +{ + PNT_PRIVATE_DATA nt_data = NULL; + + if (channel == NULL) + return 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + nt_data = (PNT_PRIVATE_DATA) channel->private_data; + EXT2_CHECK_MAGIC(nt_data, EXT2_ET_MAGIC_NT_IO_CHANNEL); + + if (--channel->refcount > 0) + return 0; + + free(channel->name); + free(channel); + + if (nt_data != NULL) { + if (nt_data->handle != NULL) + CloseHandle(nt_data->handle); + free(nt_data->buffer); + free(nt_data); + } + + return 0; +} + +static errcode_t nt_set_blksize(io_channel channel, int blksize) +{ + PNT_PRIVATE_DATA nt_data = NULL; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + nt_data = (PNT_PRIVATE_DATA) channel->private_data; + EXT2_CHECK_MAGIC(nt_data, EXT2_ET_MAGIC_NT_IO_CHANNEL); + + if (channel->block_size != blksize) { + channel->block_size = blksize; + + free(nt_data->buffer); + nt_data->buffer_block_number = 0xffffffff; + nt_data->buffer_size = channel->block_size; + ASSERT(0 == (nt_data->BufferSize % 512)); + + nt_data->buffer = malloc(nt_data->buffer_size); + if (nt_data->buffer == NULL) + return ENOMEM; + } + + return 0; +} + +static errcode_t nt_read_blk(io_channel channel, unsigned long block, int count, void *buf) +{ + PVOID read_buffer; + ULONG read_size; + ULONG size; + LARGE_INTEGER offset; + PNT_PRIVATE_DATA nt_data = NULL; + unsigned errcode = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + nt_data = (PNT_PRIVATE_DATA) channel->private_data; + EXT2_CHECK_MAGIC(nt_data, EXT2_ET_MAGIC_NT_IO_CHANNEL); + + // If it's in the cache, use it! + if ((count == 1) && (block == nt_data->buffer_block_number) && + (nt_data->buffer_block_number != 0xffffffff)) { + memcpy(buf, nt_data->buffer, channel->block_size); + return 0; + } + + size = (count < 0) ? (ULONG)(-count) : (ULONG)(count * channel->block_size); + + offset.QuadPart = block * channel->block_size; + + // If not fit to the block + if (size <= nt_data->buffer_size) { + // Update the cache + nt_data->buffer_block_number = block; + read_buffer = nt_data->buffer; + read_size = nt_data->buffer_size; + } else { + read_size = size; + read_buffer = buf; + ASSERT((read_size % channel->block_size) == 0); + } + + if (!_RawRead(nt_data->handle, offset, read_size, read_buffer, &errcode)) { + if (channel->read_error) + return (channel->read_error)(channel, block, count, buf, size, 0, errcode); + else + return errcode; + } + + if (read_buffer != buf) { + ASSERT(size <= read_size); + memcpy(buf, read_buffer, size); + } + + return 0; +} + +// TODO: Add an nt_write_blk64() +static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count, const void *buf) +{ + ULONG write_size; + LARGE_INTEGER offset; + PNT_PRIVATE_DATA nt_data = NULL; + unsigned errcode = 0; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + nt_data = (PNT_PRIVATE_DATA) channel->private_data; + EXT2_CHECK_MAGIC(nt_data, EXT2_ET_MAGIC_NT_IO_CHANNEL); + + if (nt_data->read_only) + return EACCES; + + if (count == 1) { + write_size = channel->block_size; + } else { + nt_data->buffer_block_number = 0xffffffff; + if (count < 0) + write_size = (ULONG)(-count); + else + write_size = (ULONG)(count * channel->block_size); + } + + + ASSERT(0 == (write_size % 512)); + offset.QuadPart = block * channel->block_size; + + if (!_RawWrite(nt_data->handle, offset, write_size, buf, &errcode)) { + if (channel->write_error) + return (channel->write_error)(channel, block, count, buf, write_size, 0, errcode); + else + return errcode; + } + + + // Stash a copy. + if(write_size >= nt_data->buffer_size) { + nt_data->buffer_block_number = block; + memcpy(nt_data->buffer, buf, nt_data->buffer_size); + } + + nt_data->written = TRUE; + + return 0; +} + +static errcode_t nt_flush(io_channel channel) +{ + PNT_PRIVATE_DATA nt_data = NULL; + + EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL); + nt_data = (PNT_PRIVATE_DATA) channel->private_data; + EXT2_CHECK_MAGIC(nt_data, EXT2_ET_MAGIC_NT_IO_CHANNEL); + + if(nt_data->read_only) + return 0; + + + // Flush file buffers. + _FlushDrive(nt_data->handle); + + + // Test and correct partition type. + if (nt_data->written) + _SetPartType(nt_data->handle, 0x83); + + return 0; +} diff --git a/src/ext2fs/punch.c b/src/ext2fs/punch.c new file mode 100644 index 00000000..e843bdfb --- /dev/null +++ b/src/ext2fs/punch.c @@ -0,0 +1,509 @@ +/* + * punch.c --- deallocate blocks allocated to an inode + * + * Copyright (C) 2010 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#undef PUNCH_DEBUG + +/* + * This function returns 1 if the specified block is all zeros + */ +static int check_zero_block(char *buf, int blocksize) +{ + char *cp = buf; + int left = blocksize; + + while (left > 0) { + if (*cp++) + return 0; + left--; + } + return 1; +} + +/* + * This clever recursive function handles i_blocks[] as well as + * indirect, double indirect, and triple indirect blocks. It iterates + * over the entries in the i_blocks array or indirect blocks, and for + * each one, will recursively handle any indirect blocks and then + * frees and deallocates the blocks. + */ +static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, + char *block_buf, blk_t *p, int level, + blk64_t start, blk64_t count, int max) +{ + errcode_t retval; + blk_t b; + int i; + blk64_t offset, incr; + int freed = 0; + +#ifdef PUNCH_DEBUG + printf("Entering ind_punch, level %d, start %llu, count %llu, " + "max %d\n", level, start, count, max); +#endif + incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super) - 2) * level); + for (i = 0, offset = 0; i < max; i++, p++, offset += incr) { + if (offset >= start + count) + break; + if (*p == 0 || (offset+incr) <= start) + continue; + b = *p; + if (level > 0) { + blk_t start2; +#ifdef PUNCH_DEBUG + printf("Reading indirect block %u\n", b); +#endif + retval = ext2fs_read_ind_block(fs, b, block_buf); + if (retval) + return retval; + start2 = (start > offset) ? start - offset : 0; + retval = ind_punch(fs, inode, block_buf + fs->blocksize, + (blk_t *) block_buf, level - 1, + start2, count - offset, + fs->blocksize >> 2); + if (retval) + return retval; + retval = ext2fs_write_ind_block(fs, b, block_buf); + if (retval) + return retval; + if (!check_zero_block(block_buf, fs->blocksize)) + continue; + } +#ifdef PUNCH_DEBUG + printf("Freeing block %u (offset %llu)\n", b, offset); +#endif + ext2fs_block_alloc_stats(fs, b, -1); + *p = 0; + freed++; + } +#ifdef PUNCH_DEBUG + printf("Freed %d blocks\n", freed); +#endif + return ext2fs_iblk_sub_blocks(fs, inode, freed); +} + +#define BLK_T_MAX ((blk_t)~0ULL) +static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode, + char *block_buf, blk64_t start, blk64_t end) +{ + errcode_t retval; + char *buf = 0; + int level; + int num = EXT2_NDIR_BLOCKS; + blk_t *bp = inode->i_block; + blk_t addr_per_block; + blk64_t max = EXT2_NDIR_BLOCKS; + blk_t count; + + /* Check start/end don't overflow the 2^32-1 indirect block limit */ + if (start > BLK_T_MAX) + return 0; + if (end >= BLK_T_MAX || end - start + 1 >= BLK_T_MAX) + count = BLK_T_MAX - start; + else + count = end - start + 1; + + if (!block_buf) { + retval = ext2fs_get_array(3, fs->blocksize, &buf); + if (retval) + return retval; + block_buf = buf; + } + + addr_per_block = (blk_t)fs->blocksize >> 2; + + for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) { +#ifdef PUNCH_DEBUG + printf("Main loop level %d, start %llu count %u " + "max %llu num %d\n", level, start, count, max, num); +#endif + if (start < max) { + retval = ind_punch(fs, inode, block_buf, bp, level, + start, count, num); + if (retval) + goto errout; + if (count > max) + count -= max - start; + else + break; + start = 0; + } else + start -= max; + bp += num; + if (level == 0) { + num = 1; + max = 1; + } + } + retval = 0; +errout: + if (buf) + ext2fs_free_mem(&buf); + return retval; +} +#undef BLK_T_MAX + +#ifdef PUNCH_DEBUG + +#define dbg_printf(f, a...) printf(f, ## a) + +static void dbg_print_extent(char *desc, struct ext2fs_extent *extent) +{ + if (desc) + printf("%s: ", desc); + printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ", + extent->e_lblk, extent->e_lblk + extent->e_len - 1, + extent->e_len, extent->e_pblk); + if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF) + fputs("LEAF ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT) + fputs("UNINIT ", stdout); + if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) + fputs("2ND_VISIT ", stdout); + if (!extent->e_flags) + fputs("(none)", stdout); + fputc('\n', stdout); + +} +#else +#define dbg_print_extent(desc, ex) do { } while (0) +#define dbg_printf(f, ...) do { } while (0) +#endif + +/* Free a range of blocks, respecting cluster boundaries */ +static errcode_t punch_extent_blocks(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t lfree_start, blk64_t free_start, + __u32 free_count, int *freed) +{ + blk64_t pblk; + int freed_now = 0; + __u32 cluster_freed; + errcode_t retval = 0; + + /* No bigalloc? Just free each block. */ + if (EXT2FS_CLUSTER_RATIO(fs) == 1) { + *freed += free_count; + while (free_count-- > 0) + ext2fs_block_alloc_stats2(fs, free_start++, -1); + return retval; + } + + /* + * Try to free up to the next cluster boundary. We assume that all + * blocks in a logical cluster map to blocks from the same physical + * cluster, and that the offsets within the [pl]clusters match. + */ + if (free_start & EXT2FS_CLUSTER_MASK(fs)) { + retval = ext2fs_map_cluster_block(fs, ino, inode, + lfree_start, &pblk); + if (retval) + goto errout; + if (!pblk) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + } + cluster_freed = EXT2FS_CLUSTER_RATIO(fs) - + (free_start & EXT2FS_CLUSTER_MASK(fs)); + if (cluster_freed > free_count) + cluster_freed = free_count; + free_count -= cluster_freed; + free_start += cluster_freed; + lfree_start += cluster_freed; + } + + /* Free whole clusters from the middle of the range. */ + while (free_count > 0 && free_count >= (unsigned) EXT2FS_CLUSTER_RATIO(fs)) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + cluster_freed = EXT2FS_CLUSTER_RATIO(fs); + free_count -= cluster_freed; + free_start += cluster_freed; + lfree_start += cluster_freed; + } + + /* Try to free the last cluster. */ + if (free_count > 0) { + retval = ext2fs_map_cluster_block(fs, ino, inode, + lfree_start, &pblk); + if (retval) + goto errout; + if (!pblk) { + ext2fs_block_alloc_stats2(fs, free_start, -1); + freed_now++; + } + } + +errout: + *freed += freed_now; + return retval; +} + +static errcode_t ext2fs_punch_extent(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t start, blk64_t end) +{ + ext2_extent_handle_t handle = 0; + struct ext2fs_extent extent; + errcode_t retval; + blk64_t free_start, next, lfree_start; + __u32 free_count, newlen; + int freed = 0; + int op; + + retval = ext2fs_extent_open2(fs, ino, inode, &handle); + if (retval) + return retval; + /* + * Find the extent closest to the start of the punch range. We don't + * check the return value because _goto() sets the current node to the + * next-lowest extent if 'start' is in a hole, and doesn't set a + * current node if there was a real error reading the extent tree. + * In that case, _get() will error out. + * + * Note: If _get() returns 'no current node', that simply means that + * there aren't any blocks mapped past this point in the file, so we're + * done. + */ + ext2fs_extent_goto(handle, start); + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent); + if (retval == EXT2_ET_NO_CURRENT_NODE) { + retval = 0; + goto errout; + } else if (retval) + goto errout; + while (1) { + op = EXT2_EXTENT_NEXT_LEAF; + dbg_print_extent("main loop", &extent); + next = extent.e_lblk + extent.e_len; + dbg_printf("start %llu, end %llu, next %llu\n", + (unsigned long long) start, + (unsigned long long) end, + (unsigned long long) next); + if (start <= extent.e_lblk) { + /* + * Have we iterated past the end of the punch region? + * If so, we can stop. + */ + if (end < extent.e_lblk) + break; + dbg_printf("Case #%d\n", 1); + /* Start of deleted region before extent; + adjust beginning of extent */ + free_start = extent.e_pblk; + lfree_start = extent.e_lblk; + if (next > end) + free_count = end - extent.e_lblk + 1; + else + free_count = extent.e_len; + extent.e_len -= free_count; + extent.e_lblk += free_count; + extent.e_pblk += free_count; + } else if (end >= next-1) { + /* + * Is the punch region beyond this extent? This can + * happen if start is already inside a hole. Try to + * advance to the next extent if this is the case. + */ + if (start >= next) + goto next_extent; + /* End of deleted region after extent; + adjust end of extent */ + dbg_printf("Case #%d\n", 2); + newlen = start - extent.e_lblk; + free_start = extent.e_pblk + newlen; + lfree_start = extent.e_lblk + newlen; + free_count = extent.e_len - newlen; + extent.e_len = newlen; + } else { + struct ext2fs_extent newex; + + dbg_printf("Case #%d\n", 3); + /* The hard case; we need to split the extent */ + newex.e_pblk = extent.e_pblk + + (end + 1 - extent.e_lblk); + newex.e_lblk = end + 1; + newex.e_len = next - end - 1; + newex.e_flags = extent.e_flags; + + extent.e_len = start - extent.e_lblk; + free_start = extent.e_pblk + extent.e_len; + lfree_start = extent.e_lblk + extent.e_len; + free_count = end - start + 1; + + dbg_print_extent("inserting", &newex); + retval = ext2fs_extent_insert(handle, + EXT2_EXTENT_INSERT_AFTER, &newex); + if (retval) + goto errout; + retval = ext2fs_extent_fix_parents(handle); + if (retval) + goto errout; + /* + * Now pointing at inserted extent; so go back. + * + * We cannot use EXT2_EXTENT_PREV to go back; note the + * subtlety in the comment for fix_parents(). + */ + retval = ext2fs_extent_goto(handle, extent.e_lblk); + if (retval) + goto errout; + } + if (extent.e_len) { + dbg_print_extent("replacing", &extent); + retval = ext2fs_extent_replace(handle, 0, &extent); + if (retval) + goto errout; + retval = ext2fs_extent_fix_parents(handle); + } else { + struct ext2fs_extent newex; + blk64_t old_lblk, next_lblk; + dbg_printf("deleting current extent%s\n", ""); + + /* + * Save the location of the next leaf, then slip + * back to the current extent. + */ + retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, + &newex); + if (retval) + goto errout; + old_lblk = newex.e_lblk; + + retval = ext2fs_extent_get(handle, + EXT2_EXTENT_NEXT_LEAF, + &newex); + if (retval == EXT2_ET_EXTENT_NO_NEXT) + next_lblk = old_lblk; + else if (retval) + goto errout; + else + next_lblk = newex.e_lblk; + + retval = ext2fs_extent_goto(handle, old_lblk); + if (retval) + goto errout; + + /* Now delete the extent. */ + retval = ext2fs_extent_delete(handle, 0); + if (retval) + goto errout; + + retval = ext2fs_extent_fix_parents(handle); + if (retval && retval != EXT2_ET_NO_CURRENT_NODE) + goto errout; + retval = 0; + + /* + * Jump forward to the next extent. If there are + * errors, the ext2fs_extent_get down below will + * capture them for us. + */ + (void)ext2fs_extent_goto(handle, next_lblk); + op = EXT2_EXTENT_CURRENT; + } + if (retval) + goto errout; + dbg_printf("Free start %llu, free count = %u\n", + free_start, free_count); + retval = punch_extent_blocks(fs, ino, inode, lfree_start, + free_start, free_count, &freed); + if (retval) + goto errout; + next_extent: + retval = ext2fs_extent_get(handle, op, + &extent); + if (retval == EXT2_ET_EXTENT_NO_NEXT || + retval == EXT2_ET_NO_CURRENT_NODE) + break; + if (retval) + goto errout; + } + dbg_printf("Freed %d blocks\n", freed); + retval = ext2fs_iblk_sub_blocks(fs, inode, freed); +errout: + ext2fs_extent_free(handle); + return retval; +} + +static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t start, + blk64_t end EXT2FS_ATTR((unused))) +{ + errcode_t retval; + + /* + * In libext2fs ext2fs_punch is based on block unit. So that + * means that if start > 0 we don't need to do nothing. Due + * to this we will remove all inline data in ext2fs_punch() + * now. + */ + if (start > 0) + return 0; + + memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + inode->i_size = 0; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + + return ext2fs_inline_data_ea_remove(fs, ino); +} + +/* + * Deallocate all logical _blocks_ starting at start to end, inclusive. + * If end is ~0ULL, then this is effectively truncate. + */ +errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + char *block_buf, blk64_t start, + blk64_t end) +{ + errcode_t retval; + struct ext2_inode inode_buf; + + if (start > end) + return EINVAL; + + /* Read inode structure if necessary */ + if (!inode) { + retval = ext2fs_read_inode(fs, ino, &inode_buf); + if (retval) + return retval; + inode = &inode_buf; + } + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return ext2fs_punch_inline_data(fs, ino, inode, start, end); + else if (inode->i_flags & EXT4_EXTENTS_FL) + retval = ext2fs_punch_extent(fs, ino, inode, start, end); + else + retval = ext2fs_punch_ind(fs, inode, block_buf, start, end); + if (retval) + return retval; + +#ifdef PUNCH_DEBUG + printf("%u: write inode size now %u blocks %u\n", + ino, inode->i_size, inode->i_blocks); +#endif + return ext2fs_write_inode(fs, ino, inode); +} diff --git a/src/ext2fs/rbtree.c b/src/ext2fs/rbtree.c new file mode 100644 index 00000000..5b92099d --- /dev/null +++ b/src/ext2fs/rbtree.c @@ -0,0 +1,451 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 + + linux/lib/rbtree.c +*/ + +#include "rbtree.h" + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = ext2fs_rb_parent(node); + + if ((node->rb_right = right->rb_left)) + ext2fs_rb_set_parent(right->rb_left, node); + right->rb_left = node; + + ext2fs_rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + ext2fs_rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = ext2fs_rb_parent(node); + + if ((node->rb_left = left->rb_right)) + ext2fs_rb_set_parent(left->rb_right, node); + left->rb_right = node; + + ext2fs_rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + ext2fs_rb_set_parent(node, left); +} + +void ext2fs_rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = ext2fs_rb_parent(node)) && ext2fs_rb_is_red(parent)) + { + gparent = ext2fs_rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && ext2fs_rb_is_red(uncle)) + { + ext2fs_rb_set_black(uncle); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && ext2fs_rb_is_red(uncle)) + { + ext2fs_rb_set_black(uncle); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + ext2fs_rb_set_black(parent); + ext2fs_rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + ext2fs_rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || ext2fs_rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (ext2fs_rb_is_red(other)) + { + ext2fs_rb_set_black(other); + ext2fs_rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && + (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) + { + ext2fs_rb_set_red(other); + node = parent; + parent = ext2fs_rb_parent(node); + } + else + { + if (!other->rb_right || ext2fs_rb_is_black(other->rb_right)) + { + ext2fs_rb_set_black(other->rb_left); + ext2fs_rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (ext2fs_rb_is_red(other)) + { + ext2fs_rb_set_black(other); + ext2fs_rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || ext2fs_rb_is_black(other->rb_left)) && + (!other->rb_right || ext2fs_rb_is_black(other->rb_right))) + { + ext2fs_rb_set_red(other); + node = parent; + parent = ext2fs_rb_parent(node); + } + else + { + if (!other->rb_left || ext2fs_rb_is_black(other->rb_left)) + { + ext2fs_rb_set_black(other->rb_right); + ext2fs_rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + ext2fs_rb_set_color(other, ext2fs_rb_color(parent)); + ext2fs_rb_set_black(parent); + ext2fs_rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + ext2fs_rb_set_black(node); +} + +void ext2fs_rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + + if (ext2fs_rb_parent(old)) { + if (ext2fs_rb_parent(old)->rb_left == old) + ext2fs_rb_parent(old)->rb_left = node; + else + ext2fs_rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + child = node->rb_right; + parent = ext2fs_rb_parent(node); + color = ext2fs_rb_color(node); + + if (parent == old) { + parent = node; + } else { + if (child) + ext2fs_rb_set_parent(child, parent); + parent->rb_left = child; + + node->rb_right = old->rb_right; + ext2fs_rb_set_parent(old->rb_right, node); + } + + node->rb_parent_color = old->rb_parent_color; + node->rb_left = old->rb_left; + ext2fs_rb_set_parent(old->rb_left, node); + + goto color; + } + + parent = ext2fs_rb_parent(node); + color = ext2fs_rb_color(node); + + if (child) + ext2fs_rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +static void ext2fs_rb_augment_path(struct rb_node *node, rb_augment_f func, void *data) +{ + struct rb_node *parent; + +up: + func(node, data); + parent = ext2fs_rb_parent(node); + if (!parent) + return; + + if (node == parent->rb_left && parent->rb_right) + func(parent->rb_right, data); + else if (parent->rb_left) + func(parent->rb_left, data); + + node = parent; + goto up; +} + +/* + * after inserting @node into the tree, update the tree to account for + * both the new entry and any damage done by rebalance + */ +void ext2fs_rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data) +{ + if (node->rb_left) + node = node->rb_left; + else if (node->rb_right) + node = node->rb_right; + + ext2fs_rb_augment_path(node, func, data); +} + +/* + * before removing the node, find the deepest node on the rebalance path + * that will still be there after @node gets removed + */ +struct rb_node *ext2fs_rb_augment_erase_begin(struct rb_node *node) +{ + struct rb_node *deepest; + + if (!node->rb_right && !node->rb_left) + deepest = ext2fs_rb_parent(node); + else if (!node->rb_right) + deepest = node->rb_left; + else if (!node->rb_left) + deepest = node->rb_right; + else { + deepest = ext2fs_rb_next(node); + if (deepest->rb_right) + deepest = deepest->rb_right; + else if (ext2fs_rb_parent(deepest) != node) + deepest = ext2fs_rb_parent(deepest); + } + + return deepest; +} + +/* + * after removal, update the tree to account for the removed entry + * and any rebalance damage. + */ +void ext2fs_rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data) +{ + if (node) + ext2fs_rb_augment_path(node, func, data); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *ext2fs_rb_first(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *ext2fs_rb_last(const struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *ext2fs_rb_next(struct rb_node *node) +{ + struct rb_node *parent; + + if (ext2fs_rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return (struct rb_node *)node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = ext2fs_rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *ext2fs_rb_prev(struct rb_node *node) +{ + struct rb_node *parent; + + if (ext2fs_rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return (struct rb_node *)node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = ext2fs_rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void ext2fs_rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = ext2fs_rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + ext2fs_rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + ext2fs_rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/src/ext2fs/rbtree.h b/src/ext2fs/rbtree.h new file mode 100644 index 00000000..ada31bba --- /dev/null +++ b/src/ext2fs/rbtree.h @@ -0,0 +1,195 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop dramatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + in two steps: First, the code must insert the element in order as a red leaf + in the tree, and then the support library function rb_insert_color() must + be called. Such function will do the not trivial work to rebalance the + rbtree, if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include +#include + +// TODO: MSVC __attribute__(x) +#define __attribute__(x) + +#undef offsetof +#ifdef __compiler_offsetof +#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) +#else +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif + +#define container_of(ptr, type, member) ({ \ + const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) + +struct rb_node +{ + uintptr_t rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +} __attribute__((aligned(sizeof(long)))); + /* The alignment might seem pointless, but allegedly CRIS needs it */ + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define ext2fs_rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define ext2fs_rb_color(r) ((r)->rb_parent_color & 1) +#define ext2fs_rb_is_red(r) (!ext2fs_rb_color(r)) +#define ext2fs_rb_is_black(r) ext2fs_rb_color(r) +#define ext2fs_rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define ext2fs_rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void ext2fs_rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (uintptr_t)p; +} +static inline void ext2fs_rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } +#define ext2fs_rb_entry(ptr, type, member) container_of(ptr, type, member) + +static inline int ext2fs_rb_empty_root(struct rb_root *root) +{ + return root->rb_node == NULL; +} + +static inline int ext2fs_rb_empty_node(struct rb_node *node) +{ + return ext2fs_rb_parent(node) == node; +} + +static inline void ext2fs_rb_clear_node(struct rb_node *node) +{ + ext2fs_rb_set_parent(node, node); +} + +extern void ext2fs_rb_insert_color(struct rb_node *, struct rb_root *); +extern void ext2fs_rb_erase(struct rb_node *, struct rb_root *); + +typedef void (*rb_augment_f)(struct rb_node *node, void *data); + +extern void ext2fs_rb_augment_insert(struct rb_node *node, + rb_augment_f func, void *data); +extern struct rb_node *ext2fs_rb_augment_erase_begin(struct rb_node *node); +extern void ext2fs_rb_augment_erase_end(struct rb_node *node, + rb_augment_f func, void *data); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *ext2fs_rb_next(struct rb_node *); +extern struct rb_node *ext2fs_rb_prev(struct rb_node *); +extern struct rb_node *ext2fs_rb_first(const struct rb_root *); +extern struct rb_node *ext2fs_rb_last(const struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void ext2fs_rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void ext2fs_rb_link_node(struct rb_node * node, + struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (uintptr_t)parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/src/ext2fs/read_bb.c b/src/ext2fs/read_bb.c new file mode 100644 index 00000000..e58b7cb0 --- /dev/null +++ b/src/ext2fs/read_bb.c @@ -0,0 +1,102 @@ +/* + * read_bb --- read the bad blocks inode + * + * Copyright (C) 1994 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +struct read_bb_record { + ext2_badblocks_list bb_list; + errcode_t err; +}; + +/* + * Helper function for ext2fs_read_bb_inode() + */ +#ifdef __TURBOC__ + #pragma argsused +#endif +static int mark_bad_block(ext2_filsys fs, blk_t *block_nr, + e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), + blk_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *priv_data) +{ + struct read_bb_record *rb = (struct read_bb_record *) priv_data; + + if (blockcnt < 0) + return 0; + + if ((*block_nr < fs->super->s_first_data_block) || + (*block_nr >= ext2fs_blocks_count(fs->super))) + return 0; /* Ignore illegal blocks */ + + rb->err = ext2fs_badblocks_list_add(rb->bb_list, *block_nr); + if (rb->err) + return BLOCK_ABORT; + return 0; +} + +/* + * Reads the current bad blocks from the bad blocks inode. + */ +errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list) +{ + errcode_t retval; + struct read_bb_record rb; + struct ext2_inode inode; + blk_t numblocks; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!*bb_list) { + retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode); + if (retval) + return retval; + numblocks = inode.i_blocks; + if (!(ext2fs_has_feature_huge_file(fs->super) && + (inode.i_flags & EXT4_HUGE_FILE_FL))) + numblocks = numblocks / (fs->blocksize / 512); + numblocks += 20; + if (numblocks < 50) + numblocks = 50; + if (numblocks > 50000) + numblocks = 500; + retval = ext2fs_badblocks_list_create(bb_list, numblocks); + if (retval) + return retval; + } + + rb.bb_list = *bb_list; + rb.err = 0; + retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO, BLOCK_FLAG_READ_ONLY, + 0, mark_bad_block, &rb); + if (retval) + return retval; + + return rb.err; +} + + diff --git a/src/ext2fs/rw_bitmaps.c b/src/ext2fs/rw_bitmaps.c new file mode 100644 index 00000000..e86bacd5 --- /dev/null +++ b/src/ext2fs/rw_bitmaps.c @@ -0,0 +1,430 @@ +/* + * rw_bitmaps.c --- routines to read and write the inode and block bitmaps. + * + * Copyright (C) 1993, 1994, 1994, 1996 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#ifdef HAVE_SYS_STAT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "e2image.h" + +static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) +{ + dgrp_t i; + unsigned int j; + int block_nbytes, inode_nbytes; + unsigned int nbits; + errcode_t retval; + char *block_buf = NULL, *inode_buf = NULL; + int csum_flag; + blk64_t blk; + blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); + ext2_ino_t ino_itr = 1; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_RW)) + return EXT2_ET_RO_FILSYS; + + csum_flag = ext2fs_has_group_desc_csum(fs); + + inode_nbytes = block_nbytes = 0; + if (do_block) { + block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; + retval = io_channel_alloc_buf(fs->io, 0, &block_buf); + if (retval) + goto errout; + memset(block_buf, 0xff, fs->blocksize); + } + if (do_inode) { + inode_nbytes = (size_t) + ((EXT2_INODES_PER_GROUP(fs->super)+7) / 8); + retval = io_channel_alloc_buf(fs->io, 0, &inode_buf); + if (retval) + goto errout; + memset(inode_buf, 0xff, fs->blocksize); + } + + for (i = 0; i < fs->group_desc_count; i++) { + if (!do_block) + goto skip_block_bitmap; + + if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) + ) + goto skip_this_block_bitmap; + + retval = ext2fs_get_block_bitmap_range2(fs->block_map, + blk_itr, block_nbytes << 3, block_buf); + if (retval) + goto errout; + + if (i == fs->group_desc_count - 1) { + /* Force bitmap padding for the last group */ + nbits = EXT2FS_NUM_B2C(fs, + ((ext2fs_blocks_count(fs->super) + - (__u64) fs->super->s_first_data_block) + % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super))); + if (nbits) + for (j = nbits; j < fs->blocksize * 8; j++) + ext2fs_set_bit(j, block_buf); + } + + retval = ext2fs_block_bitmap_csum_set(fs, i, block_buf, + block_nbytes); + if (retval) + return retval; + ext2fs_group_desc_csum_set(fs, i); + fs->flags |= EXT2_FLAG_DIRTY; + + blk = ext2fs_block_bitmap_loc(fs, i); + if (blk) { + retval = io_channel_write_blk64(fs->io, blk, 1, + block_buf); + if (retval) { + retval = EXT2_ET_BLOCK_BITMAP_WRITE; + goto errout; + } + } + skip_this_block_bitmap: + blk_itr += block_nbytes << 3; + skip_block_bitmap: + + if (!do_inode) + continue; + + if (csum_flag && ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) + ) + goto skip_this_inode_bitmap; + + retval = ext2fs_get_inode_bitmap_range2(fs->inode_map, + ino_itr, inode_nbytes << 3, inode_buf); + if (retval) + goto errout; + + retval = ext2fs_inode_bitmap_csum_set(fs, i, inode_buf, + inode_nbytes); + if (retval) + goto errout; + ext2fs_group_desc_csum_set(fs, i); + fs->flags |= EXT2_FLAG_DIRTY; + + blk = ext2fs_inode_bitmap_loc(fs, i); + if (blk) { + retval = io_channel_write_blk64(fs->io, blk, 1, + inode_buf); + if (retval) { + retval = EXT2_ET_INODE_BITMAP_WRITE; + goto errout; + } + } + skip_this_inode_bitmap: + ino_itr += inode_nbytes << 3; + + } + if (do_block) { + fs->flags &= ~EXT2_FLAG_BB_DIRTY; + ext2fs_free_mem(&block_buf); + } + if (do_inode) { + fs->flags &= ~EXT2_FLAG_IB_DIRTY; + ext2fs_free_mem(&inode_buf); + } + return 0; +errout: + if (inode_buf) + ext2fs_free_mem(&inode_buf); + if (block_buf) + ext2fs_free_mem(&block_buf); + return retval; +} + +static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs) +{ + dgrp_t i; + blk64_t blk; + ext2fs_block_bitmap bmap = fs->block_map; + + for (i = 0; i < fs->group_desc_count; i++) { + if (!ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT)) + continue; + + ext2fs_reserve_super_and_bgd(fs, i, bmap); + + /* + * Mark the blocks used for the inode table + */ + blk = ext2fs_inode_table_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap_range2(bmap, blk, + fs->inode_blocks_per_group); + + /* + * Mark block used for the block bitmap + */ + blk = ext2fs_block_bitmap_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap2(bmap, blk); + + /* + * Mark block used for the inode bitmap + */ + blk = ext2fs_inode_bitmap_loc(fs, i); + if (blk) + ext2fs_mark_block_bitmap2(bmap, blk); + } + return 0; +} + +static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) +{ + dgrp_t i; + char *block_bitmap = 0, *inode_bitmap = 0; + char *buf; + errcode_t retval; + int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; + int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; + int csum_flag; + unsigned int cnt; + blk64_t blk; + blk64_t blk_itr = EXT2FS_B2C(fs, fs->super->s_first_data_block); + blk64_t blk_cnt; + ext2_ino_t ino_itr = 1; + ext2_ino_t ino_cnt; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if ((block_nbytes > (int) fs->blocksize) || + (inode_nbytes > (int) fs->blocksize)) + return EXT2_ET_CORRUPT_SUPERBLOCK; + + fs->write_bitmaps = ext2fs_write_bitmaps; + + csum_flag = ext2fs_has_group_desc_csum(fs); + + retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf); + if (retval) + return retval; + if (do_block) { + if (fs->block_map) + ext2fs_free_block_bitmap(fs->block_map); + strcpy(buf, "block bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_block_bitmap(fs, buf, &fs->block_map); + if (retval) + goto cleanup; + retval = io_channel_alloc_buf(fs->io, 0, &block_bitmap); + if (retval) + goto cleanup; + } else + block_nbytes = 0; + if (do_inode) { + if (fs->inode_map) + ext2fs_free_inode_bitmap(fs->inode_map); + strcpy(buf, "inode bitmap for "); + strcat(buf, fs->device_name); + retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map); + if (retval) + goto cleanup; + retval = io_channel_alloc_buf(fs->io, 0, &inode_bitmap); + if (retval) + goto cleanup; + } else + inode_nbytes = 0; + ext2fs_free_mem(&buf); + + if (fs->flags & EXT2_FLAG_IMAGE_FILE) { + blk = (ext2fs_le32_to_cpu(fs->image_header->offset_inodemap) / fs->blocksize); + ino_cnt = fs->super->s_inodes_count; + while (inode_bitmap && ino_cnt > 0) { + retval = io_channel_read_blk64(fs->image_io, blk++, + 1, inode_bitmap); + if (retval) + goto cleanup; + cnt = fs->blocksize << 3; + if (cnt > ino_cnt) + cnt = ino_cnt; + retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, + ino_itr, cnt, inode_bitmap); + if (retval) + goto cleanup; + ino_itr += cnt; + ino_cnt -= cnt; + } + blk = (ext2fs_le32_to_cpu(fs->image_header->offset_blockmap) / + fs->blocksize); + blk_cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, + fs->group_desc_count); + while (block_bitmap && blk_cnt > 0) { + retval = io_channel_read_blk64(fs->image_io, blk++, + 1, block_bitmap); + if (retval) + goto cleanup; + cnt = fs->blocksize << 3; + if (cnt > blk_cnt) + cnt = blk_cnt; + retval = ext2fs_set_block_bitmap_range2(fs->block_map, + blk_itr, cnt, block_bitmap); + if (retval) + goto cleanup; + blk_itr += cnt; + blk_cnt -= cnt; + } + goto success_cleanup; + } + + for (i = 0; i < fs->group_desc_count; i++) { + if (block_bitmap) { + blk = ext2fs_block_bitmap_loc(fs, i); + if (csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) + blk = 0; + if (blk) { + retval = io_channel_read_blk64(fs->io, blk, + 1, block_bitmap); + if (retval) { + retval = EXT2_ET_BLOCK_BITMAP_READ; + goto cleanup; + } + /* verify block bitmap checksum */ + if (!(fs->flags & + EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_block_bitmap_csum_verify(fs, i, + block_bitmap, block_nbytes)) { + retval = + EXT2_ET_BLOCK_BITMAP_CSUM_INVALID; + goto cleanup; + } + } else + memset(block_bitmap, 0, block_nbytes); + cnt = block_nbytes << 3; + retval = ext2fs_set_block_bitmap_range2(fs->block_map, + blk_itr, cnt, block_bitmap); + if (retval) + goto cleanup; + blk_itr += block_nbytes << 3; + } + if (inode_bitmap) { + blk = ext2fs_inode_bitmap_loc(fs, i); + if (csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) + blk = 0; + if (blk) { + retval = io_channel_read_blk64(fs->io, blk, + 1, inode_bitmap); + if (retval) { + retval = EXT2_ET_INODE_BITMAP_READ; + goto cleanup; + } + + /* verify inode bitmap checksum */ + if (!(fs->flags & + EXT2_FLAG_IGNORE_CSUM_ERRORS) && + !ext2fs_inode_bitmap_csum_verify(fs, i, + inode_bitmap, inode_nbytes)) { + retval = + EXT2_ET_INODE_BITMAP_CSUM_INVALID; + goto cleanup; + } + } else + memset(inode_bitmap, 0, inode_nbytes); + cnt = inode_nbytes << 3; + retval = ext2fs_set_inode_bitmap_range2(fs->inode_map, + ino_itr, cnt, inode_bitmap); + if (retval) + goto cleanup; + ino_itr += inode_nbytes << 3; + } + } + + /* Mark group blocks for any BLOCK_UNINIT groups */ + if (do_block) { + retval = mark_uninit_bg_group_blocks(fs); + if (retval) + goto cleanup; + } + +success_cleanup: + if (inode_bitmap) + ext2fs_free_mem(&inode_bitmap); + if (block_bitmap) + ext2fs_free_mem(&block_bitmap); + return 0; + +cleanup: + if (do_block) { + ext2fs_free_mem(&fs->block_map); + fs->block_map = 0; + } + if (do_inode) { + ext2fs_free_mem(&fs->inode_map); + fs->inode_map = 0; + } + if (inode_bitmap) + ext2fs_free_mem(&inode_bitmap); + if (block_bitmap) + ext2fs_free_mem(&block_bitmap); + if (buf) + ext2fs_free_mem(&buf); + return retval; +} + +errcode_t ext2fs_read_inode_bitmap(ext2_filsys fs) +{ + return read_bitmaps(fs, 1, 0); +} + +errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) +{ + return read_bitmaps(fs, 0, 1); +} + +errcode_t ext2fs_write_inode_bitmap(ext2_filsys fs) +{ + return write_bitmaps(fs, 1, 0); +} + +errcode_t ext2fs_write_block_bitmap (ext2_filsys fs) +{ + return write_bitmaps(fs, 0, 1); +} + +errcode_t ext2fs_read_bitmaps(ext2_filsys fs) +{ + if (fs->inode_map && fs->block_map) + return 0; + + return read_bitmaps(fs, !fs->inode_map, !fs->block_map); +} + +errcode_t ext2fs_write_bitmaps(ext2_filsys fs) +{ + int do_inode = fs->inode_map && ext2fs_test_ib_dirty(fs); + int do_block = fs->block_map && ext2fs_test_bb_dirty(fs); + + if (!do_inode && !do_block) + return 0; + + return write_bitmaps(fs, do_inode, do_block); +} diff --git a/src/ext2fs/symlink.c b/src/ext2fs/symlink.c new file mode 100644 index 00000000..7f78c5f7 --- /dev/null +++ b/src/ext2fs/symlink.c @@ -0,0 +1,204 @@ +/* + * symlink.c --- make a symlink in the filesystem, based on mkdir.c + * + * Copyright (c) 2012, Intel Corporation. + * All Rights Reserved. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#include "ext2_fs.h" +#include "ext2fs.h" + +#ifndef HAVE_STRNLEN +/* + * Incredibly, libc5 doesn't appear to have strnlen. So we have to + * provide our own. + */ +static int my_strnlen(const char * s, int count) +{ + const char *cp = s; + + while (count-- && *cp) + cp++; + return cp - s; +} +#define strnlen(str, x) my_strnlen((str),(x)) +#endif + +errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, + const char *name, const char *target) +{ + errcode_t retval; + struct ext2_inode inode; + ext2_ino_t scratch_ino; + blk64_t blk; + int fastlink, inlinelink; + unsigned int target_len; + char *block_buf = 0; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + /* + * The Linux kernel doesn't allow for links longer than a block + * (counting the NUL terminator) + */ + target_len = strnlen(target, fs->blocksize + 1); + if (target_len >= fs->blocksize) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + + /* + * Allocate a data block for slow links + */ + retval = ext2fs_get_mem(fs->blocksize, &block_buf); + if (retval) + goto cleanup; + memset(block_buf, 0, fs->blocksize); + strncpy(block_buf, target, fs->blocksize); + + memset(&inode, 0, sizeof(struct ext2_inode)); + fastlink = (target_len < sizeof(inode.i_block)); + if (!fastlink) { + retval = ext2fs_new_block2(fs, ext2fs_find_inode_goal(fs, ino, + &inode, + 0), + NULL, &blk); + if (retval) + goto cleanup; + } + + /* + * Allocate an inode, if necessary + */ + if (!ino) { + retval = ext2fs_new_inode(fs, parent, LINUX_S_IFLNK | 0755, + 0, &ino); + if (retval) + goto cleanup; + } + + /* + * Create the inode structure.... + */ + inode.i_mode = LINUX_S_IFLNK | 0777; + inode.i_uid = inode.i_gid = 0; + inode.i_links_count = 1; + ext2fs_inode_size_set(fs, &inode, target_len); + /* The time fields are set by ext2fs_write_new_inode() */ + + inlinelink = !fastlink && ext2fs_has_feature_inline_data(fs->super); + if (fastlink) { + /* Fast symlinks, target stored in inode */ + strcpy((char *)&inode.i_block, target); + } else if (inlinelink) { + /* Try inserting an inline data symlink */ + inode.i_flags |= EXT4_INLINE_DATA_FL; + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + retval = ext2fs_inline_data_set(fs, ino, &inode, block_buf, + target_len); + if (retval) { + inode.i_flags &= ~EXT4_INLINE_DATA_FL; + inlinelink = 0; + goto need_block; + } + retval = ext2fs_read_inode(fs, ino, &inode); + if (retval) + goto cleanup; + } else { +need_block: + /* Slow symlinks, target stored in the first block */ + ext2fs_iblk_set(fs, &inode, 1); + if (ext2fs_has_feature_extents(fs->super)) { + /* + * The extent bmap is setup after the inode and block + * have been written out below. + */ + inode.i_flags |= EXT4_EXTENTS_FL; + } + } + + /* + * Write out the inode and inode data block. The inode generation + * number is assigned by write_new_inode, which means that the + * operations using ino must come after it. + */ + if (inlinelink) + retval = ext2fs_write_inode(fs, ino, &inode); + else + retval = ext2fs_write_new_inode(fs, ino, &inode); + if (retval) + goto cleanup; + + if (!fastlink && !inlinelink) { + retval = ext2fs_bmap2(fs, ino, &inode, NULL, BMAP_SET, 0, NULL, + &blk); + if (retval) + goto cleanup; + + retval = io_channel_write_blk64(fs->io, blk, 1, block_buf); + if (retval) + goto cleanup; + } + + /* + * Link the symlink into the filesystem hierarchy + */ + if (name) { + retval = ext2fs_lookup(fs, parent, name, strlen(name), 0, + &scratch_ino); + if (!retval) { + retval = EXT2_ET_FILE_EXISTS; + goto cleanup; + } + if (retval != EXT2_ET_FILE_NOT_FOUND) + goto cleanup; + retval = ext2fs_link(fs, parent, name, ino, EXT2_FT_SYMLINK); + if (retval) + goto cleanup; + } + + /* + * Update accounting.... + */ + if (!fastlink && !inlinelink) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 0); + +cleanup: + if (block_buf) + ext2fs_free_mem(&block_buf); + return retval; +} + +/* + * Test whether an inode is a fast symlink. + * + * A fast symlink has its symlink data stored in inode->i_block. + */ +int ext2fs_is_fast_symlink(struct ext2_inode *inode) +{ + return LINUX_S_ISLNK(inode->i_mode) && EXT2_I_SIZE(inode) && + EXT2_I_SIZE(inode) < sizeof(inode->i_block); +} diff --git a/src/ext2fs/valid_blk.c b/src/ext2fs/valid_blk.c new file mode 100644 index 00000000..db5d90ae --- /dev/null +++ b/src/ext2fs/valid_blk.c @@ -0,0 +1,68 @@ +/* + * valid_blk.c --- does the inode have valid blocks? + * + * Copyright 1997 by Theodore Ts'o + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#if HAVE_UNISTD_H +#include +#endif +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" + +/* + * This function returns 1 if the inode's block entries actually + * contain block entries. + */ +int ext2fs_inode_has_valid_blocks2(ext2_filsys fs, struct ext2_inode *inode) +{ + /* + * Only directories, regular files, and some symbolic links + * have valid block entries. + */ + if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) && + !LINUX_S_ISLNK(inode->i_mode)) + return 0; + + /* + * If the symbolic link is a "fast symlink", then the symlink + * target is stored in the block entries. + */ + if (LINUX_S_ISLNK (inode->i_mode)) { + if (ext2fs_file_acl_block(fs, inode) == 0) { + /* With no EA block, we can rely on i_blocks */ + if (inode->i_blocks == 0) + return 0; + } else { + /* With an EA block, life gets more tricky */ + if (inode->i_size >= EXT2_N_BLOCKS*4) + return 1; /* definitely using i_block[] */ + if (inode->i_size > 4 && inode->i_block[1] == 0) + return 1; /* definitely using i_block[] */ + return 0; /* Probably a fast symlink */ + } + } + + /* + * If this inode has inline data, it shouldn't have valid block + * entries. + */ + if (inode->i_flags & EXT4_INLINE_DATA_FL) + return 0; + return 1; +} + +int ext2fs_inode_has_valid_blocks(struct ext2_inode *inode) +{ + return ext2fs_inode_has_valid_blocks2(NULL, inode); +} diff --git a/src/format.c b/src/format.c index f620b8f2..fd79be9d 100644 --- a/src/format.c +++ b/src/format.c @@ -49,6 +49,7 @@ #include "format.h" #include "badblocks.h" #include "bled/bled.h" +#include "ext2fs/ext2fs.h" #include "../res/grub/grub_version.h" /* @@ -664,6 +665,124 @@ out: return r; } +extern io_manager nt_io_manager(void); +BOOL FormatExt2Fs(void) +{ + const char* path = "\\??\\C:\\tmp\\disk.img"; + int i, count; + struct ext2_super_block features = { 0 }; + io_manager manager = nt_io_manager(); + blk64_t size = 0, cur; + ext2_filsys ext2fs; + errcode_t r; + HANDLE h; + DWORD dwSize; + const uint8_t buf[1024] = { 0 }; + + // Create a 32 MB zeroed file to test + h = CreateFileU(path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + for (i = 0; i < 32 * 1024; i++) { + if (!WriteFile(h, buf, sizeof(buf), &dwSize, NULL) || (dwSize != sizeof(buf))) { + uprintf("Write error: %s", WindowsErrorString()); + break; + } + } + CloseHandle(h); + + // TODO: We could probably remove that call and get our size from a different means + r = ext2fs_get_device_size(path, EXT2_BLOCK_SIZE(&features), &size); + uprintf("ext2fs_get_device_size: %d", r); + // TODO: ERROR HANDLING + // Set the number of blocks and reserved blocks + ext2fs_blocks_count_set(&features, size); + ext2fs_r_blocks_count_set(&features, (blk64_t)(0.05f * ext2fs_blocks_count(&features))); + features.s_rev_level = 1; + features.s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; + // TODO: This needs to be computed according to volume size + features.s_inodes_count = 8192; + + // TODO: Set a volume label + + // Initialize the superblock + r = ext2fs_initialize(path, EXT2_FLAG_EXCLUSIVE | EXT2_FLAG_64BITS, &features, manager, &ext2fs); + uprintf("ext2fs_initialize: %d", r); + // TODO: ERROR HANDLING + + // TODO: Erase superblock data + // Now that the superblock has been initialized, set it up + CoCreateGuid((GUID*)ext2fs->super->s_uuid); + ext2fs_init_csum_seed(ext2fs); + ext2fs->super->s_def_hash_version = EXT2_HASH_HALF_MD4; + CoCreateGuid((GUID*)ext2fs->super->s_hash_seed); + ext2fs->super->s_max_mnt_count = -1; + ext2fs->super->s_creator_os = EXT2_OS_WINDOWS; + ext2fs->super->s_errors = EXT2_ERRORS_CONTINUE; + + // TODO: ext2 + journaling = ext3, so the way to set ext3 is to add features: + // ext_attr, resize_inode, dir_index, filetype, sparse_super, has_journal, needs_recovery + ext2fs_set_feature_xattr(&features); + // ext2fs_set_feature_resize_inode(&sb); + // ext2fs_set_feature_dir_index(&sb); + ext2fs_set_feature_filetype(&features); + // ext2fs_set_feature_sparse_super(&sb); + // ext2fs_set_feature_journal(&sb); + // ext2fs_set_feature_journal_needs_recovery(&sb); + + // Optional we may want to add: + // ext2fs_set_feature_64bit(&sb); + // NB: the following is not needed as it is set by the OS automatically when creating a > 2GB file + // ext2fs_set_feature_large_file(&sb); + + r = ext2fs_allocate_tables(ext2fs); + uprintf("ext2fs_allocate_tables: %d", r); + // TODO: ERROR HANDLING + r = ext2fs_convert_subcluster_bitmap(ext2fs, &ext2fs->block_map); + uprintf("ext2fs_convert_subcluster_bitmap: %d", r); + // TODO: ERROR HANDLING + + // Wipe inode table + for (i = 0; i < (int)ext2fs->group_desc_count; i++) { + cur = ext2fs_inode_table_loc(ext2fs, i); + count = ext2fs_div_ceil((ext2fs->super->s_inodes_per_group - ext2fs_bg_itable_unused(ext2fs, i)) + * EXT2_GOOD_OLD_INODE_SIZE, EXT2_GOOD_OLD_INODE_SIZE); + r = ext2fs_zero_blocks2(ext2fs, cur, count, &cur, &count); + if (r != 0) { + uprintf("Could not zero inode at %llu (%d blocks): %d\n", cur, count, r); + // TODO: ERROR HANDLING + break; + } + } + + // Create root dir + r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0); + uprintf("ext2fs_mkdir(root): %d", r); + // TODO: ERROR HANDLING + + // Create 'lost+found' + ext2fs->umask = 077; + r = ext2fs_mkdir(ext2fs, EXT2_ROOT_INO, 0, "lost+found"); + uprintf("ext2fs_mkdir(lost+found): %d", r); + // TODO: ERROR HANDLING + + for (i = EXT2_ROOT_INO + 1; i < (int)EXT2_FIRST_INODE(ext2fs->super); i++) + ext2fs_inode_alloc_stats2(ext2fs, i, +1, 0); + ext2fs_mark_ib_dirty(ext2fs); + + r = ext2fs_mark_inode_bitmap2(ext2fs->inode_map, EXT2_BAD_INO); + uprintf("ext2fs_mark_inode_bitmap2: %d", r); + // TODO: ERROR HANDLING + ext2fs_inode_alloc_stats2(ext2fs, EXT2_BAD_INO, 1, 0); + r = ext2fs_update_bb_inode(ext2fs, NULL); + uprintf("ext2fs_update_bb_inode: %d", r); + // TODO: ERROR HANDLING + + r = ext2fs_close_free(&ext2fs); + uprintf("ext2fs_close_free: %d", r); + // TODO: ERROR HANDLING + + return TRUE; +} + /* * Call on fmifs.dll's FormatEx() to format the drive */ diff --git a/src/license.h b/src/license.h index cd80ec87..54ba5adf 100644 --- a/src/license.h +++ b/src/license.h @@ -73,7 +73,7 @@ const char* additional_copyrights = "http://svn.reactos.org/svn/reactos/trunk/reactos\\line\n" "GNU General Public License (GPL) v2 or later\\line\n" "\\line\n" -"Bad blocks testing from e2fsprogs by Theodore T'so et al.:\\line\n" +"Bad blocks testing and ext2/ext3 formattinmg from e2fsprogs by Theodore T'so et al.:\\line\n" "http://e2fsprogs.sourceforge.net\\line\n" "GNU General Public License (GPL) v3 compatible\\line\n" "\\line\n" diff --git a/src/msvc-missing/unistd.h b/src/msvc-missing/unistd.h index 95c32208..0bc675a7 100644 --- a/src/msvc-missing/unistd.h +++ b/src/msvc-missing/unistd.h @@ -31,4 +31,12 @@ typedef int ssize_t; #endif /* _WIN64 */ #endif /* _SSIZE_T_DEFINED */ -#endif \ No newline at end of file +/* ext2fs needs this, which we picked from libcdio-driver/filemode.h */ +#if !defined S_IFBLK && defined _WIN32 +# define S_IFBLK 0x3000 +#endif +#if !defined S_ISBLK && defined S_IFBLK +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#endif + +#endif diff --git a/src/process.c b/src/process.c index 062ea8e0..f5090965 100644 --- a/src/process.c +++ b/src/process.c @@ -69,7 +69,7 @@ extern StrArray BlockingProcess; * \return An error message string. * */ -static char* NtStatusError(NTSTATUS Status) { +char* NtStatusError(NTSTATUS Status) { static char unknown[32]; switch (Status) { diff --git a/src/rufus.c b/src/rufus.c index f98bd483..0587c93a 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1860,9 +1860,11 @@ out: return ret; } + /* * Main dialog callback */ +extern BOOL FormatExt2Fs(void); static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static DWORD DeviceNum = 0; @@ -1895,10 +1897,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case WM_COMMAND: #ifdef RUFUS_TEST if (LOWORD(wParam) == IDC_TEST) { - image_path = "C:\\Downloads\\fat.iso"; - strcpy(img_report.efi_img_path, "efi.img"); - DumpFatDir("C:\\tmp", 0); - image_path = NULL; + FormatExt2Fs(); break; } #endif diff --git a/src/rufus.rc b/src/rufus.rc index d1eabb76..858910c3 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.6.1517" +CAPTION "Rufus 3.6.1518" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -394,8 +394,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,6,1517,0 - PRODUCTVERSION 3,6,1517,0 + FILEVERSION 3,6,1518,0 + PRODUCTVERSION 3,6,1518,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -413,13 +413,13 @@ BEGIN VALUE "Comments", "https://akeo.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.6.1517" + VALUE "FileVersion", "3.6.1518" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus-3.6.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.6.1517" + VALUE "ProductVersion", "3.6.1518" END END BLOCK "VarFileInfo"