--- /dev/null
+/**
+ DO NOT EDIT
+ FILE auto-generated
+ Module name:
+ AutoGen.c
+ Abstract: Auto-generated AutoGen.c for building module or library.
+**/
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+
+// Guids
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileInfoGuid = { 0x09576E92, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemInfoGuid = { 0x09576E93, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiFileSystemVolumeLabelInfoIdGuid = { 0xDB47D7D3, 0xFE81, 0x11D3, { 0x9A, 0x35, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiMdePkgTokenSpaceGuid = { 0x914AEBE7, 0x4635, 0x459b, { 0xAA, 0x1C, 0x11, 0xE2, 0x19, 0xB0, 0x3A, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventReadyToBootGuid = { 0x7CE88FB3, 0x4BD7, 0x4679, { 0x87, 0xA8, 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiEventLegacyBootGuid = { 0x2A571201, 0x4966, 0x47F6, { 0x8B, 0x86, 0xF3, 0x1E, 0x41, 0xF3, 0x2F, 0x10 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGlobalVariableGuid = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }};
+
+// Protocols
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDiskIoProtocolGuid = { 0xCE345171, 0xBA0B, 0x11D2, { 0x8E, 0x4F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleFileSystemProtocolGuid = { 0x964E5B22, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollationProtocolGuid = { 0x1D85CD7F, 0xF43D, 0x11D2, { 0x9A, 0x0C, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUnicodeCollation2ProtocolGuid = {0xa4c751fc, 0x23ae, 0x4c3e, { 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gMsgLogProtocolGuid = {0x511CE018, 0x0018, 0x4002, {0x20, 0x12, 0x17, 0x38, 0x05, 0x01, 0x02, 0x03 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDevicePathProtocolGuid = { 0x09576E91, 0x6D3F, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverBindingProtocolGuid = { 0x18A031AB, 0xB443, 0x4D1A, { 0xA5, 0xC0, 0x0C, 0x09, 0x26, 0x1E, 0x9F, 0x71 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiSimpleTextOutProtocolGuid = { 0x387477C2, 0x69C7, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiGraphicsOutputProtocolGuid = { 0x9042A9DE, 0x23DC, 0x4A38, { 0x96, 0xFB, 0x7A, 0xDE, 0xD0, 0x80, 0x51, 0x6A }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiHiiFontProtocolGuid = {0xe9ca4775, 0x8657, 0x47fc, {0x97, 0xe7, 0x7e, 0xd6, 0x5a, 0x08, 0x43, 0x24}};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiUgaDrawProtocolGuid = { 0x982C298B, 0xF4FA, 0x41CB, { 0xB8, 0x38, 0x77, 0xAA, 0x68, 0x8F, 0xB8, 0x39 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentNameProtocolGuid = { 0x107A772C, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiComponentName2ProtocolGuid = { 0x6A7A5CFF, 0xE8D9, 0x4F70, { 0xBA, 0xDA, 0x75, 0xAB, 0x30, 0x25, 0xCE, 0x14 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfigurationProtocolGuid = { 0x107A772B, 0xD5E1, 0x11D4, { 0x9A, 0x46, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverConfiguration2ProtocolGuid = { 0xBFD7DC1D, 0x24F1, 0x40D9, { 0x82, 0xE7, 0x2E, 0x09, 0xBB, 0x6B, 0x4E, 0xBE }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnosticsProtocolGuid = { 0x0784924F, 0xE296, 0x11D4, { 0x9A, 0x49, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiDriverDiagnostics2ProtocolGuid = { 0x4D330321, 0x025F, 0x4AAC, { 0x90, 0xD8, 0x5E, 0xD9, 0x00, 0x17, 0x3B, 0x63 }};
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gEfiLoadedImageProtocolGuid = { 0x5B1B31A1, 0x9562, 0x11D2, { 0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }};
+
+// Definition of PCDs used in this module
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5] = {101, 110, 103, 0 };
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7] = {101, 110, 45, 85, 83, 0 };
+
+// Definition of PCDs used in libraries
+
+#define _PCD_TOKEN_PcdDebugPrintErrorLevel 5U
+#define _PCD_VALUE_PcdDebugPrintErrorLevel 0x80000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel = _PCD_VALUE_PcdDebugPrintErrorLevel;
+extern const UINT32 _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel;
+#define _PCD_GET_MODE_32_PcdDebugPrintErrorLevel _gPcd_FixedAtBuild_PcdDebugPrintErrorLevel
+//#define _PCD_SET_MODE_32_PcdDebugPrintErrorLevel ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugClearMemoryValue 10U
+#define _PCD_VALUE_PcdDebugClearMemoryValue 0xAFU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue = _PCD_VALUE_PcdDebugClearMemoryValue;
+extern const UINT8 _gPcd_FixedAtBuild_PcdDebugClearMemoryValue;
+#define _PCD_GET_MODE_8_PcdDebugClearMemoryValue _gPcd_FixedAtBuild_PcdDebugClearMemoryValue
+//#define _PCD_SET_MODE_8_PcdDebugClearMemoryValue ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDebugPropertyMask 11U
+#define _PCD_VALUE_PcdDebugPropertyMask 0x0fU
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask = _PCD_VALUE_PcdDebugPropertyMask;
+extern const UINT8 _gPcd_FixedAtBuild_PcdDebugPropertyMask;
+#define _PCD_GET_MODE_8_PcdDebugPropertyMask _gPcd_FixedAtBuild_PcdDebugPropertyMask
+//#define _PCD_SET_MODE_8_PcdDebugPropertyMask ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumLinkedListLength 6U
+#define _PCD_VALUE_PcdMaximumLinkedListLength 1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength = _PCD_VALUE_PcdMaximumLinkedListLength;
+extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumLinkedListLength;
+#define _PCD_GET_MODE_32_PcdMaximumLinkedListLength _gPcd_FixedAtBuild_PcdMaximumLinkedListLength
+//#define _PCD_SET_MODE_32_PcdMaximumLinkedListLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumAsciiStringLength 7U
+#define _PCD_VALUE_PcdMaximumAsciiStringLength 1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength = _PCD_VALUE_PcdMaximumAsciiStringLength;
+extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumAsciiStringLength _gPcd_FixedAtBuild_PcdMaximumAsciiStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumAsciiStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdMaximumUnicodeStringLength 8U
+#define _PCD_VALUE_PcdMaximumUnicodeStringLength 1000000U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength = _PCD_VALUE_PcdMaximumUnicodeStringLength;
+extern const UINT32 _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength;
+#define _PCD_GET_MODE_32_PcdMaximumUnicodeStringLength _gPcd_FixedAtBuild_PcdMaximumUnicodeStringLength
+//#define _PCD_SET_MODE_32_PcdMaximumUnicodeStringLength ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdVerifyNodeInList 9U
+#define _PCD_VALUE_PcdVerifyNodeInList ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList = _PCD_VALUE_PcdVerifyNodeInList;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdVerifyNodeInList;
+#define _PCD_GET_MODE_BOOL_PcdVerifyNodeInList _gPcd_FixedAtBuild_PcdVerifyNodeInList
+//#define _PCD_SET_MODE_BOOL_PcdVerifyNodeInList ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnosticsDisable 12U
+#define _PCD_VALUE_PcdDriverDiagnosticsDisable ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable = _PCD_VALUE_PcdDriverDiagnosticsDisable;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnosticsDisable _gPcd_FixedAtBuild_PcdDriverDiagnosticsDisable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnosticsDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentNameDisable 13U
+#define _PCD_VALUE_PcdComponentNameDisable ((BOOLEAN)0U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable = _PCD_VALUE_PcdComponentNameDisable;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentNameDisable;
+#define _PCD_GET_MODE_BOOL_PcdComponentNameDisable _gPcd_FixedAtBuild_PcdComponentNameDisable
+//#define _PCD_SET_MODE_BOOL_PcdComponentNameDisable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdDriverDiagnostics2Disable 14U
+#define _PCD_VALUE_PcdDriverDiagnostics2Disable ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable = _PCD_VALUE_PcdDriverDiagnostics2Disable;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable;
+#define _PCD_GET_MODE_BOOL_PcdDriverDiagnostics2Disable _gPcd_FixedAtBuild_PcdDriverDiagnostics2Disable
+//#define _PCD_SET_MODE_BOOL_PcdDriverDiagnostics2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdComponentName2Disable 15U
+#define _PCD_VALUE_PcdComponentName2Disable ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable = _PCD_VALUE_PcdComponentName2Disable;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdComponentName2Disable;
+#define _PCD_GET_MODE_BOOL_PcdComponentName2Disable _gPcd_FixedAtBuild_PcdComponentName2Disable
+//#define _PCD_SET_MODE_BOOL_PcdComponentName2Disable ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUgaConsumeSupport 16U
+#define _PCD_VALUE_PcdUgaConsumeSupport ((BOOLEAN)1U)
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport = _PCD_VALUE_PcdUgaConsumeSupport;
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdUgaConsumeSupport;
+#define _PCD_GET_MODE_BOOL_PcdUgaConsumeSupport _gPcd_FixedAtBuild_PcdUgaConsumeSupport
+//#define _PCD_SET_MODE_BOOL_PcdUgaConsumeSupport ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiLibMaxPrintBufferSize 17U
+#define _PCD_VALUE_PcdUefiLibMaxPrintBufferSize 320U
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize = _PCD_VALUE_PcdUefiLibMaxPrintBufferSize;
+extern const UINT32 _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize;
+#define _PCD_GET_MODE_32_PcdUefiLibMaxPrintBufferSize _gPcd_FixedAtBuild_PcdUefiLibMaxPrintBufferSize
+//#define _PCD_SET_MODE_32_PcdUefiLibMaxPrintBufferSize ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+
+EFI_STATUS
+EFIAPI
+UefiBootServicesTableLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+UefiRuntimeServicesTableLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+EFI_STATUS
+EFIAPI
+UefiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+VOID
+EFIAPI
+ProcessLibraryConstructorList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UefiLibConstructor (ImageHandle, SystemTable);
+ ASSERT_EFI_ERROR (Status);
+
+}
+
+
+
+VOID
+EFIAPI
+ProcessLibraryDestructorList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+}
+
+const UINT32 _gUefiDriverRevision = 0x00020000U;
+const UINT32 _gDxeRevision = 0x00000000U;
+
+
+EFI_STATUS
+EFIAPI
+ProcessModuleEntryPointList (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+
+{
+ return fsw_efi_main (ImageHandle, SystemTable);
+}
+
+VOID
+EFIAPI
+ExitDriver (
+ IN EFI_STATUS Status
+ )
+{
+ if (EFI_ERROR (Status)) {
+ ProcessLibraryDestructorList (gImageHandle, gST);
+ }
+ gBS->Exit (gImageHandle, Status, 0, NULL);
+}
+
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gDriverUnloadImageCount = 0U;
+
+EFI_STATUS
+EFIAPI
+ProcessModuleUnloadList (
+ IN EFI_HANDLE ImageHandle
+ )
+{
+ return EFI_SUCCESS;
+}
--- /dev/null
+/**
+ DO NOT EDIT
+ FILE auto-generated
+ Module name:
+ AutoGen.h
+ Abstract: Auto-generated AutoGen.h for building module or library.
+**/
+
+#ifndef _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+#define _AUTOGENH_B34E5765_2E02_4DAF_867F_7F40BE6FC33D
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/PcdLib.h>
+
+// Definition of PCDs used in this module
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultLang 18U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultLang_SIZE 5
+#define _PCD_VALUE_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang[5];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUefiVariableDefaultPlatformLang 19U
+#define _PCD_PATCHABLE_PcdUefiVariableDefaultPlatformLang_SIZE 7
+#define _PCD_VALUE_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+extern const UINT8 _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang[7];
+#define _PCD_GET_MODE_PTR_PcdUefiVariableDefaultPlatformLang _gPcd_FixedAtBuild_PcdUefiVariableDefaultPlatformLang
+//#define _PCD_SET_MODE_PTR_PcdUefiVariableDefaultPlatformLang ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+// Definition of PCDs used in libraries is in AutoGen.c
+
+
+EFI_STATUS
+EFIAPI
+fsw_efi_main (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+# Doxyfile 1.4.7
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = "File System Wrapper"
+PROJECT_NUMBER = 0.1
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+BUILTIN_STL_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+#INPUT = /Users/chrisp/efi_toolkit/refit/fsw
+INPUT = .
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = YES
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = HOST_EFI HOST_POSIX
+EXPAND_AS_DEFINED = VOLSTRUCTNAME \
+ DNODESTRUCTNAME
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = NO
+CALLER_GRAPH = NO
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH = /Applications/Graphviz.app/Contents/MacOS
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = YES
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
--- /dev/null
+The below was written by Christoph Phisterer with respect to his original
+code. Since then, Oracle and the Clover team have modified the original
+files, and added the HFS+ driver, which bears Oracle and Apple copyrights
+and is released under terms of the GNU GPL.
+
+ File System Wrapper License
+=============================
+
+The various parts of the File System Wrapper source code come from
+different sources and may carry different licenses. Here's a quick
+account of the situation:
+
+ * The core code was written from scratch and is covered by a
+ BSD-style license.
+
+ * The EFI host driver was written from scratch, possibly using code
+ from the TianoCore project and Intel's EFI Application Toolkit. It
+ is covered by a BSD-style license.
+
+ * The ext2 and reiserfs file system drivers use definitions from the
+ Linux kernel source. The actual code was written from scratch,
+ using multiple sources for reference. These drivers are covered by
+ the GNU GPL.
+
+For more details, see each file's boilerplate comment. The full text
+of the GNU GPL is in the file LICENSE_GPL.txt.
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+#
+# filesystems/Make.common
+# Build control file for rEFInd's EFI filesystem drivers
+#
+
+SRCDIR = .
+
+VPATH = $(SRCDIR)
+
+HOSTARCH = $(shell uname -m | sed s,i[3456789]86,ia32,)
+ARCH := $(HOSTARCH)
+
+ifeq ($(ARCH),ia32)
+ ARCHDIR = Ia32
+ FILENAME_CODE = ia32
+endif
+
+ifeq ($(ARCH),x86_64)
+ ARCH_C_FLAGS = "-DEFIAPI=__attribute__((ms_abi))" -mcmodel=large
+ ARCHDIR = X64
+ FILENAME_CODE = x64
+endif
+
+EDK2BASE = /usr/local/UDK2010/MyWorkSpace
+
+# Below file defines TARGET (RELEASE or DEBUG), TARGET_ARCH (X64 or IA32), and TOOL_CHAIN_TAG (GCC45, GCC46, or GCC47)
+include $(EDK2BASE)/Conf/target.txt
+
+EFIINC = $(EDK2BASE)/MdePkg/Include/
+EFILIB = $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library
+ALL_EFILIBS = $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib/OUTPUT/BaseDebugPrintErrorLevelLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BasePrintLib/BasePrintLib/OUTPUT/BasePrintLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BasePcdLibNull/BasePcdLibNull/OUTPUT/BasePcdLibNull.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut/OUTPUT/UefiDebugLibConOut.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseLib/BaseLib/OUTPUT/BaseLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/BaseMemoryLib/BaseMemoryLib/OUTPUT/BaseMemoryLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib/OUTPUT/UefiBootServicesTableLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib/OUTPUT/UefiMemoryAllocationLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib/OUTPUT/UefiDevicePathLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib/OUTPUT/UefiRuntimeServicesTableLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiLib/UefiLib/OUTPUT/UefiLib.lib \
+ $(EDK2BASE)/Build/MdeModule/$(TARGET)_$(TOOL_CHAIN_TAG)/$(TARGET_ARCH)/MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint/OUTPUT/UefiDriverEntryPoint.lib
+
+OS = $(shell uname -s)
+CPPFLAGS = -I$(EFIINC) -I$(EFIINC)/$(ARCH) -I$(EFIINC)/Protocol -I$(EFIINC)/$(ARCHDIR) -DNO_BUILTIN_VA_FUNCS
+
+INCLUDE_DIRS = -I $(EDK2BASE)/MdePkg \
+ -I $(EDK2BASE)/MdePkg/Include \
+ -I $(EDK2BASE)/MdePkg/Include/$(ARCHDIR) \
+ -I $(EDK2BASE)/IntelFrameworkModulePkg \
+ -I $(EDK2BASE)/IntelFrameworkModulePkg/Include \
+
+FSW_NAMES = fsw_efi fsw_core fsw_efi_lib fsw_lib AutoGen
+OBJS = $(FSW_NAMES:=.o)
+#DRIVERNAME = ext2
+BUILDME = $(DRIVERNAME)_$(FILENAME_CODE).efi
+
+OPTIMFLAGS = -fno-strict-aliasing -mno-red-zone -Wno-address -Os
+#OPTIMFLAGS = -fno-strict-aliasing -mno-red-zone -Wno-address -mcmodel=large -Os
+DEBUGFLAGS = -Wall -Werror -Wno-missing-braces -Wno-array-bounds -ffunction-sections -fdata-sections -c -include AutoGen.h
+#CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -fpic -fshort-wchar $(DEBUGFLAGS)
+CFLAGS = $(ARCH3264) $(OPTIMFLAGS) -g -fshort-wchar -fno-stack-protector $(DEBUGFLAGS)
+ASFLAGS = $(ARCH3264)
+LDFLAGS = -nostdlib -znocombreloc -dp --entry=fsw_efi_main
+
+prefix = /usr/bin/
+CC = $(prefix)gcc
+AS = $(prefix)as
+LD = $(prefix)ld
+AR = $(prefix)ar
+RANLIB = $(prefix)ranlib
+OBJCOPY = $(prefix)objcopy
+GENFW = $(EDK2BASE)/BaseTools/BinWrappers/PosixLike/GenFw
+
+ifeq ($(ARCH),ia64)
+ # EFI specs allows only lower floating point partition to be used
+ CFLAGS += -frename-registers -mfixed-range=f32-f127
+endif
+
+ifeq ($(ARCH),x86_64)
+# CFLAGS += -DEFI_FUNCTION_WRAPPER
+# CPPFLAGS += -DEFIX64
+
+ ARCH3264 = -m64
+endif
+
+ifeq ($(ARCH),ia32)
+# CPPFLAGS += -DEFI32
+
+ ARCH3264 = -m32
+
+endif
+
+
+LDSCRIPT = $(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script
+
+LDFLAGS = -nostdlib -n -q --gc-sections --script=$(EDK2BASE)/BaseTools/Scripts/gcc4.4-ld-script \
+ --entry _ModuleEntryPoint -u _ModuleEntryPoint
+LIBS = $(shell $(CC) $(ARCH3264) -print-libgcc-file-name)
+
+%.o: %.c
+ $(CC) $(CPPFLAGS) $(ARCH_C_FLAGS) $(CFLAGS) $(INCLUDE_DIRS) -DFSTYPE=$(DRIVERNAME) -c $< -o $@
+
+FORMAT = efi-bsdrv-$(ARCH)
+
+
+ifneq (,$(filter %.efi,$(BUILDME)))
+
+SHLIB_TARGET = $(subst .efi,.lib,$(BUILDME))
+DLL_TARGET = $(subst .efi,.dll,$(BUILDME))
+
+all: $(BUILDME)
+
+$(DLL_TARGET): $(OBJS) fsw_$(DRIVERNAME).o
+ $(LD) -o $(DRIVERNAME)_$(FILENAME_CODE).dll $(LDFLAGS) --start-group $(ALL_EFILIBS) $(OBJS) fsw_$(DRIVERNAME).o --end-group
+
+$(BUILDME): $(DLL_TARGET)
+ $(OBJCOPY) --strip-unneeded $(DLL_TARGET)
+ $(OBJCOPY) $(DLL_TARGET)
+ $(GENFW) -e UEFI_DRIVER -o $(BUILDME) $(DLL_TARGET)
+ mkdir -p ../fs-drivers
+ cp $(BUILDME) ../fs-drivers
+# $(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+# -j .rela -j .reloc --target=$(FORMAT) $< $@
+
+endif
+
+# rules for libraries
+
+ifneq (,$(filter %.a,$(BUILDME)))
+
+endif
+
+# utility rules
+
+clean:
+ rm -f $(BUILDME) *~ *.so $(OBJS) *.efi *.lib *.dll
+
+
+
+# EOF
--- /dev/null
+# meta-Makefile for rEFInd filesystem drivers
+#
+# Most of the functionality is in Make.common; this Makefile merely
+# deletes critical temporary files and calls Make.common with the
+# name of the driver to be built. This is done because of a dependency
+# in the fsw_efi.c file on the filesystem type; this file must be
+# recompiled for each new filesystem built.
+
+INSTALL_DIR = /boot/efi/EFI/refind/drivers
+
+all: ext2fs reiserfs iso9660 hfs
+
+ext2fs:
+ rm -f fsw_efi.o
+ make DRIVERNAME=ext2 -f Make.common
+
+reiserfs:
+ rm -f fsw_efi.o
+ make DRIVERNAME=reiserfs -f Make.common
+
+iso9660:
+ rm -f fsw_efi.o
+ make DRIVERNAME=iso9660 -f Make.common
+
+hfs:
+ rm -f fsw_efi.o
+ make DRIVERNAME=hfs -f Make.common
+
+# utility rules
+
+clean:
+ rm -f *~ *.so *.o *.efi *.dll err.txt ext2*.txt hfs*.txt iso9660*.txt reiserfs*.txt
+
+
+install:
+ mkdir -p $(INSTALL_DIR)
+ cp *.efi $(INSTALL_DIR)
+
+# DO NOT DELETE
--- /dev/null
+/* $Id: VBoxFswParam.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * VBoxFswParam.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBOXFSPARAM_H
+#define VBOXFSPARAM_H
+/*
+ * Here is common declarations for EDK<->EDK2 compatibility
+ */
+# include <Base.h>
+# include <Uefi.h>
+# include <Library/DebugLib.h>
+# include <Library/BaseLib.h>
+# include <Protocol/DriverBinding.h>
+# include <Library/BaseMemoryLib.h>
+# include <Library/UefiRuntimeServicesTableLib.h>
+# include <Library/UefiDriverEntryPoint.h>
+# include <Library/UefiBootServicesTableLib.h>
+# include <Library/MemoryAllocationLib.h>
+# include <Library/DevicePathLib.h>
+# include <Protocol/DevicePathFromText.h>
+# include <Protocol/DevicePathToText.h>
+# include <Protocol/DebugPort.h>
+# include <Protocol/DebugSupport.h>
+# include <Library/PrintLib.h>
+# include <Library/UefiLib.h>
+# include <Protocol/SimpleFileSystem.h>
+# include <Protocol/BlockIo.h>
+# include <Protocol/DiskIo.h>
+# include <Guid/FileSystemInfo.h>
+# include <Guid/FileInfo.h>
+# include <Guid/FileSystemVolumeLabelInfo.h>
+# include <Protocol/ComponentName.h>
+
+# define BS gBS
+# define PROTO_NAME(x) gEfi ## x ## Guid
+# define GUID_NAME(x) gEfi ## x ## Guid
+
+# define EFI_FILE_HANDLE_REVISION EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
+# define SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_FILE_SYSTEM_VOLUME_LABEL_INFO EFI_FILE_SYSTEM_VOLUME_LABEL
+# define EFI_SIGNATURE_32(a, b, c, d) SIGNATURE_32(a, b, c, d)
+# define DivU64x32(x,y,z) DivU64x32((x),(y))
+
+
+INTN CompareGuidEdk1(
+ IN EFI_GUID *Guid1,
+ IN EFI_GUID *Guid2
+ );
+
+//#define CompareGuid(x, y) CompareGuidEdk1((x),(y))
+# define HOST_EFI 1
+//# define FSW_DEBUG_LEVEL 3
+
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len);
+#endif
--- /dev/null
+/*
+ * \file design.dox
+ * Documentation title page with design information
+ */
+
+
+/**
+\mainpage File System Wrapper Documentation
+
+Welcome to the documentation for FSW. This doxygen-generated documentation
+is intended for developers that either want to integrate FSW into their
+own project or want to write additional file system drivers.
+
+\section goals Design Goals
+
+File System Wrapper wants to provide reusable, read-only file system drivers
+for a range of common file systems. Reusability is achieved through a common
+abstraction layer (called the "core"), which serves as the API for the host
+environment driver. Once the required glue code is written for a host
+environment, that host has access to all file system types implemented by FSW,
+with no code to be written per file system type.
+
+Why read-only? There are a range of reasons why FSW only provides read-only
+access:
+
+- Read-only drivers are much easier to write than read-write drivers.
+- Write access isn't easily abstracted in an OS-independent way because
+ of more delicate buffer I/O handling requirements and features like
+ journalling.
+- There is no risk of destroying data on the disk.
+- Having read access is much better than having no access at all.
+ (Read-only drivers for several file systems can be written in the time
+ it would take to develop a read-write driver for just one file system.)
+- Boot loaders only need read access in most cases.
+
+\section model Object and Data Model
+
+\subsection main_objects Main Objects
+
+There are three main "objects" that FSW works with: volume, dnode, and shandle.
+
+The fsw_volume structure keeps the information that applies to a file
+system volume as a whole. Most importantly, it keeps pointers to the host driver
+and file system driver dispatch tables, which are used by the core to call
+the appropriate functions.
+
+The fsw_dnode structure represents a "directory node", that is any file-like
+object in the file system: regular files, directories, symbolic links as well
+as special files like device nodes. When compared with Unix-style file systems,
+a dnode is very similar to an inode, but it retains some essential information
+from the directory: the canonical name and the parent directory. FSW requires that
+a dnode is uniquely identified by an integer number (currently 32 bit in size).
+Inode numbers can be used for this purpose, non-Unix file systems will have to
+come up with a unique number in some way.
+
+The fsw_shandle structure is used to access file data ("storage handle").
+A dnode only represents the file as such and doesn't offer access to its data.
+An shandle is linked to a certain dnode, but there may be several shandles per
+dnode. The shandle stores a file position pointer (byte offset) that can be changed
+at will. With the current design, an shandle is also used for directory iteration,
+even if the file system stores directory information in a central tree structure.
+
+\subsection disk_access Disk Data Access
+
+Data on the disk is accessed in blocks, addressed by a sequential number starting
+at zero. The block size to use can be set by the file system driver. FSW supports
+two separate block sizes: the "physical block size" is used when accessing the disk,
+the "logical block size" is used when accessing a file's data. For most file
+systems, these two are identical, but there may be some where the file allocation
+block size is larger than the sector or block size used to store metadata. (FAT
+comes to mind as an example.)
+
+For accessing the actual file data, the file system driver doesn't handle the
+disk I/O, but merely returns information about the mapping from file logical
+blocks to disk physical blocks in the fsw_extent structure. This allows host OS
+buffer mechanisms to be used for file data. In special cases, like tail-packing,
+fragments or compressed file systems, the file system driver can return file data
+in an allocated buffer.
+
+\subsection data_hooks Data Extension Hooks
+
+File system specific data can be stored by extending the fsw_volume and fsw_dnode
+structures. The core code uses the structure sizes stored in the fsw_fstype_table
+to allocate memory for these structures. The fsw_shandle and fsw_extent structures
+are not designed to be extended.
+
+Host specific data must be stored in separate structures private to the host
+environment driver. The fsw_volume structure provides a host_data variable to
+store a pointer. The fsw_dnode structure has no such field, because it is assumed
+that all actions regarding dnodes are initiated on the host side and so the
+host-specific private structure is known.
+
+\section callconv Calling Conventions
+
+All functions that can fail return a status code in a fsw_status_t. This type is an
+integer. A boolean test yields true if there was an error and false if the function
+executed successfully, i.e. success is signalled by a 0 return value.
+
+Functions that return data do so either by filling a structure passed in by the caller,
+or by allocating a structure on the heap and returning a pointer through a
+double-indirect parameter. A returned object pointer is the last parameter in the
+parameter list.
+
+(More to be written about specific conventions for dnodes, shandles, strings.)
+
+*/
--- /dev/null
+/* $Id: fsw_base.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_base.h - Base definitions switch.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_BASE_H_
+#define _FSW_BASE_H_
+//#define HOST_EFI 1
+#define VBOX
+
+#ifdef VBOX
+#include "VBoxFswParam.h"
+#endif
+
+//#include <Protocol/MsgLog.h>
+
+#ifndef FSW_DEBUG_LEVEL
+/**
+ * Global debugging level. Can be set locally for the scope of a single
+ * file by defining the macro before fsw_base.h is included.
+ */
+#define FSW_DEBUG_LEVEL 0
+#endif
+
+
+#ifdef HOST_EFI
+#include "fsw_efi_base.h"
+#endif
+
+#ifdef HOST_POSIX
+#include "fsw_posix_base.h"
+#endif
+
+// message printing
+
+#if FSW_DEBUG_LEVEL >= 1
+#define FSW_MSG_ASSERT(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_ASSERT(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 2
+#define FSW_MSG_DEBUG(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUG(params)
+#endif
+
+#if FSW_DEBUG_LEVEL >= 3
+#define FSW_MSG_DEBUGV(params) FSW_MSGFUNC params
+#else
+#define FSW_MSG_DEBUGV(params)
+#endif
+
+
+// Documentation for system-dependent defines
+
+/**
+ * \typedef fsw_s8
+ * Signed 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_u8
+ * Unsigned 8-bit integer.
+ */
+
+/**
+ * \typedef fsw_s16
+ * Signed 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_u16
+ * Unsigned 16-bit integer.
+ */
+
+/**
+ * \typedef fsw_s32
+ * Signed 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_u32
+ * Unsigned 32-bit integer.
+ */
+
+/**
+ * \typedef fsw_s64
+ * Signed 64-bit integer.
+ */
+
+/**
+ * \typedef fsw_u64
+ * Unsigned 64-bit integer.
+ */
+
+
+/**
+ * \def fsw_alloc(size,ptrptr)
+ * Allocate memory on the heap. This function or macro allocates \a size
+ * bytes of memory using host-specific methods. The address of the
+ * allocated memory block is stored into the pointer variable pointed
+ * to by \a ptrptr. A status code is returned; FSW_SUCCESS if the block
+ * was allocated or FSW_OUT_OF_MEMORY if there is not enough memory
+ * to allocated the requested block.
+ */
+
+/**
+ * \def fsw_free(ptr)
+ * Release allocated memory. This function or macro returns an allocated
+ * memory block to the heap for reuse. Does not return a status.
+ */
+
+/**
+ * \def fsw_memcpy(dest,src,size)
+ * Copies a block of memory from \a src to \a dest. The two memory blocks
+ * must not overlap, or the result of the operation will be undefined.
+ * Does not return a status.
+ */
+
+/**
+ * \def fsw_memeq(dest,src,size)
+ * Compares two blocks of memory for equality. Returns boolean true if the
+ * memory blocks are equal, boolean false if they are different.
+ */
+
+/**
+ * \def fsw_memzero(dest,size)
+ * Initializes a block of memory with zeros. Does not return a status.
+ */
+
+
+#endif
--- /dev/null
+/* $Id: fsw_core.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_core.c - Core file system wrapper abstraction layer code.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+
+// functions
+
+static void fsw_blockcache_free(struct fsw_volume *vol);
+
+#define MAX_CACHE_LEVEL (5)
+
+
+/**
+ * Mount a volume with a given file system driver. This function is called by the
+ * host driver to make a volume accessible. The file system driver to use is specified
+ * by a pointer to its dispatch table. The file system driver will look at the
+ * data on the volume to determine if it can read the format. If the volume is found
+ * unsuitable, FSW_UNSUPPORTED is returned.
+ *
+ * If this function returns FSW_SUCCESS, *vol_out points at a valid volume data
+ * structure. The caller must release it later by calling fsw_unmount.
+ *
+ * If this function returns an error status, the caller only needs to clean up its
+ * own buffers that may have been allocated through the read_block interface.
+ */
+
+fsw_status_t fsw_mount(void *host_data,
+ struct fsw_host_table *host_table,
+ struct fsw_fstype_table *fstype_table,
+ struct fsw_volume **vol_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol;
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(fstype_table->volume_struct_size, (void **)&vol);
+ if (status)
+ return status;
+
+ // initialize fields
+ vol->phys_blocksize = 512;
+ vol->log_blocksize = 512;
+ vol->label.type = FSW_STRING_TYPE_EMPTY;
+ vol->host_data = host_data;
+ vol->host_table = host_table;
+ vol->fstype_table = fstype_table;
+ vol->host_string_type = host_table->native_string_type;
+
+ // let the fs driver mount the file system
+ status = vol->fstype_table->volume_mount(vol);
+ if (status)
+ goto errorexit;
+
+ // TODO: anything else?
+
+ *vol_out = vol;
+ return FSW_SUCCESS;
+
+errorexit:
+ fsw_unmount(vol);
+ return status;
+}
+
+/**
+ * Unmount a volume by releasing all memory associated with it. This function is
+ * called by the host driver when a volume is no longer needed. It is also called
+ * by the core after a failed mount to clean up any allocated memory.
+ *
+ * Note that all dnodes must have been released before calling this function.
+ */
+
+void fsw_unmount(struct fsw_volume *vol)
+{
+ if (vol->root)
+ fsw_dnode_release(vol->root);
+ // TODO: check that no other dnodes are still around
+
+ vol->fstype_table->volume_free(vol);
+
+ fsw_blockcache_free(vol);
+ fsw_strfree(&vol->label);
+ fsw_free(vol);
+}
+
+/**
+ * Get in-depth information on the volume. This function can be called by the host
+ * driver to get additional information on the volume.
+ */
+
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb)
+{
+ return vol->fstype_table->volume_stat(vol, sb);
+}
+
+/**
+ * Set the physical and logical block sizes of the volume. This functions is called by
+ * the file system driver to announce the block sizes it wants to use for accessing
+ * the disk (physical) and for addressing file contents (logical).
+ * Usually both sizes will be the same but there may be file systems that need to access
+ * metadata at a smaller block size than the allocation unit for files.
+ *
+ * Calling this function causes the block cache to be dropped. All pointers returned
+ * from fsw_block_get become invalid. This function should only be called while
+ * mounting the file system, not as a part of file access operations.
+ *
+ * Both sizes are measured in bytes, must be powers of 2, and must not be smaller
+ * than 512 bytes. The logical block size cannot be smaller than the physical block size.
+ */
+
+void fsw_set_blocksize(struct fsw_volume *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize)
+{
+ // TODO: Check the sizes. Both must be powers of 2. log_blocksize must not be smaller than
+ // phys_blocksize.
+
+ // drop core block cache if present
+ fsw_blockcache_free(vol);
+
+ // signal host driver to drop caches etc.
+ vol->host_table->change_blocksize(vol,
+ vol->phys_blocksize, vol->log_blocksize,
+ phys_blocksize, log_blocksize);
+
+ vol->phys_blocksize = phys_blocksize;
+ vol->log_blocksize = log_blocksize;
+}
+
+/**
+ * Get a block of data from the disk. This function is called by the file system driver
+ * or by core functions. It calls through to the host driver's device access routine.
+ * Given a physical block number, it reads the block into memory (or fetches it from the
+ * block cache) and returns the address of the memory buffer. The caller should provide
+ * an indication of how important the block is in the cache_level parameter. Blocks with
+ * a low level are purged first. Some suggestions for cache levels:
+ *
+ * - 0: File data
+ * - 1: Directory data, symlink data
+ * - 2: File system metadata
+ * - 3..5: File system metadata with a high rate of access
+ *
+ * If this function returns successfully, the returned data pointer is valid until the
+ * caller calls fsw_block_release.
+ */
+
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out)
+{
+ fsw_status_t status;
+ fsw_u32 i, discard_level, new_bcache_size;
+ struct fsw_blockcache *new_bcache;
+
+ // TODO: allow the host driver to do its own caching; just call through if
+ // the appropriate function pointers are set
+
+ if (cache_level > MAX_CACHE_LEVEL)
+ cache_level = MAX_CACHE_LEVEL;
+
+ // check block cache
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == phys_bno) {
+ // cache hit!
+ if (vol->bcache[i].cache_level < cache_level)
+ vol->bcache[i].cache_level = cache_level; // promote the entry
+ vol->bcache[i].refcount++;
+ *buffer_out = vol->bcache[i].data;
+ return FSW_SUCCESS;
+ }
+ }
+
+ // find a free entry in the cache table
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == (fsw_u32)FSW_INVALID_BNO)
+ break;
+ }
+ if (i >= vol->bcache_size) {
+ for (discard_level = 0; discard_level <= MAX_CACHE_LEVEL; discard_level++) {
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].refcount == 0 && vol->bcache[i].cache_level <= discard_level)
+ break;
+ }
+ if (i < vol->bcache_size)
+ break;
+ }
+ }
+ if (i >= vol->bcache_size) {
+ // enlarge / create the cache
+ if (vol->bcache_size < 16)
+ new_bcache_size = 16;
+ else
+ new_bcache_size = vol->bcache_size << 1;
+ status = fsw_alloc(new_bcache_size * sizeof(struct fsw_blockcache), &new_bcache);
+ if (status)
+ return status;
+ if (vol->bcache_size > 0)
+ fsw_memcpy(new_bcache, vol->bcache, vol->bcache_size * sizeof(struct fsw_blockcache));
+ for (i = vol->bcache_size; i < new_bcache_size; i++) {
+ new_bcache[i].refcount = 0;
+ new_bcache[i].cache_level = 0;
+ new_bcache[i].phys_bno = (fsw_u32)FSW_INVALID_BNO;
+ new_bcache[i].data = NULL;
+ }
+ i = vol->bcache_size;
+
+ // switch caches
+ if (vol->bcache != NULL)
+ fsw_free(vol->bcache);
+ vol->bcache = new_bcache;
+ vol->bcache_size = new_bcache_size;
+ }
+ vol->bcache[i].phys_bno = (fsw_u32)FSW_INVALID_BNO;
+
+ // read the data
+ if (vol->bcache[i].data == NULL) {
+ status = fsw_alloc(vol->phys_blocksize, &vol->bcache[i].data);
+ if (status)
+ return status;
+ }
+ status = vol->host_table->read_block(vol, phys_bno, vol->bcache[i].data);
+ if (status)
+ return status;
+
+ vol->bcache[i].phys_bno = phys_bno;
+ vol->bcache[i].cache_level = cache_level;
+ vol->bcache[i].refcount = 1;
+ *buffer_out = vol->bcache[i].data;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Releases a disk block. This function must be called to release disk blocks returned
+ * from fsw_block_get.
+ */
+
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer)
+{
+ fsw_u32 i;
+
+ // TODO: allow the host driver to do its own caching; just call through if
+ // the appropriate function pointers are set
+
+ // update block cache
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].phys_bno == phys_bno && vol->bcache[i].refcount > 0)
+ vol->bcache[i].refcount--;
+ }
+}
+
+/**
+ * Release the block cache. Called internally when changing block sizes and when
+ * unmounting the volume. It frees all data occupied by the generic block cache.
+ */
+
+static void fsw_blockcache_free(struct fsw_volume *vol)
+{
+ fsw_u32 i;
+
+ for (i = 0; i < vol->bcache_size; i++) {
+ if (vol->bcache[i].data != NULL)
+ fsw_free(vol->bcache[i].data);
+ }
+ if (vol->bcache != NULL) {
+ fsw_free(vol->bcache);
+ vol->bcache = NULL;
+ }
+ vol->bcache_size = 0;
+}
+
+/**
+ * Add a new dnode to the list of known dnodes. This internal function is used when a
+ * dnode is created to add it to the dnode list that is used to search for existing
+ * dnodes by id.
+ */
+
+static void fsw_dnode_register(struct fsw_volume *vol, struct fsw_dnode *dno)
+{
+ dno->next = vol->dnode_head;
+ if (vol->dnode_head != NULL)
+ vol->dnode_head->prev = dno;
+ dno->prev = NULL;
+ vol->dnode_head = dno;
+}
+
+/**
+ * Create a dnode representing the root directory. This function is called by the file system
+ * driver while mounting the file system. The root directory is special because it has no parent
+ * dnode, its name is defined to be empty, and its type is also fixed. Otherwise, this functions
+ * behaves in the same way as fsw_dnode_create.
+ */
+
+fsw_status_t fsw_dnode_create_root(struct fsw_volume *vol, fsw_u32 dnode_id, struct fsw_dnode **dno_out)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+ if (status)
+ return status;
+
+ // fill the structure
+ dno->vol = vol;
+ dno->parent = NULL;
+ dno->dnode_id = dnode_id;
+ dno->type = FSW_DNODE_TYPE_DIR;
+ dno->refcount = 1;
+ dno->name.type = FSW_STRING_TYPE_EMPTY;
+ // TODO: instead, call a function to create an empty string in the native string type
+
+ fsw_dnode_register(vol, dno);
+
+ *dno_out = dno;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Create a new dnode representing a file system object. This function is called by
+ * the file system driver in response to directory lookup or read requests. Note that
+ * if there already is a dnode with the given dnode_id on record, then no new object
+ * is created. Instead, the existing dnode is returned and its reference count
+ * increased. All other parameters are ignored in this case.
+ *
+ * The type passed into this function may be FSW_DNODE_TYPE_UNKNOWN. It is sufficient
+ * to fill the type field during the dnode_fill call.
+ *
+ * The name parameter must describe a string with the object's name. A copy will be
+ * stored in the dnode structure for future reference. The name will not be used to
+ * shortcut directory lookups, but may be used to reconstruct paths.
+ *
+ * If the function returns successfully, *dno_out contains a pointer to the dnode
+ * that must be released by the caller with fsw_dnode_release.
+ */
+
+fsw_status_t fsw_dnode_create(struct fsw_dnode *parent_dno, fsw_u32 dnode_id, int type,
+ struct fsw_string *name, struct fsw_dnode **dno_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = parent_dno->vol;
+ struct fsw_dnode *dno;
+
+ // check if we already have a dnode with the same id
+ for (dno = vol->dnode_head; dno; dno = dno->next) {
+ if (dno->dnode_id == dnode_id) {
+ fsw_dnode_retain(dno);
+ *dno_out = dno;
+ return FSW_SUCCESS;
+ }
+ }
+
+ // allocate memory for the structure
+ status = fsw_alloc_zero(vol->fstype_table->dnode_struct_size, (void **)&dno);
+ if (status)
+ return status;
+
+ // fill the structure
+ dno->vol = vol;
+ dno->parent = parent_dno;
+ fsw_dnode_retain(dno->parent);
+ dno->dnode_id = dnode_id;
+ dno->type = type;
+ dno->refcount = 1;
+ status = fsw_strdup_coerce(&dno->name, vol->host_table->native_string_type, name);
+ if (status) {
+ fsw_free(dno);
+ return status;
+ }
+
+ fsw_dnode_register(vol, dno);
+
+ *dno_out = dno;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Increases the reference count of a dnode. This must be balanced with
+ * fsw_dnode_release calls. Note that some dnode functions return a retained
+ * dnode pointer to their caller.
+ */
+
+void fsw_dnode_retain(struct fsw_dnode *dno)
+{
+ dno->refcount++;
+}
+
+/**
+ * Release a dnode pointer, deallocating it if this was the last reference.
+ * This function decrements the reference counter of the dnode. If the counter
+ * reaches zero, the dnode is freed. Since the parent dnode is released
+ * during that process, this function may cause it to be freed, too.
+ */
+
+void fsw_dnode_release(struct fsw_dnode *dno)
+{
+ struct fsw_volume *vol = dno->vol;
+ struct fsw_dnode *parent_dno;
+
+ dno->refcount--;
+
+ if (dno->refcount == 0) {
+ parent_dno = dno->parent;
+
+ // de-register from volume's list
+ if (dno->next)
+ dno->next->prev = dno->prev;
+ if (dno->prev)
+ dno->prev->next = dno->next;
+ if (vol->dnode_head == dno)
+ vol->dnode_head = dno->next;
+
+ // run fstype-specific cleanup
+ vol->fstype_table->dnode_free(vol, dno);
+
+ fsw_strfree(&dno->name);
+ fsw_free(dno);
+
+ // release our pointer to the parent, possibly deallocating it, too
+ if (parent_dno)
+ fsw_dnode_release(parent_dno);
+ }
+}
+
+/**
+ * Get full information about a dnode from disk. This function is called by the host
+ * driver as well as by the core functions. Some file systems defer reading full
+ * information on a dnode until it is actually needed (i.e. separation between
+ * directory and inode information). This function makes sure that all information
+ * is available in the dnode structure. The following fields may not have a correct
+ * value until fsw_dnode_fill has been called:
+ *
+ * type, size
+ */
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno)
+{
+ // TODO: check a flag right here, call fstype's dnode_fill only once per dnode
+
+ return dno->vol->fstype_table->dnode_fill(dno->vol, dno);
+}
+
+/**
+ * Get extended information about a dnode. This function can be called by the host
+ * driver to get a full compliment of information about a dnode in addition to the
+ * fields of the fsw_dnode structure itself.
+ *
+ * Some data requires host-specific conversion to be useful (i.e. timestamps) and
+ * will be passed to callback functions instead of being written into the structure.
+ * These callbacks must be filled in by the caller.
+ */
+
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+
+ sb->used_bytes = 0;
+ status = dno->vol->fstype_table->dnode_stat(dno->vol, dno, sb);
+ if (!status && !sb->used_bytes)
+ sb->used_bytes = FSW_U64_DIV(dno->size + dno->vol->log_blocksize - 1, dno->vol->log_blocksize);
+ return status;
+}
+
+/**
+ * Lookup a directory entry by name. This function is called by the host driver.
+ * Given a directory dnode and a file name, it looks up the named entry in the
+ * directory.
+ *
+ * If the dnode is not a directory, the call will fail. The caller is responsible for
+ * resolving symbolic links before calling this function.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+ if (dno->type != FSW_DNODE_TYPE_DIR)
+ return FSW_UNSUPPORTED;
+
+ return dno->vol->fstype_table->dir_lookup(dno->vol, dno, lookup_name, child_dno_out);
+}
+
+/**
+ * Find a file system object by path. This function is called by the host driver.
+ * Given a directory dnode and a relative or absolute path, it walks the directory
+ * tree until it finds the target dnode. If an intermediate node turns out to be
+ * a symlink, it is resolved automatically. If the target node is a symlink, it
+ * is not resolved.
+ *
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the requested directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+ struct fsw_string *lookup_path, char separator,
+ struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = dno->vol;
+ struct fsw_dnode *child_dno = NULL;
+ struct fsw_string lookup_name;
+ struct fsw_string remaining_path;
+ int root_if_empty;
+
+ remaining_path = *lookup_path;
+ fsw_dnode_retain(dno);
+
+ // loop over the path
+ for (root_if_empty = 1; fsw_strlen(&remaining_path) > 0; root_if_empty = 0) {
+ // parse next path component
+ fsw_strsplit(&lookup_name, &remaining_path, separator);
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: split into %d '%s' and %d '%s'\n"),
+ lookup_name.len, lookup_name.data,
+ remaining_path.len, remaining_path.data));
+
+ if (fsw_strlen(&lookup_name) == 0) { // empty path component
+ if (root_if_empty)
+ child_dno = vol->root;
+ else
+ child_dno = dno;
+ fsw_dnode_retain(child_dno);
+
+ } else {
+ // do an actual directory lookup
+
+ // ensure we have full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+
+ // resolve symlink if necessary
+ if (dno->type == FSW_DNODE_TYPE_SYMLINK) {
+ status = fsw_dnode_resolve(dno, &child_dno);
+ if (status)
+ goto errorexit;
+
+ // symlink target becomes the new dno
+ fsw_dnode_release(dno);
+ dno = child_dno; // is already retained
+ child_dno = NULL;
+
+ // ensure we have full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+ }
+
+ // make sure we operate on a directory
+ if (dno->type != FSW_DNODE_TYPE_DIR) {
+ return FSW_UNSUPPORTED;
+ goto errorexit;
+ }
+
+ // check special paths
+ if (fsw_streq_cstr(&lookup_name, ".")) { // self directory
+ child_dno = dno;
+ fsw_dnode_retain(child_dno);
+
+ } else if (fsw_streq_cstr(&lookup_name, "..")) { // parent directory
+ if (dno->parent == NULL) {
+ // We cannot go up from the root directory. Caution: Certain apps like the EFI shell
+ // rely on this behaviour!
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+ child_dno = dno->parent;
+ fsw_dnode_retain(child_dno);
+
+ } else {
+ // do an actual lookup
+ status = vol->fstype_table->dir_lookup(vol, dno, &lookup_name, &child_dno);
+ if (status)
+ goto errorexit;
+ }
+ }
+
+ // child_dno becomes the new dno
+ fsw_dnode_release(dno);
+ dno = child_dno; // is already retained
+ child_dno = NULL;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: now at inode %d\n"), dno->dnode_id));
+ }
+
+ *child_dno_out = dno;
+ return FSW_SUCCESS;
+
+errorexit:
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_dnode_lookup_path: leaving with error %d\n"), status));
+ fsw_dnode_release(dno);
+ if (child_dno != NULL)
+ fsw_dnode_release(child_dno);
+ return status;
+}
+
+/**
+ * Get the next directory item in sequential order. This function is called by the
+ * host driver to read the complete contents of a directory in sequential (file system
+ * defined) order. Calling this function returns the next entry. Iteration state is
+ * kept by a shandle on the directory's dnode. The caller must set up the shandle
+ * when starting the iteration.
+ *
+ * When the end of the directory is reached, this function returns FSW_NOT_FOUND.
+ * If the function returns FSW_SUCCESS, *child_dno_out points to the next directory
+ * entry. The caller must call fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno = shand->dnode;
+ fsw_u64 saved_pos;
+
+ if (dno->type != FSW_DNODE_TYPE_DIR)
+ return FSW_UNSUPPORTED;
+
+ saved_pos = shand->pos;
+ status = dno->vol->fstype_table->dir_read(dno->vol, dno, shand, child_dno_out);
+ if (status)
+ shand->pos = saved_pos;
+ return status;
+}
+
+/**
+ * Read the target path of a symbolic link. This function is called by the host driver
+ * to read the "content" of a symbolic link, that is the relative or absolute path
+ * it points to.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *target_name)
+{
+ fsw_status_t status;
+
+ status = fsw_dnode_fill(dno);
+ if (status)
+ return status;
+ if (dno->type != FSW_DNODE_TYPE_SYMLINK)
+ return FSW_UNSUPPORTED;
+
+ return dno->vol->fstype_table->readlink(dno->vol, dno, target_name);
+}
+
+/**
+ * Read the target path of a symbolic link by accessing file data. This function can
+ * be called by the file system driver if the file system stores the target path
+ * as normal file data. This function will open an shandle, read the whole content
+ * of the file into a buffer, and build a string from that. Currently the encoding
+ * for the string is fixed as FSW_STRING_TYPE_ISO88591.
+ *
+ * If the function returns FSW_SUCCESS, the string handle provided by the caller is
+ * filled with a string in the host's preferred encoding. The caller is responsible
+ * for calling fsw_strfree on the string.
+ */
+
+fsw_status_t fsw_dnode_readlink_data(struct fsw_dnode *dno, struct fsw_string *link_target)
+{
+ fsw_status_t status;
+ struct fsw_shandle shand;
+ fsw_u32 buffer_size;
+ char buffer[FSW_PATH_MAX];
+
+ struct fsw_string s;
+
+ if (dno->size > FSW_PATH_MAX)
+ return FSW_VOLUME_CORRUPTED;
+
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = (int)dno->size;
+ s.data = buffer;
+
+ // open shandle and read the data
+ status = fsw_shandle_open(dno, &shand);
+ if (status)
+ return status;
+ buffer_size = (fsw_u32)s.size;
+ status = fsw_shandle_read(&shand, &buffer_size, buffer);
+ fsw_shandle_close(&shand);
+ if (status)
+ return status;
+ if ((int)buffer_size < s.size)
+ return FSW_VOLUME_CORRUPTED;
+
+ status = fsw_strdup_coerce(link_target, dno->vol->host_string_type, &s);
+ return status;
+}
+
+/**
+ * Resolve a symbolic link. This function can be called by the host driver to make
+ * sure the a dnode is fully resolved instead of pointing at a symlink. If the dnode
+ * passed in is not a symlink, it is returned unmodified.
+ *
+ * Note that absolute paths will be resolved relative to the root directory of the
+ * volume. If the host is an operating system with its own VFS layer, it should
+ * resolve symlinks on its own.
+ *
+ * If the function returns FSW_SUCCESS, *target_dno_out points at a dnode that is
+ * not a symlink. The caller is responsible for calling fsw_dnode_release on it.
+ */
+
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_string target_name;
+ struct fsw_dnode *target_dno;
+
+ fsw_dnode_retain(dno);
+
+ while (1) {
+ // get full information
+ status = fsw_dnode_fill(dno);
+ if (status)
+ goto errorexit;
+ if (dno->type != FSW_DNODE_TYPE_SYMLINK) {
+ // found a non-symlink target, return it
+ *target_dno_out = dno;
+ return FSW_SUCCESS;
+ }
+ if (dno->parent == NULL) { // safety measure, cannot happen in theory
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+
+ // read the link's target
+ status = fsw_dnode_readlink(dno, &target_name);
+ if (status)
+ goto errorexit;
+
+ // resolve it
+ status = fsw_dnode_lookup_path(dno->parent, &target_name, '/', &target_dno);
+ fsw_strfree(&target_name);
+ if (status)
+ goto errorexit;
+
+ // target_dno becomes the new dno
+ fsw_dnode_release(dno);
+ dno = target_dno; // is already retained
+ }
+
+errorexit:
+ fsw_dnode_release(dno);
+ return status;
+}
+
+/**
+ * Set up a shandle (storage handle) to access a file's data. This function is called
+ * by the host driver and by the core when they need to access a file's data. It is also
+ * used in accessing the raw data of directories and symlinks if the file system uses
+ * the same mechanisms for storing the data of those items.
+ *
+ * The storage for the fsw_shandle structure is provided by the caller. The dnode and pos
+ * fields may be accessed, pos may also be written to to set the file pointer. The file's
+ * data size is available as shand->dnode->size.
+ *
+ * If this function returns FSW_SUCCESS, the caller must call fsw_shandle_close to release
+ * the dnode reference held by the shandle.
+ */
+
+fsw_status_t fsw_shandle_open(struct fsw_dnode *dno, struct fsw_shandle *shand)
+{
+ fsw_status_t status;
+ struct fsw_volume *vol = dno->vol;
+
+ // read full dnode information into memory
+ status = vol->fstype_table->dnode_fill(vol, dno);
+ if (status)
+ return status;
+
+ // setup shandle
+ fsw_dnode_retain(dno);
+
+ shand->dnode = dno;
+ shand->pos = 0;
+ shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Close a shandle after accessing the dnode's data. This function is called by the host
+ * driver or core functions when they are finished with accessing a file's data. It
+ * releases the dnode reference and frees any buffers associated with the shandle itself.
+ * The dnode is only released if this was the last reference using it.
+ */
+
+void fsw_shandle_close(struct fsw_shandle *shand)
+{
+ if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+ fsw_free(shand->extent.buffer);
+ fsw_dnode_release(shand->dnode);
+}
+
+/**
+ * Read data from a shandle (storage handle for a dnode). This function is called by the
+ * host driver or internally when data is read from a file. TODO: more
+ */
+
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer_in)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno = shand->dnode;
+ struct fsw_volume *vol = dno->vol;
+ fsw_u8 *buffer, *block_buffer;
+ fsw_u32 buflen, copylen, pos;
+ fsw_u32 log_bno, pos_in_extent, phys_bno, pos_in_physblock;
+ fsw_u32 cache_level;
+
+ if (shand->pos >= dno->size) { // already at EOF
+ *buffer_size_inout = 0;
+ return FSW_SUCCESS;
+ }
+
+ // initialize vars
+ buffer = buffer_in;
+ buflen = *buffer_size_inout;
+ pos = (fsw_u32)shand->pos;
+ cache_level = (dno->type != FSW_DNODE_TYPE_FILE) ? 1 : 0;
+ // restrict read to file size
+ if (buflen > dno->size - pos)
+ buflen = (fsw_u32)(dno->size - pos);
+
+ while (buflen > 0) {
+ // get extent for the current logical block
+ log_bno = pos / vol->log_blocksize;
+ if (shand->extent.type == FSW_EXTENT_TYPE_INVALID ||
+ log_bno < shand->extent.log_start ||
+ log_bno >= shand->extent.log_start + shand->extent.log_count) {
+
+ if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER)
+ fsw_free(shand->extent.buffer);
+
+ // ask the file system for the proper extent
+ shand->extent.log_start = log_bno;
+ status = vol->fstype_table->get_extent(vol, dno, &shand->extent);
+ if (status) {
+ shand->extent.type = FSW_EXTENT_TYPE_INVALID;
+ return status;
+ }
+ }
+
+ pos_in_extent = pos - shand->extent.log_start * vol->log_blocksize;
+
+ // dispatch by extent type
+ if (shand->extent.type == FSW_EXTENT_TYPE_PHYSBLOCK) {
+ // convert to physical block number and offset
+ phys_bno = shand->extent.phys_start + pos_in_extent / vol->phys_blocksize;
+ pos_in_physblock = pos_in_extent & (vol->phys_blocksize - 1);
+ copylen = vol->phys_blocksize - pos_in_physblock;
+ if (copylen > buflen)
+ copylen = buflen;
+
+ // get one physical block
+ status = fsw_block_get(vol, phys_bno, cache_level, (void **)&block_buffer);
+ if (status)
+ return status;
+
+ // copy data from it
+ fsw_memcpy(buffer, block_buffer + pos_in_physblock, copylen);
+ fsw_block_release(vol, phys_bno, block_buffer);
+
+ } else if (shand->extent.type == FSW_EXTENT_TYPE_BUFFER) {
+ copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+ if (copylen > buflen)
+ copylen = buflen;
+ fsw_memcpy(buffer, (fsw_u8 *)shand->extent.buffer + pos_in_extent, copylen);
+
+ } else { // _SPARSE or _INVALID
+ copylen = shand->extent.log_count * vol->log_blocksize - pos_in_extent;
+ if (copylen > buflen)
+ copylen = buflen;
+ fsw_memzero(buffer, copylen);
+
+ }
+
+ buffer += copylen;
+ buflen -= copylen;
+ pos += copylen;
+ }
+
+ *buffer_size_inout = (fsw_u32)(pos - shand->pos);
+ shand->pos = pos;
+
+ return FSW_SUCCESS;
+}
+
+// EOF
--- /dev/null
+/* $Id: fsw_core.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_core.h - Core file system wrapper abstraction layer header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) The Regents of the University of California.
+ * Portions Copyright (c) UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_CORE_H_
+#define _FSW_CORE_H_
+
+#include "fsw_base.h"
+
+
+/** Maximum size for a path, specifically symlink target paths. */
+#ifndef VBOX
+#define FSW_PATH_MAX (4096)
+#else
+/* Too big allocations are handled with alloca() */
+#define FSW_PATH_MAX (2048)
+#endif
+
+/** Helper macro for token concatenation. */
+#define FSW_CONCAT3(a,b,c) a##b##c
+/** Expands to the name of a fstype dispatch table (fsw_fstype_table) for a named file system type. */
+#define FSW_FSTYPE_TABLE_NAME(t) FSW_CONCAT3(fsw_,t,_table)
+
+/** Indicates that the block cache entry is empty. */
+#define FSW_INVALID_BNO (~0UL)
+
+
+//
+// Byte-swapping macros
+//
+
+
+/**
+ * \name Byte Order Macros
+ * Implements big endian vs. little endian awareness and conversion.
+ */
+/*@{*/
+
+typedef fsw_u16 fsw_u16_le;
+typedef fsw_u16 fsw_u16_be;
+typedef fsw_u32 fsw_u32_le;
+typedef fsw_u32 fsw_u32_be;
+typedef fsw_u64 fsw_u64_le;
+typedef fsw_u64 fsw_u64_be;
+
+#define FSW_SWAPVALUE_U16(v) ((((fsw_u16)(v) & 0xff00) >> 8) | \
+ (((fsw_u16)(v) & 0x00ff) << 8))
+#define FSW_SWAPVALUE_U32(v) ((((fsw_u32)(v) & 0xff000000UL) >> 24) | \
+ (((fsw_u32)(v) & 0x00ff0000UL) >> 8) | \
+ (((fsw_u32)(v) & 0x0000ff00UL) << 8) | \
+ (((fsw_u32)(v) & 0x000000ffUL) << 24))
+#define FSW_SWAPVALUE_U64(v) ((((fsw_u64)(v) & 0xff00000000000000ULL) >> 56) | \
+ (((fsw_u64)(v) & 0x00ff000000000000ULL) >> 40) | \
+ (((fsw_u64)(v) & 0x0000ff0000000000ULL) >> 24) | \
+ (((fsw_u64)(v) & 0x000000ff00000000ULL) >> 8) | \
+ (((fsw_u64)(v) & 0x00000000ff000000ULL) << 8) | \
+ (((fsw_u64)(v) & 0x0000000000ff0000ULL) << 24) | \
+ (((fsw_u64)(v) & 0x000000000000ff00ULL) << 40) | \
+ (((fsw_u64)(v) & 0x00000000000000ffULL) << 56))
+
+#ifdef FSW_LITTLE_ENDIAN
+
+#define fsw_u16_le_swap(v) (v)
+#define fsw_u16_be_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u32_le_swap(v) (v)
+#define fsw_u32_be_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u64_le_swap(v) (v)
+#define fsw_u64_be_swap(v) FSW_SWAPVALUE_U64(v)
+
+#define fsw_u16_le_sip(var)
+#define fsw_u16_be_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u32_le_sip(var)
+#define fsw_u32_be_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u64_le_sip(var)
+#define fsw_u64_be_sip(var) (var = FSW_SWAPVALUE_U64(var))
+
+#else
+#ifdef FSW_BIG_ENDIAN
+
+#define fsw_u16_le_swap(v) FSW_SWAPVALUE_U16(v)
+#define fsw_u16_be_swap(v) (v)
+#define fsw_u32_le_swap(v) FSW_SWAPVALUE_U32(v)
+#define fsw_u32_be_swap(v) (v)
+#define fsw_u64_le_swap(v) FSW_SWAPVALUE_U64(v)
+#define fsw_u64_be_swap(v) (v)
+
+#define fsw_u16_le_sip(var) (var = FSW_SWAPVALUE_U16(var))
+#define fsw_u16_be_sip(var)
+#define fsw_u32_le_sip(var) (var = FSW_SWAPVALUE_U32(var))
+#define fsw_u32_be_sip(var)
+#define fsw_u64_le_sip(var) (var = FSW_SWAPVALUE_U64(var))
+#define fsw_u64_be_sip(var)
+
+#else
+#fail Neither FSW_BIG_ENDIAN nor FSW_LITTLE_ENDIAN are defined
+#endif
+#endif
+
+/*@}*/
+
+
+//
+// The following evil hack avoids a lot of casts between generic and fstype-specific
+// structures.
+//
+
+#ifndef VOLSTRUCTNAME
+#define VOLSTRUCTNAME fsw_volume
+#else
+struct VOLSTRUCTNAME;
+#endif
+#ifndef DNODESTRUCTNAME
+#define DNODESTRUCTNAME fsw_dnode
+#else
+struct DNODESTRUCTNAME;
+#endif
+
+
+/**
+ * Status code type, returned from all functions that can fail.
+ */
+typedef int fsw_status_t;
+
+/**
+ * Possible status codes.
+ */
+enum {
+ FSW_SUCCESS,
+ FSW_OUT_OF_MEMORY,
+ FSW_IO_ERROR,
+ FSW_UNSUPPORTED,
+ FSW_NOT_FOUND,
+ FSW_VOLUME_CORRUPTED,
+ FSW_UNKNOWN_ERROR
+};
+
+
+/**
+ * Core: A string with explicit length and encoding information.
+ */
+
+struct fsw_string {
+ int type; //!< Encoding of the string - empty, ISO-8859-1, UTF8, UTF16
+ int len; //!< Length in characters
+ int size; //!< Total data size in bytes
+ void *data; //!< Data pointer (may be NULL if type is EMPTY or len is zero)
+};
+
+/**
+ * Possible string types / encodings. In the case of FSW_STRING_TYPE_EMPTY,
+ * all other members of the fsw_string structure may be invalid.
+ */
+enum {
+ FSW_STRING_TYPE_EMPTY,
+ FSW_STRING_TYPE_ISO88591,
+ FSW_STRING_TYPE_UTF8,
+ FSW_STRING_TYPE_UTF16,
+ FSW_STRING_TYPE_UTF16_SWAPPED
+};
+
+#ifdef FSW_LITTLE_ENDIAN
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16_SWAPPED
+#else
+#define FSW_STRING_TYPE_UTF16_LE FSW_STRING_TYPE_UTF16_SWAPPED
+#define FSW_STRING_TYPE_UTF16_BE FSW_STRING_TYPE_UTF16
+#endif
+
+/** Static initializer for an empty string. */
+#define FSW_STRING_INIT { FSW_STRING_TYPE_EMPTY, 0, 0, NULL }
+
+
+/* forward declarations */
+
+struct fsw_dnode;
+struct fsw_host_table;
+struct fsw_fstype_table;
+
+struct fsw_blockcache {
+ fsw_u32 refcount; //!< Reference count
+ fsw_u32 cache_level; //!< Level of importance of this block
+ fsw_u32 phys_bno; //!< Physical block number
+ void *data; //!< Block data buffer
+};
+
+/**
+ * Core: Represents a mounted volume.
+ */
+
+struct fsw_volume {
+ fsw_u32 phys_blocksize; //!< Block size for disk access / file system structures
+ fsw_u32 log_blocksize; //!< Block size for logical file data
+
+ struct DNODESTRUCTNAME *root; //!< Root directory dnode
+ struct fsw_string label; //!< Volume label
+
+ struct fsw_dnode *dnode_head; //!< List of all dnodes allocated for this volume
+
+ struct fsw_blockcache *bcache; //!< Array of block cache entries
+ fsw_u32 bcache_size; //!< Number of entries in the block cache array
+
+ void *host_data; //!< Hook for a host-specific data structure
+ struct fsw_host_table *host_table; //!< Dispatch table for host-specific functions
+ struct fsw_fstype_table *fstype_table; //!< Dispatch table for file system specific functions
+ int host_string_type; //!< String type used by the host environment
+};
+
+/**
+ * Core: Represents a "directory node" - a file, directory, symlink, whatever.
+ */
+
+struct fsw_dnode {
+ fsw_u32 refcount; //!< Reference count
+
+ struct VOLSTRUCTNAME *vol; //!< The volume this dnode belongs to
+ struct DNODESTRUCTNAME *parent; //!< Parent directory dnode
+ struct fsw_string name; //!< Name of this item in the parent directory
+
+ fsw_u32 dnode_id; //!< Unique id number (usually the inode number)
+ int type; //!< Type of the dnode - file, dir, symlink, special
+ fsw_u64 size; //!< Data size in bytes
+
+ struct fsw_dnode *next; //!< Doubly-linked list of all dnodes: previous dnode
+ struct fsw_dnode *prev; //!< Doubly-linked list of all dnodes: next dnode
+};
+
+/**
+ * Possible dnode types. FSW_DNODE_TYPE_UNKNOWN may only be used before
+ * fsw_dnode_fill has been called on the dnode.
+ */
+enum {
+ FSW_DNODE_TYPE_UNKNOWN,
+ FSW_DNODE_TYPE_FILE,
+ FSW_DNODE_TYPE_DIR,
+ FSW_DNODE_TYPE_SYMLINK,
+ FSW_DNODE_TYPE_SPECIAL
+};
+
+/**
+ * Core: Stores the mapping of a region of a file to the data on disk.
+ */
+
+struct fsw_extent {
+ fsw_u32 type; //!< Type of extent specification
+ fsw_u32 log_start; //!< Starting logical block number
+ fsw_u32 log_count; //!< Logical block count
+ fsw_u32 phys_start; //!< Starting physical block number (for FSW_EXTENT_TYPE_PHYSBLOCK only)
+ void *buffer; //!< Allocated buffer pointer (for FSW_EXTENT_TYPE_BUFFER only)
+};
+
+/**
+ * Possible extent representation types. FSW_EXTENT_TYPE_INVALID is for shandle's
+ * internal use only, it must not be returned from a get_extent function.
+ */
+enum {
+ FSW_EXTENT_TYPE_INVALID,
+ FSW_EXTENT_TYPE_SPARSE,
+ FSW_EXTENT_TYPE_PHYSBLOCK,
+ FSW_EXTENT_TYPE_BUFFER
+};
+
+/**
+ * Core: An access structure to a dnode's raw data. There can be multiple
+ * shandles per dnode, each of them has its own position pointer.
+ */
+
+struct fsw_shandle {
+ struct fsw_dnode *dnode; //!< The dnode this handle reads data from
+
+ fsw_u64 pos; //!< Current file pointer in bytes
+ struct fsw_extent extent; //!< Current extent
+};
+
+/**
+ * Core: Used in gathering detailed information on a volume.
+ */
+
+struct fsw_volume_stat {
+ fsw_u64 total_bytes; //!< Total size of data area size in bytes
+ fsw_u64 free_bytes; //!< Bytes still available for storing file data
+};
+
+/**
+ * Core: Used in gathering detailed information on a dnode.
+ */
+
+struct fsw_dnode_stat {
+ fsw_u64 used_bytes; //!< Bytes actually used by the file on disk
+ void (*store_time_posix)(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time); //!< Callback for storing a Posix-style timestamp
+ void (*store_attr_posix)(struct fsw_dnode_stat *sb, fsw_u16 posix_mode); //!< Callback for storing a Posix-style file mode
+ void *host_data; //!< Hook for a host-specific data structure
+};
+
+/**
+ * Type of the timestamp passed into store_time_posix.
+ */
+enum {
+ FSW_DNODE_STAT_CTIME,
+ FSW_DNODE_STAT_MTIME,
+ FSW_DNODE_STAT_ATIME
+};
+
+/**
+ * Core: Function table for a host environment.
+ */
+
+struct fsw_host_table
+{
+ int native_string_type; //!< String type used by the host environment
+
+ void (*change_blocksize)(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+ fsw_status_t (*read_block)(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+};
+
+/**
+ * Core: Function table for a file system driver.
+ */
+
+struct fsw_fstype_table
+{
+ struct fsw_string name; //!< String giving the name of the file system
+ fsw_u32 volume_struct_size; //!< Size for allocating the fsw_volume structure
+ fsw_u32 dnode_struct_size; //!< Size for allocating the fsw_dnode structure
+
+ fsw_status_t (*volume_mount)(struct VOLSTRUCTNAME *vol);
+ void (*volume_free)(struct VOLSTRUCTNAME *vol);
+ fsw_status_t (*volume_stat)(struct VOLSTRUCTNAME *vol, struct fsw_volume_stat *sb);
+
+ fsw_status_t (*dnode_fill)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+ void (*dnode_free)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno);
+ fsw_status_t (*dnode_stat)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_dnode_stat *sb);
+ fsw_status_t (*get_extent)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_extent *extent);
+
+ fsw_status_t (*dir_lookup)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_string *lookup_name, struct DNODESTRUCTNAME **child_dno);
+ fsw_status_t (*dir_read)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_shandle *shand, struct DNODESTRUCTNAME **child_dno);
+ fsw_status_t (*readlink)(struct VOLSTRUCTNAME *vol, struct DNODESTRUCTNAME *dno,
+ struct fsw_string *link_target);
+};
+
+
+/**
+ * \name Volume Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_mount(void *host_data,
+ struct fsw_host_table *host_table,
+ struct fsw_fstype_table *fstype_table,
+ struct fsw_volume **vol_out);
+void fsw_unmount(struct fsw_volume *vol);
+fsw_status_t fsw_volume_stat(struct fsw_volume *vol, struct fsw_volume_stat *sb);
+
+void fsw_set_blocksize(struct VOLSTRUCTNAME *vol, fsw_u32 phys_blocksize, fsw_u32 log_blocksize);
+fsw_status_t fsw_block_get(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, fsw_u32 cache_level, void **buffer_out);
+void fsw_block_release(struct VOLSTRUCTNAME *vol, fsw_u32 phys_bno, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name dnode Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_dnode_create_root(struct VOLSTRUCTNAME *vol, fsw_u32 dnode_id, struct DNODESTRUCTNAME **dno_out);
+fsw_status_t fsw_dnode_create(struct DNODESTRUCTNAME *parent_dno, fsw_u32 dnode_id, int type,
+ struct fsw_string *name, struct DNODESTRUCTNAME **dno_out);
+void fsw_dnode_retain(struct fsw_dnode *dno);
+void fsw_dnode_release(struct fsw_dnode *dno);
+
+fsw_status_t fsw_dnode_fill(struct fsw_dnode *dno);
+fsw_status_t fsw_dnode_stat(struct fsw_dnode *dno, struct fsw_dnode_stat *sb);
+
+fsw_status_t fsw_dnode_lookup(struct fsw_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_lookup_path(struct fsw_dnode *dno,
+ struct fsw_string *lookup_path, char separator,
+ struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_dir_read(struct fsw_shandle *shand, struct fsw_dnode **child_dno_out);
+fsw_status_t fsw_dnode_readlink(struct fsw_dnode *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_readlink_data(struct DNODESTRUCTNAME *dno, struct fsw_string *link_target);
+fsw_status_t fsw_dnode_resolve(struct fsw_dnode *dno, struct fsw_dnode **target_dno_out);
+
+/*@}*/
+
+
+/**
+ * \name shandle Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_shandle_open(struct DNODESTRUCTNAME *dno, struct fsw_shandle *shand);
+void fsw_shandle_close(struct fsw_shandle *shand);
+fsw_status_t fsw_shandle_read(struct fsw_shandle *shand, fsw_u32 *buffer_size_inout, void *buffer);
+
+/*@}*/
+
+
+/**
+ * \name Memory Functions
+ */
+/*@{*/
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out);
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len);
+
+/*@}*/
+
+
+/**
+ * \name String Functions
+ */
+/*@{*/
+
+int fsw_strlen(struct fsw_string *s);
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2);
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2);
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src);
+void fsw_strsplit(struct fsw_string *lookup_name, struct fsw_string *buffer, char separator);
+
+void fsw_strfree(struct fsw_string *s);
+fsw_u16 fsw_to_lower(fsw_u16 ch);
+
+/*@}*/
+
+
+/**
+ * \name Posix Mode Macros
+ * These macros can be used globally to test fields and bits in
+ * Posix-style modes.
+ *
+ * Taken from FreeBSD sys/stat.h.
+ */
+/*@{*/
+#ifndef S_IRWXU
+
+#define S_ISUID 0004000 /* set user id on execution */
+#define S_ISGID 0002000 /* set group id on execution */
+#define S_ISTXT 0001000 /* sticky bit */
+
+#define S_IRWXU 0000700 /* RWX mask for owner */
+#define S_IRUSR 0000400 /* R for owner */
+#define S_IWUSR 0000200 /* W for owner */
+#define S_IXUSR 0000100 /* X for owner */
+
+#define S_IRWXG 0000070 /* RWX mask for group */
+#define S_IRGRP 0000040 /* R for group */
+#define S_IWGRP 0000020 /* W for group */
+#define S_IXGRP 0000010 /* X for group */
+
+#define S_IRWXO 0000007 /* RWX mask for other */
+#define S_IROTH 0000004 /* R for other */
+#define S_IWOTH 0000002 /* W for other */
+#define S_IXOTH 0000001 /* X for other */
+
+#define S_IFMT 0170000 /* type of file mask */
+#define S_IFIFO 0010000 /* named pipe (fifo) */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFBLK 0060000 /* block special */
+#define S_IFREG 0100000 /* regular */
+#define S_IFLNK 0120000 /* symbolic link */
+#define S_IFSOCK 0140000 /* socket */
+#define S_ISVTX 0001000 /* save swapped text even after use */
+#define S_IFWHT 0160000 /* whiteout */
+
+#define S_ISDIR(m) (((m) & 0170000) == 0040000) /* directory */
+#define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special */
+#define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block special */
+#define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file */
+#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or socket */
+#define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic link */
+#define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */
+#define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */
+
+#define S_BLKSIZE 512 /* block size used in the stat struct */
+
+#endif
+/*@}*/
+
+
+#endif
--- /dev/null
+/* $Id: fsw_efi.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi.c - EFI host environment code.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+#define DEBUG_LEVEL 0
+
+#ifndef FSTYPE
+#ifdef VBOX
+#error FSTYPE must be defined!
+#else
+#define FSTYPE ext2
+#endif
+#endif
+
+#define DEBUG_VBFS 1
+// CHAR8 *msgCursor;
+// MESSAGE_LOG_PROTOCOL *Msg = NULL;
+
+#if DEBUG_VBFS==2
+#define DBG(x...) AsciiPrint(x)
+#elif DEBUG_VBFS==1
+#define DBG(x...) BootLog(x)
+#else
+#define DBG(x...)
+#endif
+
+
+/** Helper macro for stringification. */
+#define FSW_EFI_STRINGIFY(x) #x
+/** Expands to the EFI driver name given the file system type name. */
+#define FSW_EFI_DRIVER_NAME(t) L"Fsw " FSW_EFI_STRINGIFY(t) L" File System Driver"
+
+// function prototypes
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath);
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer);
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName);
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName);
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume);
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+ OUT EFI_FILE **Root);
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+ OUT EFI_FILE **NewFileHandle);
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+ OUT UINT64 *Position);
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes);
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position);
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer);
+
+/**
+ * Interface structure for the EFI Driver Binding protocol.
+ */
+
+EFI_DRIVER_BINDING_PROTOCOL fsw_efi_DriverBinding_table = {
+ fsw_efi_DriverBinding_Supported,
+ fsw_efi_DriverBinding_Start,
+ fsw_efi_DriverBinding_Stop,
+ 0x10,
+ NULL,
+ NULL
+};
+
+/**
+ * Interface structure for the EFI Component Name protocol.
+ */
+
+EFI_COMPONENT_NAME_PROTOCOL fsw_efi_ComponentName_table = {
+ fsw_efi_ComponentName_GetDriverName,
+ fsw_efi_ComponentName_GetControllerName,
+ "eng"
+};
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table fsw_efi_host_table = {
+ FSW_STRING_TYPE_UTF16,
+
+ fsw_efi_change_blocksize,
+ fsw_efi_read_block
+};
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+//#include "OverrideFunctions-kabyl.edk2.c.include"
+
+/**
+ * Image entry point. Installs the Driver Binding and Component Name protocols
+ * on the image's handle. Actually mounting a file system is initiated through
+ * the Driver Binding protocol at the firmware's request.
+ */
+EFI_STATUS EFIAPI fsw_efi_main(IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable)
+{
+ EFI_STATUS Status;
+
+#ifndef VBOX
+ InitializeLib(ImageHandle, SystemTable);
+#endif
+
+ // complete Driver Binding protocol instance
+ fsw_efi_DriverBinding_table.ImageHandle = ImageHandle;
+ fsw_efi_DriverBinding_table.DriverBindingHandle = ImageHandle;
+ // install Driver Binding protocol
+ Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+ &PROTO_NAME(DriverBindingProtocol),
+ EFI_NATIVE_INTERFACE,
+ &fsw_efi_DriverBinding_table);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ // install Component Name protocol
+ Status = BS->InstallProtocolInterface(&fsw_efi_DriverBinding_table.DriverBindingHandle,
+ &PROTO_NAME(ComponentNameProtocol),
+ EFI_NATIVE_INTERFACE,
+ &fsw_efi_ComponentName_table);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+// OverrideFunctions();
+// Msg = NULL;
+// msgCursor = NULL;
+// Status = BS->LocateProtocol(&gMsgLogProtocolGuid, NULL, (VOID **) &Msg);
+// if (!EFI_ERROR(Status) && (Msg != NULL)) {
+// msgCursor = Msg->Cursor;
+// BootLog("MsgLog installed into VBoxFs\n");
+// }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * Driver Binding EFI protocol, Supported function. This function is called by EFI
+ * to test if this driver can handle a certain device. Our implementation only checks
+ * if the device is a disk (i.e. that it supports the Block I/O and Disk I/O protocols)
+ * and implicitly checks if the disk is already in use by another driver.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Supported(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
+{
+ EFI_STATUS Status;
+ EFI_DISK_IO *DiskIo;
+
+ // we check for both DiskIO and BlockIO protocols
+
+ // first, open DiskIO
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // we were just checking, close it again
+ BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+
+ // next, check BlockIO without actually opening it
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(BlockIoProtocol),
+ NULL,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
+ return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Start function. This function is called by EFI
+ * to start driving the given device. It is still possible at this point to
+ * return EFI_UNSUPPORTED, and in fact we will do so if the file system driver
+ * cannot find the superblock signature (or equivalent) that it expects.
+ *
+ * This function allocates memory for a per-volume structure, opens the
+ * required protocols (just Disk I/O in our case, Block I/O is only looked
+ * at to get the MediaId field), and lets the FSW core mount the file system.
+ * If successful, an EFI Simple File System protocol is exported on the
+ * device handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Start(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath)
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO *BlockIo;
+ EFI_DISK_IO *DiskIo;
+ FSW_VOLUME_DATA *Volume;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_DriverBinding_Start\n");
+#endif
+
+ // open consumed protocols
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(BlockIoProtocol),
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL); // NOTE: we only want to look at the MediaId
+ if (EFI_ERROR(Status)) {
+// Print(L"Fsw ERROR: OpenProtocol(BlockIo) returned %x\n", Status);
+ return Status;
+ }
+
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ (VOID **) &DiskIo,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER);
+ if (EFI_ERROR(Status)) {
+ Print(L"Fsw ERROR: OpenProtocol(DiskIo) returned %r\n", Status);
+ return Status;
+ }
+
+ // allocate volume structure
+ Volume = AllocateZeroPool(sizeof(FSW_VOLUME_DATA));
+ Volume->Signature = FSW_VOLUME_DATA_SIGNATURE;
+ Volume->Handle = ControllerHandle;
+ Volume->DiskIo = DiskIo;
+ Volume->MediaId = BlockIo->Media->MediaId;
+ Volume->LastIOStatus = EFI_SUCCESS;
+
+ // mount the filesystem
+ Status = fsw_efi_map_status(fsw_mount(Volume, &fsw_efi_host_table,
+ &FSW_FSTYPE_TABLE_NAME(FSTYPE), &Volume->vol),
+ Volume);
+
+ if (!EFI_ERROR(Status)) {
+ // register the SimpleFileSystem protocol
+ Volume->FileSystem.Revision = EFI_FILE_IO_INTERFACE_REVISION;
+ Volume->FileSystem.OpenVolume = fsw_efi_FileSystem_OpenVolume;
+ Status = BS->InstallMultipleProtocolInterfaces(&ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol),
+ &Volume->FileSystem,
+ NULL);
+ if (EFI_ERROR(Status)) {
+// Print(L"Fsw ERROR: InstallMultipleProtocolInterfaces returned %x\n", Status);
+ }
+ }
+
+ // on errors, close the opened protocols
+ if (EFI_ERROR(Status)) {
+ if (Volume->vol != NULL)
+ fsw_unmount(Volume->vol);
+ FreePool(Volume);
+
+ BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+ }
+
+ return Status;
+}
+
+/**
+ * Driver Binding EFI protocol, Stop function. This function is called by EFI
+ * to stop the driver on the given device. This translates to an unmount
+ * call for the FSW core.
+ *
+ * We assume that all file handles on the volume have been closed before
+ * the driver is stopped. At least with the EFI shell, that is actually the
+ * case; it closes all file handles between commands.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_DriverBinding_Stop(IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_IO_INTERFACE *FileSystem;
+ FSW_VOLUME_DATA *Volume;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_DriverBinding_Stop\n");
+#endif
+
+ // get the installed SimpleFileSystem interface
+ Status = BS->OpenProtocol(ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol),
+ (VOID **) &FileSystem,
+ This->DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (EFI_ERROR(Status))
+ return EFI_UNSUPPORTED;
+
+ // get private data structure
+ Volume = FSW_VOLUME_FROM_FILE_SYSTEM(FileSystem);
+
+ // uninstall Simple File System protocol
+ Status = BS->UninstallMultipleProtocolInterfaces(ControllerHandle,
+ &PROTO_NAME(SimpleFileSystemProtocol), &Volume->FileSystem,
+ NULL);
+ if (EFI_ERROR(Status)) {
+ // Print(L"Fsw ERROR: UninstallMultipleProtocolInterfaces returned %x\n", Status);
+ return Status;
+ }
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_DriverBinding_Stop: protocol uninstalled successfully\n");
+#endif
+
+ // release private data structure
+ if (Volume->vol != NULL)
+ fsw_unmount(Volume->vol);
+ FreePool(Volume);
+
+ // close the consumed protocols
+ Status = BS->CloseProtocol(ControllerHandle,
+ &PROTO_NAME(DiskIoProtocol),
+ This->DriverBindingHandle,
+ ControllerHandle);
+
+ return Status;
+}
+
+/**
+ * Component Name EFI protocol, GetDriverName function. Used by the EFI
+ * environment to inquire the name of this driver. The name returned is
+ * based on the file system type actually used in compilation.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetDriverName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName)
+{
+ if (Language == NULL || DriverName == NULL)
+ return EFI_INVALID_PARAMETER;
+
+ if (Language[0] == 'e' && Language[1] == 'n' && Language[2] == 'g' && Language[3] == 0) {
+ *DriverName = FSW_EFI_DRIVER_NAME(FSTYPE);
+ return EFI_SUCCESS;
+ }
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * Component Name EFI protocol, GetControllerName function. Not implemented
+ * because this is not a "bus" driver in the sense of the EFI Driver Model.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_ComponentName_GetControllerName(IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName)
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_efi_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+ // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_efi_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)vol->host_data;
+
+// FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_efi_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
+
+ // read from disk
+ Status = Volume->DiskIo->ReadDisk(Volume->DiskIo, Volume->MediaId,
+ (UINT64)phys_bno * vol->phys_blocksize,
+ vol->phys_blocksize,
+ buffer);
+ Volume->LastIOStatus = Status;
+ if (EFI_ERROR(Status))
+ return FSW_IO_ERROR;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Map FSW status codes to EFI status codes. The FSW_IO_ERROR code is only produced
+ * by fsw_efi_read_block, so we map it back to the EFI status code remembered from
+ * the last I/O operation.
+ */
+
+EFI_STATUS fsw_efi_map_status(fsw_status_t fsw_status, FSW_VOLUME_DATA *Volume)
+{
+ switch (fsw_status) {
+ case FSW_SUCCESS:
+ return EFI_SUCCESS;
+ case FSW_OUT_OF_MEMORY:
+ return EFI_VOLUME_CORRUPTED;
+ case FSW_IO_ERROR:
+ return Volume->LastIOStatus;
+ case FSW_UNSUPPORTED:
+ return EFI_UNSUPPORTED;
+ case FSW_NOT_FOUND:
+ return EFI_NOT_FOUND;
+ case FSW_VOLUME_CORRUPTED:
+ return EFI_VOLUME_CORRUPTED;
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ * File System EFI protocol, OpenVolume function. Creates a file handle for
+ * the root directory and returns it. Note that this function may be called
+ * multiple times and returns a new file handle each time. Each returned
+ * handle is closed by the client using it.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileSystem_OpenVolume(IN EFI_FILE_IO_INTERFACE *This,
+ OUT EFI_FILE **Root)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = FSW_VOLUME_FROM_FILE_SYSTEM(This);
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_FileSystem_OpenVolume\n");
+#endif
+
+ Status = fsw_efi_dnode_to_FileHandle(Volume->vol->root, Root);
+
+ return Status;
+}
+
+/**
+ * File Handle EFI protocol, Open function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Open(IN EFI_FILE *This,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_open(File, NewHandle, FileName, OpenMode, Attributes);
+ // not supported for regular files
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Close function. Closes the FSW shandle
+ * and frees the memory used for the structure.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Close(IN EFI_FILE *This)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_FileHandle_Close\n");
+#endif
+
+ fsw_shandle_close(&File->shand);
+ FreePool(File);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * File Handle EFI protocol, Delete function. Calls through to Close
+ * and returns a warning because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Delete(IN EFI_FILE *This)
+{
+ EFI_STATUS Status;
+
+ Status = This->Close(This);
+ if (Status == EFI_SUCCESS) {
+ // this driver is read-only
+ Status = EFI_WARN_DELETE_FAILURE;
+ }
+
+ return Status;
+}
+
+/**
+ * File Handle EFI protocol, Read function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Read(IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_read(File, BufferSize, Buffer);
+ else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_read(File, BufferSize, Buffer);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, Write function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Write(IN EFI_FILE *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, GetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetPosition(IN EFI_FILE *This,
+ OUT UINT64 *Position)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_getpos(File, Position);
+ // not defined for directories
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, SetPosition function. Dispatches the call
+ * based on the kind of file handle.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetPosition(IN EFI_FILE *This,
+ IN UINT64 Position)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ if (File->Type == FSW_EFI_FILE_TYPE_FILE)
+ return fsw_efi_file_setpos(File, Position);
+ else if (File->Type == FSW_EFI_FILE_TYPE_DIR)
+ return fsw_efi_dir_setpos(File, Position);
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ * File Handle EFI protocol, GetInfo function. Dispatches to the common
+ * function implementing this.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_GetInfo(IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ FSW_FILE_DATA *File = FSW_FILE_FROM_FILE_HANDLE(This);
+
+ return fsw_efi_dnode_getinfo(File, InformationType, BufferSize, Buffer);
+}
+
+/**
+ * File Handle EFI protocol, SetInfo function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_SetInfo(IN EFI_FILE *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * File Handle EFI protocol, Flush function. Returns unsupported status
+ * because this driver is read-only.
+ */
+
+EFI_STATUS EFIAPI fsw_efi_FileHandle_Flush(IN EFI_FILE *This)
+{
+ // this driver is read-only
+ return EFI_WRITE_PROTECTED;
+}
+
+/**
+ * Set up a file handle for a dnode. This function allocates a data structure
+ * for a file handle, opens a FSW shandle and populates the EFI_FILE structure
+ * with the interface functions.
+ */
+
+EFI_STATUS fsw_efi_dnode_to_FileHandle(IN struct fsw_dnode *dno,
+ OUT EFI_FILE **NewFileHandle)
+{
+ EFI_STATUS Status;
+ FSW_FILE_DATA *File;
+
+ // make sure the dnode has complete info
+ Status = fsw_efi_map_status(fsw_dnode_fill(dno), (FSW_VOLUME_DATA *)dno->vol->host_data);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // check type
+ if (dno->type != FSW_DNODE_TYPE_FILE && dno->type != FSW_DNODE_TYPE_DIR)
+ return EFI_UNSUPPORTED;
+
+ // allocate file structure
+ File = AllocateZeroPool(sizeof(FSW_FILE_DATA));
+ File->Signature = FSW_FILE_DATA_SIGNATURE;
+ if (dno->type == FSW_DNODE_TYPE_FILE)
+ File->Type = FSW_EFI_FILE_TYPE_FILE;
+ else if (dno->type == FSW_DNODE_TYPE_DIR)
+ File->Type = FSW_EFI_FILE_TYPE_DIR;
+
+ // open shandle
+ Status = fsw_efi_map_status(fsw_shandle_open(dno, &File->shand),
+ (FSW_VOLUME_DATA *)dno->vol->host_data);
+ if (EFI_ERROR(Status)) {
+ FreePool(File);
+ return Status;
+ }
+
+ // populate the file handle
+ File->FileHandle.Revision = EFI_FILE_HANDLE_REVISION;
+ File->FileHandle.Open = fsw_efi_FileHandle_Open;
+ File->FileHandle.Close = fsw_efi_FileHandle_Close;
+ File->FileHandle.Delete = fsw_efi_FileHandle_Delete;
+ File->FileHandle.Read = fsw_efi_FileHandle_Read;
+ File->FileHandle.Write = fsw_efi_FileHandle_Write;
+ File->FileHandle.GetPosition = fsw_efi_FileHandle_GetPosition;
+ File->FileHandle.SetPosition = fsw_efi_FileHandle_SetPosition;
+ File->FileHandle.GetInfo = fsw_efi_FileHandle_GetInfo;
+ File->FileHandle.SetInfo = fsw_efi_FileHandle_SetInfo;
+ File->FileHandle.Flush = fsw_efi_FileHandle_Flush;
+
+ *NewFileHandle = &File->FileHandle;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Data read function for regular files. Calls through to fsw_shandle_read.
+ */
+
+EFI_STATUS fsw_efi_file_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ fsw_u32 buffer_size;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_file_read %d bytes\n", *BufferSize);
+#endif
+
+ buffer_size = (fsw_u32)*BufferSize;
+ Status = fsw_efi_map_status(fsw_shandle_read(&File->shand, &buffer_size, Buffer),
+ (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data);
+ *BufferSize = buffer_size;
+
+ return Status;
+}
+
+/**
+ * Get file position for regular files.
+ */
+
+EFI_STATUS fsw_efi_file_getpos(IN FSW_FILE_DATA *File,
+ OUT UINT64 *Position)
+{
+ *Position = File->shand.pos;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Set file position for regular files. EFI specifies the all-ones value
+ * to be a special value for the end of the file.
+ */
+
+EFI_STATUS fsw_efi_file_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position)
+{
+ if (Position == 0xFFFFFFFFFFFFFFFFULL)
+ File->shand.pos = File->shand.dnode->size;
+ else
+ File->shand.pos = Position;
+ return EFI_SUCCESS;
+}
+
+/**
+ * Open function used to open new file handles relative to a directory.
+ * In EFI, the "open file" function is implemented by directory file handles
+ * and is passed a relative or volume-absolute path to the file or directory
+ * to open. We use fsw_dnode_lookup_path to find the node plus an additional
+ * call to fsw_dnode_resolve because EFI has no concept of symbolic links.
+ */
+
+EFI_STATUS fsw_efi_dir_open(IN FSW_FILE_DATA *File,
+ OUT EFI_FILE **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ struct fsw_dnode *dno;
+ struct fsw_dnode *target_dno;
+ struct fsw_string lookup_path;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dir_open: '%s'\n", FileName);
+#endif
+
+ if (OpenMode != EFI_FILE_MODE_READ)
+ return EFI_WRITE_PROTECTED;
+
+ lookup_path.type = FSW_STRING_TYPE_UTF16;
+ lookup_path.len = (int)StrLen(FileName);
+ lookup_path.size = lookup_path.len * sizeof(fsw_u16);
+ lookup_path.data = FileName;
+
+ // resolve the path (symlinks along the way are automatically resolved)
+ Status = fsw_efi_map_status(fsw_dnode_lookup_path(File->shand.dnode, &lookup_path, '\\', &dno),
+ Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // if the final node is a symlink, also resolve it
+ Status = fsw_efi_map_status(fsw_dnode_resolve(dno, &target_dno),
+ Volume);
+ fsw_dnode_release(dno);
+ if (EFI_ERROR(Status))
+ return Status;
+ dno = target_dno;
+
+ // make a new EFI handle for the target dnode
+ Status = fsw_efi_dnode_to_FileHandle(dno, NewHandle);
+ fsw_dnode_release(dno);
+ return Status;
+}
+
+/**
+ * Read function for directories. A file handle read on a directory retrieves
+ * the next directory entry.
+ */
+
+EFI_STATUS fsw_efi_dir_read(IN FSW_FILE_DATA *File,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ struct fsw_dnode *dno;
+
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dir_read...\n");
+#endif
+
+ // read the next entry
+ Status = fsw_efi_map_status(fsw_dnode_dir_read(&File->shand, &dno),
+ Volume);
+ if (Status == EFI_NOT_FOUND) {
+ // end of directory
+ *BufferSize = 0;
+#if DEBUG_LEVEL
+ Print(L"...no more entries\n");
+#endif
+ return EFI_SUCCESS;
+ }
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // get info into buffer
+ Status = fsw_efi_dnode_fill_FileInfo(Volume, dno, BufferSize, Buffer);
+ fsw_dnode_release(dno);
+ return Status;
+}
+
+/**
+ * Set file position for directories. The only allowed set position operation
+ * for directories is to rewind the directory completely by setting the
+ * position to zero.
+ */
+
+EFI_STATUS fsw_efi_dir_setpos(IN FSW_FILE_DATA *File,
+ IN UINT64 Position)
+{
+ if (Position == 0) {
+ File->shand.pos = 0;
+ return EFI_SUCCESS;
+ } else {
+ // directories can only rewind to the start
+ return EFI_UNSUPPORTED;
+ }
+}
+
+/**
+ * Get file or volume information. This function implements the GetInfo call
+ * for all file handles. Control is dispatched according to the type of information
+ * requested by the caller.
+ */
+
+EFI_STATUS fsw_efi_dnode_getinfo(IN FSW_FILE_DATA *File,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ FSW_VOLUME_DATA *Volume = (FSW_VOLUME_DATA *)File->shand.dnode->vol->host_data;
+ EFI_FILE_SYSTEM_INFO *FSInfo;
+ UINTN RequiredSize;
+ struct fsw_volume_stat vsb;
+
+
+ if (CompareGuid(InformationType, &gEfiFileInfoGuid)) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_INFO\n");
+#endif
+
+ Status = fsw_efi_dnode_fill_FileInfo(Volume, File->shand.dnode, BufferSize, Buffer);
+
+ } else if (CompareGuid(InformationType, &gEfiFileSystemInfoGuid)) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_INFO\n");
+#endif
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + fsw_efi_strsize(&Volume->vol->label);
+ if (*BufferSize < RequiredSize) {
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ FSInfo = (EFI_FILE_SYSTEM_INFO *)Buffer;
+ FSInfo->Size = RequiredSize;
+ FSInfo->ReadOnly = TRUE;
+ FSInfo->BlockSize = Volume->vol->log_blocksize;
+ fsw_efi_strcpy(FSInfo->VolumeLabel, &Volume->vol->label);
+
+ // get the missing info from the fs driver
+ ZeroMem(&vsb, sizeof(struct fsw_volume_stat));
+ Status = fsw_efi_map_status(fsw_volume_stat(Volume->vol, &vsb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FSInfo->VolumeSize = vsb.total_bytes;
+ FSInfo->FreeSpace = vsb.free_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ Status = EFI_SUCCESS;
+
+ } else if (CompareGuid(InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) {
+#if DEBUG_LEVEL
+ Print(L"fsw_efi_dnode_getinfo: FILE_SYSTEM_VOLUME_LABEL\n");
+#endif
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL_INFO + fsw_efi_strsize(&Volume->vol->label);
+ if (*BufferSize < RequiredSize) {
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // copy volume label
+ fsw_efi_strcpy(((EFI_FILE_SYSTEM_VOLUME_LABEL_INFO *)Buffer)->VolumeLabel, &Volume->vol->label);
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ Status = EFI_SUCCESS;
+
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if (which == FSW_DNODE_STAT_CTIME)
+ fsw_efi_decode_time(&FileInfo->CreateTime, posix_time);
+ else if (which == FSW_DNODE_STAT_MTIME)
+ fsw_efi_decode_time(&FileInfo->ModificationTime, posix_time);
+ else if (which == FSW_DNODE_STAT_ATIME)
+ fsw_efi_decode_time(&FileInfo->LastAccessTime, posix_time);
+}
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+static void fsw_efi_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if ((posix_mode & S_IWUSR) == 0)
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+EFI_STATUS fsw_efi_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ UINTN RequiredSize;
+ struct fsw_dnode_stat sb;
+
+ // make sure the dnode has complete info
+ Status = fsw_efi_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // TODO: check/assert that the dno's name is in UTF16
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_efi_strsize(&dno->name);
+ if (*BufferSize < RequiredSize) {
+ // TODO: wind back the directory in this case
+
+#if DEBUG_LEVEL
+ Print(L"...BUFFER TOO SMALL\n");
+#endif
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ ZeroMem(Buffer, RequiredSize);
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = RequiredSize;
+ FileInfo->FileSize = dno->size;
+ FileInfo->Attribute = 0;
+ if (dno->type == FSW_DNODE_TYPE_DIR)
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ fsw_efi_strcpy(FileInfo->FileName, &dno->name);
+
+ // get the missing info from the fs driver
+ ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+ sb.store_time_posix = fsw_efi_store_time_posix;
+ sb.store_attr_posix = fsw_efi_store_attr_posix;
+ sb.host_data = FileInfo;
+ Status = fsw_efi_map_status(fsw_dnode_stat(dno, &sb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FileInfo->PhysicalSize = sb.used_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+#if DEBUG_LEVEL
+ Print(L"...returning '%s'\n", FileInfo->FileName);
+#endif
+ return EFI_SUCCESS;
+}
+
+// EOF
--- /dev/null
+/* $Id: fsw_efi.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_efi.h - EFI host environment header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_H_
+#define _FSW_EFI_H_
+
+#include "fsw_core.h"
+
+// extern CHAR8 *msgCursor;
+// extern MESSAGE_LOG_PROTOCOL *Msg;
+
+/**
+ * EFI Host: Private per-volume structure.
+ */
+
+typedef struct {
+ UINT64 Signature; //!< Used to identify this structure
+
+ EFI_FILE_IO_INTERFACE FileSystem; //!< Published EFI protocol interface structure
+
+ EFI_HANDLE Handle; //!< The device handle the protocol is attached to
+ EFI_DISK_IO *DiskIo; //!< The Disk I/O protocol we use for disk access
+ UINT32 MediaId; //!< The media ID from the Block I/O protocol
+ EFI_STATUS LastIOStatus; //!< Last status from Disk I/O
+
+ struct fsw_volume *vol; //!< FSW volume structure
+
+} FSW_VOLUME_DATA;
+
+/** Signature for the volume structure. */
+#define FSW_VOLUME_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'V')
+/** Access macro for the volume structure. */
+#define FSW_VOLUME_FROM_FILE_SYSTEM(a) CR (a, FSW_VOLUME_DATA, FileSystem, FSW_VOLUME_DATA_SIGNATURE)
+
+/**
+ * EFI Host: Private structure for a EFI_FILE interface.
+ */
+
+typedef struct {
+ UINT64 Signature; //!< Used to identify this structure
+
+ EFI_FILE FileHandle; //!< Published EFI protocol interface structure
+
+ UINT64 Type; //!< File type used for dispatching
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+} FSW_FILE_DATA;
+
+/** File type: regular file. */
+#define FSW_EFI_FILE_TYPE_FILE (0)
+/** File type: directory. */
+#define FSW_EFI_FILE_TYPE_DIR (1)
+
+/** Signature for the file handle structure. */
+#define FSW_FILE_DATA_SIGNATURE EFI_SIGNATURE_32 ('f', 's', 'w', 'F')
+/** Access macro for the file handle structure. */
+#define FSW_FILE_FROM_FILE_HANDLE(a) CR (a, FSW_FILE_DATA, FileHandle, FSW_FILE_DATA_SIGNATURE)
+
+
+//
+// Library functions
+//
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime);
+
+UINTN fsw_efi_strsize(struct fsw_string *s);
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src);
+
+
+#endif
--- /dev/null
+/* $Id: fsw_efi_base.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi_base.h - Base definitions for the EFI host environment.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_EFI_BASE_H_
+#define _FSW_EFI_BASE_H_
+
+#ifndef VBOX
+#include <efi.h>
+#include <efilib.h>
+#define PROTO_NAME(x) x
+#endif
+
+#define FSW_LITTLE_ENDIAN (1)
+
+
+// types, reuse EFI types
+
+typedef INT8 fsw_s8;
+typedef UINT8 fsw_u8;
+typedef INT16 fsw_s16;
+typedef UINT16 fsw_u16;
+typedef INT32 fsw_s32;
+typedef UINT32 fsw_u32;
+typedef INT64 fsw_s64;
+typedef UINT64 fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = AllocatePool(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) FreePool(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) ZeroMem(dest,size)
+#define fsw_memcpy(dest,src,size) CopyMem(dest,src,size)
+#define fsw_memeq(p1,p2,size) (CompareMem(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) L##s
+#define FSW_MSGFUNC Print
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) RShiftU64((val), (shiftbits))
+#define FSW_U64_DIV(val,divisor) DivU64x32((val), (divisor), NULL)
+
+
+#endif
--- /dev/null
+/* $Id: fsw_efi_lib.c 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_efi_lib.c - EFI host environment library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_efi.h"
+
+
+//
+// time conversion
+//
+// Adopted from public domain code in FreeBSD libc.
+//
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
+
+static const int mon_lengths[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+static const int year_lengths[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+VOID fsw_efi_decode_time(OUT EFI_TIME *EfiTime, IN UINT32 UnixTime)
+{
+ long days, rem;
+ int y, newy, yleap;
+ const int *ip;
+
+ ZeroMem(EfiTime, sizeof(EFI_TIME));
+
+ days = UnixTime / SECSPERDAY;
+ rem = UnixTime % SECSPERDAY;
+
+ EfiTime->Hour = (UINT8) (rem / SECSPERHOUR);
+ rem = rem % SECSPERHOUR;
+ EfiTime->Minute = (UINT8) (rem / SECSPERMIN);
+ EfiTime->Second = (UINT8) (rem % SECSPERMIN);
+
+ y = EPOCH_YEAR;
+ while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
+ newy = y + days / DAYSPERNYEAR;
+ if (days < 0)
+ --newy;
+ days -= (newy - y) * DAYSPERNYEAR +
+ LEAPS_THRU_END_OF(newy - 1) -
+ LEAPS_THRU_END_OF(y - 1);
+ y = newy;
+ }
+ EfiTime->Year = (UINT16)y;
+ ip = mon_lengths[yleap];
+ for (EfiTime->Month = 0; days >= (long) ip[EfiTime->Month]; ++(EfiTime->Month))
+ days = days - (long) ip[EfiTime->Month];
+ EfiTime->Month++; // adjust range to EFI conventions
+ EfiTime->Day = (UINT8) (days + 1);
+}
+
+//
+// String functions, used for file and volume info
+//
+
+UINTN fsw_efi_strsize(struct fsw_string *s)
+{
+ if (s->type == FSW_STRING_TYPE_EMPTY)
+ return sizeof(CHAR16);
+ return (s->len + 1) * sizeof(CHAR16);
+}
+
+VOID fsw_efi_strcpy(CHAR16 *Dest, struct fsw_string *src)
+{
+ if (src->type == FSW_STRING_TYPE_EMPTY) {
+ Dest[0] = 0;
+ } else if (src->type == FSW_STRING_TYPE_UTF16) {
+ CopyMem(Dest, src->data, src->size);
+ Dest[src->len] = 0;
+ } else {
+ // TODO: coerce, recurse
+ Dest[0] = 0;
+ }
+}
+
+#ifdef VBOX
+int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+
+ for (i = 0; i<len; i++)
+ {
+ if (fsw_to_lower(p1[i]) != fsw_to_lower(p2[i]))
+ {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+#endif
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_ext2.c
+ * ext2 file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "fsw_ext2.h"
+
+
+// functions
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol);
+static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol);
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno);
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno);
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry);
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2) = {
+ { FSW_STRING_TYPE_ISO88591, 4, 4, "ext2" },
+ sizeof(struct fsw_ext2_volume),
+ sizeof(struct fsw_ext2_dnode),
+
+ fsw_ext2_volume_mount,
+ fsw_ext2_volume_free,
+ fsw_ext2_volume_stat,
+ fsw_ext2_dnode_fill,
+ fsw_ext2_dnode_free,
+ fsw_ext2_dnode_stat,
+ fsw_ext2_get_extent,
+ fsw_ext2_dir_lookup,
+ fsw_ext2_dir_read,
+ fsw_ext2_readlink,
+};
+
+/**
+ * Mount an ext2 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_ext2_volume_mount(struct fsw_ext2_volume *vol)
+{
+ fsw_status_t status;
+ void *buffer;
+ fsw_u32 blocksize;
+ fsw_u32 groupcnt, groupno, gdesc_per_block, gdesc_bno, gdesc_index;
+ struct ext2_group_desc *gdesc;
+ int i;
+ struct fsw_string s;
+
+ // allocate memory to keep the superblock around
+ status = fsw_alloc(sizeof(struct ext2_super_block), &vol->sb);
+ if (status)
+ return status;
+
+ // read the superblock into its buffer
+ fsw_set_blocksize(vol, EXT2_SUPERBLOCK_BLOCKSIZE, EXT2_SUPERBLOCK_BLOCKSIZE);
+ status = fsw_block_get(vol, EXT2_SUPERBLOCK_BLOCKNO, 0, &buffer);
+ if (status)
+ return status;
+ fsw_memcpy(vol->sb, buffer, sizeof(struct ext2_super_block));
+ fsw_block_release(vol, EXT2_SUPERBLOCK_BLOCKNO, buffer);
+
+ // check the superblock
+ if (vol->sb->s_magic != EXT2_SUPER_MAGIC)
+ return FSW_UNSUPPORTED;
+ if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+ vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+ return FSW_UNSUPPORTED;
+ if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+ (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+ return FSW_UNSUPPORTED;
+
+ /*
+ if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+ (vol->sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER))
+ Print(L"Ext2 WARNING: This ext3 file system needs recovery, trying to use it anyway.\n");
+ */
+
+ // set real blocksize
+ blocksize = EXT2_BLOCK_SIZE(vol->sb);
+ fsw_set_blocksize(vol, blocksize, blocksize);
+
+ // get other info from superblock
+ vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+ vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+ vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+
+ for (i = 0; i < 16; i++)
+ if (vol->sb->s_volume_name[i] == 0)
+ break;
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = i;
+ s.data = vol->sb->s_volume_name;
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ if (status)
+ return status;
+
+ // read the group descriptors to get inode table offsets
+ groupcnt = ((vol->sb->s_inodes_count - 2) / vol->sb->s_inodes_per_group) + 1;
+ gdesc_per_block = (vol->g.phys_blocksize / sizeof(struct ext2_group_desc));
+
+ status = fsw_alloc(sizeof(fsw_u32) * groupcnt, &vol->inotab_bno);
+ if (status)
+ return status;
+ for (groupno = 0; groupno < groupcnt; groupno++) {
+ // get the block group descriptor
+ gdesc_bno = (vol->sb->s_first_data_block + 1) + groupno / gdesc_per_block;
+ gdesc_index = groupno % gdesc_per_block;
+ status = fsw_block_get(vol, gdesc_bno, 1, (void **)&buffer);
+ if (status)
+ return status;
+ gdesc = ((struct ext2_group_desc *)(buffer)) + gdesc_index;
+ vol->inotab_bno[groupno] = gdesc->bg_inode_table;
+ fsw_block_release(vol, gdesc_bno, buffer);
+ }
+
+ // setup the root dnode
+ status = fsw_dnode_create_root(vol, EXT2_ROOT_INO, &vol->g.root);
+ if (status)
+ return status;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_volume_mount: success, blocksize %d\n"), blocksize));
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_ext2_volume_free(struct fsw_ext2_volume *vol)
+{
+ if (vol->sb)
+ fsw_free(vol->sb);
+ if (vol->inotab_bno)
+ fsw_free(vol->inotab_bno);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_ext2_volume_stat(struct fsw_ext2_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = (fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
+ sb->free_bytes = (fsw_u64)vol->sb->s_free_blocks_count * vol->g.log_blocksize;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of ext2, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_ext2_dnode_fill(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+ fsw_status_t status;
+ fsw_u32 groupno, ino_in_group, ino_bno, ino_index;
+ fsw_u8 *buffer;
+
+ if (dno->raw)
+ return FSW_SUCCESS;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_ext2_dnode_fill: inode %d\n"), dno->g.dnode_id));
+
+ // read the inode block
+ groupno = (dno->g.dnode_id - 1) / vol->sb->s_inodes_per_group;
+ ino_in_group = (dno->g.dnode_id - 1) % vol->sb->s_inodes_per_group;
+ ino_bno = vol->inotab_bno[groupno] +
+ ino_in_group / (vol->g.phys_blocksize / vol->inode_size);
+ ino_index = ino_in_group % (vol->g.phys_blocksize / vol->inode_size);
+ status = fsw_block_get(vol, ino_bno, 2, (void **)&buffer);
+ if (status)
+ return status;
+
+ // keep our inode around
+ status = fsw_memdup((void **)&dno->raw, buffer + ino_index * vol->inode_size, vol->inode_size);
+ fsw_block_release(vol, ino_bno, buffer);
+ if (status)
+ return status;
+
+ // get info from the inode
+ dno->g.size = dno->raw->i_size;
+ // TODO: check docs for 64-bit sized files
+ if (S_ISREG(dno->raw->i_mode))
+ dno->g.type = FSW_DNODE_TYPE_FILE;
+ else if (S_ISDIR(dno->raw->i_mode))
+ dno->g.type = FSW_DNODE_TYPE_DIR;
+ else if (S_ISLNK(dno->raw->i_mode))
+ dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+ else
+ dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_ext2_dnode_free(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno)
+{
+ if (dno->raw)
+ fsw_free(dno->raw);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_ext2_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_ext2_dnode_stat(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ sb->used_bytes = dno->raw->i_blocks * 512; // very, very strange...
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+ sb->store_attr_posix(sb, dno->raw->i_mode);
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_ext2_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ *
+ * The ext2 file system does not use extents, but stores a list of block numbers
+ * using the usual direct, indirect, double-indirect, triple-indirect scheme. To
+ * optimize access, this function checks if the following file blocks are mapped
+ * to consecutive disk blocks and returns a combined extent if possible.
+ */
+
+static fsw_status_t fsw_ext2_get_extent(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_extent *extent)
+{
+ fsw_status_t status;
+ fsw_u32 bno, release_bno, buf_bcnt, file_bcnt;
+ fsw_u32 *buffer;
+ int path[5], i;
+
+ // Preconditions: The caller has checked that the requested logical block
+ // is within the file's size. The dnode has complete information, i.e.
+ // fsw_ext2_dnode_read_info was called successfully on it.
+
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->log_count = 1;
+ bno = extent->log_start;
+
+ // try direct block pointers in the inode
+ if (bno < EXT2_NDIR_BLOCKS) {
+ path[0] = bno;
+ path[1] = -1;
+ } else {
+ bno -= EXT2_NDIR_BLOCKS;
+
+ // try indirect block
+ if (bno < vol->ind_bcnt) {
+ path[0] = EXT2_IND_BLOCK;
+ path[1] = bno;
+ path[2] = -1;
+ } else {
+ bno -= vol->ind_bcnt;
+
+ // try double-indirect block
+ if (bno < vol->dind_bcnt) {
+ path[0] = EXT2_DIND_BLOCK;
+ path[1] = bno / vol->ind_bcnt;
+ path[2] = bno % vol->ind_bcnt;
+ path[3] = -1;
+ } else {
+ bno -= vol->dind_bcnt;
+
+ // use the triple-indirect block
+ path[0] = EXT2_TIND_BLOCK;
+ path[1] = bno / vol->dind_bcnt;
+ path[2] = (bno / vol->ind_bcnt) % vol->ind_bcnt;
+ path[3] = bno % vol->ind_bcnt;
+ path[4] = -1;
+ }
+ }
+ }
+
+ // follow the indirection path
+ buffer = dno->raw->i_block;
+ buf_bcnt = EXT2_NDIR_BLOCKS;
+ release_bno = 0;
+ for (i = 0; ; i++) {
+ bno = buffer[path[i]];
+ if (bno == 0) {
+ extent->type = FSW_EXTENT_TYPE_SPARSE;
+ if (release_bno)
+ fsw_block_release(vol, release_bno, buffer);
+ return FSW_SUCCESS;
+ }
+ if (path[i+1] < 0)
+ break;
+
+ if (release_bno)
+ fsw_block_release(vol, release_bno, buffer);
+ status = fsw_block_get(vol, bno, 1, (void **)&buffer);
+ if (status)
+ return status;
+ release_bno = bno;
+ buf_bcnt = vol->ind_bcnt;
+ }
+ extent->phys_start = bno;
+
+ // check if the following blocks can be aggregated into one extent
+ file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+ while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers
+ extent->log_start + extent->log_count < file_bcnt) { // file has more blocks
+ if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+ extent->log_count++;
+ else
+ break;
+ }
+
+ if (release_bno)
+ fsw_block_release(vol, release_bno, buffer);
+ return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_ext2_dir_lookup(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_ext2_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_shandle shand;
+ fsw_u32 child_ino;
+ struct ext2_dir_entry entry;
+ struct fsw_string entry_name;
+
+ // Preconditions: The caller has checked that dno is a directory node.
+
+ entry_name.type = FSW_STRING_TYPE_ISO88591;
+
+ // setup handle to read the directory
+ status = fsw_shandle_open(dno, &shand);
+ if (status)
+ return status;
+
+ // scan the directory for the file
+ child_ino = 0;
+ while (child_ino == 0) {
+ // read next entry
+ status = fsw_ext2_read_dentry(&shand, &entry);
+ if (status)
+ goto errorexit;
+ if (entry.inode == 0) {
+ // end of directory reached
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+
+ // compare name
+ entry_name.len = entry_name.size = entry.name_len;
+ entry_name.data = entry.name;
+ if (fsw_streq(lookup_name, &entry_name)) {
+ child_ino = entry.inode;
+ break;
+ }
+ }
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, child_ino, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+errorexit:
+ fsw_shandle_close(&shand);
+ return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_ext2_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_ext2_dir_read(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_ext2_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct ext2_dir_entry entry;
+ struct fsw_string entry_name;
+
+ // Preconditions: The caller has checked that dno is a directory node. The caller
+ // has opened a storage handle to the directory's storage and keeps it around between
+ // calls.
+
+ while (1) {
+ // read next entry
+ status = fsw_ext2_read_dentry(shand, &entry);
+ if (status)
+ return status;
+ if (entry.inode == 0) // end of directory
+ return FSW_NOT_FOUND;
+
+ // skip . and ..
+ if ((entry.name_len == 1 && entry.name[0] == '.') ||
+ (entry.name_len == 2 && entry.name[0] == '.' && entry.name[1] == '.'))
+ continue;
+ break;
+ }
+
+ // setup name
+ entry_name.type = FSW_STRING_TYPE_ISO88591;
+ entry_name.len = entry_name.size = entry.name_len;
+ entry_name.data = entry.name;
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, entry.inode, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+
+ return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw ext2 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_ext2_read_dentry(struct fsw_shandle *shand, struct ext2_dir_entry *entry)
+{
+ fsw_status_t status;
+ fsw_u32 buffer_size;
+
+ while (1) {
+ // read dir_entry header (fixed length)
+ buffer_size = 8;
+ status = fsw_shandle_read(shand, &buffer_size, entry);
+ if (status)
+ return status;
+
+ if (buffer_size < 8 || entry->rec_len == 0) {
+ // end of directory reached
+ entry->inode = 0;
+ return FSW_SUCCESS;
+ }
+ if (entry->rec_len < 8)
+ return FSW_VOLUME_CORRUPTED;
+ if (entry->inode != 0) {
+ // this entry is used
+ if (entry->rec_len < 8 + entry->name_len)
+ return FSW_VOLUME_CORRUPTED;
+ break;
+ }
+
+ // valid, but unused entry, skip it
+ shand->pos += entry->rec_len - 8;
+ }
+
+ // read file name (variable length)
+ buffer_size = entry->name_len;
+ status = fsw_shandle_read(shand, &buffer_size, entry->name);
+ if (status)
+ return status;
+ if (buffer_size < entry->name_len)
+ return FSW_VOLUME_CORRUPTED;
+
+ // skip any remaining padding
+ shand->pos += entry->rec_len - (8 + entry->name_len);
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_ext2_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For ext2, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_ext2_readlink(struct fsw_ext2_volume *vol, struct fsw_ext2_dnode *dno,
+ struct fsw_string *link_target)
+{
+ fsw_status_t status;
+ int ea_blocks;
+ struct fsw_string s;
+
+ if (dno->g.size > FSW_PATH_MAX)
+ return FSW_VOLUME_CORRUPTED;
+
+ ea_blocks = dno->raw->i_file_acl ? (vol->g.log_blocksize >> 9) : 0;
+
+ if (dno->raw->i_blocks - ea_blocks == 0) {
+ // "fast" symlink, path is stored inside the inode
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = (int)dno->g.size;
+ s.data = dno->raw->i_block;
+ status = fsw_strdup_coerce(link_target, vol->g.host_string_type, &s);
+ } else {
+ // "slow" symlink, path is stored in normal inode data
+ status = fsw_dnode_readlink_data(dno, link_target);
+ }
+
+ return status;
+}
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_ext2.h
+ * ext2 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_H_
+#define _FSW_EXT2_H_
+
+#define VOLSTRUCTNAME fsw_ext2_volume
+#define DNODESTRUCTNAME fsw_ext2_dnode
+#include "fsw_core.h"
+
+#include "fsw_ext2_disk.h"
+
+
+//! Block size to be used when reading the ext2 superblock.
+#define EXT2_SUPERBLOCK_BLOCKSIZE 1024
+//! Block number where the (master copy of the) ext2 superblock resides.
+#define EXT2_SUPERBLOCK_BLOCKNO 1
+
+
+/**
+ * ext2: Volume structure with ext2-specific data.
+ */
+
+struct fsw_ext2_volume {
+ struct fsw_volume g; //!< Generic volume structure
+
+ struct ext2_super_block *sb; //!< Full raw ext2 superblock structure
+ fsw_u32 *inotab_bno; //!< Block numbers of the inode tables
+ fsw_u32 ind_bcnt; //!< Number of blocks addressable through an indirect block
+ fsw_u32 dind_bcnt; //!< Number of blocks addressable through a double-indirect block
+ fsw_u32 inode_size; //!< Size of inode structure in bytes
+};
+
+/**
+ * ext2: Dnode structure with ext2-specific data.
+ */
+
+struct fsw_ext2_dnode {
+ struct fsw_dnode g; //!< Generic dnode structure
+
+ struct ext2_inode *raw; //!< Full raw inode structure
+};
+
+
+#endif
--- /dev/null
+/**
+ * \file fsw_ext2_disk.h
+ * ext2 file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FSW_EXT2_DISK_H_
+#define _FSW_EXT2_DISK_H_
+
+// types
+
+typedef fsw_s8 __s8;
+typedef fsw_u8 __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16 __le16;
+typedef __u32 __le32;
+typedef __u64 __le64;
+
+//
+// from Linux kernel, include/linux/ext2_fs.h
+//
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_SIZE 1024
+#define EXT2_MAX_BLOCK_SIZE 4096
+#define EXT2_MIN_BLOCK_LOG_SIZE 10
+#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
+#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)
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+ __le32 bg_block_bitmap; /* Blocks bitmap block */
+ __le32 bg_inode_bitmap; /* Inodes bitmap block */
+ __le32 bg_inode_table; /* Inodes table block */
+ __le16 bg_free_blocks_count; /* Free blocks count */
+ __le16 bg_free_inodes_count; /* Free inodes count */
+ __le16 bg_used_dirs_count; /* Directories count */
+ __le16 bg_pad;
+ __le32 bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
+#define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+
+/*
+ * 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_NOCOMP_FL 0x00000400 /* Don't compress */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* 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 /* AFS directory */
+#define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ __le16 i_mode; /* 0: File mode */
+ __le16 i_uid; /* 2: Low 16 bits of Owner Uid */
+ __le32 i_size; /* 4: Size in bytes */
+ __le32 i_atime; /* 8: Access time */
+ __le32 i_ctime; /* 12: Creation time */
+ __le32 i_mtime; /* 16: Modification time */
+ __le32 i_dtime; /* 20: Deletion Time */
+ __le16 i_gid; /* 24: Low 16 bits of Group Id */
+ __le16 i_links_count; /* 26: Links count */
+ __le32 i_blocks; /* 28: Blocks count */
+ __le32 i_flags; /* 32: File flags */
+ union {
+ struct {
+ __le32 l_i_reserved1;
+ } linux1;
+ struct {
+ __le32 h_i_translator;
+ } hurd1;
+ struct {
+ __le32 m_i_reserved1;
+ } masix1;
+ } osd1; /* 36: OS dependent 1 */
+ __le32 i_block[EXT2_N_BLOCKS];/* 40: Pointers to blocks */
+ __le32 i_generation; /* 100: File version (for NFS) */
+ __le32 i_file_acl; /* 104: File ACL */
+ __le32 i_dir_acl; /* 108: Directory ACL */
+ __le32 i_faddr; /* 112: Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* 116: Fragment number */
+ __u8 l_i_fsize; /* 117: Fragment size */
+ __u16 i_pad1;
+ __le16 l_i_uid_high; /* 120: these 2 fields */
+ __le16 l_i_gid_high; /* 122: were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __le16 h_i_mode_high;
+ __le16 h_i_uid_high;
+ __le16 h_i_gid_high;
+ __le32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __u16 m_pad1;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+};
+
+#define i_size_high i_dir_acl
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __le32 s_inodes_count; /* Inodes count */
+ __le32 s_blocks_count; /* Blocks count */
+ __le32 s_r_blocks_count; /* Reserved blocks count */
+ __le32 s_free_blocks_count; /* Free blocks count */
+ __le32 s_free_inodes_count; /* Free inodes count */
+ __le32 s_first_data_block; /* First Data Block */
+ __le32 s_log_block_size; /* Block size */
+ __le32 s_log_frag_size; /* Fragment size */
+ __le32 s_blocks_per_group; /* # Blocks per group */
+ __le32 s_frags_per_group; /* # Fragments per group */
+ __le32 s_inodes_per_group; /* # Inodes per group */
+ __le32 s_mtime; /* Mount time */
+ __le32 s_wtime; /* Write time */
+ __le16 s_mnt_count; /* Mount count */
+ __le16 s_max_mnt_count; /* Maximal mount count */
+ __le16 s_magic; /* Magic signature */
+ __le16 s_state; /* File system state */
+ __le16 s_errors; /* Behaviour when detecting errors */
+ __le16 s_minor_rev_level; /* minor revision level */
+ __le32 s_lastcheck; /* time of last check */
+ __le32 s_checkinterval; /* max. time between checks */
+ __le32 s_creator_os; /* OS */
+ __le32 s_rev_level; /* Revision level */
+ __le16 s_def_resuid; /* Default uid for reserved blocks */
+ __le16 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...
+ */
+ __le32 s_first_ino; /* First non-reserved inode */
+ __le16 s_inode_size; /* size of inode structure */
+ __le16 s_block_group_nr; /* block group # of this superblock */
+ __le32 s_feature_compat; /* compatible feature set */
+ __le32 s_feature_incompat; /* incompatible feature set */
+ __le32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __le32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_COMPAT_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_padding1;
+ /*
+ * Journaling support valid if EXT3_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_reserved_char_pad;
+ __u16 s_reserved_word_pad;
+ __le32 s_default_mount_opts;
+ __le32 s_first_meta_bg; /* First metablock block group */
+ __u32 s_reserved[190]; /* Padding to the end of the block */
+};
+
+/*
+ * 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
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT2_SET_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT2_SET_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask) \
+ EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(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_INO 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+#define EXT2_FEATURE_COMPAT_ANY 0xffffffff
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT2_FEATURE_RO_COMPAT_ANY 0xffffffff
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+/*
+#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+ EXT2_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED ~EXT2_FEATURE_RO_COMPAT_SUPP
+#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED ~EXT2_FEATURE_INCOMPAT_SUPP
+*/
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ __le32 inode; /* Inode number */
+ __le16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+// NOTE: The original Linux kernel header defines ext2_dir_entry with the original
+// layout and ext2_dir_entry_2 with the revised layout. We simply use the revised one.
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+enum {
+ EXT2_FT_UNKNOWN,
+ EXT2_FT_REG_FILE,
+ EXT2_FT_DIR,
+ EXT2_FT_CHRDEV,
+ EXT2_FT_BLKDEV,
+ EXT2_FT_FIFO,
+ EXT2_FT_SOCK,
+ EXT2_FT_SYMLINK,
+ EXT2_FT_MAX
+};
+
+
+#endif
--- /dev/null
+/* $Id: fsw_hfs.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.c - HFS file system driver code, see
+ *
+ * http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ * Current limitations:
+ * - Doesn't support permissions
+ * - Complete Unicode case-insensitiveness disabled (large tables)
+ * - No links
+ * - Only supports pure HFS+ (i.e. no HFS, or HFS+ embedded to HFS)
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#include "fsw_hfs.h"
+
+#ifdef HOST_POSIX
+#define DPRINT(x) printf(x)
+#define DPRINT2(x,y) printf(x,y)
+#define BP(msg) do { printf("ERROR: %s", msg); asm("int3"); } while (0)
+#else
+#define CONCAT(x,y) x##y
+#define DPRINT(x) Print(CONCAT(L,x))
+#define DPRINT2(x,y) Print(CONCAT(L,x), y)
+#define BP(msg) DPRINT(msg)
+#endif
+
+// functions
+#if 0
+void dump_str(fsw_u16* p, fsw_u32 len, int swap)
+{
+ int i;
+
+ for (i=0; i<len; i++)
+ {
+ fprintf(stderr, "%c", swap ? be16_to_cpu(p[i]) : p[i]);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol);
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol);
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno);
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_hfs_dnode **child_dno);
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_hfs_dnode **child_dno);
+#if 0
+static fsw_status_t fsw_hfs_read_dirrec(struct fsw_shandle *shand, struct hfs_dirrec_buffer *dirrec_buffer);
+#endif
+
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *link);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs) = {
+ { FSW_STRING_TYPE_ISO88591, 4, 4, "hfs" },
+ sizeof(struct fsw_hfs_volume),
+ sizeof(struct fsw_hfs_dnode),
+
+ fsw_hfs_volume_mount, // volume open
+ fsw_hfs_volume_free, // volume close
+ fsw_hfs_volume_stat, // volume info: total_bytes, free_bytes
+ fsw_hfs_dnode_fill, //return FSW_SUCCESS;
+ fsw_hfs_dnode_free, // empty
+ fsw_hfs_dnode_stat, //size and times
+ fsw_hfs_get_extent, // get the physical disk block number for the requested logical block number
+ fsw_hfs_dir_lookup, //retrieve the directory entry with the given name
+ fsw_hfs_dir_read, // next directory entry when reading a directory
+ fsw_hfs_readlink, // return FSW_UNSUPPORTED;
+};
+
+static fsw_s32
+fsw_hfs_read_block (struct fsw_hfs_dnode * dno,
+ fsw_u32 log_bno,
+ fsw_u32 off,
+ fsw_s32 len,
+ fsw_u8 * buf)
+{
+ fsw_status_t status;
+ struct fsw_extent extent;
+ fsw_u32 phys_bno;
+ fsw_u8* buffer;
+
+ extent.log_start = log_bno;
+ status = fsw_hfs_get_extent(dno->g.vol, dno, &extent);
+ if (status)
+ return status;
+
+ phys_bno = extent.phys_start;
+ //Slice - increase cache level from 0 to 3
+ status = fsw_block_get(dno->g.vol, phys_bno, 3, (void **)&buffer);
+ if (status)
+ return status;
+
+ fsw_memcpy(buf, buffer + off, len);
+
+ fsw_block_release(dno->g.vol, phys_bno, buffer);
+
+ return FSW_SUCCESS;
+
+}
+
+/* Read data from HFS file. */
+static fsw_s32
+fsw_hfs_read_file (struct fsw_hfs_dnode * dno,
+ fsw_u64 pos,
+ fsw_s32 len,
+ fsw_u8 * buf)
+{
+
+ fsw_status_t status;
+ fsw_u32 log_bno;
+ fsw_u32 block_size_bits = dno->g.vol->block_size_shift;
+ fsw_u32 block_size = (1 << block_size_bits);
+ fsw_u32 block_size_mask = block_size - 1;
+ fsw_s32 read = 0;
+
+ while (len > 0)
+ {
+ fsw_u32 off = (fsw_u32)(pos & block_size_mask);
+ fsw_s32 next_len = len;
+
+ log_bno = (fsw_u32)RShiftU64(pos, block_size_bits);
+
+ if ( next_len >= 0
+ && (fsw_u32)next_len > block_size)
+ next_len = block_size;
+ status = fsw_hfs_read_block(dno, log_bno, off, next_len, buf);
+ if (status)
+ return -1;
+ buf += next_len;
+ pos += next_len;
+ len -= next_len;
+ read += next_len;
+ }
+
+ return read;
+}
+
+
+static fsw_s32
+fsw_hfs_compute_shift(fsw_u32 size)
+{
+ fsw_s32 i;
+
+ for (i=0; i<32; i++)
+ {
+ if ((size >> i) == 0)
+ return i - 1;
+ }
+
+// BP("BUG\n");
+ return 0;
+}
+
+/**
+ * Mount an HFS+ volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+//algo from Chameleon
+/*
+void
+HFSGetDescription(CICell ih, char *str, long strMaxLen)
+{
+
+ UInt16 nodeSize;
+ UInt32 firstLeafNode;
+ long long dirIndex;
+ char *name;
+ long flags, time;
+
+ if (HFSInitPartition(ih) == -1) { return; }
+
+ // Fill some crucial data structures by side effect.
+ dirIndex = 0;
+ HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+
+ // Now we can loook up the volume name node.
+ nodeSize = be16_to_cpu(gBTHeaders[kBTreeCatalog]->nodeSize);
+ firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+
+ dirIndex = (long long) firstLeafNode * nodeSize;
+
+ GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+
+ strncpy(str, name, strMaxLen);
+ str[strMaxLen] = '\0';
+}
+*/
+
+
+static fsw_status_t fsw_hfs_volume_mount(struct fsw_hfs_volume *vol)
+{
+ fsw_status_t status, rv;
+ void *buffer = NULL;
+ HFSPlusVolumeHeader *voldesc;
+ fsw_u32 blockno;
+ struct fsw_string s;
+ HFSMasterDirectoryBlock* mdb;
+ UINTN i;
+
+ rv = FSW_UNSUPPORTED;
+
+ vol->primary_voldesc = NULL;
+ fsw_set_blocksize(vol, HFS_BLOCKSIZE, HFS_BLOCKSIZE);
+ blockno = HFS_SUPERBLOCK_BLOCKNO;
+
+#define CHECK(s) \
+ if (status) { \
+ rv = status; \
+ break; \
+ }
+
+ vol->emb_block_off = 0;
+ vol->hfs_kind = 0;
+ do {
+ fsw_u16 signature;
+ BTHeaderRec tree_header;
+ fsw_s32 r;
+ fsw_u32 block_size;
+
+ status = fsw_block_get(vol, blockno, 0, &buffer);
+ CHECK(status);
+ voldesc = (HFSPlusVolumeHeader *)buffer;
+ mdb = (HFSMasterDirectoryBlock*)buffer;
+ signature = be16_to_cpu(voldesc->signature);
+
+ if ((signature == kHFSPlusSigWord) || (signature == kHFSXSigWord)) //H+ or HX
+ {
+ if (vol->hfs_kind == 0)
+ {
+ // DPRINT("found HFS+\n");
+ vol->hfs_kind = FSW_HFS_PLUS;
+ }
+ }
+ else if (signature == kHFSSigWord) // 'BD'
+ {
+// HFSMasterDirectoryBlock* mdb = (HFSMasterDirectoryBlock*)buffer;
+//VolumeName = mdb->drVN 28bytes
+ if (be16_to_cpu(mdb->drEmbedSigWord) == kHFSPlusSigWord)
+ {
+ DPRINT("found HFS+ inside HFS, untested\n");
+ vol->hfs_kind = FSW_HFS_PLUS_EMB;
+ vol->emb_block_off = be32_to_cpu(mdb->drEmbedExtent.startBlock);
+ blockno += vol->emb_block_off;
+ /* retry */
+ continue;
+ }
+ else
+ {
+ DPRINT("found plain HFS, unsupported\n");
+ vol->hfs_kind = FSW_HFS_PLAIN;
+ }
+ rv = FSW_UNSUPPORTED;
+ break;
+ }
+ else
+ {
+ rv = FSW_UNSUPPORTED;
+ break;
+ }
+
+ status = fsw_memdup((void **)&vol->primary_voldesc, voldesc,
+ sizeof(*voldesc));
+ CHECK(status);
+
+
+ block_size = be32_to_cpu(voldesc->blockSize);
+ vol->block_size_shift = fsw_hfs_compute_shift(block_size);
+
+ fsw_block_release(vol, blockno, buffer);
+ buffer = NULL;
+ voldesc = NULL;
+ fsw_set_blocksize(vol, block_size, block_size);
+
+ /* get volume name */
+ for (i = kHFSMaxVolumeNameChars; i > 0; i--)
+ if (mdb->drVN[i-1] != ' ')
+ break;
+
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = 0;
+ s.data = NULL; //&mdb->drVN; //"HFS+ volume";
+
+ //fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ CHECK(status);
+
+ /* Setup catalog dnode */
+ status = fsw_dnode_create_root(vol, kHFSCatalogFileID, &vol->catalog_tree.file);
+ CHECK(status);
+ fsw_memcpy (vol->catalog_tree.file->extents,
+ vol->primary_voldesc->catalogFile.extents,
+ sizeof vol->catalog_tree.file->extents);
+ vol->catalog_tree.file->g.size =
+ be64_to_cpu(vol->primary_voldesc->catalogFile.logicalSize);
+
+ /* Setup extents overflow file */
+ status = fsw_dnode_create_root(vol, kHFSExtentsFileID, &vol->extents_tree.file);
+ fsw_memcpy (vol->extents_tree.file->extents,
+ vol->primary_voldesc->extentsFile.extents,
+ sizeof vol->extents_tree.file->extents);
+ vol->extents_tree.file->g.size =
+ be64_to_cpu(vol->primary_voldesc->extentsFile.logicalSize);
+
+ /* Setup the root dnode */
+ status = fsw_dnode_create_root(vol, kHFSRootFolderID, &vol->g.root);
+ CHECK(status);
+
+ /*
+ * Read catalog file, we know that first record is in the first node, right after
+ * the node descriptor.
+ */
+ r = fsw_hfs_read_file(vol->catalog_tree.file,
+ sizeof (BTNodeDescriptor),
+ sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+ if (r <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+ vol->case_sensitive =
+ (signature == kHFSXSigWord) &&
+ (tree_header.keyCompareType == kHFSBinaryCompare);
+ vol->catalog_tree.root_node = be32_to_cpu (tree_header.rootNode);
+ vol->catalog_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+ /* Read extents overflow file */
+ r = fsw_hfs_read_file(vol->extents_tree.file,
+ sizeof (BTNodeDescriptor),
+ sizeof (BTHeaderRec), (fsw_u8 *) &tree_header);
+ if (r <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+
+ vol->extents_tree.root_node = be32_to_cpu (tree_header.rootNode);
+ vol->extents_tree.node_size = be16_to_cpu (tree_header.nodeSize);
+
+ rv = FSW_SUCCESS;
+ } while (0);
+
+#undef CHECK
+
+
+ if (buffer != NULL)
+ fsw_block_release(vol, blockno, buffer);
+
+ return rv;
+}
+//Here is a method to obtain Volume label from Apple
+//how to implement it?
+/*
+UInt16 nodeSize;
+UInt32 firstLeafNode;
+long long dirIndex;
+char *name;
+long flags, time;
+ char *nodeBuf, *testKey, *entry;
+
+
+if (HFSInitPartition(ih) == -1) { return; }
+
+// Fill some crucial data structures by side effect.
+dirIndex = 0;
+HFSGetDirEntry(ih, "/", &dirIndex, &name, &flags, &time, 0, 0);
+
+// Now we can loook up the volume name node.
+nodeSize = SWAP_BE16(gBTHeaders[kBTreeCatalog]->nodeSize);
+firstLeafNode = SWAP_BE32(gBTHeaders[kBTreeCatalog]->firstLeafNode);
+
+dirIndex = (long long) firstLeafNode * nodeSize;
+ index = (long) (*dirIndex % nodeSize); == 0
+ curNode = (long) (*dirIndex / nodeSize); == firstLeafNode
+
+//GetCatalogEntry(&dirIndex, &name, &flags, &time, 0, 0);
+ // Read the BTree node and get the record for index.
+ ReadExtent(extent, extentSize, kHFSCatalogFileID,
+ (long long) curNode * nodeSize, nodeSize, nodeBuf, 1);
+ GetBTreeRecord(index, nodeBuf, nodeSize, &testKey, &entry);
+
+ utf_encodestr(((HFSPlusCatalogKey *)testKey)->nodeName.unicode,
+ SWAP_BE16(((HFSPlusCatalogKey *)testKey)->nodeName.length),
+ (u_int8_t *)gTempStr, 256, OSBigEndian);
+
+ *name = gTempStr;
+
+strncpy(str, name, strMaxLen);
+str[strMaxLen] = '\0';
+*/
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_hfs_volume_free(struct fsw_hfs_volume *vol)
+{
+ if (vol->primary_voldesc)
+ {
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+ }
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_hfs_volume_stat(struct fsw_hfs_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = be32_to_cpu(vol->primary_voldesc->totalBlocks) << vol->block_size_shift;
+ sb->free_bytes = be32_to_cpu(vol->primary_voldesc->freeBlocks) << vol->block_size_shift;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode.
+ */
+
+static fsw_status_t fsw_hfs_dnode_fill(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_hfs_dnode_free(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno)
+{
+}
+
+static fsw_u32 mac_to_posix(fsw_u32 mac_time)
+{
+ /* Mac time is 1904 year based */
+ return mac_time ? mac_time - 2082844800 : 0;
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_hfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_hfs_dnode_stat(struct fsw_hfs_volume *vol,
+ struct fsw_hfs_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ sb->used_bytes = dno->used_bytes;
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, mac_to_posix(dno->ctime));
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, mac_to_posix(dno->mtime));
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, 0);
+ sb->store_attr_posix(sb, 0700);
+
+ return FSW_SUCCESS;
+}
+
+static int
+fsw_hfs_find_block(HFSPlusExtentRecord * exts,
+ fsw_u32 * lbno,
+ fsw_u32 * pbno)
+{
+ int i;
+ fsw_u32 cur_lbno = *lbno;
+
+ for (i = 0; i < 8; i++)
+ {
+ fsw_u32 start = be32_to_cpu ((*exts)[i].startBlock);
+ fsw_u32 count = be32_to_cpu ((*exts)[i].blockCount);
+
+ if (cur_lbno < count)
+ {
+ *pbno = start + cur_lbno;
+ return 1;
+ }
+
+ cur_lbno -= count;
+ }
+
+ *lbno = cur_lbno;
+
+ return 0;
+}
+
+/* Find record offset, numbering starts from the end */
+static fsw_u32
+fsw_hfs_btree_recoffset (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * node,
+ fsw_u32 index)
+{
+ fsw_u8 *cnode = (fsw_u8 *) node;
+ fsw_u16 *recptr;
+ recptr = (fsw_u16 *) (cnode+btree->node_size - index * 2 - 2);
+ return be16_to_cpu(*recptr);
+}
+
+/* Pointer to the key inside node */
+static BTreeKey *
+fsw_hfs_btree_rec (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * node,
+ fsw_u32 index)
+{
+ fsw_u8 *cnode = (fsw_u8 *) node;
+ fsw_u32 offset;
+ offset = fsw_hfs_btree_recoffset (btree, node, index);
+ return (BTreeKey *) (cnode + offset);
+}
+
+
+static fsw_status_t
+fsw_hfs_btree_search (struct fsw_hfs_btree * btree,
+ BTreeKey * key,
+ int (*compare_keys) (BTreeKey* key1, BTreeKey* key2),
+ BTNodeDescriptor ** result,
+ fsw_u32 * key_offset)
+{
+ BTNodeDescriptor* node;
+ fsw_u32 currnode;
+ fsw_u32 rec;
+ fsw_status_t status;
+ fsw_u8* buffer = NULL;
+
+ currnode = btree->root_node;
+ status = fsw_alloc(btree->node_size, &buffer);
+ if (status)
+ return status;
+ node = (BTNodeDescriptor*)buffer;
+
+ while (1)
+ {
+ int cmp = 0;
+ int match;
+ fsw_u32 count;
+
+ readnode:
+ match = 0;
+ /* Read a node. */
+ if (fsw_hfs_read_file (btree->file,
+ (fsw_u64)currnode * btree->node_size,
+ btree->node_size, buffer) <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ break;
+ }
+
+ if (be16_to_cpu(*(fsw_u16*)(buffer + btree->node_size - 2)) != sizeof(BTNodeDescriptor))
+ BP("corrupted node\n");
+
+ count = be16_to_cpu (node->numRecords);
+
+#if 1
+ for (rec = 0; rec < count; rec++)
+ {
+ BTreeKey *currkey;
+
+ currkey = fsw_hfs_btree_rec (btree, node, rec);
+ cmp = compare_keys (currkey, key);
+ //fprintf(stderr, "rec=%d cmp=%d kind=%d \n", rec, cmp, node->kind);
+
+ /* Leaf node. */
+ if (node->kind == kBTLeafNode)
+ {
+ if (cmp == 0)
+ {
+ /* Found! */
+ *result = node;
+ *key_offset = rec;
+
+ status = FSW_SUCCESS;
+ goto done;
+ }
+ }
+ else if (node->kind == kBTIndexNode)
+ {
+ fsw_u32 *pointer;
+
+ if (cmp > 0)
+ break;
+
+ pointer = (fsw_u32 *) ((char *) currkey
+ + be16_to_cpu (currkey->length16)
+ + 2);
+ currnode = be32_to_cpu (*pointer);
+ match = 1;
+ }
+ }
+
+ if (node->kind == kBTLeafNode && cmp < 0 && node->fLink)
+ {
+ currnode = be32_to_cpu(node->fLink);
+ goto readnode;
+ }
+ else if (!match)
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+#else
+ /* Perform binary search */
+ fsw_u32 lower = 0;
+ fsw_u32 upper = count - 1;
+ fsw_s32 cmp = -1;
+ BTreeKey *currkey = NULL;
+
+ if (count == 0)
+ {
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+
+ while (lower <= upper)
+ {
+ fsw_u32 index = (lower + upper) / 2;
+
+ currkey = fsw_hfs_btree_rec (btree, node, index);
+
+ cmp = compare_keys (currkey, key);
+ if (cmp < 0) upper = index - 1;
+ if (cmp > 0) lower = index + 1;
+ if (cmp == 0)
+ {
+ /* Found! */
+ *result = node;
+ *key_offset = rec;
+
+ status = FSW_SUCCESS;
+ goto done;
+ }
+ }
+
+ if (cmp < 0)
+ currkey = fsw_hfs_btree_rec (btree, node, upper);
+
+ if (node->kind == kBTIndexNode && currkey)
+ {
+ fsw_u32 *pointer;
+
+ pointer = (fsw_u32 *) ((char *) currkey
+ + be16_to_cpu (currkey->length16)
+ + 2);
+ currnode = be32_to_cpu (*pointer);
+ }
+ else
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+#endif
+ }
+
+
+ done:
+ if (buffer != NULL && status != FSW_SUCCESS)
+ fsw_free(buffer);
+
+ return status;
+}
+typedef struct
+{
+ fsw_u32 id;
+ fsw_u32 type;
+ struct fsw_string * name;
+ fsw_u64 size;
+ fsw_u64 used;
+ fsw_u32 ctime;
+ fsw_u32 mtime;
+ HFSPlusExtentRecord extents;
+} file_info_t;
+
+typedef struct
+{
+ fsw_u32 cur_pos; /* current position */
+ fsw_u32 parent;
+ struct fsw_hfs_volume * vol;
+
+ struct fsw_shandle * shandle; /* this one track iterator's state */
+ file_info_t file_info;
+} visitor_parameter_t;
+
+static int
+fsw_hfs_btree_visit_node(BTreeKey *record, void* param)
+{
+ visitor_parameter_t* vp = (visitor_parameter_t*)param;
+ fsw_u8* base = (fsw_u8*)record->rawData + be16_to_cpu(record->length16) + 2;
+ fsw_u16 rec_type = be16_to_cpu(*(fsw_u16*)base);
+ struct HFSPlusCatalogKey* cat_key = (HFSPlusCatalogKey*)record;
+ fsw_u16 name_len;
+ fsw_u16 *name_ptr;
+ fsw_u32 i;
+ struct fsw_string * file_name;
+
+ if (be32_to_cpu(cat_key->parentID) != vp->parent)
+ return -1;
+
+ /* not smth we care about */
+ if (vp->shandle->pos != vp->cur_pos++)
+ return 0;
+
+ switch (rec_type)
+ {
+ case kHFSPlusFolderRecord:
+ {
+ HFSPlusCatalogFolder* folder_info = (HFSPlusCatalogFolder*)base;
+
+ vp->file_info.id = be32_to_cpu(folder_info->folderID);
+ vp->file_info.type = FSW_DNODE_TYPE_DIR;
+ vp->file_info.size = be32_to_cpu(folder_info->valence);
+ vp->file_info.used = be32_to_cpu(folder_info->valence);
+ vp->file_info.ctime = be32_to_cpu(folder_info->createDate);
+ vp->file_info.mtime = be32_to_cpu(folder_info->contentModDate);
+ break;
+ }
+ case kHFSPlusFileRecord:
+ {
+ HFSPlusCatalogFile* file_info = (HFSPlusCatalogFile*)base;
+
+ vp->file_info.id = be32_to_cpu(file_info->fileID);
+ vp->file_info.type = FSW_DNODE_TYPE_FILE;
+ vp->file_info.size = be64_to_cpu(file_info->dataFork.logicalSize);
+ vp->file_info.used = LShiftU64(be32_to_cpu(file_info->dataFork.totalBlocks),
+ vp->vol->block_size_shift);
+ vp->file_info.ctime = be32_to_cpu(file_info->createDate);
+ vp->file_info.mtime = be32_to_cpu(file_info->contentModDate);
+ fsw_memcpy(&vp->file_info.extents, &file_info->dataFork.extents,
+ sizeof vp->file_info.extents);
+ break;
+ }
+ case kHFSPlusFolderThreadRecord:
+ case kHFSPlusFileThreadRecord:
+ {
+ vp->shandle->pos++;
+ return 0;
+ }
+ default:
+ BP("unknown file type\n");
+ vp->file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+ break;
+ }
+
+ name_len = be16_to_cpu(cat_key->nodeName.length);
+
+ file_name = vp->file_info.name;
+ file_name->len = name_len;
+ fsw_memdup(&file_name->data, &cat_key->nodeName.unicode[0], 2*name_len);
+ file_name->size = 2*name_len;
+ file_name->type = FSW_STRING_TYPE_UTF16;
+ name_ptr = (fsw_u16*)file_name->data;
+ for (i=0; i<name_len; i++)
+ {
+ name_ptr[i] = be16_to_cpu(name_ptr[i]);
+ }
+ vp->shandle->pos++;
+
+ return 1;
+}
+
+static fsw_status_t
+fsw_hfs_btree_iterate_node (struct fsw_hfs_btree * btree,
+ BTNodeDescriptor * first_node,
+ fsw_u32 first_rec,
+ int (*callback) (BTreeKey *record, void* param),
+ void * param)
+{
+ fsw_status_t status;
+ /* We modify node, so make a copy */
+ BTNodeDescriptor* node = first_node;
+ fsw_u8* buffer = NULL;
+
+ status = fsw_alloc(btree->node_size, &buffer);
+ if (status)
+ return status;
+
+ while (1)
+ {
+ fsw_u32 i;
+ fsw_u32 count = be16_to_cpu(node->numRecords);
+ fsw_u32 next_node;
+
+ /* Iterate over all records in this node. */
+ for (i = first_rec; i < count; i++)
+ {
+ int rv = callback(fsw_hfs_btree_rec (btree, node, i), param);
+
+ switch (rv)
+ {
+ case 1:
+ status = FSW_SUCCESS;
+ goto done;
+ case -1:
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+ /* if callback returned 0 - continue */
+ }
+
+ next_node = be32_to_cpu(node->fLink);
+
+ if (!next_node)
+ {
+ status = FSW_NOT_FOUND;
+ break;
+ }
+
+ if (fsw_hfs_read_file (btree->file,
+ next_node * btree->node_size,
+ btree->node_size, buffer) <= 0)
+ {
+ status = FSW_VOLUME_CORRUPTED;
+ return 1;
+ }
+
+ node = (BTNodeDescriptor*)buffer;
+ first_rec = 0;
+ }
+ done:
+ if (buffer)
+ fsw_free(buffer);
+
+ return status;
+}
+
+#if 0
+void deb(fsw_u16* p, int len, int swap)
+{
+ int i;
+ for (i=0; i<len; i++)
+ {
+ printf("%c", swap ? be16_to_cpu(p[i]) : p[i]);
+ }
+ printf("\n");
+}
+#endif
+
+static int
+fsw_hfs_cmp_extkey(BTreeKey* key1, BTreeKey* key2)
+{
+ HFSPlusExtentKey* ekey1 = (HFSPlusExtentKey*)key1;
+ HFSPlusExtentKey* ekey2 = (HFSPlusExtentKey*)key2;
+ int result;
+
+ /* First key is read from the FS data, second is in-memory in CPU endianess */
+ result = be32_to_cpu(ekey1->fileID) - ekey2->fileID;
+
+ if (result)
+ return result;
+
+ result = ekey1->forkType - ekey2->forkType;
+
+ if (result)
+ return result;
+
+ result = be32_to_cpu(ekey1->startBlock) - ekey2->startBlock;
+ return result;
+}
+
+static int
+fsw_hfs_cmp_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+ HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+ HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+ int apos, bpos, lc;
+ fsw_u16 ac, bc;
+ fsw_u32 parentId1;
+ int key1Len;
+ fsw_u16 *p1;
+ fsw_u16 *p2;
+
+ parentId1 = be32_to_cpu(ckey1->parentID);
+
+ if (parentId1 > ckey2->parentID)
+ return 1;
+ if (parentId1 < ckey2->parentID)
+ return -1;
+
+ p1 = &ckey1->nodeName.unicode[0];
+ p2 = &ckey2->nodeName.unicode[0];
+ key1Len = be16_to_cpu (ckey1->nodeName.length);
+ apos = bpos = 0;
+
+ while(1)
+ {
+ /* get next valid character from ckey1 */
+ for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+ ac = be16_to_cpu(p1[apos]);
+ lc = ac;
+ };
+ ac = (fsw_u16)lc;
+
+ /* get next valid character from ckey2 */
+ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+ bc = p2[bpos];
+ lc = bc;
+ };
+ bc = (fsw_u16)lc;
+
+ if (ac != bc || (ac == 0 && bc == 0))
+ return ac - bc;
+ }
+}
+
+static int
+fsw_hfs_cmpi_catkey (BTreeKey *key1, BTreeKey *key2)
+{
+ HFSPlusCatalogKey *ckey1 = (HFSPlusCatalogKey*)key1;
+ HFSPlusCatalogKey *ckey2 = (HFSPlusCatalogKey*)key2;
+
+ int apos, bpos, lc;
+ fsw_u16 ac, bc;
+ fsw_u32 parentId1;
+ int key1Len;
+ fsw_u16 *p1;
+ fsw_u16 *p2;
+
+ parentId1 = be32_to_cpu(ckey1->parentID);
+
+ if (parentId1 > ckey2->parentID)
+ return 1;
+ if (parentId1 < ckey2->parentID)
+ return -1;
+
+ key1Len = be16_to_cpu (ckey1->nodeName.length);
+
+ if (key1Len == 0 && ckey2->nodeName.length == 0)
+ return 0;
+
+ p1 = &ckey1->nodeName.unicode[0];
+ p2 = &ckey2->nodeName.unicode[0];
+
+ apos = bpos = 0;
+
+ while(1)
+ {
+ /* get next valid character from ckey1 */
+ for (lc = 0; lc == 0 && apos < key1Len; apos++) {
+ ac = be16_to_cpu(p1[apos]);
+ lc = ac ? fsw_to_lower(ac) : 0;
+ };
+ ac = (fsw_u16)lc;
+
+ /* get next valid character from ckey2 */
+ for (lc = 0; lc == 0 && bpos < ckey2->nodeName.length; bpos++) {
+ bc = p2[bpos];
+ lc = bc ? fsw_to_lower(bc) : 0;
+ };
+ bc = (fsw_u16)lc;
+
+ if (ac != bc || (ac == 0 && bc == 0))
+ return ac - bc;
+ }
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_hfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_hfs_get_extent(struct fsw_hfs_volume * vol,
+ struct fsw_hfs_dnode * dno,
+ struct fsw_extent * extent)
+{
+ fsw_status_t status;
+ fsw_u32 lbno;
+ HFSPlusExtentRecord *exts;
+ BTNodeDescriptor *node = NULL;
+
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->log_count = 1;
+ lbno = extent->log_start;
+
+ /* we only care about data forks atm, do we? */
+ exts = &dno->extents;
+
+ while (1)
+ {
+ struct HFSPlusExtentKey* key;
+ struct HFSPlusExtentKey overflowkey;
+ fsw_u32 ptr;
+ fsw_u32 phys_bno;
+
+ if (fsw_hfs_find_block(exts, &lbno, &phys_bno))
+ {
+ extent->phys_start = phys_bno + vol->emb_block_off;
+ status = FSW_SUCCESS;
+ break;
+ }
+
+
+ /* Find appropriate overflow record */
+ overflowkey.fileID = dno->g.dnode_id;
+ overflowkey.startBlock = extent->log_start - lbno;
+
+ if (node != NULL)
+ {
+ fsw_free(node);
+ node = NULL;
+ }
+
+ status = fsw_hfs_btree_search (&vol->extents_tree,
+ (BTreeKey*)&overflowkey,
+ fsw_hfs_cmp_extkey,
+ &node, &ptr);
+ if (status)
+ break;
+
+ key = (struct HFSPlusExtentKey *)
+ fsw_hfs_btree_rec (&vol->extents_tree, node, ptr);
+ exts = (HFSPlusExtentRecord*) (key + 1);
+ }
+
+ if (node != NULL)
+ fsw_free(node);
+
+ return status;
+}
+
+static const fsw_u16* g_blacklist[] =
+{
+ //L"AppleIntelCPUPowerManagement.kext",
+ NULL
+};
+
+
+//#define HFS_FILE_INJECTION
+
+#ifdef HFS_FILE_INJECTION
+static struct
+{
+ const fsw_u16* path;
+ const fsw_u16* name;
+} g_injectList[] =
+{
+ {
+ L"/System/Library/Extensions",
+ L"ApplePS2Controller.kext"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+#endif
+
+static fsw_status_t
+create_hfs_dnode(struct fsw_hfs_dnode * dno,
+ file_info_t * file_info,
+ struct fsw_hfs_dnode ** child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_hfs_dnode * baby;
+
+ status = fsw_dnode_create(dno, file_info->id, file_info->type,
+ file_info->name, &baby);
+ if (status)
+ return status;
+
+ baby->g.size = file_info->size;
+ baby->used_bytes = file_info->used;
+ baby->ctime = file_info->ctime;
+ baby->mtime = file_info->mtime;
+
+
+ /* Fill-in extents info */
+ if (file_info->type == FSW_DNODE_TYPE_FILE)
+ {
+ fsw_memcpy(baby->extents, &file_info->extents, sizeof file_info->extents);
+ }
+
+ *child_dno_out = baby;
+
+ return FSW_SUCCESS;
+}
+
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_hfs_dir_lookup(struct fsw_hfs_volume * vol,
+ struct fsw_hfs_dnode * dno,
+ struct fsw_string * lookup_name,
+ struct fsw_hfs_dnode ** child_dno_out)
+{
+ fsw_status_t status;
+ struct HFSPlusCatalogKey catkey;
+ fsw_u32 ptr;
+ fsw_u16 rec_type;
+ BTNodeDescriptor * node = NULL;
+ struct fsw_string rec_name;
+ int free_data = 0, i;
+ HFSPlusCatalogKey* file_key;
+ file_info_t file_info;
+ fsw_u8* base;
+
+
+ fsw_memzero(&file_info, sizeof file_info);
+ file_info.name = &rec_name;
+
+ catkey.parentID = dno->g.dnode_id;
+ catkey.nodeName.length = (fsw_u16)lookup_name->len;
+
+ /* no need to allocate anything */
+ if (lookup_name->type == FSW_STRING_TYPE_UTF16)
+ {
+ fsw_memcpy(catkey.nodeName.unicode, lookup_name->data, lookup_name->size);
+ rec_name = *lookup_name;
+ } else
+ {
+ status = fsw_strdup_coerce(&rec_name, FSW_STRING_TYPE_UTF16, lookup_name);
+ /* nothing allocated so far */
+ if (status)
+ goto done;
+ free_data = 1;
+ fsw_memcpy(catkey.nodeName.unicode, rec_name.data, rec_name.size);
+ }
+
+ /* Dirty hack: blacklisting of certain files on FS driver level */
+ for (i = 0; g_blacklist[i]; i++)
+ {
+ if (fsw_memeq(g_blacklist[i], catkey.nodeName.unicode, catkey.nodeName.length*2))
+ {
+ DPRINT2("Blacklisted %s\n", g_blacklist[i]);
+ status = FSW_NOT_FOUND;
+ goto done;
+ }
+ }
+
+#ifdef HFS_FILE_INJECTION
+ if (fsw_hfs_inject(vol,
+ dno,
+ catkey.nodeName.unicode,
+ catkey.nodeName.length,
+ &file_info))
+ {
+ status = FSW_SUCCESS;
+ goto create;
+ }
+#endif
+
+ catkey.keyLength = (fsw_u16)(5 + rec_name.size);
+
+ status = fsw_hfs_btree_search (&vol->catalog_tree,
+ (BTreeKey*)&catkey,
+ vol->case_sensitive ?
+ fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+ &node, &ptr);
+ if (status)
+ goto done;
+
+ file_key = (HFSPlusCatalogKey *)fsw_hfs_btree_rec (&vol->catalog_tree, node, ptr);
+ /* for plain HFS "-(keySize & 1)" would be needed */
+ base = (fsw_u8*)file_key + be16_to_cpu(file_key->keyLength) + 2;
+ rec_type = be16_to_cpu(*(fsw_u16*)base);
+
+ /** @todo: read additional info */
+ switch (rec_type)
+ {
+ case kHFSPlusFolderRecord:
+ {
+ HFSPlusCatalogFolder* info = (HFSPlusCatalogFolder*)base;
+
+ file_info.id = be32_to_cpu(info->folderID);
+ file_info.type = FSW_DNODE_TYPE_DIR;
+ /* @todo: return number of elements, maybe use smth else */
+ file_info.size = be32_to_cpu(info->valence);
+ file_info.used = be32_to_cpu(info->valence);
+ file_info.ctime = be32_to_cpu(info->createDate);
+ file_info.mtime = be32_to_cpu(info->contentModDate);
+ break;
+ }
+ case kHFSPlusFileRecord:
+ {
+ HFSPlusCatalogFile* info = (HFSPlusCatalogFile*)base;
+
+ file_info.id = be32_to_cpu(info->fileID);
+ file_info.type = FSW_DNODE_TYPE_FILE;
+ file_info.size = be64_to_cpu(info->dataFork.logicalSize);
+ file_info.used = LShiftU64(be32_to_cpu(info->dataFork.totalBlocks), vol->block_size_shift);
+ file_info.ctime = be32_to_cpu(info->createDate);
+ file_info.mtime = be32_to_cpu(info->contentModDate);
+ fsw_memcpy(&file_info.extents, &info->dataFork.extents,
+ sizeof file_info.extents);
+ break;
+ }
+ default:
+ BP("unknown file type\n");
+ file_info.type = FSW_DNODE_TYPE_UNKNOWN;
+
+ break;
+ }
+#ifdef HFS_FILE_INJECTION
+create:
+#endif
+ status = create_hfs_dnode(dno, &file_info, child_dno_out);
+ if (status)
+ goto done;
+
+done:
+
+ if (node != NULL)
+ fsw_free(node);
+
+ if (free_data)
+ fsw_strfree(&rec_name);
+
+ return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_hfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_hfs_dir_read(struct fsw_hfs_volume *vol,
+ struct fsw_hfs_dnode *dno,
+ struct fsw_shandle *shand,
+ struct fsw_hfs_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct HFSPlusCatalogKey catkey;
+ fsw_u32 ptr;
+ BTNodeDescriptor * node = NULL;
+
+ visitor_parameter_t param;
+ struct fsw_string rec_name;
+
+ catkey.parentID = dno->g.dnode_id;
+ catkey.nodeName.length = 0;
+
+ fsw_memzero(¶m, sizeof(param));
+
+ rec_name.type = FSW_STRING_TYPE_EMPTY;
+ param.file_info.name = &rec_name;
+
+ status = fsw_hfs_btree_search (&vol->catalog_tree,
+ (BTreeKey*)&catkey,
+ vol->case_sensitive ?
+ fsw_hfs_cmp_catkey : fsw_hfs_cmpi_catkey,
+ &node, &ptr);
+ if (status)
+ goto done;
+
+ /* Iterator updates shand state */
+ param.vol = vol;
+ param.shandle = shand;
+ param.parent = dno->g.dnode_id;
+ param.cur_pos = 0;
+ status = fsw_hfs_btree_iterate_node (&vol->catalog_tree,
+ node,
+ ptr,
+ fsw_hfs_btree_visit_node,
+ ¶m);
+ if (status)
+ goto done;
+
+ status = create_hfs_dnode(dno, ¶m.file_info, child_dno_out);
+
+ if (status)
+ goto done;
+
+ done:
+ fsw_strfree(&rec_name);
+
+ return status;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_hfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ */
+static fsw_status_t fsw_hfs_readlink(struct fsw_hfs_volume *vol, struct fsw_hfs_dnode *dno,
+ struct fsw_string *link_target)
+{
+ return FSW_UNSUPPORTED;
+}
+
+// EOF
--- /dev/null
+/* $Id: fsw_hfs.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_hfs.h - HFS file system driver header.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef _FSW_HFS_H_
+#define _FSW_HFS_H_
+
+#define VOLSTRUCTNAME fsw_hfs_volume
+#define DNODESTRUCTNAME fsw_hfs_dnode
+
+#include "fsw_core.h"
+
+
+//! Block size for HFS volumes.
+#define HFS_BLOCKSIZE 512
+
+//! Block number where the HFS superblock resides.
+#define HFS_SUPERBLOCK_BLOCKNO 2
+
+/* Make world look Applish enough for the system header describing HFS layout */
+#define __APPLE_API_PRIVATE
+#define __APPLE_API_UNSTABLE
+
+#define u_int8_t fsw_u8
+#define u_int16_t fsw_u16
+#define u_int32_t fsw_u32
+#define u_int64_t fsw_u64
+#define int8_t fsw_s8
+#define int16_t fsw_s16
+#define int32_t fsw_s32
+#define int64_t fsw_s64
+
+#include "hfs_format.h"
+
+#undef u_int8_t
+#undef u_int16_t
+#undef u_int32_t
+#undef u_int64_t
+#undef int8_t
+#undef int16_t
+#undef int32_t
+#undef int64_t
+
+#pragma pack(1)
+#ifdef _MSC_VER
+/* vasily: disable warning for non-standard anonymous struct/union
+ * declarations
+ */
+# pragma warning (disable:4201)
+# define inline __inline
+#endif
+
+struct hfs_dirrec {
+ fsw_u8 _dummy;
+};
+
+struct fsw_hfs_key
+{
+ union
+ {
+ struct HFSPlusExtentKey ext_key;
+ struct HFSPlusCatalogKey cat_key;
+ fsw_u16 key_len; /* Length is at the beginning of all keys */
+ };
+};
+
+#pragma pack()
+
+typedef enum {
+ /* Regular HFS */
+ FSW_HFS_PLAIN = 0,
+ /* HFS+ */
+ FSW_HFS_PLUS,
+ /* HFS+ embedded to HFS */
+ FSW_HFS_PLUS_EMB
+} fsw_hfs_kind;
+
+/**
+ * HFS: Dnode structure with HFS-specific data.
+ */
+
+struct fsw_hfs_dnode
+{
+ struct fsw_dnode g; //!< Generic dnode structure
+ HFSPlusExtentRecord extents;
+ fsw_u32 ctime;
+ fsw_u32 mtime;
+ fsw_u64 used_bytes;
+};
+
+/**
+ * HFS: In-memory B-tree structure.
+ */
+struct fsw_hfs_btree
+{
+ fsw_u32 root_node;
+ fsw_u32 node_size;
+ struct fsw_hfs_dnode* file;
+};
+
+
+/**
+ * HFS: In-memory volume structure with HFS-specific data.
+ */
+
+struct fsw_hfs_volume
+{
+ struct fsw_volume g; //!< Generic volume structure
+
+ struct HFSPlusVolumeHeader *primary_voldesc; //!< Volume Descriptor
+ struct fsw_hfs_btree catalog_tree; // Catalog tree
+ struct fsw_hfs_btree extents_tree; // Extents overflow tree
+ struct fsw_hfs_dnode root_file;
+ int case_sensitive;
+ fsw_u32 block_size_shift;
+ fsw_hfs_kind hfs_kind;
+ fsw_u32 emb_block_off;
+};
+
+/* Endianess swappers */
+static inline fsw_u16
+swab16(fsw_u16 x)
+{
+ return (x<<8 | ((x & 0xff00)>>8));
+}
+
+static inline fsw_u32
+swab32(fsw_u32 x)
+{
+ return x<<24 | x>>24 |
+ (x & (fsw_u32)0x0000ff00UL)<<8 |
+ (x & (fsw_u32)0x00ff0000UL)>>8;
+}
+
+
+static inline fsw_u64
+swab64(fsw_u64 x)
+{
+ return x<<56 | x>>56 |
+ (x & (fsw_u64)0x000000000000ff00ULL)<<40 |
+ (x & (fsw_u64)0x0000000000ff0000ULL)<<24 |
+ (x & (fsw_u64)0x00000000ff000000ULL)<< 8 |
+ (x & (fsw_u64)0x000000ff00000000ULL)>> 8 |
+ (x & (fsw_u64)0x0000ff0000000000ULL)>>24 |
+ (x & (fsw_u64)0x00ff000000000000ULL)>>40;
+}
+
+static inline fsw_u16
+be16_to_cpu(fsw_u16 x)
+{
+ return swab16(x);
+}
+
+static inline fsw_u16
+cpu_to_be16(fsw_u16 x)
+{
+ return swab16(x);
+}
+
+
+static inline fsw_u32
+cpu_to_be32(fsw_u32 x)
+{
+ return swab32(x);
+}
+
+static inline fsw_u32
+be32_to_cpu(fsw_u32 x)
+{
+ return swab32(x);
+}
+
+static inline fsw_u64
+be64_to_cpu(fsw_u64 x)
+{
+ return swab64(x);
+}
+
+#endif
--- /dev/null
+/* $Id: fsw_iso9660.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.c - ISO9660 file system driver code.
+ *
+ * Current limitations:
+ * - Files must be in one extent (i.e. Level 2)
+ * - No Joliet or Rock Ridge extensions
+ * - No interleaving
+ * - inode number generation strategy fails on volumes > 2 GB
+ * - No blocksizes != 2048
+ * - No High Sierra or anything else != 'CD001'
+ * - No volume sets with directories pointing at other volumes
+ * - No extended attribute records
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_iso9660.h"
+//#include <Protocol/MsgLog.h>
+
+#ifndef DEBUG_ISO
+#define DEBUG_ISO 1
+#endif
+
+#if DEBUG_ISO == 2
+#define DBG(x...) AsciiPrint(x)
+#elif DEBUG_ISO == 1
+#define DBG(x...) BootLog(x)
+#else
+#define DBG(x...)
+#endif
+
+//#define MsgLog(x...) if(msgCursor){AsciiSPrint(msgCursor, BOOTER_LOG_SIZE, x); while(*msgCursor){msgCursor++;}}
+
+// extern CHAR8 *msgCursor;
+// extern MESSAGE_LOG_PROTOCOL *Msg;
+// functions
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol);
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol);
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno);
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno);
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer);
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *link);
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp);
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str);
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin);
+//static void dump_dirrec(struct iso9660_dirrec *dirrec);
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660) = {
+ { FSW_STRING_TYPE_ISO88591, 4, 4, "iso9660" },
+ sizeof(struct fsw_iso9660_volume),
+ sizeof(struct fsw_iso9660_dnode),
+
+ fsw_iso9660_volume_mount,
+ fsw_iso9660_volume_free,
+ fsw_iso9660_volume_stat,
+ fsw_iso9660_dnode_fill,
+ fsw_iso9660_dnode_free,
+ fsw_iso9660_dnode_stat,
+ fsw_iso9660_get_extent,
+ fsw_iso9660_dir_lookup,
+ fsw_iso9660_dir_read,
+ fsw_iso9660_readlink,
+};
+
+static fsw_status_t rr_find_sp(struct iso9660_dirrec *dirrec, struct fsw_rock_ridge_susp_sp **psp)
+{
+ fsw_u8 *r;
+ int off = 0;
+ struct fsw_rock_ridge_susp_sp *sp;
+ r = (fsw_u8 *)((fsw_u8 *)dirrec + sizeof(*dirrec) + dirrec->file_identifier_length);
+ off = (int)(r - (fsw_u8 *)dirrec);
+ while(off < dirrec->dirrec_length)
+ {
+ if (*r == 'S')
+ {
+ sp = (struct fsw_rock_ridge_susp_sp *)r;
+ if( sp->e.sig[0] == 'S'
+ && sp->e.sig[1] == 'P'
+ && sp->magic[0] == 0xbe
+ && sp->magic[1] == 0xef)
+ {
+ *psp = sp;
+ return FSW_SUCCESS;
+ }
+ }
+ r++;
+ off = (int)(r - (fsw_u8 *)dirrec);
+ }
+ *psp = NULL;
+ return FSW_NOT_FOUND;
+}
+
+static fsw_status_t rr_find_nm(struct fsw_iso9660_volume *vol, struct iso9660_dirrec *dirrec, int off, struct fsw_string *str)
+{
+ fsw_u8 *r, *begin;
+ int fCe = 0;
+ struct fsw_rock_ridge_susp_nm *nm;
+ int limit = dirrec->dirrec_length;
+ begin = (fsw_u8 *)dirrec;
+ r = (fsw_u8 *)dirrec + off;
+ str->data = NULL;
+ str->len = 0;
+ str->size = 0;
+ str->type = 0;
+ while(off < limit)
+ {
+ if (r[0] == 'C' && r[1] == 'E' && r[2] == 28)
+ {
+ int rc;
+ int ce_off;
+ union fsw_rock_ridge_susp_ce *ce;
+ if (fCe == 0)
+ fsw_alloc_zero(ISO9660_BLOCKSIZE, (void *)&begin);
+ fCe = 1;
+ // DEBUG((DEBUG_WARN, "%a:%d we found CE before NM or its continuation\n", __FILE__, __LINE__));
+ ce = (union fsw_rock_ridge_susp_ce *)r;
+ limit = ISOINT(ce->X.len);
+ ce_off = ISOINT(ce->X.offset);
+ rc = rr_read_ce(vol, ce, begin);
+ if (rc != FSW_SUCCESS)
+ {
+ fsw_free(begin);
+ return rc;
+ }
+ begin += ce_off;
+ r = begin;
+ }
+ if (r[0] == 'N' && r[1] == 'M')
+ {
+ nm = (struct fsw_rock_ridge_susp_nm *)r;
+ if( nm->e.sig[0] == 'N'
+ && nm->e.sig[1] == 'M')
+ {
+ int len = 0;
+ fsw_u8 *tmp = NULL;
+ if (nm->flags & RR_NM_CURR)
+ {
+ fsw_memdup(str->data, ".", 1);
+ str->len = 1;
+ goto done;
+ }
+ if (nm->flags & RR_NM_PARE)
+ {
+ fsw_memdup(str->data, "..", 2);
+ str->len = 2;
+ goto done;
+ }
+ len = nm->e.len - sizeof(struct fsw_rock_ridge_susp_nm) + 1;
+ fsw_alloc_zero(str->len + len, (void **)&tmp);
+ if (str->data != NULL)
+ {
+ fsw_memcpy(tmp, str->data, str->len);
+ fsw_free(str->data);
+ }
+ // DEBUG((DEBUG_INFO, "dst:%p src:%p len:%d\n", tmp + str->len, &nm->name[0], len));
+ fsw_memcpy(tmp + str->len, &nm->name[0], len);
+ str->data = tmp;
+ str->len += len;
+
+ if ((nm->flags & RR_NM_CONT) == 0);
+ goto done;
+ }
+ }
+ r++;
+ off = (int)(r - (fsw_u8 *)begin);
+ }
+ if(fCe == 1)
+ fsw_free(begin);
+ return FSW_NOT_FOUND;
+done:
+ str->type = FSW_STRING_TYPE_ISO88591;
+ str->size = str->len;
+ if(fCe == 1)
+ fsw_free(begin);
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t rr_read_ce(struct fsw_iso9660_volume *vol, union fsw_rock_ridge_susp_ce *ce, fsw_u8 *begin)
+{
+ int rc;
+// int i;
+// fsw_u8 *r = begin + ISOINT(ce->X.offset);
+// int len = ISOINT(ce->X.len);
+ rc = vol->g.host_table->read_block(&vol->g, ISOINT(ce->X.block_loc), begin);
+ if (rc != FSW_SUCCESS)
+ return rc;
+/* for (i = 0; i < len; ++i)
+ {
+ DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+ }*/
+ return FSW_SUCCESS;
+}
+/*
+static void dump_dirrec(struct iso9660_dirrec *dirrec)
+{
+ int i;
+ fsw_u8 *r = (fsw_u8 *)dirrec + dirrec->file_identifier_length;
+ int len = dirrec->dirrec_length;
+ for (i = dirrec->file_identifier_length; i < len; ++i)
+ {
+ DEBUG((DEBUG_INFO, "%d: (%d:%x)%c ", i, r[i], r[i], r[i]));
+ }
+}*/
+/**
+ * Mount an ISO9660 volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_iso9660_volume_mount(struct fsw_iso9660_volume *vol)
+{
+ fsw_status_t status;
+ void *buffer;
+ fsw_u32 blockno;
+ struct iso9660_volume_descriptor *voldesc;
+ struct iso9660_primary_volume_descriptor *pvoldesc;
+ fsw_u32 voldesc_type;
+ int i;
+ struct fsw_string s;
+ struct iso9660_dirrec rootdir;
+ int sua_pos;
+ char *sig;
+ int skip;
+ struct fsw_rock_ridge_susp_entry *entry;
+
+ // read through the Volume Descriptor Set
+ fsw_set_blocksize(vol, ISO9660_BLOCKSIZE, ISO9660_BLOCKSIZE);
+ blockno = ISO9660_SUPERBLOCK_BLOCKNO;
+
+ do {
+// DBG("iso9660: check blockno=%d\n", blockno);
+ status = fsw_block_get(vol, blockno, 0, &buffer);
+ if (status)
+ return status;
+
+ voldesc = (struct iso9660_volume_descriptor *)buffer;
+ voldesc_type = voldesc->volume_descriptor_type;
+ if (fsw_memeq(voldesc->standard_identifier, "CD001", 5)) {
+ // descriptor follows ISO 9660 standard
+ if (voldesc_type == 1 && voldesc->volume_descriptor_version == 1) {
+ // suitable Primary Volume Descriptor found
+// DBG("iso9660: suitable Primary Volume Descriptor found\n");
+ if (vol->primary_voldesc) {
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+ }
+ status = fsw_memdup((void **)&vol->primary_voldesc, voldesc, ISO9660_BLOCKSIZE);
+ }
+ } else if (!fsw_memeq(voldesc->standard_identifier, "CD", 2)) {
+ // completely alien standard identifier, stop reading
+ voldesc_type = 255;
+ }
+
+ fsw_block_release(vol, blockno, buffer);
+ blockno++;
+ } while (!status && voldesc_type != 255);
+ if (status)
+ return status;
+
+ // get information from Primary Volume Descriptor
+ if (vol->primary_voldesc == NULL)
+ return FSW_UNSUPPORTED;
+ pvoldesc = vol->primary_voldesc;
+ if (ISOINT(pvoldesc->logical_block_size) != 2048)
+ return FSW_UNSUPPORTED;
+
+ // get volume name
+ for (i = 32; i > 0; i--)
+ if (pvoldesc->volume_identifier[i-1] != ' ')
+ break;
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = i;
+ s.data = pvoldesc->volume_identifier;
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ if (status)
+ return status;
+
+ // setup the root dnode
+ status = fsw_dnode_create_root(vol, ISO9660_SUPERBLOCK_BLOCKNO << ISO9660_BLOCKSIZE_BITS, &vol->g.root);
+ if (status)
+ return status;
+ fsw_memcpy(&vol->g.root->dirrec, &pvoldesc->root_directory, sizeof(struct iso9660_dirrec));
+
+ if ( pvoldesc->escape[0] == 0x25
+ && pvoldesc->escape[1] == 0x2f
+ && ( pvoldesc->escape[2] == 0x40
+ || pvoldesc->escape[2] == 0x43
+ || pvoldesc->escape[2] == 0x45))
+ {
+ // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (joliet!!!)\n")));
+// DBG("fsw_iso9660_volume_mount: success (joliet!!!)\n");
+ vol->fJoliet = 1;
+ }
+
+
+ rootdir = pvoldesc->root_directory;
+ sua_pos = (sizeof(struct iso9660_dirrec)) + rootdir.file_identifier_length + (rootdir.file_identifier_length % 2) - 2;
+ //int sua_size = rootdir.dirrec_length - rootdir.file_identifier_length;
+ //FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success (SUA(pos:%x, sz:%d)!!!)\n"), sua_pos, sua_size));
+
+#if 1
+ status = fsw_block_get(vol, ISOINT(rootdir.extent_location), 0, &buffer);
+ sig = (char *)buffer + sua_pos;
+ skip = 0;
+ entry = (struct fsw_rock_ridge_susp_entry *)sig;
+ if ( entry->sig[0] == 'S'
+ && entry->sig[1] == 'P')
+ {
+ struct fsw_rock_ridge_susp_sp *sp = (struct fsw_rock_ridge_susp_sp *)entry;
+ if (sp->magic[0] == 0xbe && sp->magic[1] == 0xef)
+ {
+ vol->fRockRidge = 1;
+ } else {
+ // FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: SP magic isn't valid\n")));
+// DBG("fsw_iso9660_volume_mount: SP magic isn't valid\n");
+ }
+ skip = sp->skip;
+ }
+#endif
+ // release volume descriptors
+ fsw_free(vol->primary_voldesc);
+ vol->primary_voldesc = NULL;
+
+
+// FSW_MSG_DEBUG((FSW_MSGSTR("fsw_iso9660_volume_mount: success\n")));
+// DBG("fsw_iso9660_volume_mount: success\n");
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_iso9660_volume_free(struct fsw_iso9660_volume *vol)
+{
+ if (vol->primary_voldesc)
+ fsw_free(vol->primary_voldesc);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_iso9660_volume_stat(struct fsw_iso9660_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = 0; //(fsw_u64)vol->sb->s_blocks_count * vol->g.log_blocksize;
+ sb->free_bytes = 0;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of iso9660, we
+ * delay fetching of the inode structure until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_fill(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+ // get info from the directory record
+ dno->g.size = ISOINT(dno->dirrec.data_length);
+ if (dno->dirrec.file_flags & 0x02)
+ dno->g.type = FSW_DNODE_TYPE_DIR;
+ else
+ dno->g.type = FSW_DNODE_TYPE_FILE;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_iso9660_dnode_free(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno)
+{
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_iso9660_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_iso9660_dnode_stat(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ sb->used_bytes = (dno->g.size + (ISO9660_BLOCKSIZE-1)) & ~(ISO9660_BLOCKSIZE-1);
+ /*
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->raw->i_ctime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->raw->i_atime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->raw->i_mtime);
+ sb->store_attr_posix(sb, dno->raw->i_mode);
+ */
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_iso9660_get_extent(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_extent *extent)
+{
+ // Preconditions: The caller has checked that the requested logical block
+ // is within the file's size. The dnode has complete information, i.e.
+ // fsw_iso9660_dnode_read_info was called successfully on it.
+
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->phys_start = ISOINT(dno->dirrec.extent_location);
+ extent->log_start = 0;
+ extent->log_count = (ISOINT(dno->dirrec.data_length) + (ISO9660_BLOCKSIZE-1)) >> ISO9660_BLOCKSIZE_BITS;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_iso9660_dir_lookup(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_iso9660_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_shandle shand;
+ struct iso9660_dirrec_buffer dirrec_buffer;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+ // Preconditions: The caller has checked that dno is a directory node.
+
+ // setup handle to read the directory
+ status = fsw_shandle_open(dno, &shand);
+ if (status)
+ return status;
+
+ // scan the directory for the file
+ while (1) {
+ // read next entry
+ status = fsw_iso9660_read_dirrec(vol, &shand, &dirrec_buffer);
+ if (status)
+ goto errorexit;
+ if (dirrec->dirrec_length == 0) {
+ // end of directory reached
+ status = FSW_NOT_FOUND;
+ goto errorexit;
+ }
+
+ // skip . and ..
+ if (dirrec->file_identifier_length == 1 &&
+ (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+ continue;
+
+ // compare name
+ if (fsw_streq(lookup_name, &dirrec_buffer.name)) // TODO: compare case-insensitively
+ break;
+ }
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+ if (status == FSW_SUCCESS)
+ fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+errorexit:
+ fsw_shandle_close(&shand);
+ return status;
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_iso9660_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_iso9660_dir_read(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_iso9660_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct iso9660_dirrec_buffer dirrec_buffer;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer.dirrec;
+
+ // Preconditions: The caller has checked that dno is a directory node. The caller
+ // has opened a storage handle to the directory's storage and keeps it around between
+ // calls.
+ /* (vasily) directory nodes are 4096 bytes that is two logical blocks so read dir operation
+ * should read both blocks.
+ */
+
+ while (1) {
+ // read next entry
+ if (shand->pos >= dno->g.size)
+ return FSW_NOT_FOUND; // end of directory
+ status = fsw_iso9660_read_dirrec(vol, shand, &dirrec_buffer);
+ if (status)
+ return status;
+ if (dirrec->dirrec_length == 0)
+ {
+ // try the next block
+ shand->pos =(shand->pos & ~(vol->g.log_blocksize - 1)) + vol->g.log_blocksize;
+ continue;
+ }
+
+ // skip . and ..
+ if (dirrec->file_identifier_length == 1 &&
+ (dirrec->file_identifier[0] == 0 || dirrec->file_identifier[0] == 1))
+ continue;
+ break;
+ }
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dirrec_buffer.ino, FSW_DNODE_TYPE_UNKNOWN, &dirrec_buffer.name, child_dno_out);
+ if (status == FSW_SUCCESS)
+ fsw_memcpy(&(*child_dno_out)->dirrec, dirrec, sizeof(struct iso9660_dirrec));
+
+ return status;
+}
+
+/**
+ * Read a directory entry from the directory's raw data. This internal function is used
+ * to read a raw iso9660 directory entry into memory. The shandle's position pointer is adjusted
+ * to point to the next entry.
+ */
+
+static fsw_status_t fsw_iso9660_read_dirrec(struct fsw_iso9660_volume *vol, struct fsw_shandle *shand, struct iso9660_dirrec_buffer *dirrec_buffer)
+{
+ fsw_status_t status;
+ fsw_u32 i, buffer_size, remaining_size, name_len;
+ struct fsw_rock_ridge_susp_sp *sp = NULL;
+ struct iso9660_dirrec *dirrec = &dirrec_buffer->dirrec;
+ int sp_off;
+ int rc;
+
+ dirrec_buffer->ino = (ISOINT(((struct fsw_iso9660_dnode *)shand->dnode)->dirrec.extent_location)
+ << ISO9660_BLOCKSIZE_BITS)
+ + (fsw_u32)shand->pos;
+
+ // read fixed size part of directory record
+ buffer_size = 33;
+ status = fsw_shandle_read(shand, &buffer_size, dirrec);
+ if (status)
+ {
+ // DEBUG((DEBUG_INFO, "%a:%d \n", __FILE__, __LINE__));
+ return status;
+ }
+
+ if (buffer_size < 33 || dirrec->dirrec_length == 0) {
+ // end of directory reached
+ fsw_u8 *r;
+ r = (fsw_u8 *)dirrec;
+ // DEBUG((DEBUG_INFO, "%a:%d bs:%d dl:%d\n", __FILE__, __LINE__, buffer_size, dirrec->dirrec_length));
+ for(i = 0; i < buffer_size; ++i)
+ {
+ DEBUG((DEBUG_INFO, "r[%d]:%c", i, r[i]));
+ }
+ dirrec->dirrec_length = 0;
+ return FSW_SUCCESS;
+ }
+ if (dirrec->dirrec_length < 33 ||
+ dirrec->dirrec_length < 33 + dirrec->file_identifier_length)
+ return FSW_VOLUME_CORRUPTED;
+
+// DEBUG((DEBUG_INFO, "%a:%d, dirrec_length: %d\n", __FILE__, __LINE__, dirrec->dirrec_length));
+
+ // read variable size part of directory record
+ buffer_size = remaining_size = dirrec->dirrec_length - 33;
+ status = fsw_shandle_read(shand, &buffer_size, dirrec->file_identifier);
+ if (status)
+ return status;
+ if (buffer_size < remaining_size)
+ return FSW_VOLUME_CORRUPTED;
+
+// dump_dirrec(dirrec);
+ if (vol->fRockRidge)
+ {
+ sp_off = sizeof(*dirrec) + dirrec->file_identifier_length;
+ rc = rr_find_sp(dirrec, &sp);
+ if ( rc == FSW_SUCCESS
+ && sp != NULL)
+ {
+ sp_off = (fsw_u8 *)&sp[1] - (fsw_u8*)dirrec + sp->skip;
+ }
+ rc = rr_find_nm(vol, dirrec, sp_off, &dirrec_buffer->name);
+ if (rc == FSW_SUCCESS)
+ return FSW_SUCCESS;
+ }
+
+ // setup name
+ name_len = dirrec->file_identifier_length;
+ for (i = name_len - 1; i > 0; i--) {
+ if (dirrec->file_identifier[i] == ';') {
+ name_len = i; // cut the ISO9660 version number off
+ break;
+ }
+ }
+ if (name_len > 0 && dirrec->file_identifier[name_len-1] == '.')
+ name_len--; // also cut the extension separator if the extension is empty
+ dirrec_buffer->name.type = FSW_STRING_TYPE_ISO88591;
+ dirrec_buffer->name.len = dirrec_buffer->name.size = name_len;
+ dirrec_buffer->name.data = dirrec->file_identifier;
+// DEBUG((DEBUG_INFO, "%a:%d: dirrec_buffer->name.data:%a\n", __FILE__, __LINE__, dirrec_buffer->name.data));
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_iso9660_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ *
+ * For iso9660, the target path can be stored inline in the inode structure (in the space
+ * otherwise occupied by the block pointers) or in the inode's data. There is no flag
+ * indicating this, only the number of blocks entry (i_blocks) can be used as an
+ * indication. The check used here comes from the Linux kernel.
+ */
+
+static fsw_status_t fsw_iso9660_readlink(struct fsw_iso9660_volume *vol, struct fsw_iso9660_dnode *dno,
+ struct fsw_string *link_target)
+{
+ fsw_status_t status;
+
+ if (dno->g.size > FSW_PATH_MAX)
+ return FSW_VOLUME_CORRUPTED;
+
+ status = fsw_dnode_readlink_data(dno, link_target);
+
+ return status;
+}
+
+// EOF
--- /dev/null
+/* $Id: fsw_iso9660.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_iso9660.h - ISO9660 file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_ISO9660_H_
+#define _FSW_ISO9660_H_
+
+#define VOLSTRUCTNAME fsw_iso9660_volume
+#define DNODESTRUCTNAME fsw_iso9660_dnode
+#include "fsw_core.h"
+
+
+//! Block size for ISO9660 volumes.
+#define ISO9660_BLOCKSIZE 2048
+#define ISO9660_BLOCKSIZE_BITS 11
+//! Block number where the ISO9660 superblock resides.
+#define ISO9660_SUPERBLOCK_BLOCKNO 16
+//Slice - we already have shifted blockIO by 16
+//but we should use ParentBlockIo
+//#define ISO9660_SUPERBLOCK_BLOCKNO 0
+
+#pragma pack(1)
+
+typedef struct {
+ fsw_u16 lsb;
+ fsw_u16 msb;
+} iso9660_u16;
+
+typedef struct {
+ fsw_u32 lsb;
+ fsw_u32 msb;
+} iso9660_u32;
+
+#define ISOINT(lsbmsbvalue) ((lsbmsbvalue).lsb)
+
+struct iso9660_dirrec {
+ fsw_u8 dirrec_length;
+ fsw_u8 ear_length;
+ iso9660_u32 extent_location;
+ iso9660_u32 data_length;
+ fsw_u8 recording_datetime[7];
+ fsw_u8 file_flags;
+ fsw_u8 file_unit_size;
+ fsw_u8 interleave_gap_size;
+ iso9660_u16 volume_sequence_number;
+ fsw_u8 file_identifier_length;
+ char file_identifier[1];
+};
+//#if sizeof(struct fsw_iso9660_dirrec) != 34
+//#fail Structure fsw_iso9660_dirrec has wrong size
+//#endif
+
+struct iso9660_volume_descriptor {
+ fsw_u8 volume_descriptor_type;
+ char standard_identifier[5];
+ fsw_u8 volume_descriptor_version;
+};
+
+struct iso9660_primary_volume_descriptor {
+ fsw_u8 volume_descriptor_type;
+ char standard_identifier[5];
+ fsw_u8 volume_descriptor_version;
+ fsw_u8 unused1;
+ char system_identifier[32];
+ char volume_identifier[32];
+ fsw_u8 unused2[8];
+ iso9660_u32 volume_space_size;
+ fsw_u8 unused3[4];
+ fsw_u8 escape[3];
+ fsw_u8 unused4[25];
+ iso9660_u16 volume_set_size;
+ iso9660_u16 volume_sequence_number;
+ iso9660_u16 logical_block_size;
+ iso9660_u32 path_table_size;
+ fsw_u32 location_type_l_path_table;
+ fsw_u32 location_optional_type_l_path_table;
+ fsw_u32 location_type_m_path_table;
+ fsw_u32 location_optional_type_m_path_table;
+ struct iso9660_dirrec root_directory;
+ char volume_set_identifier[128];
+ char publisher_identifier[128];
+ char data_preparer_identifier[128];
+ char application_identifier[128];
+ char copyright_file_identifier[37];
+ char abstract_file_identifier[37];
+ char bibliographic_file_identifier[37];
+ char volume_creation_datetime[17];
+ char volume_modification_datetime[17];
+ char volume_expiration_datetime[17];
+ char volume_effective_datetime[17];
+ fsw_u8 file_structure_version;
+ fsw_u8 reserved1;
+ fsw_u8 application_use[512];
+ fsw_u8 reserved2[653];
+};
+//#if sizeof(struct fsw_iso9660_volume_descriptor) != 2048
+//#fail Structure fsw_iso9660_volume_descriptor has wrong size
+//#endif
+
+#pragma pack()
+
+struct iso9660_dirrec_buffer {
+ fsw_u32 ino;
+ struct fsw_string name;
+ struct iso9660_dirrec dirrec;
+ char dirrec_buffer[222];
+};
+
+
+/**
+ * ISO9660: Volume structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_volume {
+ struct fsw_volume g; //!< Generic volume structure
+ /*Note: don't move g!*/
+ int fJoliet;
+ /*Joliet specific fields*/
+ int fRockRidge;
+ /*Rock Ridge specific fields*/
+ int rr_susp_skip;
+
+ struct iso9660_primary_volume_descriptor *primary_voldesc; //!< Full Primary Volume Descriptor
+};
+
+/**
+ * ISO9660: Dnode structure with ISO9660-specific data.
+ */
+
+struct fsw_iso9660_dnode {
+ struct fsw_dnode g; //!< Generic dnode structure
+
+ struct iso9660_dirrec dirrec; //!< Fixed part of the directory record (i.e. w/o name)
+};
+
+
+struct fsw_rock_ridge_susp_entry
+{
+ fsw_u8 sig[2];
+ fsw_u8 len;
+ fsw_u8 ver;
+};
+
+struct fsw_rock_ridge_susp_sp
+{
+ struct fsw_rock_ridge_susp_entry e;
+ fsw_u8 magic[2];
+ fsw_u8 skip;
+};
+
+struct fsw_rock_ridge_susp_nm
+{
+ struct fsw_rock_ridge_susp_entry e;
+ fsw_u8 flags;
+ fsw_u8 name[1];
+};
+
+#define RR_NM_CONT (1<<0)
+#define RR_NM_CURR (1<<1)
+#define RR_NM_PARE (1<<2)
+
+union fsw_rock_ridge_susp_ce
+{
+ struct X{
+ struct fsw_rock_ridge_susp_entry e;
+ iso9660_u32 block_loc;
+ iso9660_u32 offset;
+ iso9660_u32 len;
+ } X;
+ fsw_u8 raw[28];
+};
+
+#endif
--- /dev/null
+/* $Id: fsw_lib.c 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * fsw_lib.c - Core file system wrapper library functions.
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*-
+ * This code is based on:
+ *
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_core.h"
+
+/* Include generated string encoding specific functions */
+#include "fsw_strfunc.h"
+
+
+/**
+ * Allocate memory and clear it.
+ */
+
+fsw_status_t fsw_alloc_zero(int len, void **ptr_out)
+{
+ fsw_status_t status;
+
+ status = fsw_alloc(len, ptr_out);
+ if (status)
+ return status;
+ fsw_memzero(*ptr_out, len);
+ return FSW_SUCCESS;
+}
+
+/**
+ * Duplicate a piece of data.
+ */
+
+fsw_status_t fsw_memdup(void **dest_out, void *src, int len)
+{
+ fsw_status_t status;
+
+ status = fsw_alloc(len, dest_out);
+ if (status)
+ return status;
+ fsw_memcpy(*dest_out, src, len);
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get the length of a string. Returns the number of characters in the string.
+ */
+
+int fsw_strlen(struct fsw_string *s)
+{
+ if (s->type == FSW_STRING_TYPE_EMPTY)
+ return 0;
+ return s->len;
+}
+
+#if 0
+static const fsw_u16
+fsw_lower_case_table[] =
+{
+
+ /* High-byte indices ( == 0 iff no case mapping and no ignorables ) */
+
+ /* 0 */ 0x0000, 0x0100, 0x0000, 0x0200, 0x0300, 0x0400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 1 */ 0x0500, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 2 */ 0x0600, 0x0700, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0800, 0x0900,
+
+ /* Table 1 (for high byte 0x01) */
+
+ /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+ /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117, 0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+ /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127, 0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+ /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137, 0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+ /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147, 0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+ /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157, 0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+ /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167, 0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+ /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177, 0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+ /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+ /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+ /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8, 0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+ /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292, 0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+ /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9, 0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+ /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7, 0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+ /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7, 0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+ /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7, 0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+ /* Table 2 (for high byte 0x03) */
+
+ /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+ /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+ /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+ /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+ /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347, 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+ /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+ /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+ /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+ /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+ /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+ /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+ /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7, 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+ /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7, 0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+ /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7, 0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+ /* Table 3 (for high byte 0x04) */
+
+ /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407, 0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+ /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+ /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+ /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477, 0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+ /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+ /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+ /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7, 0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+ /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7, 0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+ /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8, 0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+ /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7, 0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+ /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7, 0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+ /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7, 0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+ /* Table 4 (for high byte 0x05) */
+
+ /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+ /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+ /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+ /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+ /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+ /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+ /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+ /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+ /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+ /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+ /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7, 0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+ /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, 0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+ /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7, 0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+ /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+ /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+ /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7, 0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+ /* Table 5 (for high byte 0x10) */
+
+ /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+ /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017, 0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+ /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027, 0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+ /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037, 0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+ /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047, 0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+ /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057, 0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+ /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067, 0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+ /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077, 0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+ /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087, 0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+ /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097, 0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+ /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+ /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+ /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7, 0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+ /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7, 0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+ /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+ /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7, 0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+ /* Table 6 (for high byte 0x20) */
+
+ /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017, 0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+ /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027, 0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+ /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037, 0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+ /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047, 0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+ /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057, 0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+ /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067, 0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077, 0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+ /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087, 0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+ /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097, 0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+ /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7, 0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+ /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7, 0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+ /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7, 0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+ /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7, 0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+ /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7, 0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+ /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7, 0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+ /* Table 7 (for high byte 0x21) */
+
+ /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+ /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+ /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127, 0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+ /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+ /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+ /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+ /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+ /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+ /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+ /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+ /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7, 0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+ /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7, 0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+ /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7, 0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+ /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7, 0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+ /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7, 0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+ /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7, 0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+ /* Table 8 (for high byte 0xFE) */
+
+ /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07, 0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+ /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17, 0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+ /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27, 0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+ /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37, 0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+ /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47, 0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+ /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57, 0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+ /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67, 0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+ /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77, 0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+ /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87, 0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+ /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97, 0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+ /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+ /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+ /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+ /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7, 0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+ /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+ /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7, 0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+ /* Table 9 (for high byte 0xFF) */
+
+ /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07, 0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+ /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+ /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+ /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+ /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+ /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+ /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+ /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+ /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+ /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+ /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+ /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+ /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+ /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+ /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+#endif
+
+static const fsw_u16 fsw_latin_case_fold[] =
+{
+ /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+ /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+ /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+ /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+ /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+ /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+};
+
+
+fsw_u16 fsw_to_lower(fsw_u16 ch)
+{
+#if 0
+ fsw_u16 temp = temp;
+#endif
+
+ if (ch < 0x0100)
+ return fsw_latin_case_fold[ch];
+#if 0
+ /*
+ * Uncomment this along with above huge table (fsw_lower_case_table)
+ * for full UTF-16 case insensitivity
+ */
+ temp = fsw_lower_case_table[ch>>8];
+ if (temp != 0)
+ return fsw_lower_case_table[temp + (ch & 0x00FF)];
+#endif
+
+ return ch;
+}
+
+/**
+ * Compare two strings for equality. The two strings are compared, taking their
+ * encoding into account. If they are considered equal, boolean true is returned.
+ * Otherwise, boolean false is returned.
+ */
+
+int fsw_streq(struct fsw_string *s1, struct fsw_string *s2)
+{
+ struct fsw_string temp_s;
+
+ // handle empty strings
+ if (s1->type == FSW_STRING_TYPE_EMPTY) {
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = 0;
+ temp_s.data = NULL;
+ return fsw_streq(&temp_s, s2);
+ }
+ if (s2->type == FSW_STRING_TYPE_EMPTY) {
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = 0;
+ temp_s.data = NULL;
+ return fsw_streq(s1, &temp_s);
+ }
+
+ // check length (count of chars)
+ if (s1->len != s2->len)
+ return 0;
+ if (s1->len == 0) // both strings are empty
+ return 1;
+
+ if (s1->type == s2->type) {
+ // same type, do a dumb memory compare
+ if (s1->size != s2->size)
+ return 0;
+ return fsw_memeq(s1->data, s2->data, s1->size);
+ }
+
+ // dispatch to type-specific functions
+ #define STREQ_DISPATCH(type1, type2) \
+ if (s1->type == FSW_STRING_TYPE_##type1 && s2->type == FSW_STRING_TYPE_##type2) \
+ return fsw_streq_##type1##_##type2(s1->data, s2->data, s1->len); \
+ if (s2->type == FSW_STRING_TYPE_##type1 && s1->type == FSW_STRING_TYPE_##type2) \
+ return fsw_streq_##type1##_##type2(s2->data, s1->data, s1->len);
+ STREQ_DISPATCH(ISO88591, UTF8);
+ STREQ_DISPATCH(ISO88591, UTF16);
+ STREQ_DISPATCH(ISO88591, UTF16_SWAPPED);
+ STREQ_DISPATCH(UTF8, UTF16);
+ STREQ_DISPATCH(UTF8, UTF16_SWAPPED);
+ STREQ_DISPATCH(UTF16, UTF16_SWAPPED);
+
+ // final fallback
+ return 0;
+}
+
+/**
+ * Compare a string with a C string constant. This sets up a string descriptor
+ * for the string constant (second argument) and runs fsw_streq on the two
+ * strings. Currently the C string is interpreted as ISO 8859-1.
+ * Returns boolean true if the strings are considered equal, boolean false otherwise.
+ */
+
+int fsw_streq_cstr(struct fsw_string *s1, const char *s2)
+{
+ struct fsw_string temp_s;
+ int i;
+
+ for (i = 0; s2[i]; i++)
+ ;
+
+ temp_s.type = FSW_STRING_TYPE_ISO88591;
+ temp_s.size = temp_s.len = i;
+ temp_s.data = (char *)s2;
+
+ return fsw_streq(s1, &temp_s);
+}
+
+/**
+ * Creates a duplicate of a string, converting it to the given encoding during the copy.
+ * If the function returns FSW_SUCCESS, the caller must free the string later with
+ * fsw_strfree.
+ */
+
+fsw_status_t fsw_strdup_coerce(struct fsw_string *dest, int type, struct fsw_string *src)
+{
+ fsw_status_t status;
+
+ if (src->type == FSW_STRING_TYPE_EMPTY || src->len == 0) {
+ dest->type = type;
+ dest->size = dest->len = 0;
+ dest->data = NULL;
+ return FSW_SUCCESS;
+ }
+
+ if (src->type == type) {
+ dest->type = type;
+ dest->len = src->len;
+ dest->size = src->size;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ fsw_memcpy(dest->data, src->data, dest->size);
+ return FSW_SUCCESS;
+ }
+
+ // dispatch to type-specific functions
+ #define STRCOERCE_DISPATCH(type1, type2) \
+ if (src->type == FSW_STRING_TYPE_##type1 && type == FSW_STRING_TYPE_##type2) \
+ return fsw_strcoerce_##type1##_##type2(src->data, src->len, dest);
+ STRCOERCE_DISPATCH(UTF8, ISO88591);
+ STRCOERCE_DISPATCH(UTF16, ISO88591);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, ISO88591);
+ STRCOERCE_DISPATCH(ISO88591, UTF8);
+ STRCOERCE_DISPATCH(UTF16, UTF8);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF8);
+ STRCOERCE_DISPATCH(ISO88591, UTF16);
+ STRCOERCE_DISPATCH(UTF8, UTF16);
+ STRCOERCE_DISPATCH(UTF16_SWAPPED, UTF16);
+
+ return FSW_UNSUPPORTED;
+}
+
+/**
+ * Splits a string at the first occurrence of the separator character.
+ * The buffer string is searched for the separator character. If it is found, the
+ * element string descriptor is filled to point at the part of the buffer string
+ * before the separator. The buffer string itself is adjusted to point at the
+ * remaining part of the string (without the separator).
+ *
+ * If the separator is not found in the buffer string, then element is changed to
+ * point at the whole buffer string, and the buffer string itself is changed into
+ * an empty string.
+ *
+ * This function only manipulates the pointers and lengths in the two string descriptors,
+ * it does not change the actual string. If the buffer string is dynamically allocated,
+ * you must make a copy of it so that you can release it later.
+ */
+
+void fsw_strsplit(struct fsw_string *element, struct fsw_string *buffer, char separator)
+{
+ int i, maxlen;
+
+ if (buffer->type == FSW_STRING_TYPE_EMPTY || buffer->len == 0) {
+ element->type = FSW_STRING_TYPE_EMPTY;
+ return;
+ }
+
+ maxlen = buffer->len;
+ *element = *buffer;
+
+ if (buffer->type == FSW_STRING_TYPE_ISO88591) {
+ fsw_u8 *p;
+
+ p = (fsw_u8 *)element->data;
+ for (i = 0; i < maxlen; i++, p++) {
+ if (*p == separator) {
+ buffer->data = p + 1;
+ buffer->len -= i + 1;
+ break;
+ }
+ }
+ element->len = i;
+ if (i == maxlen) {
+ buffer->data = p;
+ buffer->len -= i;
+ }
+
+ element->size = element->len;
+ buffer->size = buffer->len;
+
+ } else if (buffer->type == FSW_STRING_TYPE_UTF16) {
+ fsw_u16 *p;
+
+ p = (fsw_u16 *)element->data;
+ for (i = 0; i < maxlen; i++, p++) {
+ if (*p == separator) {
+ buffer->data = p + 1;
+ buffer->len -= i + 1;
+ break;
+ }
+ }
+ element->len = i;
+ if (i == maxlen) {
+ buffer->data = p;
+ buffer->len -= i;
+ }
+
+ element->size = element->len * sizeof(fsw_u16);
+ buffer->size = buffer->len * sizeof(fsw_u16);
+
+ } else {
+ // fallback
+ buffer->type = FSW_STRING_TYPE_EMPTY;
+ }
+
+ // TODO: support UTF8 and UTF16_SWAPPED
+}
+
+/**
+ * Frees the memory used by a string returned from fsw_strdup_coerce.
+ */
+
+void fsw_strfree(struct fsw_string *s)
+{
+ if (s->type != FSW_STRING_TYPE_EMPTY && s->data)
+ fsw_free(s->data);
+ s->type = FSW_STRING_TYPE_EMPTY;
+}
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_reiserfs.c
+ * ReiserFS file system driver code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "fsw_reiserfs.h"
+
+
+// functions
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol);
+static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol);
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb);
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno);
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_dnode_stat *sb);
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_extent *extent);
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno);
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno);
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_string *link);
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+ fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+ struct fsw_reiserfs_item *item);
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+ struct fsw_reiserfs_item *item);
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+ struct fsw_reiserfs_item *item);
+
+//
+// Dispatch Table
+//
+
+struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs) = {
+ { FSW_STRING_TYPE_ISO88591, 8, 8, "reiserfs" },
+ sizeof(struct fsw_reiserfs_volume),
+ sizeof(struct fsw_reiserfs_dnode),
+
+ fsw_reiserfs_volume_mount,
+ fsw_reiserfs_volume_free,
+ fsw_reiserfs_volume_stat,
+ fsw_reiserfs_dnode_fill,
+ fsw_reiserfs_dnode_free,
+ fsw_reiserfs_dnode_stat,
+ fsw_reiserfs_get_extent,
+ fsw_reiserfs_dir_lookup,
+ fsw_reiserfs_dir_read,
+ fsw_reiserfs_readlink,
+};
+
+// misc data
+
+static fsw_u32 superblock_offsets[3] = {
+ REISERFS_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+ REISERFS_OLD_DISK_OFFSET_IN_BYTES >> REISERFS_SUPERBLOCK_BLOCKSIZEBITS,
+ 0
+};
+
+/**
+ * Mount an reiserfs volume. Reads the superblock and constructs the
+ * root directory dnode.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_mount(struct fsw_reiserfs_volume *vol)
+{
+ fsw_status_t status;
+ void *buffer;
+ fsw_u32 blocksize;
+ int i;
+ struct fsw_string s;
+
+ // allocate memory to keep the superblock around
+ status = fsw_alloc(sizeof(struct reiserfs_super_block), &vol->sb);
+ if (status)
+ return status;
+
+ // read the superblock into its buffer
+ fsw_set_blocksize(vol, REISERFS_SUPERBLOCK_BLOCKSIZE, REISERFS_SUPERBLOCK_BLOCKSIZE);
+ for (i = 0; superblock_offsets[i]; i++) {
+ status = fsw_block_get(vol, superblock_offsets[i], 0, &buffer);
+ if (status)
+ return status;
+ fsw_memcpy(vol->sb, buffer, sizeof(struct reiserfs_super_block));
+ fsw_block_release(vol, superblock_offsets[i], buffer);
+
+ // check for one of the magic strings
+ if (fsw_memeq(vol->sb->s_v1.s_magic,
+ REISERFS_SUPER_MAGIC_STRING, 8)) {
+ vol->version = REISERFS_VERSION_1;
+ break;
+ } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+ REISER2FS_SUPER_MAGIC_STRING, 9)) {
+ vol->version = REISERFS_VERSION_2;
+ break;
+ } else if (fsw_memeq(vol->sb->s_v1.s_magic,
+ REISER2FS_JR_SUPER_MAGIC_STRING, 9)) {
+ vol->version = vol->sb->s_v1.s_version;
+ if (vol->version == REISERFS_VERSION_1 || vol->version == REISERFS_VERSION_2)
+ break;
+ }
+ }
+ if (superblock_offsets[i] == 0)
+ return FSW_UNSUPPORTED;
+
+ // check the superblock
+ if (vol->sb->s_v1.s_root_block == -1) // unfinished 'reiserfsck --rebuild-tree'
+ return FSW_VOLUME_CORRUPTED;
+
+ /*
+ if (vol->sb->s_rev_level != EXT2_GOOD_OLD_REV &&
+ vol->sb->s_rev_level != EXT2_DYNAMIC_REV)
+ return FSW_UNSUPPORTED;
+ if (vol->sb->s_rev_level == EXT2_DYNAMIC_REV &&
+ (vol->sb->s_feature_incompat & ~(EXT2_FEATURE_INCOMPAT_FILETYPE | EXT3_FEATURE_INCOMPAT_RECOVER)))
+ return FSW_UNSUPPORTED;
+ */
+
+ // set real blocksize
+ blocksize = vol->sb->s_v1.s_blocksize;
+ fsw_set_blocksize(vol, blocksize, blocksize);
+
+ // get other info from superblock
+ /*
+ vol->ind_bcnt = EXT2_ADDR_PER_BLOCK(vol->sb);
+ vol->dind_bcnt = vol->ind_bcnt * vol->ind_bcnt;
+ vol->inode_size = EXT2_INODE_SIZE(vol->sb);
+ */
+
+ for (i = 0; i < 16; i++)
+ if (vol->sb->s_label[i] == 0)
+ break;
+ s.type = FSW_STRING_TYPE_ISO88591;
+ s.size = s.len = i;
+ s.data = vol->sb->s_label;
+ status = fsw_strdup_coerce(&vol->g.label, vol->g.host_string_type, &s);
+ if (status)
+ return status;
+
+ // setup the root dnode
+ status = fsw_dnode_create_root(vol, REISERFS_ROOT_OBJECTID, &vol->g.root);
+ if (status)
+ return status;
+ vol->g.root->dir_id = REISERFS_ROOT_PARENT_OBJECTID;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_volume_mount: success, blocksize %d tree height %d\n"),
+ blocksize, vol->sb->s_v1.s_tree_height));
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the volume data structure. Called by the core after an unmount or after
+ * an unsuccessful mount to release the memory used by the file system type specific
+ * part of the volume structure.
+ */
+
+static void fsw_reiserfs_volume_free(struct fsw_reiserfs_volume *vol)
+{
+ if (vol->sb)
+ fsw_free(vol->sb);
+}
+
+/**
+ * Get in-depth information on a volume.
+ */
+
+static fsw_status_t fsw_reiserfs_volume_stat(struct fsw_reiserfs_volume *vol, struct fsw_volume_stat *sb)
+{
+ sb->total_bytes = (fsw_u64)vol->sb->s_v1.s_block_count * vol->g.log_blocksize;
+ sb->free_bytes = (fsw_u64)vol->sb->s_v1.s_free_blocks * vol->g.log_blocksize;
+ return FSW_SUCCESS;
+}
+
+/**
+ * Get full information on a dnode from disk. This function is called by the core
+ * whenever it needs to access fields in the dnode structure that may not
+ * be filled immediately upon creation of the dnode. In the case of reiserfs, we
+ * delay fetching of the stat data until dnode_fill is called. The size and
+ * type fields are invalid until this function has been called.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_fill(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+ fsw_status_t status;
+ fsw_u32 item_len, mode;
+ struct fsw_reiserfs_item item;
+
+ if (dno->sd_v1 || dno->sd_v2)
+ return FSW_SUCCESS;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_dnode_fill: object %d/%d\n"), dno->dir_id, dno->g.dnode_id));
+
+ // find stat data item in reiserfs tree
+ status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, 0, &item);
+ if (status == FSW_NOT_FOUND) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: cannot find stat_data for object %d/%d\n"),
+ dno->dir_id, dno->g.dnode_id));
+ return FSW_VOLUME_CORRUPTED;
+ }
+ if (status)
+ return status;
+ if (item.item_offset != 0) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: got item that's not stat_data\n")));
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_VOLUME_CORRUPTED;
+ }
+ item_len = item.ih.ih_item_len;
+
+ // get data in appropriate version
+ if (item.ih.ih_version == KEY_FORMAT_3_5 && item_len == SD_V1_SIZE) {
+ // have stat_data_v1 structure
+ status = fsw_memdup((void **)&dno->sd_v1, item.item_data, item_len);
+ fsw_reiserfs_item_release(vol, &item);
+ if (status)
+ return status;
+
+ // get info from the inode
+ dno->g.size = dno->sd_v1->sd_size;
+ mode = dno->sd_v1->sd_mode;
+
+ } else if (item.ih.ih_version == KEY_FORMAT_3_6 && item_len == SD_V2_SIZE) {
+ // have stat_data_v2 structure
+ status = fsw_memdup((void **)&dno->sd_v2, item.item_data, item_len);
+ fsw_reiserfs_item_release(vol, &item);
+ if (status)
+ return status;
+
+ // get info from the inode
+ dno->g.size = dno->sd_v2->sd_size;
+ mode = dno->sd_v2->sd_mode;
+
+ } else {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_dnode_fill: version %d(%d) and size %d(%d) not recognized for stat_data\n"),
+ item.ih.ih_version, KEY_FORMAT_3_6, item_len, SD_V2_SIZE));
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_VOLUME_CORRUPTED;
+ }
+
+ // get node type from mode field
+ if (S_ISREG(mode))
+ dno->g.type = FSW_DNODE_TYPE_FILE;
+ else if (S_ISDIR(mode))
+ dno->g.type = FSW_DNODE_TYPE_DIR;
+ else if (S_ISLNK(mode))
+ dno->g.type = FSW_DNODE_TYPE_SYMLINK;
+ else
+ dno->g.type = FSW_DNODE_TYPE_SPECIAL;
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Free the dnode data structure. Called by the core when deallocating a dnode
+ * structure to release the memory used by the file system type specific part
+ * of the dnode structure.
+ */
+
+static void fsw_reiserfs_dnode_free(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno)
+{
+ if (dno->sd_v1)
+ fsw_free(dno->sd_v1);
+ if (dno->sd_v2)
+ fsw_free(dno->sd_v2);
+}
+
+/**
+ * Get in-depth information on a dnode. The core makes sure that fsw_reiserfs_dnode_fill
+ * has been called on the dnode before this function is called. Note that some
+ * data is not directly stored into the structure, but passed to a host-specific
+ * callback that converts it to the host-specific format.
+ */
+
+static fsw_status_t fsw_reiserfs_dnode_stat(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_dnode_stat *sb)
+{
+ if (dno->sd_v1) {
+ if (dno->g.type == FSW_DNODE_TYPE_SPECIAL)
+ sb->used_bytes = 0;
+ else
+ sb->used_bytes = dno->sd_v1->u.sd_blocks * vol->g.log_blocksize;
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v1->sd_ctime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v1->sd_atime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v1->sd_mtime);
+ sb->store_attr_posix(sb, dno->sd_v1->sd_mode);
+ } else if (dno->sd_v2) {
+ sb->used_bytes = dno->sd_v2->sd_blocks * vol->g.log_blocksize;
+ sb->store_time_posix(sb, FSW_DNODE_STAT_CTIME, dno->sd_v2->sd_ctime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_ATIME, dno->sd_v2->sd_atime);
+ sb->store_time_posix(sb, FSW_DNODE_STAT_MTIME, dno->sd_v2->sd_mtime);
+ sb->store_attr_posix(sb, dno->sd_v2->sd_mode);
+ }
+
+ return FSW_SUCCESS;
+}
+
+/**
+ * Retrieve file data mapping information. This function is called by the core when
+ * fsw_shandle_read needs to know where on the disk the required piece of the file's
+ * data can be found. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * on the dnode before. Our task here is to get the physical disk block number for
+ * the requested logical block number.
+ */
+
+static fsw_status_t fsw_reiserfs_get_extent(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_extent *extent)
+{
+ fsw_status_t status;
+ fsw_u64 search_offset, intra_offset;
+ struct fsw_reiserfs_item item;
+ fsw_u32 intra_bno, nr_item;
+
+ // Preconditions: The caller has checked that the requested logical block
+ // is within the file's size. The dnode has complete information, i.e.
+ // fsw_reiserfs_dnode_read_info was called successfully on it.
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_get_extent: mapping block %d of object %d/%d\n"),
+ extent->log_start, dno->dir_id, dno->g.dnode_id));
+
+ extent->type = FSW_EXTENT_TYPE_SPARSE;
+ extent->log_count = 1;
+
+ // get the item for the requested block
+ search_offset = (fsw_u64)extent->log_start * vol->g.log_blocksize + 1;
+ status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, search_offset, &item);
+ if (status)
+ return status;
+ if (item.item_offset == 0) {
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_SUCCESS; // no data items found, assume all-sparse file
+ }
+ intra_offset = search_offset - item.item_offset;
+
+ // check the kind of block
+ if (item.item_type == TYPE_INDIRECT || item.item_type == V1_INDIRECT_UNIQUENESS) {
+ // indirect item, contains block numbers
+
+ if (intra_offset & (vol->g.log_blocksize - 1)) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not block-aligned for indirect block\n")));
+ goto bail;
+ }
+ intra_bno = (fsw_u32)FSW_U64_DIV(intra_offset, vol->g.log_blocksize);
+ nr_item = item.ih.ih_item_len / sizeof(fsw_u32);
+ if (intra_bno >= nr_item) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: indirect block too small\n")));
+ goto bail;
+ }
+ extent->type = FSW_EXTENT_TYPE_PHYSBLOCK;
+ extent->phys_start = ((fsw_u32 *)item.item_data)[intra_bno];
+
+ // TODO: check if the following blocks can be aggregated into one extent
+
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_SUCCESS;
+
+ } else if (item.item_type == TYPE_DIRECT || item.item_type == V1_DIRECT_UNIQUENESS) {
+ // direct item, contains file data
+
+ // TODO: Check if direct items always start on block boundaries. If not, we may have
+ // to do extra work here.
+
+ if (intra_offset != 0) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_get_extent: intra_offset not aligned for direct block\n")));
+ goto bail;
+ }
+
+ extent->type = FSW_EXTENT_TYPE_BUFFER;
+ status = fsw_memdup(&extent->buffer, item.item_data, item.ih.ih_item_len);
+ fsw_reiserfs_item_release(vol, &item);
+ if (status)
+ return status;
+
+ return FSW_SUCCESS;
+
+ }
+
+bail:
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_VOLUME_CORRUPTED;
+
+ /*
+ // check if the following blocks can be aggregated into one extent
+ file_bcnt = (fsw_u32)((dno->g.size + vol->g.log_blocksize - 1) & (vol->g.log_blocksize - 1));
+ while (path[i] + extent->log_count < buf_bcnt && // indirect block has more block pointers
+ extent->log_start + extent->log_count < file_bcnt) { // file has more blocks
+ if (buffer[path[i] + extent->log_count] == buffer[path[i] + extent->log_count - 1] + 1)
+ extent->log_count++;
+ else
+ break;
+ }
+ */
+}
+
+/**
+ * Lookup a directory's child dnode by name. This function is called on a directory
+ * to retrieve the directory entry with the given name. A dnode is constructed for
+ * this entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_lookup(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_string *lookup_name, struct fsw_reiserfs_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_reiserfs_item item;
+ fsw_u32 nr_item, i, name_offset, next_name_offset, name_len;
+ fsw_u32 child_dir_id;
+ struct reiserfs_de_head *dhead;
+ struct fsw_string entry_name;
+
+ // Preconditions: The caller has checked that dno is a directory node.
+
+ // BIG TODOS: Use the hash function to start with the item containing the entry.
+ // Use binary search within the item.
+
+ entry_name.type = FSW_STRING_TYPE_ISO88591;
+
+ // get the item for that position
+ status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, FIRST_ITEM_OFFSET, &item);
+ if (status)
+ return status;
+ if (item.item_offset == 0) {
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_NOT_FOUND; // empty directory or something
+ }
+
+ for(;;) {
+
+ // search the directory item
+ dhead = (struct reiserfs_de_head *)item.item_data;
+ nr_item = item.ih.u.ih_entry_count;
+ next_name_offset = item.ih.ih_item_len;
+ for (i = 0; i < nr_item; i++, dhead++, next_name_offset = name_offset) {
+ // get the name
+ name_offset = dhead->deh_location;
+ name_len = next_name_offset - name_offset;
+ while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+ name_len--;
+
+ entry_name.len = entry_name.size = name_len;
+ entry_name.data = item.item_data + name_offset;
+
+ // compare name
+ if (fsw_streq(lookup_name, &entry_name)) {
+ // found the entry we're looking for!
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+ child_dir_id = dhead->deh_dir_id;
+ fsw_reiserfs_item_release(vol, &item);
+ if (status)
+ return status;
+ (*child_dno_out)->dir_id = child_dir_id;
+
+ return FSW_SUCCESS;
+ }
+ }
+
+ // We didn't find the next directory entry in this item. Look for the next
+ // item of the directory.
+
+ status = fsw_reiserfs_item_next(vol, &item);
+ if (status)
+ return status;
+
+ }
+}
+
+/**
+ * Get the next directory entry when reading a directory. This function is called during
+ * directory iteration to retrieve the next directory entry. A dnode is constructed for
+ * the entry and returned. The core makes sure that fsw_reiserfs_dnode_fill has been called
+ * and the dnode is actually a directory. The shandle provided by the caller is used to
+ * record the position in the directory between calls.
+ */
+
+static fsw_status_t fsw_reiserfs_dir_read(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_shandle *shand, struct fsw_reiserfs_dnode **child_dno_out)
+{
+ fsw_status_t status;
+ struct fsw_reiserfs_item item;
+ fsw_u32 nr_item, i, name_offset, next_name_offset, name_len;
+ fsw_u32 child_dir_id;
+ struct reiserfs_de_head *dhead;
+ struct fsw_string entry_name;
+
+ // Preconditions: The caller has checked that dno is a directory node. The caller
+ // has opened a storage handle to the directory's storage and keeps it around between
+ // calls.
+
+ // BIG TODOS: Use binary search within the item.
+
+ // adjust pointer to first entry if necessary
+ if (shand->pos == 0)
+ shand->pos = FIRST_ITEM_OFFSET;
+
+ // get the item for that position
+ status = fsw_reiserfs_item_search(vol, dno->dir_id, dno->g.dnode_id, shand->pos, &item);
+ if (status)
+ return status;
+ if (item.item_offset == 0) {
+ fsw_reiserfs_item_release(vol, &item);
+ return FSW_NOT_FOUND; // empty directory or something
+ }
+
+ for(;;) {
+
+ // search the directory item
+ dhead = (struct reiserfs_de_head *)item.item_data;
+ nr_item = item.ih.u.ih_entry_count;
+ for (i = 0; i < nr_item; i++, dhead++) {
+ if (dhead->deh_offset < shand->pos)
+ continue; // not yet past the last entry returned
+ if (dhead->deh_offset == DOT_OFFSET || dhead->deh_offset == DOT_DOT_OFFSET)
+ continue; // never report . or ..
+
+ // get the name
+ name_offset = dhead->deh_location;
+ if (i == 0)
+ next_name_offset = item.ih.ih_item_len;
+ else
+ next_name_offset = dhead[-1].deh_location;
+ name_len = next_name_offset - name_offset;
+ while (name_len > 0 && item.item_data[name_offset + name_len - 1] == 0)
+ name_len--;
+
+ entry_name.type = FSW_STRING_TYPE_ISO88591;
+ entry_name.len = entry_name.size = name_len;
+ entry_name.data = item.item_data + name_offset;
+
+ if (fsw_streq_cstr(&entry_name, ".reiserfs_priv"))
+ continue; // never report this special file
+
+ // found the next entry!
+ shand->pos = dhead->deh_offset + 1;
+
+ // setup a dnode for the child item
+ status = fsw_dnode_create(dno, dhead->deh_objectid, FSW_DNODE_TYPE_UNKNOWN, &entry_name, child_dno_out);
+ child_dir_id = dhead->deh_dir_id;
+ fsw_reiserfs_item_release(vol, &item);
+ if (status)
+ return status;
+ (*child_dno_out)->dir_id = child_dir_id;
+
+ return FSW_SUCCESS;
+ }
+
+ // We didn't find the next directory entry in this item. Look for the next
+ // item of the directory.
+
+ status = fsw_reiserfs_item_next(vol, &item);
+ if (status)
+ return status;
+
+ }
+}
+
+/**
+ * Get the target path of a symbolic link. This function is called when a symbolic
+ * link needs to be resolved. The core makes sure that the fsw_reiserfs_dnode_fill has been
+ * called on the dnode and that it really is a symlink.
+ */
+
+static fsw_status_t fsw_reiserfs_readlink(struct fsw_reiserfs_volume *vol, struct fsw_reiserfs_dnode *dno,
+ struct fsw_string *link_target)
+{
+ return fsw_dnode_readlink_data(dno, link_target);
+}
+
+/**
+ * Compare an on-disk tree key against the search key.
+ */
+
+static int fsw_reiserfs_compare_key(struct reiserfs_key *key,
+ fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset)
+{
+ fsw_u32 key_type;
+ fsw_u64 key_offset;
+
+ if (key->k_dir_id > dir_id)
+ return FIRST_GREATER;
+ if (key->k_dir_id < dir_id)
+ return SECOND_GREATER;
+
+ if (key->k_objectid > objectid)
+ return FIRST_GREATER;
+ if (key->k_objectid < objectid)
+ return SECOND_GREATER;
+
+ // determine format of the on-disk key
+ key_type = (fsw_u32)FSW_U64_SHR(key->u.k_offset_v2.v, 60);
+ if (key_type != TYPE_DIRECT && key_type != TYPE_INDIRECT && key_type != TYPE_DIRENTRY) {
+ // detected 3.5 format (_v1)
+ key_offset = key->u.k_offset_v1.k_offset;
+ } else {
+ // detected 3.6 format (_v2)
+ key_offset = key->u.k_offset_v2.v & (~0ULL >> 4);
+ }
+ if (key_offset > offset)
+ return FIRST_GREATER;
+ if (key_offset < offset)
+ return SECOND_GREATER;
+ return KEYS_IDENTICAL;
+}
+
+/**
+ * Find an item by key in the reiserfs tree.
+ */
+
+static fsw_status_t fsw_reiserfs_item_search(struct fsw_reiserfs_volume *vol,
+ fsw_u32 dir_id, fsw_u32 objectid, fsw_u64 offset,
+ struct fsw_reiserfs_item *item)
+{
+ fsw_status_t status;
+ int comp_result;
+ fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, i;
+ fsw_u8 *buffer;
+ struct block_head *bhead;
+ struct reiserfs_key *key;
+ struct item_head *ihead;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: searching %d/%d/%lld\n"), dir_id, objectid, offset));
+
+ // BIG TODOS: Use binary search within the item.
+ // Remember tree path for "get next item" function.
+
+ item->valid = 0;
+ item->block_bno = 0;
+
+ // walk the tree
+ tree_bno = vol->sb->s_v1.s_root_block;
+ for (tree_level = vol->sb->s_v1.s_tree_height - 1; ; tree_level--) {
+
+ // get the current tree block into memory
+ status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+ if (status)
+ return status;
+ bhead = (struct block_head *)buffer;
+ if (bhead->blk_level != tree_level) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_search: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_VOLUME_CORRUPTED;
+ }
+ nr_item = bhead->blk_nr_item;
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_search: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+ item->path_bno[tree_level] = tree_bno;
+
+ // check if we have reached a leaf block
+ if (tree_level == DISK_LEAF_NODE_LEVEL)
+ break;
+
+ // search internal node block, look for the path to follow
+ key = (struct reiserfs_key *)(buffer + BLKH_SIZE);
+ for (i = 0; i < nr_item; i++, key++) {
+ if (fsw_reiserfs_compare_key(key, dir_id, objectid, offset) == FIRST_GREATER)
+ break;
+ }
+ item->path_index[tree_level] = i;
+ next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[i].dc_block_number;
+ fsw_block_release(vol, tree_bno, buffer);
+ tree_bno = next_tree_bno;
+ }
+
+ // search leaf node block, look for our data
+ ihead = (struct item_head *)(buffer + BLKH_SIZE);
+ for (i = 0; i < nr_item; i++, ihead++) {
+ comp_result = fsw_reiserfs_compare_key(&ihead->ih_key, dir_id, objectid, offset);
+ if (comp_result == KEYS_IDENTICAL)
+ break;
+ if (comp_result == FIRST_GREATER) {
+ // Current key is greater than the search key. Use the last key before this
+ // one as the preliminary result.
+ if (i == 0) {
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_NOT_FOUND;
+ }
+ i--, ihead--;
+ break;
+ }
+ }
+ if (i >= nr_item) {
+ // Go back to the last key, it was smaller than the search key.
+ // NOTE: The first key of the next leaf block is guaranteed to be greater than
+ // our search key.
+ i--, ihead--;
+ }
+ item->path_index[tree_level] = i;
+ // Since we may have a key that is smaller than the search key, verify that
+ // it is for the same object.
+ if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_NOT_FOUND; // Found no key for this object at all
+ }
+
+ // return results
+ fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+ item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+ if (item->item_type != TYPE_DIRECT &&
+ item->item_type != TYPE_INDIRECT &&
+ item->item_type != TYPE_DIRENTRY) {
+ // 3.5 format (_v1)
+ item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+ item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+ } else {
+ // 3.6 format (_v2)
+ item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+ }
+ item->item_data = buffer + ihead->ih_item_location;
+ item->valid = 1;
+
+ // add information for block release
+ item->block_bno = tree_bno;
+ item->block_buffer = buffer;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_search: found %d/%d/%lld (%d)\n"),
+ ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+ return FSW_SUCCESS;
+}
+
+/**
+ * Find the next item in the reiserfs tree for an already-found item.
+ */
+
+static fsw_status_t fsw_reiserfs_item_next(struct fsw_reiserfs_volume *vol,
+ struct fsw_reiserfs_item *item)
+{
+ fsw_status_t status;
+ fsw_u32 dir_id, objectid;
+ fsw_u64 offset;
+ fsw_u32 tree_bno, next_tree_bno, tree_level, nr_item, nr_ptr_item;
+ fsw_u8 *buffer;
+ struct block_head *bhead;
+ struct item_head *ihead;
+
+ if (!item->valid)
+ return FSW_NOT_FOUND;
+ fsw_reiserfs_item_release(vol, item); // TODO: maybe delay this and/or use the cached block!
+
+ dir_id = item->ih.ih_key.k_dir_id;
+ objectid = item->ih.ih_key.k_objectid;
+ offset = item->item_offset;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: next for %d/%d/%lld\n"), dir_id, objectid, offset));
+
+ // find a node that has more items, moving up until we find one
+
+ for (tree_level = DISK_LEAF_NODE_LEVEL; tree_level < vol->sb->s_v1.s_tree_height; tree_level++) {
+
+ // get the current tree block into memory
+ tree_bno = item->path_bno[tree_level];
+ status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+ if (status)
+ return status;
+ bhead = (struct block_head *)buffer;
+ if (bhead->blk_level != tree_level) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_VOLUME_CORRUPTED;
+ }
+ nr_item = bhead->blk_nr_item;
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+
+ nr_ptr_item = nr_item + ((tree_level > DISK_LEAF_NODE_LEVEL) ? 1 : 0); // internal nodes have (nr_item) keys and (nr_item+1) pointers
+ item->path_index[tree_level]++;
+ if (item->path_index[tree_level] >= nr_ptr_item) {
+ item->path_index[tree_level] = 0;
+ fsw_block_release(vol, tree_bno, buffer);
+ continue; // this node doesn't have any more items, move up one level
+ }
+
+ // we have a new path to follow, move down to the leaf node again
+ while (tree_level > DISK_LEAF_NODE_LEVEL) {
+ // get next pointer from current block
+ next_tree_bno = ((struct disk_child *)(buffer + BLKH_SIZE + nr_item * KEY_SIZE))[item->path_index[tree_level]].dc_block_number;
+ fsw_block_release(vol, tree_bno, buffer);
+ tree_bno = next_tree_bno;
+ tree_level--;
+
+ // get the current tree block into memory
+ status = fsw_block_get(vol, tree_bno, tree_level, (void **)&buffer);
+ if (status)
+ return status;
+ bhead = (struct block_head *)buffer;
+ if (bhead->blk_level != tree_level) {
+ FSW_MSG_ASSERT((FSW_MSGSTR("fsw_reiserfs_item_next: tree block %d has not expected level %d\n"), tree_bno, tree_level));
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_VOLUME_CORRUPTED;
+ }
+ nr_item = bhead->blk_nr_item;
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_reiserfs_item_next: visiting block %d level %d items %d\n"), tree_bno, tree_level, nr_item));
+ item->path_bno[tree_level] = tree_bno;
+ }
+
+ // get the item from the leaf node
+ ihead = ((struct item_head *)(buffer + BLKH_SIZE)) + item->path_index[tree_level];
+
+ // We now have the item that follows the previous one in the tree. Check that it
+ // belongs to the same object.
+ if (ihead->ih_key.k_dir_id != dir_id || ihead->ih_key.k_objectid != objectid) {
+ fsw_block_release(vol, tree_bno, buffer);
+ return FSW_NOT_FOUND; // Found no next key for this object
+ }
+
+ // return results
+ fsw_memcpy(&item->ih, ihead, sizeof(struct item_head));
+ item->item_type = (fsw_u32)FSW_U64_SHR(ihead->ih_key.u.k_offset_v2.v, 60);
+ if (item->item_type != TYPE_DIRECT &&
+ item->item_type != TYPE_INDIRECT &&
+ item->item_type != TYPE_DIRENTRY) {
+ // 3.5 format (_v1)
+ item->item_type = ihead->ih_key.u.k_offset_v1.k_uniqueness;
+ item->item_offset = ihead->ih_key.u.k_offset_v1.k_offset;
+ } else {
+ // 3.6 format (_v2)
+ item->item_offset = ihead->ih_key.u.k_offset_v2.v & (~0ULL >> 4);
+ }
+ item->item_data = buffer + ihead->ih_item_location;
+ item->valid = 1;
+
+ // add information for block release
+ item->block_bno = tree_bno;
+ item->block_buffer = buffer;
+
+ FSW_MSG_DEBUG((FSW_MSGSTR("fsw_reiserfs_item_next: found %d/%d/%lld (%d)\n"),
+ ihead->ih_key.k_dir_id, ihead->ih_key.k_objectid, item->item_offset, item->item_type));
+ return FSW_SUCCESS;
+ }
+
+ // we went to the highest level node and there still were no more items...
+ return FSW_NOT_FOUND;
+}
+
+/**
+ * Release the disk block still referenced by an item search result.
+ */
+
+static void fsw_reiserfs_item_release(struct fsw_reiserfs_volume *vol,
+ struct fsw_reiserfs_item *item)
+{
+ if (!item->valid)
+ return;
+
+ if (item->block_bno > 0) {
+ fsw_block_release(vol, item->block_bno, item->block_buffer);
+ item->block_bno = 0;
+ }
+}
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_reiserfs.h
+ * ReiserFS file system driver header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_H_
+#define _FSW_REISERFS_H_
+
+#define VOLSTRUCTNAME fsw_reiserfs_volume
+#define DNODESTRUCTNAME fsw_reiserfs_dnode
+#include "fsw_core.h"
+
+#include "fsw_reiserfs_disk.h"
+
+
+//! Block size (in shift bits) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZEBITS 12
+//! Block size (in bytes) to be used when reading the reiserfs superblock.
+#define REISERFS_SUPERBLOCK_BLOCKSIZE (1<<REISERFS_SUPERBLOCK_BLOCKSIZEBITS)
+
+
+/**
+ * ReiserFS: Results from a tree search.
+ */
+
+struct fsw_reiserfs_item {
+ int valid;
+
+ // the found item
+ struct item_head ih;
+ fsw_u64 item_offset;
+ fsw_u32 item_type;
+
+ fsw_u8 *item_data;
+
+ // path information
+ fsw_u32 path_bno[MAX_HEIGHT];
+ fsw_u32 path_index[MAX_HEIGHT];
+
+ // block release information
+ fsw_u32 block_bno;
+ void *block_buffer;
+};
+
+
+/**
+ * ReiserFS: Volume structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_volume {
+ struct fsw_volume g; //!< Generic volume structure
+
+ struct reiserfs_super_block *sb; //!< Full raw reiserfs superblock structure
+ int version; //!< Flag for 3.5 or 3.6 format
+};
+
+/**
+ * ReiserFS: Dnode structure with reiserfs-specific data.
+ */
+
+struct fsw_reiserfs_dnode {
+ struct fsw_dnode g; //!< Generic dnode structure
+
+ fsw_u32 dir_id; //!< Locality ID for the reiserfs tree (parent dir id)
+ struct stat_data_v1 *sd_v1; //!< Full stat_data, version 1
+ struct stat_data *sd_v2; //!< Full stat_data, version 2
+};
+
+
+#endif
--- /dev/null
+/**
+ * \file fsw_reiserfs_disk.h
+ * ReiserFS file system on-disk structures.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ * Portions Copyright (c) 1991-2006 by various Linux kernel contributors
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _FSW_REISERFS_DISK_H_
+#define _FSW_REISERFS_DISK_H_
+
+// types
+
+typedef fsw_s8 __s8;
+typedef fsw_u8 __u8;
+typedef fsw_s16 __s16;
+typedef fsw_u16 __u16;
+typedef fsw_s32 __s32;
+typedef fsw_u32 __u32;
+typedef fsw_s64 __s64;
+typedef fsw_u64 __u64;
+
+typedef __u16 __le16;
+typedef __u32 __le32;
+typedef __u64 __le64;
+
+#define le16_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le64_to_cpu(x) (x)
+#define cpu_to_le64(x) (x)
+
+#ifdef __GCC__
+#define ATTR_PACKED __attribute__ ((__packed__))
+#else
+#define ATTR_PACKED
+#endif
+
+#pragma pack(1)
+
+//
+// from Linux kernel, include/linux/reiserfs_fs.h
+//
+
+
+
+/*
+ * Disk Data Structures
+ */
+
+/***************************************************************************/
+/* SUPER BLOCK */
+/***************************************************************************/
+
+/*
+ * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
+ * the version in RAM is part of a larger structure containing fields never written to disk.
+ */
+#define UNSET_HASH 0 // read_super will guess about, what hash names
+ // in directories were sorted with
+#define TEA_HASH 1
+#define YURA_HASH 2
+#define R5_HASH 3
+#define DEFAULT_HASH R5_HASH
+
+struct journal_params {
+ __le32 jp_journal_1st_block; /* where does journal start from on its
+ * device */
+ __le32 jp_journal_dev; /* journal device st_rdev */
+ __le32 jp_journal_size; /* size of the journal */
+ __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */
+ __le32 jp_journal_magic; /* random value made on fs creation (this
+ * was sb_journal_block_count) */
+ __le32 jp_journal_max_batch; /* max number of blocks to batch into a
+ * trans */
+ __le32 jp_journal_max_commit_age; /* in seconds, how old can an async
+ * commit be */
+ __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction
+ * be */
+};
+
+/* this is the super from 3.5.X, where X >= 10 */
+struct reiserfs_super_block_v1 {
+ __le32 s_block_count; /* blocks count */
+ __le32 s_free_blocks; /* free blocks count */
+ __le32 s_root_block; /* root block number */
+ struct journal_params s_journal;
+ __le16 s_blocksize; /* block size */
+ __le16 s_oid_maxsize; /* max size of object id array, see
+ * get_objectid() commentary */
+ __le16 s_oid_cursize; /* current size of object id array */
+ __le16 s_umount_state; /* this is set to 1 when filesystem was
+ * umounted, to 2 - when not */
+ char s_magic[10]; /* reiserfs magic string indicates that
+ * file system is reiserfs:
+ * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+ __le16 s_fs_state; /* it is set to used by fsck to mark which
+ * phase of rebuilding is done */
+ __le32 s_hash_function_code; /* indicate, what hash function is being use
+ * to sort names in a directory*/
+ __le16 s_tree_height; /* height of disk tree */
+ __le16 s_bmap_nr; /* amount of bitmap blocks needed to address
+ * each block of file system */
+ __le16 s_version; /* this field is only reliable on filesystem
+ * with non-standard journal */
+ __le16 s_reserved_for_journal; /* size in blocks of journal area on main
+ * device, we need to keep after
+ * making fs with non-standard journal */
+} ATTR_PACKED;
+
+#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
+
+/* this is the on disk super block */
+struct reiserfs_super_block {
+ struct reiserfs_super_block_v1 s_v1;
+ __le32 s_inode_generation;
+ __le32 s_flags; /* Right now used only by inode-attributes, if enabled */
+ unsigned char s_uuid[16]; /* filesystem unique identifier */
+ unsigned char s_label[16]; /* filesystem volume label */
+ char s_unused[88]; /* zero filled by mkreiserfs and
+ * reiserfs_convert_objectid_map_v1()
+ * so any additions must be updated
+ * there as well. */
+} ATTR_PACKED;
+
+#define SB_SIZE (sizeof(struct reiserfs_super_block))
+
+#define REISERFS_VERSION_1 0
+#define REISERFS_VERSION_2 2
+
+// on-disk super block fields converted to cpu form
+#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
+#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
+#define SB_BLOCKSIZE(s) \
+ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize))
+#define SB_BLOCK_COUNT(s) \
+ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count))
+#define SB_FREE_BLOCKS(s) \
+ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks))
+#define SB_REISERFS_MAGIC(s) \
+ (SB_V1_DISK_SUPER_BLOCK(s)->s_magic)
+#define SB_ROOT_BLOCK(s) \
+ le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block))
+#define SB_TREE_HEIGHT(s) \
+ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height))
+#define SB_REISERFS_STATE(s) \
+ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state))
+#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version))
+#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr))
+
+#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
+#define SB_ONDISK_JOURNAL_SIZE(s) \
+ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
+#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \
+ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block))
+#define SB_ONDISK_JOURNAL_DEVICE(s) \
+ le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev))
+#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \
+ le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal))
+
+#define is_block_in_log_or_reserved_area(s, block) \
+ block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
+ && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \
+ ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
+ SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
+
+ /* used by gcc */
+#define REISERFS_SUPER_MAGIC 0x52654973
+ /* used by file system utilities that
+ look at the superblock, etc. */
+#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
+#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
+#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
+
+/* ReiserFS leaves the first 64k unused, so that partition labels have
+ enough space. If someone wants to write a fancy bootloader that
+ needs more than 64k, let us know, and this will be increased in size.
+ This number must be larger than than the largest block size on any
+ platform, or code will break. -Hans */
+#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024)
+#define REISERFS_FIRST_BLOCK unused_define
+#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES
+
+/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */
+#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024)
+
+// reiserfs internal error code (used by search_by_key adn fix_nodes))
+#define CARRY_ON 0
+#define REPEAT_SEARCH -1
+#define IO_ERROR -2
+#define NO_DISK_SPACE -3
+#define NO_BALANCING_NEEDED (-4)
+#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5)
+#define QUOTA_EXCEEDED -6
+
+typedef __u32 b_blocknr_t;
+typedef __le32 unp_t;
+
+struct unfm_nodeinfo {
+ unp_t unfm_nodenum;
+ unsigned short unfm_freespace;
+};
+
+/* there are two formats of keys: 3.5 and 3.6
+ */
+#define KEY_FORMAT_3_5 0
+#define KEY_FORMAT_3_6 1
+
+/* there are two stat datas */
+#define STAT_DATA_V1 0
+#define STAT_DATA_V2 1
+
+
+
+/** this says about version of key of all items (but stat data) the
+ object consists of */
+#define get_inode_item_key_version( inode ) \
+ ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5)
+
+#define set_inode_item_key_version( inode, version ) \
+ ({ if((version)==KEY_FORMAT_3_6) \
+ REISERFS_I(inode)->i_flags |= i_item_key_version_mask; \
+ else \
+ REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; })
+
+#define get_inode_sd_version(inode) \
+ ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1)
+
+#define set_inode_sd_version(inode, version) \
+ ({ if((version)==STAT_DATA_V2) \
+ REISERFS_I(inode)->i_flags |= i_stat_data_version_mask; \
+ else \
+ REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; })
+
+/* This is an aggressive tail suppression policy, I am hoping it
+ improves our benchmarks. The principle behind it is that percentage
+ space saving is what matters, not absolute space saving. This is
+ non-intuitive, but it helps to understand it if you consider that the
+ cost to access 4 blocks is not much more than the cost to access 1
+ block, if you have to do a seek and rotate. A tail risks a
+ non-linear disk access that is significant as a percentage of total
+ time cost for a 4 block file and saves an amount of space that is
+ less significant as a percentage of space, or so goes the hypothesis.
+ -Hans */
+#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \
+(\
+ (!(n_tail_size)) || \
+ (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \
+ ( (n_file_size) >= (n_block_size) * 4 ) || \
+ ( ( (n_file_size) >= (n_block_size) * 3 ) && \
+ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \
+ ( ( (n_file_size) >= (n_block_size) * 2 ) && \
+ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \
+ ( ( (n_file_size) >= (n_block_size) ) && \
+ ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \
+)
+
+/* Another strategy for tails, this one means only create a tail if all the
+ file would fit into one DIRECT item.
+ Primary intention for this one is to increase performance by decreasing
+ seeking.
+*/
+#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
+(\
+ (!(n_tail_size)) || \
+ (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
+)
+
+/*
+ * values for s_umount_state field
+ */
+#define REISERFS_VALID_FS 1
+#define REISERFS_ERROR_FS 2
+
+//
+// there are 5 item types currently
+//
+#define TYPE_STAT_DATA 0
+#define TYPE_INDIRECT 1
+#define TYPE_DIRECT 2
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15 // FIXME: comment is required
+
+/***************************************************************************/
+/* KEY & ITEM HEAD */
+/***************************************************************************/
+
+//
+// directories use this key as well as old files
+//
+struct offset_v1 {
+ __le32 k_offset;
+ __le32 k_uniqueness;
+} ATTR_PACKED;
+
+struct offset_v2 {
+ __le64 v;
+} ATTR_PACKED;
+
+/*
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
+{
+ __u8 type = le64_to_cpu(v2->v) >> 60;
+ return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
+}
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
+{
+ return le64_to_cpu(v2->v) & (~0ULL >> 4);
+}
+*/
+
+/* Key of an item determines its location in the S+tree, and
+ is composed of 4 components */
+struct reiserfs_key {
+ __le32 k_dir_id; /* packing locality: by default parent
+ directory object id */
+ __le32 k_objectid; /* object identifier */
+ union {
+ struct offset_v1 k_offset_v1;
+ struct offset_v2 k_offset_v2;
+ } ATTR_PACKED u;
+} ATTR_PACKED;
+
+struct in_core_key {
+ __u32 k_dir_id; /* packing locality: by default parent
+ directory object id */
+ __u32 k_objectid; /* object identifier */
+ __u64 k_offset;
+ __u8 k_type;
+};
+
+struct cpu_key {
+ struct in_core_key on_disk_key;
+ int version;
+ int key_length; /* 3 in all cases but direct2indirect and
+ indirect2direct conversion */
+};
+
+/* Our function for comparing keys can compare keys of different
+ lengths. It takes as a parameter the length of the keys it is to
+ compare. These defines are used in determining what is to be passed
+ to it as that parameter. */
+#define REISERFS_FULL_KEY_LEN 4
+#define REISERFS_SHORT_KEY_LEN 2
+
+/* The result of the key compare */
+#define FIRST_GREATER 1
+#define SECOND_GREATER -1
+#define KEYS_IDENTICAL 0
+#define KEY_FOUND 1
+#define KEY_NOT_FOUND 0
+
+#define KEY_SIZE (sizeof(struct reiserfs_key))
+#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32))
+
+/* return values for search_by_key and clones */
+#define ITEM_FOUND 1
+#define ITEM_NOT_FOUND 0
+#define ENTRY_FOUND 1
+#define ENTRY_NOT_FOUND 0
+#define DIRECTORY_NOT_FOUND -1
+#define REGULAR_FILE_FOUND -2
+#define DIRECTORY_FOUND -3
+#define BYTE_FOUND 1
+#define BYTE_NOT_FOUND 0
+#define FILE_NOT_FOUND -1
+
+#define POSITION_FOUND 1
+#define POSITION_NOT_FOUND 0
+
+// return values for reiserfs_find_entry and search_by_entry_key
+#define NAME_FOUND 1
+#define NAME_NOT_FOUND 0
+#define GOTO_PREVIOUS_ITEM 2
+#define NAME_FOUND_INVISIBLE 3
+
+/* Everything in the filesystem is stored as a set of items. The
+ item head contains the key of the item, its free space (for
+ indirect items) and specifies the location of the item itself
+ within the block. */
+
+struct item_head {
+ /* Everything in the tree is found by searching for it based on
+ * its key.*/
+ struct reiserfs_key ih_key;
+ union {
+ /* The free space in the last unformatted node of an
+ indirect item if this is an indirect item. This
+ equals 0xFFFF iff this is a direct item or stat data
+ item. Note that the key, not this field, is used to
+ determine the item type, and thus which field this
+ union contains. */
+ __le16 ih_free_space_reserved;
+ /* Iff this is a directory item, this field equals the
+ number of directory entries in the directory item. */
+ __le16 ih_entry_count;
+ } ATTR_PACKED u;
+ __le16 ih_item_len; /* total size of the item body */
+ __le16 ih_item_location; /* an offset to the item body
+ * within the block */
+ __le16 ih_version; /* 0 for all old items, 2 for new
+ ones. Highest bit is set by fsck
+ temporary, cleaned after all
+ done */
+} ATTR_PACKED;
+/* size of item header */
+#define IH_SIZE (sizeof(struct item_head))
+
+#define ih_free_space(ih) le16_to_cpu((ih)->u.ih_free_space_reserved)
+#define ih_version(ih) le16_to_cpu((ih)->ih_version)
+#define ih_entry_count(ih) le16_to_cpu((ih)->u.ih_entry_count)
+#define ih_location(ih) le16_to_cpu((ih)->ih_item_location)
+#define ih_item_len(ih) le16_to_cpu((ih)->ih_item_len)
+
+#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
+
+#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
+
+/* these operate on indirect items, where you've got an array of ints
+** at a possibly unaligned location. These are a noop on ia32
+**
+** p is the array of __u32, i is the index into the array, v is the value
+** to store there.
+*/
+#define get_block_num(p, i) le32_to_cpu(get_unaligned((p) + (i)))
+
+//
+// in old version uniqueness field shows key type
+//
+#define V1_SD_UNIQUENESS 0
+#define V1_INDIRECT_UNIQUENESS 0xfffffffe
+#define V1_DIRECT_UNIQUENESS 0xffffffff
+#define V1_DIRENTRY_UNIQUENESS 500
+#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required
+
+//
+// here are conversion routines
+//
+/*
+static inline int uniqueness2type(__u32 uniqueness)
+{
+ switch ((int)uniqueness) {
+ case V1_SD_UNIQUENESS:
+ return TYPE_STAT_DATA;
+ case V1_INDIRECT_UNIQUENESS:
+ return TYPE_INDIRECT;
+ case V1_DIRECT_UNIQUENESS:
+ return TYPE_DIRECT;
+ case V1_DIRENTRY_UNIQUENESS:
+ return TYPE_DIRENTRY;
+ default:
+ reiserfs_warning(NULL, "vs-500: unknown uniqueness %d",
+ uniqueness);
+ case V1_ANY_UNIQUENESS:
+ return TYPE_ANY;
+ }
+}
+
+static inline __u32 type2uniqueness(int type)
+{
+ switch (type) {
+ case TYPE_STAT_DATA:
+ return V1_SD_UNIQUENESS;
+ case TYPE_INDIRECT:
+ return V1_INDIRECT_UNIQUENESS;
+ case TYPE_DIRECT:
+ return V1_DIRECT_UNIQUENESS;
+ case TYPE_DIRENTRY:
+ return V1_DIRENTRY_UNIQUENESS;
+ default:
+ reiserfs_warning(NULL, "vs-501: unknown type %d", type);
+ case TYPE_ANY:
+ return V1_ANY_UNIQUENESS;
+ }
+}
+*/
+
+//
+// key is pointer to on disk key which is stored in le, result is cpu,
+// there is no way to get version of object from key, so, provide
+// version to these defines
+//
+/*
+static inline loff_t le_key_k_offset(int version,
+ const struct reiserfs_key *key)
+{
+ return (version == KEY_FORMAT_3_5) ?
+ le32_to_cpu(key->u.k_offset_v1.k_offset) :
+ offset_v2_k_offset(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
+{
+ return le_key_k_offset(ih_version(ih), &(ih->ih_key));
+}
+
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
+{
+ return (version == KEY_FORMAT_3_5) ?
+ uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+ offset_v2_k_type(&(key->u.k_offset_v2));
+}
+
+static inline loff_t le_ih_k_type(const struct item_head *ih)
+{
+ return le_key_k_type(ih_version(ih), &(ih->ih_key));
+}
+*/
+
+#define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY)
+#define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT)
+#define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT)
+#define is_statdata_le_key(version,key) (le_key_k_type (version, key) == TYPE_STAT_DATA)
+
+//
+// item header has version.
+//
+#define is_direntry_le_ih(ih) is_direntry_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_direct_le_ih(ih) is_direct_le_key (ih_version (ih), &((ih)->ih_key))
+#define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key))
+#define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key))
+
+//
+// key is pointer to cpu key, result is cpu
+//
+/*
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
+{
+ return key->on_disk_key.k_offset;
+}
+
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
+{
+ return key->on_disk_key.k_type;
+}
+
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
+{
+ key->on_disk_key.k_offset--;
+}
+*/
+
+#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
+#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT)
+#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
+#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
+
+/* are these used ? */
+#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
+#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
+#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
+#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
+
+#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
+ ( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \
+ I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
+
+/* maximal length of item */
+#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
+#define MIN_ITEM_LEN 1
+
+/* object identifier for root dir */
+#define REISERFS_ROOT_OBJECTID 2
+#define REISERFS_ROOT_PARENT_OBJECTID 1
+
+/*
+ * Picture represents a leaf of the S+tree
+ * ______________________________________________________
+ * | | Array of | | |
+ * |Block | Object-Item | F r e e | Objects- |
+ * | head | Headers | S p a c e | Items |
+ * |______|_______________|___________________|___________|
+ */
+
+/* Header of a disk block. More precisely, header of a formatted leaf
+ or internal node, and not the header of an unformatted node. */
+struct block_head {
+ __le16 blk_level; /* Level of a block in the tree. */
+ __le16 blk_nr_item; /* Number of keys/items in a block. */
+ __le16 blk_free_space; /* Block free space in bytes. */
+ __le16 blk_reserved;
+ /* dump this in v4/planA */
+ struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */
+};
+
+#define BLKH_SIZE (sizeof(struct block_head))
+#define blkh_level(p_blkh) (le16_to_cpu((p_blkh)->blk_level))
+#define blkh_nr_item(p_blkh) (le16_to_cpu((p_blkh)->blk_nr_item))
+#define blkh_free_space(p_blkh) (le16_to_cpu((p_blkh)->blk_free_space))
+#define blkh_reserved(p_blkh) (le16_to_cpu((p_blkh)->blk_reserved))
+#define blkh_right_delim_key(p_blkh) ((p_blkh)->blk_right_delim_key)
+
+/*
+ * values for blk_level field of the struct block_head
+ */
+
+#define FREE_LEVEL 0 /* when node gets removed from the tree its
+ blk_level is set to FREE_LEVEL. It is then
+ used to see whether the node is still in the
+ tree */
+
+#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */
+
+/* Given the buffer head of a formatted node, resolve to the block head of that node. */
+#define B_BLK_HEAD(p_s_bh) ((struct block_head *)((p_s_bh)->b_data))
+/* Number of items that are in buffer. */
+#define B_NR_ITEMS(p_s_bh) (blkh_nr_item(B_BLK_HEAD(p_s_bh)))
+#define B_LEVEL(p_s_bh) (blkh_level(B_BLK_HEAD(p_s_bh)))
+#define B_FREE_SPACE(p_s_bh) (blkh_free_space(B_BLK_HEAD(p_s_bh)))
+
+/* Get right delimiting key. -- little endian */
+#define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))
+
+/* Does the buffer contain a disk leaf. */
+#define B_IS_ITEMS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) == DISK_LEAF_NODE_LEVEL)
+
+/* Does the buffer contain a disk internal node */
+#define B_IS_KEYS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
+ && B_LEVEL(p_s_bh) <= MAX_HEIGHT)
+
+/***************************************************************************/
+/* STAT DATA */
+/***************************************************************************/
+
+//
+// old stat data is 32 bytes long. We are going to distinguish new one by
+// different size
+//
+struct stat_data_v1 {
+ __le16 sd_mode; /* file type, permissions */
+ __le16 sd_nlink; /* number of hard links */
+ __le16 sd_uid; /* owner */
+ __le16 sd_gid; /* group */
+ __le32 sd_size; /* file size */
+ __le32 sd_atime; /* time of last access */
+ __le32 sd_mtime; /* time file was last modified */
+ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+ union {
+ __le32 sd_rdev;
+ __le32 sd_blocks; /* number of blocks file uses */
+ } ATTR_PACKED u;
+ __le32 sd_first_direct_byte; /* first byte of file which is stored
+ in a direct item: except that if it
+ equals 1 it is a symlink and if it
+ equals ~(__u32)0 there is no
+ direct item. The existence of this
+ field really grates on me. Let's
+ replace it with a macro based on
+ sd_size and our tail suppression
+ policy. Someday. -Hans */
+} ATTR_PACKED;
+
+#define SD_V1_SIZE (sizeof(struct stat_data_v1))
+#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5)
+#define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v))
+#define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink))
+#define set_sd_v1_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le16(v))
+#define sd_v1_uid(sdp) (le16_to_cpu((sdp)->sd_uid))
+#define set_sd_v1_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le16(v))
+#define sd_v1_gid(sdp) (le16_to_cpu((sdp)->sd_gid))
+#define set_sd_v1_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le16(v))
+#define sd_v1_size(sdp) (le32_to_cpu((sdp)->sd_size))
+#define set_sd_v1_size(sdp,v) ((sdp)->sd_size = cpu_to_le32(v))
+#define sd_v1_atime(sdp) (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v1_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v1_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v1_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v1_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v1_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v1_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v1_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v1_blocks(sdp) (le32_to_cpu((sdp)->u.sd_blocks))
+#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v))
+#define sd_v1_first_direct_byte(sdp) \
+ (le32_to_cpu((sdp)->sd_first_direct_byte))
+#define set_sd_v1_first_direct_byte(sdp,v) \
+ ((sdp)->sd_first_direct_byte = cpu_to_le32(v))
+
+/*
+#include <linux/ext2_fs.h>
+*/
+
+/* inode flags stored in sd_attrs (nee sd_reserved) */
+
+/* we want common flags to have the same values as in ext2,
+ so chattr(1) will work without problems */
+#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+#define REISERFS_APPEND_FL EXT2_APPEND_FL
+#define REISERFS_SYNC_FL EXT2_SYNC_FL
+#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
+#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
+#define REISERFS_SECRM_FL EXT2_SECRM_FL
+#define REISERFS_UNRM_FL EXT2_UNRM_FL
+#define REISERFS_COMPR_FL EXT2_COMPR_FL
+#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL
+
+/* persistent flags that file inherits from the parent directory */
+#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \
+ REISERFS_SYNC_FL | \
+ REISERFS_NOATIME_FL | \
+ REISERFS_NODUMP_FL | \
+ REISERFS_SECRM_FL | \
+ REISERFS_COMPR_FL | \
+ REISERFS_NOTAIL_FL )
+
+/* Stat Data on disk (reiserfs version of UFS disk inode minus the
+ address blocks) */
+struct stat_data {
+ __le16 sd_mode; /* file type, permissions */
+ __le16 sd_attrs; /* persistent inode flags */
+ __le32 sd_nlink; /* number of hard links */
+ __le64 sd_size; /* file size */
+ __le32 sd_uid; /* owner */
+ __le32 sd_gid; /* group */
+ __le32 sd_atime; /* time of last access */
+ __le32 sd_mtime; /* time file was last modified */
+ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+ __le32 sd_blocks;
+ union {
+ __le32 sd_rdev;
+ __le32 sd_generation;
+ //__le32 sd_first_direct_byte;
+ /* first byte of file which is stored in a
+ direct item: except that if it equals 1
+ it is a symlink and if it equals
+ ~(__u32)0 there is no direct item. The
+ existence of this field really grates
+ on me. Let's replace it with a macro
+ based on sd_size and our tail
+ suppression policy? */
+ } ATTR_PACKED u;
+} ATTR_PACKED;
+//
+// this is 44 bytes long
+//
+#define SD_SIZE (sizeof(struct stat_data))
+#define SD_V2_SIZE SD_SIZE
+#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6)
+#define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode))
+#define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v))
+/* sd_reserved */
+/* set_sd_reserved */
+#define sd_v2_nlink(sdp) (le32_to_cpu((sdp)->sd_nlink))
+#define set_sd_v2_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le32(v))
+#define sd_v2_size(sdp) (le64_to_cpu((sdp)->sd_size))
+#define set_sd_v2_size(sdp,v) ((sdp)->sd_size = cpu_to_le64(v))
+#define sd_v2_uid(sdp) (le32_to_cpu((sdp)->sd_uid))
+#define set_sd_v2_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le32(v))
+#define sd_v2_gid(sdp) (le32_to_cpu((sdp)->sd_gid))
+#define set_sd_v2_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le32(v))
+#define sd_v2_atime(sdp) (le32_to_cpu((sdp)->sd_atime))
+#define set_sd_v2_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v))
+#define sd_v2_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime))
+#define set_sd_v2_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v))
+#define sd_v2_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime))
+#define set_sd_v2_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v))
+#define sd_v2_blocks(sdp) (le32_to_cpu((sdp)->sd_blocks))
+#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v))
+#define sd_v2_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev))
+#define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v))
+#define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation))
+#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v))
+#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs))
+#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v))
+
+/***************************************************************************/
+/* DIRECTORY STRUCTURE */
+/***************************************************************************/
+/*
+ Picture represents the structure of directory items
+ ________________________________________________
+ | Array of | | | | | |
+ | directory |N-1| N-2 | .... | 1st |0th|
+ | entry headers | | | | | |
+ |_______________|___|_____|________|_______|___|
+ <---- directory entries ------>
+
+ First directory item has k_offset component 1. We store "." and ".."
+ in one item, always, we never split "." and ".." into differing
+ items. This makes, among other things, the code for removing
+ directories simpler. */
+#define SD_OFFSET 0
+#define SD_UNIQUENESS 0
+#define DOT_OFFSET 1
+#define DOT_DOT_OFFSET 2
+#define DIRENTRY_UNIQUENESS 500
+
+/* */
+#define FIRST_ITEM_OFFSET 1
+
+/*
+ Q: How to get key of object pointed to by entry from entry?
+
+ A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key
+ of object, entry points to */
+
+/* NOT IMPLEMENTED:
+ Directory will someday contain stat data of object */
+
+struct reiserfs_de_head {
+ __le32 deh_offset; /* third component of the directory entry key */
+ __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced
+ by directory entry */
+ __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */
+ __le16 deh_location; /* offset of name in the whole item */
+ __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether
+ entry is hidden (unlinked) */
+} ATTR_PACKED;
+#define DEH_SIZE sizeof(struct reiserfs_de_head)
+#define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset))
+#define deh_dir_id(p_deh) (le32_to_cpu((p_deh)->deh_dir_id))
+#define deh_objectid(p_deh) (le32_to_cpu((p_deh)->deh_objectid))
+#define deh_location(p_deh) (le16_to_cpu((p_deh)->deh_location))
+#define deh_state(p_deh) (le16_to_cpu((p_deh)->deh_state))
+
+#define put_deh_offset(p_deh,v) ((p_deh)->deh_offset = cpu_to_le32((v)))
+#define put_deh_dir_id(p_deh,v) ((p_deh)->deh_dir_id = cpu_to_le32((v)))
+#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v)))
+#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v)))
+#define put_deh_state(p_deh,v) ((p_deh)->deh_state = cpu_to_le16((v)))
+
+/* empty directory contains two entries "." and ".." and their headers */
+#define EMPTY_DIR_SIZE \
+(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen ("..")))
+
+/* old format directories have this size when empty */
+#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
+
+#define DEH_Statdata 0 /* not used now */
+#define DEH_Visible 2
+
+/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
+#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__)
+# define ADDR_UNALIGNED_BITS (3)
+#endif
+
+/* These are only used to manipulate deh_state.
+ * Because of this, we'll use the ext2_ bit routines,
+ * since they are little endian */
+#ifdef ADDR_UNALIGNED_BITS
+
+# define aligned_address(addr) ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1)))
+# define unaligned_offset(addr) (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3)
+
+# define set_bit_unaligned(nr, addr) ext2_set_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+# define clear_bit_unaligned(nr, addr) ext2_clear_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+# define test_bit_unaligned(nr, addr) ext2_test_bit((nr) + unaligned_offset(addr), aligned_address(addr))
+
+#else
+
+# define set_bit_unaligned(nr, addr) ext2_set_bit(nr, addr)
+# define clear_bit_unaligned(nr, addr) ext2_clear_bit(nr, addr)
+# define test_bit_unaligned(nr, addr) ext2_test_bit(nr, addr)
+
+#endif
+
+#define mark_de_with_sd(deh) set_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_without_sd(deh) clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define mark_de_visible(deh) set_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define mark_de_hidden(deh) clear_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+#define de_with_sd(deh) test_bit_unaligned (DEH_Statdata, &((deh)->deh_state))
+#define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+#define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
+
+/*
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid);
+*/
+
+/* array of the entry headers */
+ /* get item body */
+#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) )
+#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih)))
+
+/* length of the directory entry in directory item. This define
+ calculates length of i-th directory entry using directory entry
+ locations from dir entry head. When it calculates length of 0-th
+ directory entry, it uses length of whole item in place of entry
+ location of the non-existent following entry in the calculation.
+ See picture above.*/
+/*
+#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
+((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
+*/
+/*
+static inline int entry_length(const struct buffer_head *bh,
+ const struct item_head *ih, int pos_in_item)
+{
+ struct reiserfs_de_head *deh;
+
+ deh = B_I_DEH(bh, ih) + pos_in_item;
+ if (pos_in_item)
+ return deh_location(deh - 1) - deh_location(deh);
+
+ return ih_item_len(ih) - deh_location(deh);
+}
+*/
+
+/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
+#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
+
+/* name by bh, ih and entry_num */
+#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
+
+// two entries per block (at least)
+#define REISERFS_MAX_NAME(block_size) 255
+
+/* this structure is used for operations on directory entries. It is
+ not a disk structure. */
+/* When reiserfs_find_entry or search_by_entry_key find directory
+ entry, they return filled reiserfs_dir_entry structure */
+struct reiserfs_dir_entry {
+ struct buffer_head *de_bh;
+ int de_item_num;
+ struct item_head *de_ih;
+ int de_entry_num;
+ struct reiserfs_de_head *de_deh;
+ int de_entrylen;
+ int de_namelen;
+ char *de_name;
+ unsigned long *de_gen_number_bit_string;
+
+ __u32 de_dir_id;
+ __u32 de_objectid;
+
+ struct cpu_key de_entry_key;
+};
+
+/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
+
+/* pointer to file name, stored in entry */
+#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh))
+
+/* length of name */
+#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
+(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
+
+/* hash value occupies bits from 7 up to 30 */
+#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
+/* generation number occupies 7 bits starting from 0 up to 6 */
+#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL)
+#define MAX_GENERATION_NUMBER 127
+
+#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
+
+/*
+ * Picture represents an internal node of the reiserfs tree
+ * ______________________________________________________
+ * | | Array of | Array of | Free |
+ * |block | keys | pointers | space |
+ * | head | N | N+1 | |
+ * |______|_______________|___________________|___________|
+ */
+
+/***************************************************************************/
+/* DISK CHILD */
+/***************************************************************************/
+/* Disk child pointer: The pointer from an internal node of the tree
+ to a node that is on disk. */
+struct disk_child {
+ __le32 dc_block_number; /* Disk child's block number. */
+ __le16 dc_size; /* Disk child's used space. */
+ __le16 dc_reserved;
+};
+
+#define DC_SIZE (sizeof(struct disk_child))
+#define dc_block_number(dc_p) (le32_to_cpu((dc_p)->dc_block_number))
+#define dc_size(dc_p) (le16_to_cpu((dc_p)->dc_size))
+
+/* Get disk child by buffer header and position in the tree node. */
+#define B_N_CHILD(p_s_bh,n_pos) ((struct disk_child *)\
+((p_s_bh)->b_data+BLKH_SIZE+B_NR_ITEMS(p_s_bh)*KEY_SIZE+DC_SIZE*(n_pos)))
+
+/* Get disk child number by buffer header and position in the tree node. */
+#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
+#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
+
+ /* maximal value of field child_size in structure disk_child */
+ /* child size is the combined size of all items and their headers */
+#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
+
+/* amount of used space in buffer (not including block head) */
+#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur)))
+
+/* max and min number of keys in internal node */
+#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) )
+#define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2)
+
+/***************************************************************************/
+/* PATH STRUCTURES AND DEFINES */
+/***************************************************************************/
+
+/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
+ key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it
+ does not find them in the cache it reads them from disk. For each node search_by_key finds using
+ reiserfs_bread it then uses bin_search to look through that node. bin_search will find the
+ position of the block_number of the next node if it is looking through an internal node. If it
+ is looking through a leaf node bin_search will find the position of the item which has key either
+ equal to given key, or which is the maximal key less than the given key. */
+
+struct path_element {
+ struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */
+ int pe_position; /* Position in the tree node which is placed in the */
+ /* buffer above. */
+};
+
+#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */
+
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */
+
+/* We need to keep track of who the ancestors of nodes are. When we
+ perform a search we record which nodes were visited while
+ descending the tree looking for the node we searched for. This list
+ of nodes is called the path. This information is used while
+ performing balancing. Note that this path information may become
+ invalid, and this means we must check it when using it to see if it
+ is still valid. You'll need to read search_by_key and the comments
+ in it, especially about decrement_counters_in_path(), to understand
+ this structure.
+
+Paths make the code so much harder to work with and debug.... An
+enormous number of bugs are due to them, and trying to write or modify
+code that uses them just makes my head hurt. They are based on an
+excessive effort to avoid disturbing the precious VFS code.:-( The
+gods only know how we are going to SMP the code that uses them.
+znodes are the way! */
+
+#define PATH_READA 0x1 /* do read ahead */
+#define PATH_READA_BACK 0x2 /* read backwards */
+
+struct path {
+ int path_length; /* Length of the array above. */
+ int reada;
+ struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
+ int pos_in_item;
+};
+
+#define pos_in_item(path) ((path)->pos_in_item)
+
+#define INITIALIZE_PATH(var) \
+struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
+
+/* Get path element by path and path position. */
+#define PATH_OFFSET_PELEMENT(p_s_path,n_offset) ((p_s_path)->path_elements +(n_offset))
+
+/* Get buffer header at the path by path and path position. */
+#define PATH_OFFSET_PBUFFER(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_buffer)
+
+/* Get position in the element at the path by path and path position. */
+#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
+
+#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
+ /* you know, to the person who didn't
+ write this the macro name does not
+ at first suggest what it does.
+ Maybe POSITION_FROM_PATH_END? Or
+ maybe we should just focus on
+ dumping paths... -Hans */
+#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
+
+#define PATH_PITEM_HEAD(p_s_path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
+
+/* in do_balance leaf has h == 0 in contrast with path structure,
+ where root has level == 0. That is why we need these defines */
+#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h)) /* tb->S[h] */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */
+
+#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
+
+#define get_last_bh(path) PATH_PLAST_BUFFER(path)
+#define get_ih(path) PATH_PITEM_HEAD(path)
+#define get_item_pos(path) PATH_LAST_POSITION(path)
+#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path)))
+#define item_moved(ih,path) comp_items(ih, path)
+#define path_changed(ih,path) comp_items (ih, path)
+
+/***************************************************************************/
+/* MISC */
+/***************************************************************************/
+
+/* Size of pointer to the unformatted node. */
+#define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
+
+// in in-core inode key is stored on le form
+#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key))
+
+#define MAX_UL_INT 0xffffffff
+#define MAX_INT 0x7ffffff
+#define MAX_US_INT 0xffff
+
+// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
+#define U32_MAX (~(__u32)0)
+
+/*
+static inline loff_t max_reiserfs_offset(struct inode *inode)
+{
+ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+ return (loff_t) U32_MAX;
+
+ return (loff_t) ((~(__u64) 0) >> 4);
+}
+*/
+
+/*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/
+#define MAX_KEY_OBJECTID MAX_UL_INT
+
+#define MAX_B_NUM MAX_UL_INT
+#define MAX_FC_NUM MAX_US_INT
+
+/* the purpose is to detect overflow of an unsigned short */
+#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
+
+/* The following defines are used in reiserfs_insert_item and reiserfs_append_item */
+#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */
+#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */
+
+#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
+#define get_generation(s) atomic_read (&fs_generation(s))
+#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen)
+#define __fs_changed(gen,s) (gen != get_generation (s))
+#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
+
+/***************************************************************************/
+/* FIXATE NODES */
+/***************************************************************************/
+
+#define VI_TYPE_LEFT_MERGEABLE 1
+#define VI_TYPE_RIGHT_MERGEABLE 2
+
+/* To make any changes in the tree we always first find node, that
+ contains item to be changed/deleted or place to insert a new
+ item. We call this node S. To do balancing we need to decide what
+ we will shift to left/right neighbor, or to a new node, where new
+ item will be etc. To make this analysis simpler we build virtual
+ node. Virtual node is an array of items, that will replace items of
+ node S. (For instance if we are going to delete an item, virtual
+ node does not contain it). Virtual node keeps information about
+ item sizes and types, mergeability of first and last items, sizes
+ of all entries in directory item. We use this array of items when
+ calculating what we can shift to neighbors and how many nodes we
+ have to have if we do not any shiftings, if we shift to left/right
+ neighbor or to both. */
+struct virtual_item {
+ int vi_index; // index in the array of item operations
+ unsigned short vi_type; // left/right mergeability
+ unsigned short vi_item_len; /* length of item that it will have after balancing */
+ struct item_head *vi_ih;
+ const char *vi_item; // body of item (old or new)
+ const void *vi_new_data; // 0 always but paste mode
+ void *vi_uarea; // item specific area
+};
+
+struct virtual_node {
+ char *vn_free_ptr; /* this is a pointer to the free space in the buffer */
+ unsigned short vn_nr_item; /* number of items in virtual node */
+ short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */
+ short vn_mode; /* mode of balancing (paste, insert, delete, cut) */
+ short vn_affected_item_num;
+ short vn_pos_in_item;
+ struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */
+ const void *vn_data;
+ struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */
+};
+
+/* used by directory items when creating virtual nodes */
+struct direntry_uarea {
+ int flags;
+ __u16 entry_count;
+ __u16 entry_sizes[1];
+} ATTR_PACKED;
+
+/***************************************************************************/
+/* TREE BALANCE */
+/***************************************************************************/
+
+/* This temporary structure is used in tree balance algorithms, and
+ constructed as we go to the extent that its various parts are
+ needed. It contains arrays of nodes that can potentially be
+ involved in the balancing of node S, and parameters that define how
+ each of the nodes must be balanced. Note that in these algorithms
+ for balancing the worst case is to need to balance the current node
+ S and the left and right neighbors and all of their parents plus
+ create a new node. We implement S1 balancing for the leaf nodes
+ and S0 balancing for the internal nodes (S1 and S0 are defined in
+ our papers.)*/
+
+#define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */
+
+/* maximum number of FEB blocknrs on a single level */
+#define MAX_AMOUNT_NEEDED 2
+
+/* someday somebody will prefix every field in this struct with tb_ */
+struct tree_balance {
+ int tb_mode;
+ int need_balance_dirty;
+ struct super_block *tb_sb;
+ struct reiserfs_transaction_handle *transaction_handle;
+ struct path *tb_path;
+ struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */
+ struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */
+ struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */
+ struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */
+ struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */
+ struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */
+
+ struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals
+ cur_blknum. */
+ struct buffer_head *used[MAX_FEB_SIZE];
+ struct buffer_head *thrown[MAX_FEB_SIZE];
+ int lnum[MAX_HEIGHT]; /* array of number of items which must be
+ shifted to the left in order to balance the
+ current node; for leaves includes item that
+ will be partially shifted; for internal
+ nodes, it is the number of child pointers
+ rather than items. It includes the new item
+ being created. The code sometimes subtracts
+ one to get the number of wholly shifted
+ items for other purposes. */
+ int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */
+ int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and
+ S[h] to its item number within the node CFL[h] */
+ int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */
+ int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from
+ S[h]. A negative value means removing. */
+ int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
+ balancing on the level h of the tree. If 0 then S is
+ being deleted, if 1 then S is remaining and no new nodes
+ are being created, if 2 or 3 then 1 or 2 new nodes is
+ being created */
+
+ /* fields that are used only for balancing leaves of the tree */
+ int cur_blknum; /* number of empty blocks having been already allocated */
+ int s0num; /* number of items that fall into left most node when S[0] splits */
+ int s1num; /* number of items that fall into first new node when S[0] splits */
+ int s2num; /* number of items that fall into second new node when S[0] splits */
+ int lbytes; /* number of bytes which can flow to the left neighbor from the left */
+ /* most liquid item that cannot be shifted from S[0] entirely */
+ /* if -1 then nothing will be partially shifted */
+ int rbytes; /* number of bytes which will flow to the right neighbor from the right */
+ /* most liquid item that cannot be shifted from S[0] entirely */
+ /* if -1 then nothing will be partially shifted */
+ int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */
+ /* note: if S[0] splits into 3 nodes, then items do not need to be cut */
+ int s2bytes;
+ struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+ char *vn_buf; /* kmalloced memory. Used to create
+ virtual node and keep map of
+ dirtied bitmap blocks */
+ int vn_buf_size; /* size of the vn_buf */
+ struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */
+
+ int fs_gen; /* saved value of `reiserfs_generation' counter
+ see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+#ifdef DISPLACE_NEW_PACKING_LOCALITIES
+ struct in_core_key key; /* key pointer, to pass to block allocator or
+ another low-level subsystem */
+#endif
+};
+
+/* These are modes of balancing */
+
+/* When inserting an item. */
+#define M_INSERT 'i'
+/* When inserting into (directories only) or appending onto an already
+ existant item. */
+#define M_PASTE 'p'
+/* When deleting an item. */
+#define M_DELETE 'd'
+/* When truncating an item or removing an entry from a (directory) item. */
+#define M_CUT 'c'
+
+/* used when balancing on leaf level skipped (in reiserfsck) */
+#define M_INTERNAL 'n'
+
+/* When further balancing is not needed, then do_balance does not need
+ to be called. */
+#define M_SKIP_BALANCING 's'
+#define M_CONVERT 'v'
+
+/* modes of leaf_move_items */
+#define LEAF_FROM_S_TO_L 0
+#define LEAF_FROM_S_TO_R 1
+#define LEAF_FROM_R_TO_L 2
+#define LEAF_FROM_L_TO_R 3
+#define LEAF_FROM_S_TO_SNEW 4
+
+#define FIRST_TO_LAST 0
+#define LAST_TO_FIRST 1
+
+/* used in do_balance for passing parent of node information that has
+ been gotten from tb struct */
+struct buffer_info {
+ struct tree_balance *tb;
+ struct buffer_head *bi_bh;
+ struct buffer_head *bi_parent;
+ int bi_position;
+};
+
+/* there are 4 types of items: stat data, directory item, indirect, direct.
++-------------------+------------+--------------+------------+
+| | k_offset | k_uniqueness | mergeable? |
++-------------------+------------+--------------+------------+
+| stat data | 0 | 0 | no |
++-------------------+------------+--------------+------------+
+| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no |
+| non 1st directory | hash value | | yes |
+| item | | | |
++-------------------+------------+--------------+------------+
+| indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object
++-------------------+------------+--------------+------------+
+| direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object
++-------------------+------------+--------------+------------+
+*/
+
+struct item_operations {
+ int (*bytes_number) (struct item_head * ih, int block_size);
+ void (*decrement_key) (struct cpu_key *);
+ int (*is_left_mergeable) (struct reiserfs_key * ih,
+ unsigned long bsize);
+ void (*print_item) (struct item_head *, char *item);
+ void (*check_item) (struct item_head *, char *item);
+
+ int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+ int is_affected, int insert_size);
+ int (*check_left) (struct virtual_item * vi, int free,
+ int start_skip, int end_skip);
+ int (*check_right) (struct virtual_item * vi, int free);
+ int (*part_size) (struct virtual_item * vi, int from, int to);
+ int (*unit_num) (struct virtual_item * vi);
+ void (*print_vi) (struct virtual_item * vi);
+};
+
+extern struct item_operations *item_ops[TYPE_ANY + 1];
+
+#define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
+#define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
+#define op_print_item(ih,item) item_ops[le_ih_k_type (ih)]->print_item (ih, item)
+#define op_check_item(ih,item) item_ops[le_ih_k_type (ih)]->check_item (ih, item)
+#define op_create_vi(vn,vi,is_affected,insert_size) item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size)
+#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip)
+#define op_check_right(vi,free) item_ops[(vi)->vi_index]->check_right (vi, free)
+#define op_part_size(vi,from,to) item_ops[(vi)->vi_index]->part_size (vi, from, to)
+#define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi)
+#define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi)
+
+#define COMP_SHORT_KEYS comp_short_keys
+
+/* number of blocks pointed to by the indirect item */
+#define I_UNFM_NUM(p_s_ih) ( ih_item_len(p_s_ih) / UNFM_P_SIZE )
+
+/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */
+#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size))
+
+/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
+
+/* get the item header */
+#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get key */
+#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) )
+
+/* get the key */
+#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) )
+
+/* get item body */
+#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num))))
+
+/* get the stat data by the buffer header and the item order */
+#define B_N_STAT_DATA(bh,nr) \
+( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) )
+
+ /* following defines use reiserfs buffer header and item header */
+
+/* get stat-data */
+#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) )
+
+// this is 3976 for size==4096
+#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE)
+
+/* indirect items consist of entries which contain blocknrs, pos
+ indicates which entry, and B_I_POS_UNFM_POINTER resolves to the
+ blocknr contained by the entry pos points to */
+#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)))
+#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
+
+struct reiserfs_iget_args {
+ __u32 objectid;
+ __u32 dirid;
+};
+
+/***************************************************************************/
+/* FUNCTION DECLARATIONS */
+/***************************************************************************/
+
+/*#ifdef __KERNEL__*/
+#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12)
+
+#define journal_trans_half(blocksize) \
+ ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32))
+
+/* journal.c see journal.c for all the comments here */
+
+/* first block written in a commit. */
+struct reiserfs_journal_desc {
+ __le32 j_trans_id; /* id of commit */
+ __le32 j_len; /* length of commit. len +1 is the commit block */
+ __le32 j_mount_id; /* mount id of this trans */
+ __le32 j_realblock[1]; /* real locations for each block */
+};
+
+#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id)
+#define get_desc_trans_len(d) le32_to_cpu((d)->j_len)
+#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id)
+
+#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0)
+#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0)
+
+/* last block written in a commit */
+struct reiserfs_journal_commit {
+ __le32 j_trans_id; /* must match j_trans_id from the desc block */
+ __le32 j_len; /* ditto */
+ __le32 j_realblock[1]; /* real locations for each block */
+};
+
+#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
+#define get_commit_trans_len(c) le32_to_cpu((c)->j_len)
+#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id)
+
+#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0)
+#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0)
+
+/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the
+** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk,
+** and this transaction does not need to be replayed.
+*/
+struct reiserfs_journal_header {
+ __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */
+ __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */
+ __le32 j_mount_id;
+ /* 12 */ struct journal_params jh_journal;
+};
+
+/* biggest tunable defines are right here */
+#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_TRANS_MIN_DEFAULT 256
+#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MIN_RATIO 2
+#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_TRANS_AGE 30
+#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
+#ifdef CONFIG_QUOTA
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
+#else
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
+#endif
+
+/* both of these can be as low as 1, or as high as you want. The min is the
+** number of 4k bitmap nodes preallocated on mount. New nodes are allocated
+** as needed, and released when transactions are committed. On release, if
+** the current number of nodes is > max, the node is freed, otherwise,
+** it is put on a free list for faster use later.
+*/
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
+
+#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */
+#define JBH_HASH_MASK 8191
+
+#define _jhashfn(sb,block) \
+ (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \
+ (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12))))
+#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK])
+
+// We need these to make journal.c code more readable
+#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
+
+//enum reiserfs_bh_state_bits {
+// BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */
+// BH_JDirty_wait,
+// BH_JNew, /* disk block was taken off free list before
+// * being in a finished transaction, or
+// * written to disk. Can be reused immed. */
+// BH_JPrepared,
+// BH_JRestore_dirty,
+// BH_JTest, // debugging only will go away
+//};
+
+/*
+BUFFER_FNS(JDirty, journaled);
+TAS_BUFFER_FNS(JDirty, journaled);
+BUFFER_FNS(JDirty_wait, journal_dirty);
+TAS_BUFFER_FNS(JDirty_wait, journal_dirty);
+BUFFER_FNS(JNew, journal_new);
+TAS_BUFFER_FNS(JNew, journal_new);
+BUFFER_FNS(JPrepared, journal_prepared);
+TAS_BUFFER_FNS(JPrepared, journal_prepared);
+BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty);
+BUFFER_FNS(JTest, journal_test);
+TAS_BUFFER_FNS(JTest, journal_test);
+*/
+
+/*
+** transaction handle which is passed around for all journal calls
+*/
+struct reiserfs_transaction_handle {
+ struct super_block *t_super; /* super for this FS when journal_begin was
+ called. saves calls to reiserfs_get_super
+ also used by nested transactions to make
+ sure they are nesting on the right FS
+ _must_ be first in the handle
+ */
+ int t_refcount;
+ int t_blocks_logged; /* number of blocks this writer has logged */
+ int t_blocks_allocated; /* number of blocks this writer allocated */
+ unsigned long t_trans_id; /* sanity check, equals the current trans id */
+ void *t_handle_save; /* save existing current->journal_info */
+ unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
+ should be displaced from others */
+ //struct list_head t_list;
+};
+
+/* used to keep track of ordered and tail writes, attached to the buffer
+ * head through b_journal_head.
+ */
+struct reiserfs_jh {
+ struct reiserfs_journal_list *jl;
+ struct buffer_head *bh;
+ //struct list_head list;
+};
+
+//
+// get key version from on disk key - kludge
+//
+/*
+static inline int le_key_version(const struct reiserfs_key *key)
+{
+ int type;
+
+ type = offset_v2_k_type(&(key->u.k_offset_v2));
+ if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+ && type != TYPE_DIRENTRY)
+ return KEY_FORMAT_3_5;
+
+ return KEY_FORMAT_3_6;
+
+}
+
+static inline void copy_key(struct reiserfs_key *to,
+ const struct reiserfs_key *from)
+{
+ memcpy(to, from, KEY_SIZE);
+}
+*/
+
+#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
+#define file_size(inode) ((inode)->i_size)
+#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1))
+
+#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
+!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
+
+/* inode.c */
+/* args for the create parameter of reiserfs_get_block */
+#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1 /* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_IMUX 8 /* i_mutex is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
+
+/* bitmap.c */
+
+/* structure contains hints for block allocator, and it is a container for
+ * arguments, such as node, search path, transaction_handle, etc. */
+struct __reiserfs_blocknr_hint {
+ struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */
+ long block; /* file offset, in blocks */
+ struct in_core_key key;
+ struct path *path; /* search path, used by allocator to deternine search_start by
+ * various ways */
+ struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
+ * bitmap blocks changes */
+ b_blocknr_t beg, end;
+ b_blocknr_t search_start; /* a field used to transfer search start value (block number)
+ * between different block allocator procedures
+ * (determine_search_start() and others) */
+ int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed
+ * function that do actual allocation */
+
+ unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for
+ * formatted/unformatted blocks with/without preallocation */
+ unsigned preallocate:1;
+};
+
+typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
+
+/* hashes.c */
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
+
+/* the ext2 bit routines adjust for big or little endian as
+** appropriate for the arch, so in our laziness we use them rather
+** than using the bit routines they call more directly. These
+** routines must be used when changing on disk bitmaps. */
+#define reiserfs_test_and_set_le_bit ext2_set_bit
+#define reiserfs_test_and_clear_le_bit ext2_clear_bit
+#define reiserfs_test_le_bit ext2_test_bit
+#define reiserfs_find_next_zero_le_bit ext2_find_next_zero_bit
+
+/* sometimes reiserfs_truncate may require to allocate few new blocks
+ to perform indirect2direct conversion. People probably used to
+ think, that truncate should work without problems on a filesystem
+ without free disk space. They may complain that they can not
+ truncate due to lack of free disk space. This spare space allows us
+ to not worry about it. 500 is probably too much, but it should be
+ absolutely safe */
+#define SPARE_SPACE 500
+
+/* ioctl's command */
+#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
+/* define following flags to be the same as in ext2, so that chattr(1),
+ lsattr(1) will work with us. */
+#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
+#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
+#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION
+#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION
+
+
+
+#pragma pack()
+
+
+#endif
--- /dev/null
+/* $Id: fsw_strfunc.h 29125 2010-05-06 09:43:05Z vboxsync $ */
+/** @file
+ * fsw_strfunc.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/* fsw_strfunc.h generated by mk_fsw_strfunc.py */
+
+static int fsw_streq_ISO88591_UTF8(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u8 *p2 = (fsw_u8 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++;
+ if ((c2 & 0xe0) == 0xc0) {
+ c2 = ((c2 & 0x1f) << 6) | (*p2++ & 0x3f);
+ } else if ((c2 & 0xf0) == 0xe0) {
+ c2 = ((c2 & 0x0f) << 12) | ((*p2++ & 0x3f) << 6);
+ c2 |= (*p2++ & 0x3f);
+ } else if ((c2 & 0xf8) == 0xf0) {
+ c2 = ((c2 & 0x07) << 18) | ((*p2++ & 0x3f) << 12);
+ c2 |= ((*p2++ & 0x3f) << 6);
+ c2 |= (*p2++ & 0x3f);
+ }
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+#ifndef HOST_EFI
+static int fsw_streq_ISO88591_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++;
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+static int fsw_streq_ISO88591_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF8_UTF16(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ if ((c1 & 0xe0) == 0xc0) {
+ c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+ } else if ((c1 & 0xf0) == 0xe0) {
+ c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ } else if ((c1 & 0xf8) == 0xf0) {
+ c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+ c1 |= ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ }
+ c2 = *p2++;
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF8_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u8 *p1 = (fsw_u8 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ if ((c1 & 0xe0) == 0xc0) {
+ c1 = ((c1 & 0x1f) << 6) | (*p1++ & 0x3f);
+ } else if ((c1 & 0xf0) == 0xe0) {
+ c1 = ((c1 & 0x0f) << 12) | ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ } else if ((c1 & 0xf8) == 0xf0) {
+ c1 = ((c1 & 0x07) << 18) | ((*p1++ & 0x3f) << 12);
+ c1 |= ((*p1++ & 0x3f) << 6);
+ c1 |= (*p1++ & 0x3f);
+ }
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static int fsw_streq_UTF16_UTF16_SWAPPED(void *s1data, void *s2data, int len)
+{
+ int i;
+ fsw_u16 *p1 = (fsw_u16 *)s1data;
+ fsw_u16 *p2 = (fsw_u16 *)s2data;
+ fsw_u32 c1, c2;
+
+ for (i = 0; i < len; i++) {
+ c1 = *p1++;
+ c2 = *p2++; c2 = FSW_SWAPVALUE_U16(c2);
+ if (c1 != c2)
+ return 0;
+ }
+ return 1;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ if ((c & 0xe0) == 0xc0) {
+ c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+ } else if ((c & 0xf0) == 0xe0) {
+ c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ } else if ((c & 0xf8) == 0xf0) {
+ c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+ c |= ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ }
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_ISO88591(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_ISO88591;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u8);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+ *dp++ = (fsw_u8)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF8_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u8 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+ if ((c & 0xe0) == 0xc0) {
+ c = ((c & 0x1f) << 6) | (*sp++ & 0x3f);
+ } else if ((c & 0xf0) == 0xe0) {
+ c = ((c & 0x0f) << 12) | ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ } else if ((c & 0xf8) == 0xf0) {
+ c = ((c & 0x07) << 18) | ((*sp++ & 0x3f) << 12);
+ c |= ((*sp++ & 0x3f) << 6);
+ c |= (*sp++ & 0x3f);
+ }
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF16(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i;
+ fsw_u16 *sp;
+ fsw_u16 *dp;
+ fsw_u32 c;
+
+ dest->type = FSW_STRING_TYPE_UTF16;
+ dest->len = srclen;
+ dest->size = srclen * sizeof(fsw_u16);
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u16 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+ *dp++ = (fsw_u16)c;
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_ISO88591_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u8 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u8 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u8 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u16 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++;
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
+
+static fsw_status_t fsw_strcoerce_UTF16_SWAPPED_UTF8(void *srcdata, int srclen, struct fsw_string *dest)
+{
+ fsw_status_t status;
+ int i, destsize;
+ fsw_u16 *sp;
+ fsw_u8 *dp;
+ fsw_u32 c;
+
+ sp = (fsw_u16 *)srcdata;
+ destsize = 0;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+
+ if (c < 0x000080)
+ destsize++;
+ else if (c < 0x000800)
+ destsize += 2;
+ else if (c < 0x010000)
+ destsize += 3;
+ else
+ destsize += 4;
+ }
+
+ dest->type = FSW_STRING_TYPE_UTF8;
+ dest->len = srclen;
+ dest->size = destsize;
+ status = fsw_alloc(dest->size, &dest->data);
+ if (status)
+ return status;
+
+ sp = (fsw_u16 *)srcdata;
+ dp = (fsw_u8 *)dest->data;
+ for (i = 0; i < srclen; i++) {
+ c = *sp++; c = FSW_SWAPVALUE_U16(c);
+
+ if (c < 0x000080) {
+ *dp++ = (fsw_u8)c;
+ } else if (c < 0x000800) {
+ *dp++ = (fsw_u8)(0xc0 | ((c >> 6) & 0x1f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else if (c < 0x010000) {
+ *dp++ = (fsw_u8)(0xe0 | ((c >> 12) & 0x0f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ } else {
+ *dp++ = (fsw_u8)(0xf0 | ((c >> 18) & 0x07));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 12) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | ((c >> 6) & 0x3f));
+ *dp++ = (fsw_u8)(0x80 | (c & 0x3f));
+ }
+ }
+ return FSW_SUCCESS;
+}
--- /dev/null
+/* $Id: hfs_format.h 33540 2010-10-28 09:27:05Z vboxsync $ */
+/** @file
+ * hfs_format.h
+ */
+
+/*
+ * Copyright (C) 2010 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*
+ * This code is based on:
+ *
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#ifndef __HFS_FORMAT__
+#define __HFS_FORMAT__
+
+#if !defined(VBOX) && !defined(HOST_POSIX)
+#include <sys/types.h>
+#include <sys/appleapiopts.h>
+#endif
+
+#ifdef _MSC_VER
+# pragma pack(push,2)
+# define HFS_ALIGNMENT
+#else
+#define HFS_ALIGNMENT __attribute__((aligned(2), packed))
+#endif
+
+/*
+ * hfs_format.c
+ *
+ * This file describes the on-disk format for HFS and HFS Plus volumes.
+ * The HFS Plus volume format is described in detail in Apple Technote 1150.
+ *
+ * http://developer.apple.com/technotes/tn/tn1150.html
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* some on-disk hfs structures have 68K alignment (misaligned) */
+
+/* Signatures used to differentiate between HFS and HFS Plus volumes */
+enum {
+ kHFSSigWord = 0x4244, /* 'BD' in ASCII */
+ kHFSPlusSigWord = 0x482B, /* 'H+' in ASCII */
+ kHFSXSigWord = 0x4858, /* 'HX' in ASCII */
+
+ kHFSPlusVersion = 0x0004, /* 'H+' volumes are version 4 only */
+ kHFSXVersion = 0x0005, /* 'HX' volumes start with version 5 */
+
+ kHFSPlusMountVersion = 0x31302E30, /* '10.0' for Mac OS X */
+ kHFSJMountVersion = 0x4846534a, /* 'HFSJ' for journaled HFS+ on OS X */
+ kFSKMountVersion = 0x46534b21 /* 'FSK!' for failed journal replay */
+};
+
+
+#ifdef __APPLE_API_PRIVATE
+/*
+ * Mac OS X has two special directories on HFS+ volumes for hardlinked files
+ * and hardlinked directories as well as for open-unlinked files.
+ *
+ * These directories and their contents are not exported from the filesystem
+ * under Mac OS X.
+ */
+#define HFSPLUSMETADATAFOLDER "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data"
+#define HFSPLUS_DIR_METADATA_FOLDER ".HFS+ Private Directory Data\xd"
+
+/*
+ * Files in the "HFS+ Private Data" folder have one of the following prefixes
+ * followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * Note: Earlier version of Mac OS X used a 32 bit random number for the link
+ * ref number instead of the file id.
+ *
+ * e.g. iNode7182000 and temp3296
+ */
+#define HFS_INODE_PREFIX "iNode"
+#define HFS_DELETE_PREFIX "temp"
+
+/*
+ * Files in the ".HFS+ Private Directory Data" folder have the following
+ * prefix followed by a decimal number (no leading zeros) for the file ID.
+ *
+ * e.g. dir_555
+ */
+#define HFS_DIRINODE_PREFIX "dir_"
+
+/*
+ * Hardlink inodes save the head of the link chain in
+ * an extended attribute named FIRST_LINK_XATTR_NAME.
+ * The attribute data is the decimal value in ASCII
+ * of the cnid for the first link in the chain.
+ *
+ * This extended attribute is private (i.e. its not
+ * exported in the getxattr/listxattr POSIX APIs).
+ */
+#define FIRST_LINK_XATTR_NAME "com.apple.system.hfs.firstlink"
+#define FIRST_LINK_XATTR_REC_SIZE (sizeof(HFSPlusAttrData) - 2 + 12)
+
+#endif /* __APPLE_API_PRIVATE */
+
+/*
+ * Indirect link files (hard links) have the following type/creator.
+ */
+enum {
+ kHardLinkFileType = 0x686C6E6B, /* 'hlnk' */
+ kHFSPlusCreator = 0x6866732B /* 'hfs+' */
+};
+
+
+/*
+ * File type and creator for symbolic links
+ */
+enum {
+ kSymLinkFileType = 0x736C6E6B, /* 'slnk' */
+ kSymLinkCreator = 0x72686170 /* 'rhap' */
+};
+
+
+#ifndef _HFSUNISTR255_DEFINED_
+#define _HFSUNISTR255_DEFINED_
+/* Unicode strings are used for HFS Plus file and folder names */
+struct HFSUniStr255 {
+ u_int16_t length; /* number of unicode characters */
+ u_int16_t unicode[255]; /* unicode characters */
+} HFS_ALIGNMENT;
+typedef struct HFSUniStr255 HFSUniStr255;
+typedef const HFSUniStr255 *ConstHFSUniStr255Param;
+#endif /* _HFSUNISTR255_DEFINED_ */
+
+enum {
+ kHFSMaxVolumeNameChars = 27,
+ kHFSMaxFileNameChars = 31,
+ kHFSPlusMaxFileNameChars = 255
+};
+
+
+/* Extent overflow file data structures */
+
+/* HFS Extent key */
+struct HFSExtentKey {
+ u_int8_t keyLength; /* length of key, excluding this field */
+ u_int8_t forkType; /* 0 = data fork, FF = resource fork */
+ u_int32_t fileID; /* file ID */
+ u_int16_t startBlock; /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentKey HFSExtentKey;
+
+/* HFS Plus Extent key */
+struct HFSPlusExtentKey {
+ u_int16_t keyLength; /* length of key, excluding this field */
+ u_int8_t forkType; /* 0 = data fork, FF = resource fork */
+ u_int8_t pad; /* make the other fields align on 32-bit boundary */
+ u_int32_t fileID; /* file ID */
+ u_int32_t startBlock; /* first file allocation block number in this extent */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentKey HFSPlusExtentKey;
+
+/* Number of extent descriptors per extent record */
+enum {
+ kHFSExtentDensity = 3,
+ kHFSPlusExtentDensity = 8
+};
+
+/* HFS extent descriptor */
+struct HFSExtentDescriptor {
+ u_int16_t startBlock; /* first allocation block */
+ u_int16_t blockCount; /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSExtentDescriptor HFSExtentDescriptor;
+
+/* HFS Plus extent descriptor */
+struct HFSPlusExtentDescriptor {
+ u_int32_t startBlock; /* first allocation block */
+ u_int32_t blockCount; /* number of allocation blocks */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusExtentDescriptor HFSPlusExtentDescriptor;
+
+/* HFS extent record */
+typedef HFSExtentDescriptor HFSExtentRecord[3];
+
+/* HFS Plus extent record */
+typedef HFSPlusExtentDescriptor HFSPlusExtentRecord[8];
+
+
+/* Finder information */
+struct FndrFileInfo {
+ u_int32_t fdType; /* file type */
+ u_int32_t fdCreator; /* file creator */
+ u_int16_t fdFlags; /* Finder flags */
+ struct {
+ int16_t v; /* file's location */
+ int16_t h;
+ } fdLocation;
+ int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrFileInfo FndrFileInfo;
+
+struct FndrDirInfo {
+ struct { /* folder's window rectangle */
+ int16_t top;
+ int16_t left;
+ int16_t bottom;
+ int16_t right;
+ } frRect;
+ unsigned short frFlags; /* Finder flags */
+ struct {
+ u_int16_t v; /* folder's location */
+ u_int16_t h;
+ } frLocation;
+ int16_t opaque;
+} HFS_ALIGNMENT;
+typedef struct FndrDirInfo FndrDirInfo;
+
+struct FndrOpaqueInfo {
+ int8_t opaque[16];
+} HFS_ALIGNMENT;
+typedef struct FndrOpaqueInfo FndrOpaqueInfo;
+
+
+/* HFS Plus Fork data info - 80 bytes */
+struct HFSPlusForkData {
+ u_int64_t logicalSize; /* fork's logical size in bytes */
+ u_int32_t clumpSize; /* fork's clump size in bytes */
+ u_int32_t totalBlocks; /* total blocks used by this fork */
+ HFSPlusExtentRecord extents; /* initial set of extents */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusForkData HFSPlusForkData;
+
+
+/* Mac OS X has 16 bytes worth of "BSD" info.
+ *
+ * Note: Mac OS 9 implementations and applications
+ * should preserve, but not change, this information.
+ */
+struct HFSPlusBSDInfo {
+ u_int32_t ownerID; /* user-id of owner or hard link chain previous link */
+ u_int32_t groupID; /* group-id of owner or hard link chain next link */
+ u_int8_t adminFlags; /* super-user changeable flags */
+ u_int8_t ownerFlags; /* owner changeable flags */
+ u_int16_t fileMode; /* file type and permission bits */
+ union {
+ u_int32_t iNodeNum; /* indirect node number (hard links only) */
+ u_int32_t linkCount; /* links that refer to this indirect node */
+ u_int32_t rawDevice; /* special file device (FBLK and FCHR only) */
+ } special;
+} HFS_ALIGNMENT;
+typedef struct HFSPlusBSDInfo HFSPlusBSDInfo;
+
+/*
+ * Hardlink "links" resolve to an inode
+ * and the actual uid/gid comes from that
+ * inode.
+ *
+ * We repurpose the links's uid/gid fields
+ * for the hardlink link chain. The chain
+ * consists of a doubly linked list of file
+ * ids.
+ */
+
+#define hl_firstLinkID reserved1 /* Valid only if HasLinkChain flag is set (indirect nodes only) */
+
+#define hl_prevLinkID bsdInfo.ownerID /* Valid only if HasLinkChain flag is set */
+#define hl_nextLinkID bsdInfo.groupID /* Valid only if HasLinkChain flag is set */
+
+#define hl_linkReference bsdInfo.special.iNodeNum
+#define hl_linkCount bsdInfo.special.linkCount
+
+
+/* Catalog file data structures */
+
+enum {
+ kHFSRootParentID = 1, /* Parent ID of the root folder */
+ kHFSRootFolderID = 2, /* Folder ID of the root folder */
+ kHFSExtentsFileID = 3, /* File ID of the extents file */
+ kHFSCatalogFileID = 4, /* File ID of the catalog file */
+ kHFSBadBlockFileID = 5, /* File ID of the bad allocation block file */
+ kHFSAllocationFileID = 6, /* File ID of the allocation file (HFS Plus only) */
+ kHFSStartupFileID = 7, /* File ID of the startup file (HFS Plus only) */
+ kHFSAttributesFileID = 8, /* File ID of the attribute file (HFS Plus only) */
+ kHFSAttributeDataFileID = 13, /* Used in Mac OS X runtime for extent based attributes */
+ /* kHFSAttributeDataFileID is never stored on disk. */
+ kHFSRepairCatalogFileID = 14, /* Used when rebuilding Catalog B-tree */
+ kHFSBogusExtentFileID = 15, /* Used for exchanging extents in extents file */
+ kHFSFirstUserCatalogNodeID = 16
+};
+
+/* HFS catalog key */
+struct HFSCatalogKey {
+ u_int8_t keyLength; /* key length (in bytes) */
+ u_int8_t reserved; /* reserved (set to zero) */
+ u_int32_t parentID; /* parent folder ID */
+ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogKey HFSCatalogKey;
+
+/* HFS Plus catalog key */
+struct HFSPlusCatalogKey {
+ u_int16_t keyLength; /* key length (in bytes) */
+ u_int32_t parentID; /* parent folder ID */
+ HFSUniStr255 nodeName; /* catalog node name */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogKey HFSPlusCatalogKey;
+
+/* Catalog record types */
+enum {
+ /* HFS Catalog Records */
+ kHFSFolderRecord = 0x0100, /* Folder record */
+ kHFSFileRecord = 0x0200, /* File record */
+ kHFSFolderThreadRecord = 0x0300, /* Folder thread record */
+ kHFSFileThreadRecord = 0x0400, /* File thread record */
+
+ /* HFS Plus Catalog Records */
+ kHFSPlusFolderRecord = 1, /* Folder record */
+ kHFSPlusFileRecord = 2, /* File record */
+ kHFSPlusFolderThreadRecord = 3, /* Folder thread record */
+ kHFSPlusFileThreadRecord = 4 /* File thread record */
+};
+
+
+/* Catalog file record flags */
+enum {
+ kHFSFileLockedBit = 0x0000, /* file is locked and cannot be written to */
+ kHFSFileLockedMask = 0x0001,
+
+ kHFSThreadExistsBit = 0x0001, /* a file thread record exists for this file */
+ kHFSThreadExistsMask = 0x0002,
+
+ kHFSHasAttributesBit = 0x0002, /* object has extended attributes */
+ kHFSHasAttributesMask = 0x0004,
+
+ kHFSHasSecurityBit = 0x0003, /* object has security data (ACLs) */
+ kHFSHasSecurityMask = 0x0008,
+
+ kHFSHasFolderCountBit = 0x0004, /* only for HFSX, folder maintains a separate sub-folder count */
+ kHFSHasFolderCountMask = 0x0010, /* (sum of folder records and directory hard links) */
+
+ kHFSHasLinkChainBit = 0x0005, /* has hardlink chain (inode or link) */
+ kHFSHasLinkChainMask = 0x0020,
+
+ kHFSHasChildLinkBit = 0x0006, /* folder has a child that's a dir link */
+ kHFSHasChildLinkMask = 0x0040
+};
+
+
+/* HFS catalog folder record - 70 bytes */
+struct HFSCatalogFolder {
+ int16_t recordType; /* == kHFSFolderRecord */
+ u_int16_t flags; /* folder flags */
+ u_int16_t valence; /* folder valence */
+ u_int32_t folderID; /* folder ID */
+ u_int32_t createDate; /* date and time of creation */
+ u_int32_t modifyDate; /* date and time of last modification */
+ u_int32_t backupDate; /* date and time of last backup */
+ FndrDirInfo userInfo; /* Finder information */
+ FndrOpaqueInfo finderInfo; /* additional Finder information */
+ u_int32_t reserved[4]; /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFolder HFSCatalogFolder;
+
+/* HFS Plus catalog folder record - 88 bytes */
+struct HFSPlusCatalogFolder {
+ int16_t recordType; /* == kHFSPlusFolderRecord */
+ u_int16_t flags; /* file flags */
+ u_int32_t valence; /* folder's item count */
+ u_int32_t folderID; /* folder ID */
+ u_int32_t createDate; /* date and time of creation */
+ u_int32_t contentModDate; /* date and time of last content modification */
+ u_int32_t attributeModDate; /* date and time of last attribute modification */
+ u_int32_t accessDate; /* date and time of last access (MacOS X only) */
+ u_int32_t backupDate; /* date and time of last backup */
+ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */
+ FndrDirInfo userInfo; /* Finder information */
+ FndrOpaqueInfo finderInfo; /* additional Finder information */
+ u_int32_t textEncoding; /* hint for name conversions */
+ u_int32_t folderCount; /* number of enclosed folders, active when HasFolderCount is set */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFolder HFSPlusCatalogFolder;
+
+/* HFS catalog file record - 102 bytes */
+struct HFSCatalogFile {
+ int16_t recordType; /* == kHFSFileRecord */
+ u_int8_t flags; /* file flags */
+ int8_t fileType; /* file type (unused ?) */
+ FndrFileInfo userInfo; /* Finder information */
+ u_int32_t fileID; /* file ID */
+ u_int16_t dataStartBlock; /* not used - set to zero */
+ int32_t dataLogicalSize; /* logical EOF of data fork */
+ int32_t dataPhysicalSize; /* physical EOF of data fork */
+ u_int16_t rsrcStartBlock; /* not used - set to zero */
+ int32_t rsrcLogicalSize; /* logical EOF of resource fork */
+ int32_t rsrcPhysicalSize; /* physical EOF of resource fork */
+ u_int32_t createDate; /* date and time of creation */
+ u_int32_t modifyDate; /* date and time of last modification */
+ u_int32_t backupDate; /* date and time of last backup */
+ FndrOpaqueInfo finderInfo; /* additional Finder information */
+ u_int16_t clumpSize; /* file clump size (not used) */
+ HFSExtentRecord dataExtents; /* first data fork extent record */
+ HFSExtentRecord rsrcExtents; /* first resource fork extent record */
+ u_int32_t reserved; /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogFile HFSCatalogFile;
+
+/* HFS Plus catalog file record - 248 bytes */
+struct HFSPlusCatalogFile {
+ int16_t recordType; /* == kHFSPlusFileRecord */
+ u_int16_t flags; /* file flags */
+ u_int32_t reserved1; /* reserved - initialized as zero */
+ u_int32_t fileID; /* file ID */
+ u_int32_t createDate; /* date and time of creation */
+ u_int32_t contentModDate; /* date and time of last content modification */
+ u_int32_t attributeModDate; /* date and time of last attribute modification */
+ u_int32_t accessDate; /* date and time of last access (MacOS X only) */
+ u_int32_t backupDate; /* date and time of last backup */
+ HFSPlusBSDInfo bsdInfo; /* permissions (for MacOS X) */
+ FndrFileInfo userInfo; /* Finder information */
+ FndrOpaqueInfo finderInfo; /* additional Finder information */
+ u_int32_t textEncoding; /* hint for name conversions */
+ u_int32_t reserved2; /* reserved - initialized as zero */
+
+ /* Note: these start on double long (64 bit) boundary */
+ HFSPlusForkData dataFork; /* size and block data for data fork */
+ HFSPlusForkData resourceFork; /* size and block data for resource fork */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogFile HFSPlusCatalogFile;
+
+/* HFS catalog thread record - 46 bytes */
+struct HFSCatalogThread {
+ int16_t recordType; /* == kHFSFolderThreadRecord or kHFSFileThreadRecord */
+ int32_t reserved[2]; /* reserved - initialized as zero */
+ u_int32_t parentID; /* parent ID for this catalog node */
+ u_int8_t nodeName[kHFSMaxFileNameChars + 1]; /* name of this catalog node */
+} HFS_ALIGNMENT;
+typedef struct HFSCatalogThread HFSCatalogThread;
+
+/* HFS Plus catalog thread record -- 264 bytes */
+struct HFSPlusCatalogThread {
+ int16_t recordType; /* == kHFSPlusFolderThreadRecord or kHFSPlusFileThreadRecord */
+ int16_t reserved; /* reserved - initialized as zero */
+ u_int32_t parentID; /* parent ID for this catalog node */
+ HFSUniStr255 nodeName; /* name of this catalog node (variable length) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusCatalogThread HFSPlusCatalogThread;
+
+#ifdef __APPLE_API_UNSTABLE
+/*
+ These are the types of records in the attribute B-tree. The values were
+ chosen so that they wouldn't conflict with the catalog record types.
+*/
+enum {
+ kHFSPlusAttrInlineData = 0x10, /* attributes whose data fits in a b-tree node */
+ kHFSPlusAttrForkData = 0x20, /* extent based attributes (data lives in extents) */
+ kHFSPlusAttrExtents = 0x30 /* overflow extents for large attributes */
+};
+
+
+/*
+ HFSPlusAttrForkData
+ For larger attributes, whose value is stored in allocation blocks.
+ If the attribute has more than 8 extents, there will be additional
+ records (of type HFSPlusAttrExtents) for this attribute.
+*/
+struct HFSPlusAttrForkData {
+ u_int32_t recordType; /* == kHFSPlusAttrForkData*/
+ u_int32_t reserved;
+ HFSPlusForkData theFork; /* size and first extents of value*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrForkData HFSPlusAttrForkData;
+
+/*
+ HFSPlusAttrExtents
+ This record contains information about overflow extents for large,
+ fragmented attributes.
+*/
+struct HFSPlusAttrExtents {
+ u_int32_t recordType; /* == kHFSPlusAttrExtents*/
+ u_int32_t reserved;
+ HFSPlusExtentRecord extents; /* additional extents*/
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrExtents HFSPlusAttrExtents;
+
+/*
+ * Attributes B-tree Data Record
+ *
+ * For small attributes, whose entire value is stored
+ * within a single B-tree record.
+ */
+struct HFSPlusAttrData {
+ u_int32_t recordType; /* == kHFSPlusAttrInlineData */
+ u_int32_t reserved[2];
+ u_int32_t attrSize; /* size of attribute data in bytes */
+ u_int8_t attrData[2]; /* variable length */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrData HFSPlusAttrData;
+
+
+/* HFSPlusAttrInlineData is obsolete use HFSPlusAttrData instead */
+struct HFSPlusAttrInlineData {
+ u_int32_t recordType;
+ u_int32_t reserved;
+ u_int32_t logicalSize;
+ u_int8_t userData[2];
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrInlineData HFSPlusAttrInlineData;
+
+
+/* A generic Attribute Record*/
+union HFSPlusAttrRecord {
+ u_int32_t recordType;
+ HFSPlusAttrInlineData inlineData; /* NOT USED */
+ HFSPlusAttrData attrData;
+ HFSPlusAttrForkData forkData;
+ HFSPlusAttrExtents overflowExtents;
+};
+typedef union HFSPlusAttrRecord HFSPlusAttrRecord;
+
+/* Attribute key */
+enum { kHFSMaxAttrNameLen = 127 };
+struct HFSPlusAttrKey {
+ u_int16_t keyLength; /* key length (in bytes) */
+ u_int16_t pad; /* set to zero */
+ u_int32_t fileID; /* file associated with attribute */
+ u_int32_t startBlock; /* first allocation block number for extents */
+ u_int16_t attrNameLen; /* number of unicode characters */
+ u_int16_t attrName[kHFSMaxAttrNameLen]; /* attribute name (Unicode) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusAttrKey HFSPlusAttrKey;
+
+#define kHFSPlusAttrKeyMaximumLength (sizeof(HFSPlusAttrKey) - sizeof(u_int16_t))
+#define kHFSPlusAttrKeyMinimumLength (kHFSPlusAttrKeyMaximumLength - kHFSMaxAttrNameLen*sizeof(u_int16_t))
+
+#endif /* __APPLE_API_UNSTABLE */
+
+
+/* Key and node lengths */
+enum {
+ kHFSPlusExtentKeyMaximumLength = sizeof(HFSPlusExtentKey) - sizeof(u_int16_t),
+ kHFSExtentKeyMaximumLength = sizeof(HFSExtentKey) - sizeof(u_int8_t),
+ kHFSPlusCatalogKeyMaximumLength = sizeof(HFSPlusCatalogKey) - sizeof(u_int16_t),
+ kHFSPlusCatalogKeyMinimumLength = kHFSPlusCatalogKeyMaximumLength - sizeof(HFSUniStr255) + sizeof(u_int16_t),
+ kHFSCatalogKeyMaximumLength = sizeof(HFSCatalogKey) - sizeof(u_int8_t),
+ kHFSCatalogKeyMinimumLength = kHFSCatalogKeyMaximumLength - (kHFSMaxFileNameChars + 1) + sizeof(u_int8_t),
+ kHFSPlusCatalogMinNodeSize = 4096,
+ kHFSPlusExtentMinNodeSize = 512,
+ kHFSPlusAttrMinNodeSize = 4096
+};
+
+/* HFS and HFS Plus volume attribute bits */
+enum {
+ /* Bits 0-6 are reserved (always cleared by MountVol call) */
+ kHFSVolumeHardwareLockBit = 7, /* volume is locked by hardware */
+ kHFSVolumeUnmountedBit = 8, /* volume was successfully unmounted */
+ kHFSVolumeSparedBlocksBit = 9, /* volume has bad blocks spared */
+ kHFSVolumeNoCacheRequiredBit = 10, /* don't cache volume blocks (i.e. RAM or ROM disk) */
+ kHFSBootVolumeInconsistentBit = 11, /* boot volume is inconsistent (System 7.6 and later) */
+ kHFSCatalogNodeIDsReusedBit = 12,
+ kHFSVolumeJournaledBit = 13, /* this volume has a journal on it */
+ kHFSVolumeInconsistentBit = 14, /* serious inconsistencies detected at runtime */
+ kHFSVolumeSoftwareLockBit = 15, /* volume is locked by software */
+
+ kHFSVolumeHardwareLockMask = 1 << kHFSVolumeHardwareLockBit,
+ kHFSVolumeUnmountedMask = 1 << kHFSVolumeUnmountedBit,
+ kHFSVolumeSparedBlocksMask = 1 << kHFSVolumeSparedBlocksBit,
+ kHFSVolumeNoCacheRequiredMask = 1 << kHFSVolumeNoCacheRequiredBit,
+ kHFSBootVolumeInconsistentMask = 1 << kHFSBootVolumeInconsistentBit,
+ kHFSCatalogNodeIDsReusedMask = 1 << kHFSCatalogNodeIDsReusedBit,
+ kHFSVolumeJournaledMask = 1 << kHFSVolumeJournaledBit,
+ kHFSVolumeInconsistentMask = 1 << kHFSVolumeInconsistentBit,
+ kHFSVolumeSoftwareLockMask = 1 << kHFSVolumeSoftwareLockBit,
+ kHFSMDBAttributesMask = 0x8380
+};
+
+/* HFS Master Directory Block - 162 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSMasterDirectoryBlock {
+ u_int16_t drSigWord; /* == kHFSSigWord = 0x4244 = 'BD' or 'H+' or 'HX'*/
+ u_int32_t drCrDate; /* date and time of volume creation */
+ u_int32_t drLsMod; /* date and time of last modification */
+ u_int16_t drAtrb; /* volume attributes */
+ u_int16_t drNmFls; /* number of files in root folder */
+ u_int16_t drVBMSt; /* first block of volume bitmap */
+ u_int16_t drAllocPtr; /* start of next allocation search */
+ u_int16_t drNmAlBlks; /* number of allocation blocks in volume */
+ u_int32_t drAlBlkSiz; /* size (in bytes) of allocation blocks */
+ u_int32_t drClpSiz; /* default clump size */
+ u_int16_t drAlBlSt; /* first allocation block in volume */
+ u_int32_t drNxtCNID; /* next unused catalog node ID */
+ u_int16_t drFreeBks; /* number of unused allocation blocks */
+ u_int8_t drVN[kHFSMaxVolumeNameChars + 1]; /* volume name */
+ u_int32_t drVolBkUp; /* date and time of last backup */
+ u_int16_t drVSeqNum; /* volume backup sequence number */
+ u_int32_t drWrCnt; /* volume write count */
+ u_int32_t drXTClpSiz; /* clump size for extents overflow file */
+ u_int32_t drCTClpSiz; /* clump size for catalog file */
+ u_int16_t drNmRtDirs; /* number of directories in root folder */
+ u_int32_t drFilCnt; /* number of files in volume */
+ u_int32_t drDirCnt; /* number of directories in volume */
+ u_int32_t drFndrInfo[8]; /* information used by the Finder */
+ u_int16_t drEmbedSigWord; /* embedded volume signature (formerly drVCSize) */
+ HFSExtentDescriptor drEmbedExtent; /* embedded volume location and size (formerly drVBMCSize and drCtlCSize) */
+ u_int32_t drXTFlSize; /* size of extents overflow file */
+ HFSExtentRecord drXTExtRec; /* extent record for extents overflow file */
+ u_int32_t drCTFlSize; /* size of catalog file */
+ HFSExtentRecord drCTExtRec; /* extent record for catalog file */
+} HFS_ALIGNMENT;
+typedef struct HFSMasterDirectoryBlock HFSMasterDirectoryBlock;
+
+
+#ifdef __APPLE_API_UNSTABLE
+#define SET_HFS_TEXT_ENCODING(hint) \
+ (0x656e6300 | ((hint) & 0xff))
+#define GET_HFS_TEXT_ENCODING(hint) \
+ (((hint) & 0xffffff00) == 0x656e6300 ? (hint) & 0x000000ff : 0xffffffffU)
+#endif /* __APPLE_API_UNSTABLE */
+
+ /*
+ 48 2B 00 04 80 00 20 00 48 46 53 4A 00 AD 7E 98 //H+ HFSJ
+ C9 12 D3 9E CB 84 F3 1D 00 00 00 00 C9 26 31 A8
+ 00 12 1D 9D 00 03 66 B9 00 00 10 00 01 A1 2C CF
+ 00 44 67 DF 01 35 EB A8 00 01 00 00 00 01 00 00
+ 10 8B 1C EA 08 E4 9C 1B 00 00 00 00 02 00 00 8B
+ 00 00 02 E7 10 3F CB 93 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 02 E7 6A 45 F3 37 EF 97 E9 A6
+ 00 00 00 00 00 34 30 00 00 00 00 00 00 00 03 43
+ 00 00 00 01 00 00 03 43 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 70 00 00 00 70 00 00 00 00 07 00
+ 00 00 13 45 00 00 07 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 2A F8 00 00 01 90 00 00 00 02 AF 80
+ 00 01 AA 55 00 01 90 00 00 14 5A C7 00 00 19 00
+ 00 3D E4 E3 00 00 19 00 00 95 44 F7 00 00 19 00
+ 00 9D 3B 18 00 00 32 00 00 E3 58 1C 00 00 19 00
+ 00 48 1C 72 00 00 19 00 00 BB 6A 05 00 00 19 00
+ 00 00 00 00 06 40 00 00 01 90 00 00 00 00 64 00
+ 00 06 80 00 00 00 19 00 00 38 2A 2F 00 00 19 00
+ 00 38 DB 2C 00 00 19 00 00 A6 A2 1F 00 00 19 00
+ */
+
+
+/* HFS Plus Volume Header - 512 bytes */
+/* Stored at sector #2 (3rd sector) and second-to-last sector. */
+struct HFSPlusVolumeHeader {
+ u_int16_t signature; /* == kHFSPlusSigWord */
+ u_int16_t version; /* == kHFSPlusVersion */
+ u_int32_t attributes; /* volume attributes */
+ u_int32_t lastMountedVersion; /* implementation version which last mounted volume */
+ u_int32_t journalInfoBlock; /* block addr of journal info (if volume is journaled, zero otherwise) */
+
+ u_int32_t createDate; /* date and time of volume creation */
+ u_int32_t modifyDate; /* date and time of last modification */
+ u_int32_t backupDate; /* date and time of last backup */
+ u_int32_t checkedDate; /* date and time of last disk check */
+
+ u_int32_t fileCount; /* number of files in volume */
+ u_int32_t folderCount; /* number of directories in volume */
+
+ u_int32_t blockSize; /* size (in bytes) of allocation blocks */
+ u_int32_t totalBlocks; /* number of allocation blocks in volume (includes this header and VBM*/
+ u_int32_t freeBlocks; /* number of unused allocation blocks */
+
+ u_int32_t nextAllocation; /* start of next allocation search */
+ u_int32_t rsrcClumpSize; /* default resource fork clump size */
+ u_int32_t dataClumpSize; /* default data fork clump size */
+ u_int32_t nextCatalogID; /* next unused catalog node ID */
+
+ u_int32_t writeCount; /* volume write count */
+ u_int64_t encodingsBitmap; /* which encodings have been use on this volume */
+
+ u_int8_t finderInfo[32]; /* information used by the Finder */
+
+ HFSPlusForkData allocationFile; /* allocation bitmap file */
+ HFSPlusForkData extentsFile; /* extents B-tree file */
+ HFSPlusForkData catalogFile; /* catalog B-tree file */
+ HFSPlusForkData attributesFile; /* extended attributes B-tree file */
+ HFSPlusForkData startupFile; /* boot file (secondary loader) */
+} HFS_ALIGNMENT;
+typedef struct HFSPlusVolumeHeader HFSPlusVolumeHeader;
+
+
+/* B-tree structures */
+
+enum BTreeKeyLimits{
+ kMaxKeyLength = 520
+};
+
+union BTreeKey{
+ u_int8_t length8;
+ u_int16_t length16;
+ u_int8_t rawData [kMaxKeyLength+2];
+};
+typedef union BTreeKey BTreeKey;
+
+/* BTNodeDescriptor -- Every B-tree node starts with these fields. */
+struct BTNodeDescriptor {
+ u_int32_t fLink; /* next node at this level*/
+ u_int32_t bLink; /* previous node at this level*/
+ int8_t kind; /* kind of node (leaf, index, header, map)*/
+ u_int8_t height; /* zero for header, map; child is one more than parent*/
+ u_int16_t numRecords; /* number of records in this node*/
+ u_int16_t reserved; /* reserved - initialized as zero */
+} HFS_ALIGNMENT;
+typedef struct BTNodeDescriptor BTNodeDescriptor;
+
+/* Constants for BTNodeDescriptor kind */
+enum {
+ kBTLeafNode = -1,
+ kBTIndexNode = 0,
+ kBTHeaderNode = 1,
+ kBTMapNode = 2
+};
+
+/* BTHeaderRec -- The first record of a B-tree header node */
+struct BTHeaderRec {
+ u_int16_t treeDepth; /* maximum height (usually leaf nodes) */
+ u_int32_t rootNode; /* node number of root node */
+ u_int32_t leafRecords; /* number of leaf records in all leaf nodes */
+ u_int32_t firstLeafNode; /* node number of first leaf node */
+ u_int32_t lastLeafNode; /* node number of last leaf node */
+ u_int16_t nodeSize; /* size of a node, in bytes */
+ u_int16_t maxKeyLength; /* reserved */
+ u_int32_t totalNodes; /* total number of nodes in tree */
+ u_int32_t freeNodes; /* number of unused (free) nodes in tree */
+ u_int16_t reserved1; /* unused */
+ u_int32_t clumpSize; /* reserved */
+ u_int8_t btreeType; /* reserved */
+ u_int8_t keyCompareType; /* Key string Comparison Type */
+ u_int32_t attributes; /* persistent attributes about the tree */
+ u_int32_t reserved3[16]; /* reserved */
+} HFS_ALIGNMENT;
+typedef struct BTHeaderRec BTHeaderRec;
+
+/* Constants for BTHeaderRec attributes */
+enum {
+ kBTBadCloseMask = 0x00000001, /* reserved */
+ kBTBigKeysMask = 0x00000002, /* key length field is 16 bits */
+ kBTVariableIndexKeysMask = 0x00000004 /* keys in index nodes are variable length */
+};
+
+
+/* Catalog Key Name Comparison Type */
+enum {
+ kHFSCaseFolding = 0xCF, /* case folding (case-insensitive) */
+ kHFSBinaryCompare = 0xBC /* binary compare (case-sensitive) */
+};
+
+/* JournalInfoBlock - Structure that describes where our journal lives */
+struct JournalInfoBlock {
+ u_int32_t flags;
+ u_int32_t device_signature[8]; // signature used to locate our device.
+ u_int64_t offset; // byte offset to the journal on the device
+ u_int64_t size; // size in bytes of the journal
+ u_int32_t reserved[32];
+} HFS_ALIGNMENT;
+typedef struct JournalInfoBlock JournalInfoBlock;
+
+enum {
+ kJIJournalInFSMask = 0x00000001,
+ kJIJournalOnOtherDeviceMask = 0x00000002,
+ kJIJournalNeedInitMask = 0x00000004
+};
+
+
+#ifdef __cplusplus
+}
+#endif
+#ifdef _MSC_VER
+# pragma pack(pop)
+#endif
+
+#endif /* __HFS_FORMAT__ */
--- /dev/null
+K 25
+svn:wc:ra_dav:version-url
+V 48
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test
+END
+fsw_posix_base.h
+K 25
+svn:wc:ra_dav:version-url
+V 65
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix_base.h
+END
+fsw_posix.c
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix.c
+END
+lsroot.c
+K 25
+svn:wc:ra_dav:version-url
+V 57
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/lsroot.c
+END
+fsw_posix.h
+K 25
+svn:wc:ra_dav:version-url
+V 60
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/fsw_posix.h
+END
+README
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/README
+END
+lslr.c
+K 25
+svn:wc:ra_dav:version-url
+V 55
+/svnroot/cloverefiboot/!svn/ver/1/VBoxFsDxe/test/lslr.c
+END
--- /dev/null
+10
+
+dir
+432
+https://cloverefiboot.svn.sourceforge.net/svnroot/cloverefiboot/VBoxFsDxe/test
+https://cloverefiboot.svn.sourceforge.net/svnroot/cloverefiboot
+
+
+
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+0f885799-303c-4bf3-9050-968124707f2f
+\f
+fsw_posix_base.h
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+17516f05bd8d1ca74803cd8e1bc8b20f
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2920
+\f
+fsw_posix.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+c847b0b03df254cb7f31e25315063957
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+13763
+\f
+lsroot.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+55a5a9b6c4ec0b2f6ee39d14ec82b276
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2807
+\f
+fsw_posix.h
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+cbfe2e553a18fcb978b5ebfd3a06def1
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3297
+\f
+README
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+9fbd16e1fb2413b7e0780f603f26de91
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+134
+\f
+lslr.c
+file
+
+
+
+
+2012-05-15T01:06:34.000000Z
+a26b88236b0a0e7bfbb2adaa5d4836f4
+2011-04-04T13:39:25.410063Z
+1
+slice2009
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4059
+\f
--- /dev/null
+This folder contains tests for VBoxFsDxe module, allowing up
+and test filesystems without EFI environment and launching whole VBox.
--- /dev/null
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+ struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table fsw_posix_host_table = {
+ FSW_STRING_TYPE_ISO88591,
+
+ fsw_posix_change_blocksize,
+ fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+ fsw_status_t status;
+ struct fsw_posix_volume *pvol;
+
+ // allocate volume structure
+ status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+ if (status)
+ return NULL;
+ pvol->fd = -1;
+
+ // open underlying file/device
+ pvol->fd = open(path, O_RDONLY, 0);
+ if (pvol->fd < 0) {
+ fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ // mount the filesystem
+ if (fstype_table == NULL)
+ fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+ status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+ if (status) {
+ fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+ if (pvol->vol != NULL)
+ fsw_unmount(pvol->vol);
+ fsw_free(pvol);
+ return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+ fsw_status_t status;
+ struct fsw_posix_file *file;
+
+ // TODO: check flags for unwanted values
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+ if (status)
+ return NULL;
+ file->pvol = pvol;
+
+ // open the file
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+ fsw_free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+ fsw_status_t status;
+ fsw_u32 buffer_size;
+
+ buffer_size = nbytes;
+ status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+ if (status)
+ return -1;
+ return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+ fsw_u64 base_offset = 0;
+
+ // get base offset
+ base_offset = 0;
+ if (whence == SEEK_CUR)
+ base_offset = file->shand.pos;
+ else if (whence == SEEK_END)
+ base_offset = file->shand.dnode->size;
+
+ // calculate new offset, prevent seeks before the start of the file
+ if (offset < 0 && -offset > base_offset)
+ file->shand.pos = 0;
+ else
+ file->shand.pos = base_offset + offset;
+
+ return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+ fsw_shandle_close(&file->shand);
+ fsw_free(file);
+ return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+ fsw_status_t status;
+ struct fsw_posix_dir *dir;
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+ if (status)
+ return NULL;
+ dir->pvol = pvol;
+
+ // open the directory
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+ fsw_free(dir);
+ return NULL;
+ }
+
+ return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ static struct dirent dent;
+
+ // get next entry from file system
+ status = fsw_dnode_dir_read(&dir->shand, &dno);
+ if (status) {
+ if (status != 4)
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+ return NULL;
+ }
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return NULL;
+ }
+
+ // fill dirent structure
+ dent.d_fileno = dno->dnode_id;
+ dent.d_reclen = 8 + dno->name.size + 1;
+ switch (dno->type) {
+ case FSW_DNODE_TYPE_FILE:
+ dent.d_type = DT_REG;
+ break;
+ case FSW_DNODE_TYPE_DIR:
+ dent.d_type = DT_DIR;
+ break;
+ case FSW_DNODE_TYPE_SYMLINK:
+ dent.d_type = DT_LNK;
+ break;
+ default:
+ dent.d_type = DT_UNKNOWN;
+ break;
+ }
+#if 0
+ dent.d_namlen = dno->name.size;
+#endif
+ memcpy(dent.d_name, dno->name.data, dno->name.size);
+ dent.d_name[dno->name.size] = 0;
+
+ return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+ dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+ fsw_shandle_close(&dir->shand);
+ fsw_free(dir);
+ return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ struct fsw_dnode *target_dno;
+ struct fsw_string lookup_path;
+
+ lookup_path.type = FSW_STRING_TYPE_ISO88591;
+ lookup_path.len = strlen(path);
+ lookup_path.size = lookup_path.len;
+ lookup_path.data = (void *)path;
+
+ // resolve the path (symlinks along the way are automatically resolved)
+ status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+ return status;
+ }
+
+ // if the final node is a symlink, also resolve it
+ status = fsw_dnode_resolve(dno, &target_dno);
+ fsw_dnode_release(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+ return status;
+ }
+ dno = target_dno;
+
+ // check that it is a regular file
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return status;
+ }
+ if (dno->type != required_type) {
+ fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+ fsw_dnode_release(dno);
+ return FSW_UNSUPPORTED;
+ }
+
+ // open shandle
+ status = fsw_shandle_open(dno, shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+ }
+ fsw_dnode_release(dno);
+ return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+ // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+ struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+ off_t block_offset, seek_result;
+ ssize_t read_result;
+
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
+
+ // read from disk
+ block_offset = (off_t)phys_bno * vol->phys_blocksize;
+ seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+ if (seek_result != block_offset)
+ return FSW_IO_ERROR;
+ read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+ if (read_result != vol->phys_blocksize)
+ return FSW_IO_ERROR;
+
+ return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if (which == FSW_DNODE_STAT_CTIME)
+ fsw_posix_decode_time(&FileInfo->CreateTime, posix_time);
+ else if (which == FSW_DNODE_STAT_MTIME)
+ fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+ else if (which == FSW_DNODE_STAT_ATIME)
+ fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if ((posix_mode & S_IWUSR) == 0)
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ UINTN RequiredSize;
+ struct fsw_dnode_stat sb;
+
+ // make sure the dnode has complete info
+ Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // TODO: check/assert that the dno's name is in UTF16
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+ if (*BufferSize < RequiredSize) {
+ // TODO: wind back the directory in this case
+
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ ZeroMem(Buffer, RequiredSize);
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = RequiredSize;
+ FileInfo->FileSize = dno->size;
+ FileInfo->Attribute = 0;
+ if (dno->type == FSW_DNODE_TYPE_DIR)
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+ // get the missing info from the fs driver
+ ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+ sb.store_time_posix = fsw_posix_store_time_posix;
+ sb.store_attr_posix = fsw_posix_store_attr_posix;
+ sb.host_data = FileInfo;
+ Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FileInfo->PhysicalSize = sb.used_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ return EFI_SUCCESS;
+}
+*/
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+ struct fsw_volume *vol; //!< FSW volume structure
+
+ int fd; //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
--- /dev/null
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef signed char fsw_s8;
+typedef unsigned char fsw_u8;
+typedef short fsw_s16;
+typedef unsigned short fsw_u16;
+typedef long fsw_s32;
+typedef unsigned long fsw_u32;
+typedef long long fsw_s64;
+typedef unsigned long long fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC printf
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
--- /dev/null
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+ //&FSW_FSTYPE_TABLE_NAME(ext2),
+ //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+ &FSW_FSTYPE_TABLE_NAME(FSTYPE ),
+ NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+ struct fsw_posix_dir *dir;
+ struct dirent *dent;
+ int i;
+ char subpath[4096];
+
+ dir = fsw_posix_opendir(vol, path);
+ if (dir == NULL) {
+ printf("opendir(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ for (i = 0; i < level*2; i++)
+ fputc(' ', stdout);
+ printf("%d %s\n", dent->d_type, dent->d_name);
+
+ if (dent->d_type == DT_DIR) {
+ snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+ listdir(vol, subpath, level + 1);
+ }
+ }
+ fsw_posix_closedir(dir);
+
+ return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+ struct fsw_posix_file *file;
+ int r;
+ char buf[256];
+
+ file = fsw_posix_open(vol, path, 0, 0);
+ if (file == NULL) {
+ printf("open(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+ {
+ int i;
+ for (i=0; i<r; i++)
+ {
+ printf("%c", buf[i]);
+ }
+ }
+ fsw_posix_close(file);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ int i;
+
+ if (argc != 2) {
+ printf("Usage: lslr <file/device>\n");
+ return 1;
+ }
+
+ for (i = 0; fstypes[i]; i++) {
+ vol = fsw_posix_mount(argv[1], fstypes[i]);
+ if (vol != NULL) {
+ printf("Mounted as '%s'.\n", fstypes[i]->name.data);
+ break;
+ }
+ }
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+
+ //listdir(vol, "/System/Library/Extensions/udf.kext/", 0);
+ //listdir(vol, "/System/Library/Extensions/AppleACPIPlatform.kext/", 0);
+ //listdir(vol, "/System/Library/Extensions/", 0);
+ catfile(vol, "/System/Library/Extensions/AppleHPET.kext/Contents/Info.plist");
+ //listdir(vol, "/", 0);
+
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF
--- /dev/null
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ struct fsw_posix_dir *dir;
+ struct dirent *dent;
+
+ if (argc != 2) {
+ printf("Usage: lsroot <file/device>\n");
+ return 1;
+ }
+
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+ vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+ //dir = fsw_posix_opendir(vol, "/drivers/net/");
+ dir = fsw_posix_opendir(vol, "/");
+ if (dir == NULL) {
+ printf("opendir call failed.\n");
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ printf("- %s\n", dent->d_name);
+ }
+ fsw_posix_closedir(dir);
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF
--- /dev/null
+This folder contains tests for VBoxFsDxe module, allowing up
+and test filesystems without EFI environment and launching whole VBox.
--- /dev/null
+/**
+ * \file fsw_posix.c
+ * POSIX user space host environment code.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+#ifndef FSTYPE
+/** The file system type name to use. */
+#define FSTYPE ext2
+#endif
+
+
+// function prototypes
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type,
+ struct fsw_shandle *shand);
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize);
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer);
+
+/**
+ * Dispatch table for our FSW host driver.
+ */
+
+struct fsw_host_table fsw_posix_host_table = {
+ FSW_STRING_TYPE_ISO88591,
+
+ fsw_posix_change_blocksize,
+ fsw_posix_read_block
+};
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+
+/**
+ * Mount function.
+ */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table)
+{
+ fsw_status_t status;
+ struct fsw_posix_volume *pvol;
+
+ // allocate volume structure
+ status = fsw_alloc_zero(sizeof(struct fsw_posix_volume), (void **)&pvol);
+ if (status)
+ return NULL;
+ pvol->fd = -1;
+
+ // open underlying file/device
+ pvol->fd = open(path, O_RDONLY, 0);
+ if (pvol->fd < 0) {
+ fprintf(stderr, "fsw_posix_mount: %s: %s\n", path, strerror(errno));
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ // mount the filesystem
+ if (fstype_table == NULL)
+ fstype_table = &FSW_FSTYPE_TABLE_NAME(FSTYPE);
+ status = fsw_mount(pvol, &fsw_posix_host_table, fstype_table, &pvol->vol);
+ if (status) {
+ fprintf(stderr, "fsw_posix_mount: fsw_mount returned %d\n", status);
+ fsw_free(pvol);
+ return NULL;
+ }
+
+ return pvol;
+}
+
+/**
+ * Unmount function.
+ */
+
+int fsw_posix_unmount(struct fsw_posix_volume *pvol)
+{
+ if (pvol->vol != NULL)
+ fsw_unmount(pvol->vol);
+ fsw_free(pvol);
+ return 0;
+}
+
+/**
+ * Open a named regular file.
+ */
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode)
+{
+ fsw_status_t status;
+ struct fsw_posix_file *file;
+
+ // TODO: check flags for unwanted values
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_file), &file);
+ if (status)
+ return NULL;
+ file->pvol = pvol;
+
+ // open the file
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_FILE, &file->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open: open_dno returned %d\n", status);
+ fsw_free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+/**
+ * Read data from a regular file.
+ */
+
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes)
+{
+ fsw_status_t status;
+ fsw_u32 buffer_size;
+
+ buffer_size = nbytes;
+ status = fsw_shandle_read(&file->shand, &buffer_size, buf);
+ if (status)
+ return -1;
+ return buffer_size;
+}
+
+/**
+ * Change position within a regular file.
+ */
+
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence)
+{
+ fsw_u64 base_offset = 0;
+
+ // get base offset
+ base_offset = 0;
+ if (whence == SEEK_CUR)
+ base_offset = file->shand.pos;
+ else if (whence == SEEK_END)
+ base_offset = file->shand.dnode->size;
+
+ // calculate new offset, prevent seeks before the start of the file
+ if (offset < 0 && -offset > base_offset)
+ file->shand.pos = 0;
+ else
+ file->shand.pos = base_offset + offset;
+
+ return file->shand.pos;
+}
+
+/**
+ * Close a regular file.
+ */
+
+int fsw_posix_close(struct fsw_posix_file *file)
+{
+ fsw_shandle_close(&file->shand);
+ fsw_free(file);
+ return 0;
+}
+
+/**
+ * Open a directory for iteration.
+ */
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path)
+{
+ fsw_status_t status;
+ struct fsw_posix_dir *dir;
+
+ // allocate file structure
+ status = fsw_alloc(sizeof(struct fsw_posix_dir), &dir);
+ if (status)
+ return NULL;
+ dir->pvol = pvol;
+
+ // open the directory
+ status = fsw_posix_open_dno(pvol, path, FSW_DNODE_TYPE_DIR, &dir->shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_opendir: open_dno returned %d\n", status);
+ fsw_free(dir);
+ return NULL;
+ }
+
+ return dir;
+}
+
+/**
+ * Read the next entry from a directory.
+ */
+
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ static struct dirent dent;
+
+ // get next entry from file system
+ status = fsw_dnode_dir_read(&dir->shand, &dno);
+ if (status) {
+ if (status != 4)
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_dir_read returned %d\n", status);
+ return NULL;
+ }
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_readdir: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return NULL;
+ }
+
+ // fill dirent structure
+ dent.d_fileno = dno->dnode_id;
+ dent.d_reclen = 8 + dno->name.size + 1;
+ switch (dno->type) {
+ case FSW_DNODE_TYPE_FILE:
+ dent.d_type = DT_REG;
+ break;
+ case FSW_DNODE_TYPE_DIR:
+ dent.d_type = DT_DIR;
+ break;
+ case FSW_DNODE_TYPE_SYMLINK:
+ dent.d_type = DT_LNK;
+ break;
+ default:
+ dent.d_type = DT_UNKNOWN;
+ break;
+ }
+#if 0
+ dent.d_namlen = dno->name.size;
+#endif
+ memcpy(dent.d_name, dno->name.data, dno->name.size);
+ dent.d_name[dno->name.size] = 0;
+
+ return &dent;
+}
+
+/**
+ * Rewind a directory to the start.
+ */
+
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir)
+{
+ dir->shand.pos = 0;
+}
+
+/**
+ * Close a directory.
+ */
+
+int fsw_posix_closedir(struct fsw_posix_dir *dir)
+{
+ fsw_shandle_close(&dir->shand);
+ fsw_free(dir);
+ return 0;
+}
+
+/**
+ * Open a shand of a required type by path.
+ */
+
+fsw_status_t fsw_posix_open_dno(struct fsw_posix_volume *pvol, const char *path, int required_type, struct fsw_shandle *shand)
+{
+ fsw_status_t status;
+ struct fsw_dnode *dno;
+ struct fsw_dnode *target_dno;
+ struct fsw_string lookup_path;
+
+ lookup_path.type = FSW_STRING_TYPE_ISO88591;
+ lookup_path.len = strlen(path);
+ lookup_path.size = lookup_path.len;
+ lookup_path.data = (void *)path;
+
+ // resolve the path (symlinks along the way are automatically resolved)
+ status = fsw_dnode_lookup_path(pvol->vol->root, &lookup_path, '/', &dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_lookup_path returned %d\n", status);
+ return status;
+ }
+
+ // if the final node is a symlink, also resolve it
+ status = fsw_dnode_resolve(dno, &target_dno);
+ fsw_dnode_release(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_resolve returned %d\n", status);
+ return status;
+ }
+ dno = target_dno;
+
+ // check that it is a regular file
+ status = fsw_dnode_fill(dno);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_dnode_fill returned %d\n", status);
+ fsw_dnode_release(dno);
+ return status;
+ }
+ if (dno->type != required_type) {
+ fprintf(stderr, "fsw_posix_open_dno: dnode is not of the requested type\n");
+ fsw_dnode_release(dno);
+ return FSW_UNSUPPORTED;
+ }
+
+ // open shandle
+ status = fsw_shandle_open(dno, shand);
+ if (status) {
+ fprintf(stderr, "fsw_posix_open_dno: fsw_shandle_open returned %d\n", status);
+ }
+ fsw_dnode_release(dno);
+ return status;
+}
+
+/**
+ * FSW interface function for block size changes. This function is called by the FSW core
+ * when the file system driver changes the block sizes for the volume.
+ */
+
+void fsw_posix_change_blocksize(struct fsw_volume *vol,
+ fsw_u32 old_phys_blocksize, fsw_u32 old_log_blocksize,
+ fsw_u32 new_phys_blocksize, fsw_u32 new_log_blocksize)
+{
+ // nothing to do
+}
+
+/**
+ * FSW interface function to read data blocks. This function is called by the FSW core
+ * to read a block of data from the device. The buffer is allocated by the core code.
+ */
+
+fsw_status_t fsw_posix_read_block(struct fsw_volume *vol, fsw_u32 phys_bno, void *buffer)
+{
+ struct fsw_posix_volume *pvol = (struct fsw_posix_volume *)vol->host_data;
+ off_t block_offset, seek_result;
+ ssize_t read_result;
+
+ FSW_MSG_DEBUGV((FSW_MSGSTR("fsw_posix_read_block: %d (%d)\n"), phys_bno, vol->phys_blocksize));
+
+ // read from disk
+ block_offset = (off_t)phys_bno * vol->phys_blocksize;
+ seek_result = lseek(pvol->fd, block_offset, SEEK_SET);
+ if (seek_result != block_offset)
+ return FSW_IO_ERROR;
+ read_result = read(pvol->fd, buffer, vol->phys_blocksize);
+ if (read_result != vol->phys_blocksize)
+ return FSW_IO_ERROR;
+
+ return FSW_SUCCESS;
+}
+
+
+/**
+ * Time mapping callback for the fsw_dnode_stat call. This function converts
+ * a Posix style timestamp into an EFI_TIME structure and writes it to the
+ * appropriate member of the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_time_posix(struct fsw_dnode_stat *sb, int which, fsw_u32 posix_time)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if (which == FSW_DNODE_STAT_CTIME)
+ fsw_posix_decode_time(&FileInfo->CreateTime, posix_time);
+ else if (which == FSW_DNODE_STAT_MTIME)
+ fsw_posix_decode_time(&FileInfo->ModificationTime, posix_time);
+ else if (which == FSW_DNODE_STAT_ATIME)
+ fsw_posix_decode_time(&FileInfo->LastAccessTime, posix_time);
+}
+*/
+
+/**
+ * Mode mapping callback for the fsw_dnode_stat call. This function looks at
+ * the Posix mode passed by the file system driver and makes appropriate
+ * adjustments to the EFI_FILE_INFO structure that we're filling.
+ */
+
+/*
+static void fsw_posix_store_attr_posix(struct fsw_dnode_stat *sb, fsw_u16 posix_mode)
+{
+ EFI_FILE_INFO *FileInfo = (EFI_FILE_INFO *)sb->host_data;
+
+ if ((posix_mode & S_IWUSR) == 0)
+ FileInfo->Attribute |= EFI_FILE_READ_ONLY;
+}
+*/
+
+/**
+ * Common function to fill an EFI_FILE_INFO with information about a dnode.
+ */
+
+/*
+EFI_STATUS fsw_posix_dnode_fill_FileInfo(IN FSW_VOLUME_DATA *Volume,
+ IN struct fsw_dnode *dno,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer)
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+ UINTN RequiredSize;
+ struct fsw_dnode_stat sb;
+
+ // make sure the dnode has complete info
+ Status = fsw_posix_map_status(fsw_dnode_fill(dno), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+
+ // TODO: check/assert that the dno's name is in UTF16
+
+ // check buffer size
+ RequiredSize = SIZE_OF_EFI_FILE_INFO + fsw_posix_strsize(&dno->name);
+ if (*BufferSize < RequiredSize) {
+ // TODO: wind back the directory in this case
+
+ *BufferSize = RequiredSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // fill structure
+ ZeroMem(Buffer, RequiredSize);
+ FileInfo = (EFI_FILE_INFO *)Buffer;
+ FileInfo->Size = RequiredSize;
+ FileInfo->FileSize = dno->size;
+ FileInfo->Attribute = 0;
+ if (dno->type == FSW_DNODE_TYPE_DIR)
+ FileInfo->Attribute |= EFI_FILE_DIRECTORY;
+ fsw_posix_strcpy(FileInfo->FileName, &dno->name);
+
+ // get the missing info from the fs driver
+ ZeroMem(&sb, sizeof(struct fsw_dnode_stat));
+ sb.store_time_posix = fsw_posix_store_time_posix;
+ sb.store_attr_posix = fsw_posix_store_attr_posix;
+ sb.host_data = FileInfo;
+ Status = fsw_posix_map_status(fsw_dnode_stat(dno, &sb), Volume);
+ if (EFI_ERROR(Status))
+ return Status;
+ FileInfo->PhysicalSize = sb.used_bytes;
+
+ // prepare for return
+ *BufferSize = RequiredSize;
+ return EFI_SUCCESS;
+}
+*/
+
+// EOF
--- /dev/null
+/**
+ * \file fsw_posix.h
+ * POSIX user space host environment header.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_H_
+#define _FSW_POSIX_H_
+
+#include "fsw_core.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dir.h>
+
+
+/**
+ * POSIX Host: Private per-volume structure.
+ */
+
+struct fsw_posix_volume {
+ struct fsw_volume *vol; //!< FSW volume structure
+
+ int fd; //!< System file descriptor for data access
+
+};
+
+/**
+ * POSIX Host: Private structure for an open file.
+ */
+
+struct fsw_posix_file {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+/**
+ * POSIX Host: Private structure for an open directory.
+ */
+
+struct fsw_posix_dir {
+ struct fsw_posix_volume *pvol; //!< POSIX host volume structure
+
+ struct fsw_shandle shand; //!< FSW handle for this file
+
+};
+
+
+/* functions */
+
+struct fsw_posix_volume * fsw_posix_mount(const char *path, struct fsw_fstype_table *fstype_table);
+int fsw_posix_unmount(struct fsw_posix_volume *pvol);
+
+struct fsw_posix_file * fsw_posix_open(struct fsw_posix_volume *pvol, const char *path, int flags, mode_t mode);
+ssize_t fsw_posix_read(struct fsw_posix_file *file, void *buf, size_t nbytes);
+off_t fsw_posix_lseek(struct fsw_posix_file *file, off_t offset, int whence);
+int fsw_posix_close(struct fsw_posix_file *file);
+
+struct fsw_posix_dir * fsw_posix_opendir(struct fsw_posix_volume *pvol, const char *path);
+struct dirent * fsw_posix_readdir(struct fsw_posix_dir *dir);
+void fsw_posix_rewinddir(struct fsw_posix_dir *dir);
+int fsw_posix_closedir(struct fsw_posix_dir *dir);
+
+
+#endif
--- /dev/null
+/**
+ * \file fsw_posix_base.h
+ * Base definitions for the POSIX user space host environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FSW_POSIX_BASE_H_
+#define _FSW_POSIX_BASE_H_
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FSW_LITTLE_ENDIAN (1)
+// TODO: use info from the headers to define FSW_LITTLE_ENDIAN or FSW_BIG_ENDIAN
+
+
+// types
+
+typedef signed char fsw_s8;
+typedef unsigned char fsw_u8;
+typedef short fsw_s16;
+typedef unsigned short fsw_u16;
+typedef long fsw_s32;
+typedef unsigned long fsw_u32;
+typedef long long fsw_s64;
+typedef unsigned long long fsw_u64;
+
+
+// allocation functions
+
+#define fsw_alloc(size, ptrptr) (((*(ptrptr) = malloc(size)) == NULL) ? FSW_OUT_OF_MEMORY : FSW_SUCCESS)
+#define fsw_free(ptr) free(ptr)
+
+// memory functions
+
+#define fsw_memzero(dest,size) memset(dest,0,size)
+#define fsw_memcpy(dest,src,size) memcpy(dest,src,size)
+#define fsw_memeq(p1,p2,size) (memcmp(p1,p2,size) == 0)
+
+// message printing
+
+#define FSW_MSGSTR(s) s
+#define FSW_MSGFUNC printf
+
+// 64-bit hooks
+
+#define FSW_U64_SHR(val,shiftbits) ((val) >> (shiftbits))
+#define FSW_U64_DIV(val,divisor) ((val) / (divisor))
+#define DEBUG(x)
+
+#define RShiftU64(val, shift) ((val) >> (shift))
+#define LShiftU64(val, shift) ((val) << (shift))
+
+#endif
--- /dev/null
+/**
+ * \file lslr.c
+ * Test program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+//extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(FSTYPE);
+
+static struct fsw_fstype_table *fstypes[] = {
+ //&FSW_FSTYPE_TABLE_NAME(ext2),
+ //&FSW_FSTYPE_TABLE_NAME(reiserfs),
+ &FSW_FSTYPE_TABLE_NAME(FSTYPE ),
+ NULL
+};
+
+static int listdir(struct fsw_posix_volume *vol, char *path, int level)
+{
+ struct fsw_posix_dir *dir;
+ struct dirent *dent;
+ int i;
+ char subpath[4096];
+
+ dir = fsw_posix_opendir(vol, path);
+ if (dir == NULL) {
+ printf("opendir(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ for (i = 0; i < level*2; i++)
+ fputc(' ', stdout);
+ printf("%d %s\n", dent->d_type, dent->d_name);
+
+ if (dent->d_type == DT_DIR) {
+ snprintf(subpath, 4095, "%s%s/", path, dent->d_name);
+ listdir(vol, subpath, level + 1);
+ }
+ }
+ fsw_posix_closedir(dir);
+
+ return 0;
+}
+
+static int catfile(struct fsw_posix_volume *vol, char *path)
+{
+ struct fsw_posix_file *file;
+ int r;
+ char buf[256];
+
+ file = fsw_posix_open(vol, path, 0, 0);
+ if (file == NULL) {
+ printf("open(%s) call failed.\n", path);
+ return 1;
+ }
+ while ((r=fsw_posix_read(file, buf, sizeof(buf))) > 0)
+ {
+ int i;
+ for (i=0; i<r; i++)
+ {
+ printf("%c", buf[i]);
+ }
+ }
+ fsw_posix_close(file);
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ int i;
+
+ if (argc != 2) {
+ printf("Usage: lslr <file/device>\n");
+ return 1;
+ }
+
+ for (i = 0; fstypes[i]; i++) {
+ vol = fsw_posix_mount(argv[1], fstypes[i]);
+ if (vol != NULL) {
+ printf("Mounted as '%s'.\n", fstypes[i]->name.data);
+ break;
+ }
+ }
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+
+ //listdir(vol, "/System/Library/Extensions/udf.kext/", 0);
+ //listdir(vol, "/System/Library/Extensions/AppleACPIPlatform.kext/", 0);
+ //listdir(vol, "/System/Library/Extensions/", 0);
+ catfile(vol, "/System/Library/Extensions/AppleHPET.kext/Contents/Info.plist");
+ //listdir(vol, "/", 0);
+
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF
--- /dev/null
+/**
+ * \file lsroot.c
+ * Example program for the POSIX user space environment.
+ */
+
+/*-
+ * Copyright (c) 2006 Christoph Pfisterer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ *
+ * * Neither the name of Christoph Pfisterer nor the names of the
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fsw_posix.h"
+
+
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(ext2);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(reiserfs);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(iso9660);
+extern struct fsw_fstype_table FSW_FSTYPE_TABLE_NAME(hfs);
+
+int main(int argc, char **argv)
+{
+ struct fsw_posix_volume *vol;
+ struct fsw_posix_dir *dir;
+ struct dirent *dent;
+
+ if (argc != 2) {
+ printf("Usage: lsroot <file/device>\n");
+ return 1;
+ }
+
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(ext2));
+ //vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(reiserfs));
+ vol = fsw_posix_mount(argv[1], &FSW_FSTYPE_TABLE_NAME(FSTYPE));
+ if (vol == NULL) {
+ printf("Mounting failed.\n");
+ return 1;
+ }
+ //dir = fsw_posix_opendir(vol, "/drivers/net/");
+ dir = fsw_posix_opendir(vol, "/");
+ if (dir == NULL) {
+ printf("opendir call failed.\n");
+ return 1;
+ }
+ while ((dent = fsw_posix_readdir(dir)) != NULL) {
+ printf("- %s\n", dent->d_name);
+ }
+ fsw_posix_closedir(dir);
+ fsw_posix_unmount(vol);
+
+ return 0;
+}
+
+// EOF